# HG changeset patch # User Paul Boddie # Date 1645123283 -3600 # Node ID b8f26cc013ed441de6ad022daebd065cbfcb3717 # Parent 8145967ef0123ba1c2475f3fd07da4811a1ea6b1 Introduced empty directory testing. diff -r 8145967ef012 -r b8f26cc013ed libfsserver/include/fsserver/ext2_file_opener.h --- a/libfsserver/include/fsserver/ext2_file_opener.h Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/include/fsserver/ext2_file_opener.h Thu Feb 17 19:41:23 2022 +0100 @@ -44,6 +44,8 @@ virtual bool accessing_file(flags_t flags, fileid_t fileid); + virtual bool directory_is_empty(fileid_t fileid); + public: explicit Ext2FileOpener(ResourceRegistry *registry, Ext2FileOperations *ops, user_t user) : OpenerResource(registry), _ops(ops), _user(user) diff -r 8145967ef012 -r b8f26cc013ed libfsserver/include/fsserver/ext2_file_operations.h --- a/libfsserver/include/fsserver/ext2_file_operations.h Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/include/fsserver/ext2_file_operations.h Thu Feb 17 19:41:23 2022 +0100 @@ -61,6 +61,8 @@ bool can_access(user_t user, flags_t flags, ext2_ino_t ino); + bool directory_is_empty(ext2_ino_t ino); + bool is_directory(ext2_ino_t ino_file); bool is_file(ext2_ino_t ino_file); diff -r 8145967ef012 -r b8f26cc013ed libfsserver/include/fsserver/file_opening.h --- a/libfsserver/include/fsserver/file_opening.h Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/include/fsserver/file_opening.h Thu Feb 17 19:41:23 2022 +0100 @@ -35,6 +35,8 @@ virtual bool accessing_file(flags_t flags, fileid_t fileid) = 0; + virtual bool directory_is_empty(fileid_t fileid) = 0; + virtual long get_fileid(const char *path, flags_t flags, fileid_t *fileid) = 0; virtual long get_parent(const char *path, fileid_t *fileid); diff -r 8145967ef012 -r b8f26cc013ed libfsserver/include/fsserver/host_file_opener.h --- a/libfsserver/include/fsserver/host_file_opener.h Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/include/fsserver/host_file_opener.h Thu Feb 17 19:41:23 2022 +0100 @@ -58,6 +58,8 @@ virtual bool accessing_file(flags_t flags, fileid_t fileid); + virtual bool directory_is_empty(fileid_t fileid); + public: explicit HostFileOpener(ResourceRegistry *registry) : OpenerResource(registry) diff -r 8145967ef012 -r b8f26cc013ed libfsserver/include/fsserver/test_file_opener.h --- a/libfsserver/include/fsserver/test_file_opener.h Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/include/fsserver/test_file_opener.h Thu Feb 17 19:41:23 2022 +0100 @@ -38,6 +38,8 @@ virtual bool accessing_file(flags_t flags, fileid_t fileid); + virtual bool directory_is_empty(fileid_t fileid); + public: explicit TestFileOpener(ResourceRegistry *registry, offset_t file_size=0); diff -r 8145967ef012 -r b8f26cc013ed libfsserver/lib/files/ext2_file_opener.cc --- a/libfsserver/lib/files/ext2_file_opener.cc Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/lib/files/ext2_file_opener.cc Thu Feb 17 19:41:23 2022 +0100 @@ -52,6 +52,13 @@ return _ops->is_file((ext2_ino_t) fileid); } +/* Test if a directory is empty. */ + +bool Ext2FileOpener::directory_is_empty(fileid_t fileid) +{ + return _ops->directory_is_empty(fileid); +} + /* Return a file identifier for the given 'path'. */ long Ext2FileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid) diff -r 8145967ef012 -r b8f26cc013ed libfsserver/lib/files/ext2_file_operations.cc --- a/libfsserver/lib/files/ext2_file_operations.cc Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/lib/files/ext2_file_operations.cc Thu Feb 17 19:41:23 2022 +0100 @@ -44,6 +44,17 @@ return access_can_read(user, &inode); } +/* Assert that a directory is empty. */ + +bool Ext2FileOperations::directory_is_empty(ext2_ino_t ino) +{ + std::lock_guard guard(_lock); + + return !image_dir_empty_by_inode(_fs, ino); +} + +/* Test for a directory. */ + bool Ext2FileOperations::is_directory(ext2_ino_t ino_file) { std::lock_guard guard(_lock); @@ -51,6 +62,8 @@ return _image_isdir(_fs, ino_file); } +/* Test for a file. */ + bool Ext2FileOperations::is_file(ext2_ino_t ino_file) { std::lock_guard guard(_lock); diff -r 8145967ef012 -r b8f26cc013ed libfsserver/lib/files/host_file_opener.cc --- a/libfsserver/lib/files/host_file_opener.cc Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/lib/files/host_file_opener.cc Thu Feb 17 19:41:23 2022 +0100 @@ -19,7 +19,9 @@ * Boston, MA 02110-1301, USA */ +#include #include +#include #include #include @@ -69,6 +71,34 @@ return (st.st_mode & S_IFREG) ? true : false; } +/* Test if a directory is empty. */ + +bool HostFileOpener::directory_is_empty(fileid_t fileid) +{ + const char *path = _get_path(fileid); + + if (path == NULL) + return false; + + DIR *dir = opendir(path); + struct dirent *entry; + + if (dir == NULL) + return false; + + while ((entry = readdir(dir)) != NULL) + { + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) + { + closedir(dir); + return false; + } + } + + closedir(dir); + return true; +} + /* Return a file identifier for the given 'path'. */ long HostFileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid) diff -r 8145967ef012 -r b8f26cc013ed libfsserver/lib/files/test_file_opener.cc --- a/libfsserver/lib/files/test_file_opener.cc Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/lib/files/test_file_opener.cc Thu Feb 17 19:41:23 2022 +0100 @@ -47,6 +47,14 @@ return true; } +/* Test if a directory is empty. */ + +bool TestFileOpener::directory_is_empty(fileid_t fileid) +{ + (void) fileid; + return false; +} + /* Return a file identifier for the given 'path'. */ long TestFileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid) diff -r 8145967ef012 -r b8f26cc013ed libfsserver/lib/generic/resource_registry.cc --- a/libfsserver/lib/generic/resource_registry.cc Thu Feb 17 00:37:13 2022 +0100 +++ b/libfsserver/lib/generic/resource_registry.cc Thu Feb 17 19:41:23 2022 +0100 @@ -207,6 +207,12 @@ if (err) return err; + /* Test for an empty directory. + NOTE: A descriptive error should be communicated. */ + + if (opening->accessing_directory(0, fileid) && !opening->directory_is_empty(fileid)) + return -L4_EIO; + /* Unlink the object regardless of whether it will be removed. */ err = opening->unlink_object(parent_fileid, fileid);