# HG changeset patch # User Paul Boddie # Date 1646261622 -3600 # Node ID f488a98bcc342cabc8a6b0eca45da5c2c8227f22 # Parent ee7ee27c8a97b9468e47fa29a1d51a14e7b18e2e Added mkdir operation support. diff -r ee7ee27c8a97 -r f488a98bcc34 conf/dstest_file_rename.cfg --- a/conf/dstest_file_rename.cfg Wed Mar 02 23:23:37 2022 +0100 +++ b/conf/dstest_file_rename.cfg Wed Mar 02 23:53:42 2022 +0100 @@ -48,4 +48,4 @@ log = { "client", "g" }, }, -- program, directory to read - "rom/dstest_file_rename", "home/paulb/many"); + "rom/dstest_file_rename", "home/paulb/many", "home/paulb/new"); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsclient/include/fsclient/client.h --- a/libfsclient/include/fsclient/client.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsclient/include/fsclient/client.h Wed Mar 02 23:53:42 2022 +0100 @@ -49,6 +49,9 @@ /* Other file operations. */ +long client_mkdir(const char *path, mode_t mode); +long client_mkdir_using(const char *path, mode_t mode, l4_cap_idx_t server); + long client_remove(const char *path); long client_remove_using(const char *path, l4_cap_idx_t server); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsclient/include/fsclient/file.h --- a/libfsclient/include/fsclient/file.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsclient/include/fsclient/file.h Wed Mar 02 23:53:42 2022 +0100 @@ -85,6 +85,7 @@ /* File operations. */ void file_close(file_t *file); +long file_mkdir(const char *filename, mode_t mode, l4_cap_idx_t server); long file_open(file_t *file, const char *filename, flags_t flags, l4_cap_idx_t server); long file_remove(const char *filename, l4_cap_idx_t server); long file_rename(const char *source, const char *target, l4_cap_idx_t server); @@ -93,6 +94,7 @@ /* File lifecycle operations. */ long file_context(file_t *file, l4_cap_idx_t server); +long file_context_mkdir(mode_t mode, file_t *context); long file_context_open(file_t *file, flags_t flags, file_t *context); long file_context_remove(file_t *context); long file_context_rename(file_t *context); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsclient/lib/src/client.cc --- a/libfsclient/lib/src/client.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsclient/lib/src/client.cc Wed Mar 02 23:53:42 2022 +0100 @@ -359,6 +359,24 @@ +/* Make a directory in the filesystem. */ + +long client_mkdir(const char *path, mode_t mode) +{ + l4_cap_idx_t server = l4re_env_get_cap("server"); + + return client_mkdir_using(path, mode, server); +} + +/* Make a directory in the filesystem via a named capability. */ + +long client_mkdir_using(const char *path, mode_t mode, l4_cap_idx_t server) +{ + return file_mkdir(path, mode, server); +} + + + /* Remove a file from the filesystem. */ long client_remove(const char *path) diff -r ee7ee27c8a97 -r f488a98bcc34 libfsclient/lib/src/file.cc --- a/libfsclient/lib/src/file.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsclient/lib/src/file.cc Wed Mar 02 23:53:42 2022 +0100 @@ -113,6 +113,30 @@ file_init(file); } +/* Make a directory in the filesystem. This is a convenience function invoking + file_context and file_context_mkdir. */ + +long file_mkdir(const char *filename, mode_t mode, l4_cap_idx_t server) +{ + file_t context; + long err; + + err = file_context(&context, server); + if (err) + return err; + + if (!file_string_set(&context, filename, 0, NULL)) + return -L4_ENOMEM; + + err = file_context_mkdir(systypes_to_sys_mode(mode), &context); + + /* Close the context, although a separate mechanism could permit contexts to + remove several files. */ + + file_close(&context); + return err; +} + /* Open a file using the given structure, indicating the filename and filesystem server. The file_mmap function should be used to obtain access to memory providing file data. This is a convenience function invoking @@ -249,6 +273,14 @@ return ipc_attach_dataspace(file->ref, size, (void **) &file->memory); } +/* Make a directory using the given context. */ + +long file_context_mkdir(mode_t mode, file_t *context) +{ + client_OpenerContext openercontext(context->ref); + return openercontext.mkdir(mode); +} + /* Open a file using the given structure and context. */ long file_context_open(file_t *file, flags_t flags, file_t *context) diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/include/fsserver/ext2_file_opener.h --- a/libfsserver/include/fsserver/ext2_file_opener.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/include/fsserver/ext2_file_opener.h Wed Mar 02 23:53:42 2022 +0100 @@ -66,6 +66,8 @@ /* Filesystem object access and manipulation methods. */ + virtual long make_directory_object(const char *path, sys_mode_t mode); + virtual long remove_object(fileid_t fileid); virtual long rename_object(const char *source, const char *target); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/include/fsserver/ext2_file_operations.h --- a/libfsserver/include/fsserver/ext2_file_operations.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/include/fsserver/ext2_file_operations.h Wed Mar 02 23:53:42 2022 +0100 @@ -78,6 +78,9 @@ long find_file(const char *path, ext2_ino_t *ino, const char **remaining); + long mkdir(ext2_ino_t ino_parent, const char *basename, sys_mode_t mode, + user_t user); + long open_file(ext2_ino_t ino, ext2_file_t *file); long remove(ext2_ino_t ino); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/include/fsserver/file_opening.h --- a/libfsserver/include/fsserver/file_opening.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/include/fsserver/file_opening.h Wed Mar 02 23:53:42 2022 +0100 @@ -49,6 +49,8 @@ /* Filesystem object access and manipulation methods. */ + virtual long make_directory_object(const char *path, sys_mode_t mode) = 0; + virtual long stat_object(const char *path, void *base, offset_t size) = 0; virtual long remove_object(fileid_t fileid) = 0; diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/include/fsserver/host_file_opener.h --- a/libfsserver/include/fsserver/host_file_opener.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/include/fsserver/host_file_opener.h Wed Mar 02 23:53:42 2022 +0100 @@ -80,6 +80,8 @@ /* Filesystem object access and manipulation methods. */ + virtual long make_directory_object(const char *path, sys_mode_t mode); + virtual long remove_object(fileid_t fileid); virtual long rename_object(const char *source, const char *target); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/include/fsserver/opener_context_resource.h --- a/libfsserver/include/fsserver/opener_context_resource.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/include/fsserver/opener_context_resource.h Wed Mar 02 23:53:42 2022 +0100 @@ -57,6 +57,8 @@ /* Opener context interface methods. */ + long mkdir(sys_mode_t mode); + long open(flags_t flags, offset_t *size, l4_cap_idx_t *file, object_flags_t *object_flags); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/include/fsserver/opener_resource.h --- a/libfsserver/include/fsserver/opener_resource.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/include/fsserver/opener_resource.h Wed Mar 02 23:53:42 2022 +0100 @@ -56,6 +56,8 @@ /* Direct access methods. */ + long mkdir(const char *path, sys_mode_t mode); + long open(const char *path, flags_t flags, offset_t *size, l4_cap_idx_t *cap, object_flags_t *object_flags); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/include/fsserver/test_file_opener.h --- a/libfsserver/include/fsserver/test_file_opener.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/include/fsserver/test_file_opener.h Wed Mar 02 23:53:42 2022 +0100 @@ -57,6 +57,8 @@ /* Filesystem object access and manipulation methods. */ + virtual long make_directory_object(const char *path, sys_mode_t mode); + virtual long remove_object(fileid_t fileid); virtual long rename_object(const char *source, const char *target); diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/lib/files/ext2_file_opener.cc --- a/libfsserver/lib/files/ext2_file_opener.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/lib/files/ext2_file_opener.cc Wed Mar 02 23:53:42 2022 +0100 @@ -132,6 +132,34 @@ +/* Make a new directory. */ + +long Ext2FileOpener::make_directory_object(const char *path, sys_mode_t mode) +{ + fileid_t fileid, parent; + long err; + + /* Test for an existing object. */ + + err = get_fileid(path, 0, &fileid); + + if (!err) + return -L4_EEXIST; + + if (err != -L4_ENOENT) + return err; + + /* Obtain the parent of the new directory. */ + + err = get_parent(path, &parent); + + if (err) + return err; + + return _ops->mkdir((ext2_ino_t) parent, path_basename(path), + systypes_from_sys_mode(mode), _user); +} + /* Remove a filesystem object. */ long Ext2FileOpener::remove_object(fileid_t fileid) diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/lib/files/ext2_file_operations.cc --- a/libfsserver/lib/files/ext2_file_operations.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/lib/files/ext2_file_operations.cc Wed Mar 02 23:53:42 2022 +0100 @@ -129,6 +129,34 @@ return L4_EOK; } +/* Make a new directory. */ + +long Ext2FileOperations::mkdir(ext2_ino_t ino_parent, const char *basename, + sys_mode_t mode, user_t user) +{ + std::lock_guard guard(_lock); + + ext2_ino_t ino; + errcode_t retval; + + /* Test for permission to create the directory. */ + + if (!can_access(user, O_WRONLY, ino_parent)) + return -L4_EPERM; + + /* Make the directory. */ + + retval = image_make_dir(_fs, ino_parent, basename, mode, user.uid, user.gid, + &ino); + + // NOTE: Map error conditions. + + if (retval) + return -L4_EIO; + + return L4_EOK; +} + /* Open the file associated with the indicated inode. */ long Ext2FileOperations::open_file(ext2_ino_t ino, ext2_file_t *file) diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/lib/files/host_file_opener.cc --- a/libfsserver/lib/files/host_file_opener.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/lib/files/host_file_opener.cc Wed Mar 02 23:53:42 2022 +0100 @@ -198,6 +198,31 @@ +/* Make a new directory. */ + +long HostFileOpener::make_directory_object(const char *path, sys_mode_t mode) +{ + int err = mkdir(path, systypes_from_sys_mode(mode)); + + // NOTE: Other return codes may need converting. + + switch (err) + { + case 0: break; + case EACCES: return -L4_EPERM; + case EEXIST: return -L4_EEXIST; + case ENOENT: return -L4_ENOENT; + default: return -L4_EIO; + } + + fileid_t fileid = _get_fileid(path, true); + + _fileids[path] = fileid; + _paths[fileid] = path; + + return L4_EOK; +} + /* Remove a filesystem object. */ long HostFileOpener::remove_object(fileid_t fileid) diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/lib/files/opener_context_resource.cc --- a/libfsserver/lib/files/opener_context_resource.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/lib/files/opener_context_resource.cc Wed Mar 02 23:53:42 2022 +0100 @@ -67,6 +67,16 @@ /* Opener context interface methods. */ +long OpenerContextResource::mkdir(sys_mode_t mode) +{ + char *path = get_path(); + + if (path == NULL) + return -L4_EINVAL; + + return _opener->mkdir(path, mode); +} + long OpenerContextResource::open(flags_t flags, offset_t *size, l4_cap_idx_t *file, object_flags_t *object_flags) { diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/lib/files/opener_resource.cc --- a/libfsserver/lib/files/opener_resource.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/lib/files/opener_resource.cc Wed Mar 02 23:53:42 2022 +0100 @@ -78,6 +78,13 @@ +/* Make a directory. */ + +long OpenerResource::mkdir(const char *path, sys_mode_t mode) +{ + return make_directory_object(path, mode); +} + /* Return an object for the given path and flags. */ long OpenerResource::open(const char *path, flags_t flags, offset_t *size, diff -r ee7ee27c8a97 -r f488a98bcc34 libfsserver/lib/files/test_file_opener.cc --- a/libfsserver/lib/files/test_file_opener.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/libfsserver/lib/files/test_file_opener.cc Wed Mar 02 23:53:42 2022 +0100 @@ -88,6 +88,14 @@ +/* Make a new directory. */ + +long TestFileOpener::make_directory_object(const char *path, sys_mode_t mode) +{ + (void) path; (void) mode; + return -L4_EIO; +} + /* Remove a filesystem object. */ long TestFileOpener::remove_object(fileid_t fileid) diff -r ee7ee27c8a97 -r f488a98bcc34 libsystypes/idl/opener_context.idl --- a/libsystypes/idl/opener_context.idl Wed Mar 02 23:23:37 2022 +0100 +++ b/libsystypes/idl/opener_context.idl Wed Mar 02 23:53:42 2022 +0100 @@ -15,6 +15,10 @@ [opcode(1)] void getfs(out cap fs); + /* Make a new directory given a path written to the context's dataspace. */ + + [opcode(18)] void mkdir(in sys_mode_t mode); + /* Obtain a file reference given a path written to the context's dataspace. */ [opcode(12)] void open(in flags_t flags, out offset_t size, out cap file, diff -r ee7ee27c8a97 -r f488a98bcc34 libsystypes/include/systypes/base.h --- a/libsystypes/include/systypes/base.h Wed Mar 02 23:23:37 2022 +0100 +++ b/libsystypes/include/systypes/base.h Wed Mar 02 23:53:42 2022 +0100 @@ -81,6 +81,14 @@ typedef long sys_blksize_t; /* input/output block size */ typedef long sys_blkcnt_t; /* number of 512-byte blocks */ +/* Conversions. */ + +#define systypes_from_sys_mode(mode) \ +((mode_t) mode) + +#define systypes_to_sys_mode(mode) \ +((sys_mode_t) mode) + /* Factory types for L4 factory interface invocations. */ ipc_varg_typedef(sys_mode_t, ipc_varg_sys_mode_t) diff -r ee7ee27c8a97 -r f488a98bcc34 tests/dstest_file_rename.cc --- a/tests/dstest_file_rename.cc Wed Mar 02 23:23:37 2022 +0100 +++ b/tests/dstest_file_rename.cc Wed Mar 02 23:53:42 2022 +0100 @@ -31,15 +31,52 @@ -int main(int argc, char *argv[]) +/* Show a directory's contents and determine if all expected files are + present. */ + +static int show_directory(const char *filename, int expected) { - if (argc < 2) + file_t *reader = client_opendir(filename); + + if (reader == NULL) { - printf("Need a directory name.\n"); + printf("Could not read from directory.\n"); return 1; } - char *filename = argv[1]; + printf("Reading...\n"); + + struct dirent *dirent; + int renamed = 0; + + while ((dirent = client_readdir(reader)) != NULL) + { + if (!strncmp(dirent->d_name, "renamed-", 8)) + renamed++; + + printf("> %s\n", dirent->d_name); + free(dirent); + } + + printf("Directory shown.\n"); + + printf("Renamed files: %d (%d)\n", renamed, expected); + + if (renamed != expected) + return 1; + + return 0; +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) + { + printf("Need a directory containing files and a new directory name.\n"); + return 1; + } + + char *filename = argv[1], *newdir = argv[2]; printf("Opening %s...\n", filename); @@ -68,13 +105,14 @@ char source[strlen(filename) + strlen("/file-XXXX.txt") + 10]; char target[strlen(filename) + strlen("/file-XXXX.txt") + 10]; int filenum, to_rename = 100; + long err; for (filenum = 1; filenum <= to_rename; filenum++) { sprintf(source, "%s/file-%d.txt", filename, filenum); sprintf(target, "%s/renamed-%d.txt", filename, filenum); - long err = client_rename(source, target); + err = client_rename(source, target); if (err) { @@ -85,6 +123,19 @@ /* Show the new listing. */ + if (show_directory(filename, to_rename)) + return 1; + + /* Create a directory and move files into it. */ + + err = client_mkdir(newdir, 0755); + + if (err) + { + printf("Could not make directory: %s\n", newdir); + return 1; + } + reader = client_opendir(filename); if (reader == NULL) @@ -93,22 +144,33 @@ return 1; } - printf("Reading...\n"); - - int renamed = 0; + printf("Renaming...\n"); while ((dirent = client_readdir(reader)) != NULL) { if (!strncmp(dirent->d_name, "renamed-", 8)) - renamed++; + { + sprintf(source, "%s/%s", filename, dirent->d_name); + sprintf(target, "%s/%s", newdir, dirent->d_name); + + err = client_rename(source, target); - printf("> %s\n", dirent->d_name); + if (err) + { + printf("Could not rename file: %s\n", source); + return 1; + } + } + free(dirent); } - printf("Directory shown.\n"); + /* Show the new directory's listing. */ - printf("Renamed files: %d (%d)\n", renamed, to_rename); + if (show_directory(newdir, to_rename)) + return 1; + + printf("End of tests.\n"); return 0; }