1.1 --- a/libfsserver/include/fsserver/ext2_file_opener.h Thu Feb 17 00:37:13 2022 +0100 1.2 +++ b/libfsserver/include/fsserver/ext2_file_opener.h Thu Feb 17 19:41:23 2022 +0100 1.3 @@ -44,6 +44,8 @@ 1.4 1.5 virtual bool accessing_file(flags_t flags, fileid_t fileid); 1.6 1.7 + virtual bool directory_is_empty(fileid_t fileid); 1.8 + 1.9 public: 1.10 explicit Ext2FileOpener(ResourceRegistry *registry, Ext2FileOperations *ops, user_t user) 1.11 : OpenerResource(registry), _ops(ops), _user(user)
2.1 --- a/libfsserver/include/fsserver/ext2_file_operations.h Thu Feb 17 00:37:13 2022 +0100 2.2 +++ b/libfsserver/include/fsserver/ext2_file_operations.h Thu Feb 17 19:41:23 2022 +0100 2.3 @@ -61,6 +61,8 @@ 2.4 2.5 bool can_access(user_t user, flags_t flags, ext2_ino_t ino); 2.6 2.7 + bool directory_is_empty(ext2_ino_t ino); 2.8 + 2.9 bool is_directory(ext2_ino_t ino_file); 2.10 2.11 bool is_file(ext2_ino_t ino_file);
3.1 --- a/libfsserver/include/fsserver/file_opening.h Thu Feb 17 00:37:13 2022 +0100 3.2 +++ b/libfsserver/include/fsserver/file_opening.h Thu Feb 17 19:41:23 2022 +0100 3.3 @@ -35,6 +35,8 @@ 3.4 3.5 virtual bool accessing_file(flags_t flags, fileid_t fileid) = 0; 3.6 3.7 + virtual bool directory_is_empty(fileid_t fileid) = 0; 3.8 + 3.9 virtual long get_fileid(const char *path, flags_t flags, fileid_t *fileid) = 0; 3.10 3.11 virtual long get_parent(const char *path, fileid_t *fileid);
4.1 --- a/libfsserver/include/fsserver/host_file_opener.h Thu Feb 17 00:37:13 2022 +0100 4.2 +++ b/libfsserver/include/fsserver/host_file_opener.h Thu Feb 17 19:41:23 2022 +0100 4.3 @@ -58,6 +58,8 @@ 4.4 4.5 virtual bool accessing_file(flags_t flags, fileid_t fileid); 4.6 4.7 + virtual bool directory_is_empty(fileid_t fileid); 4.8 + 4.9 public: 4.10 explicit HostFileOpener(ResourceRegistry *registry) 4.11 : OpenerResource(registry)
5.1 --- a/libfsserver/include/fsserver/test_file_opener.h Thu Feb 17 00:37:13 2022 +0100 5.2 +++ b/libfsserver/include/fsserver/test_file_opener.h Thu Feb 17 19:41:23 2022 +0100 5.3 @@ -38,6 +38,8 @@ 5.4 5.5 virtual bool accessing_file(flags_t flags, fileid_t fileid); 5.6 5.7 + virtual bool directory_is_empty(fileid_t fileid); 5.8 + 5.9 public: 5.10 explicit TestFileOpener(ResourceRegistry *registry, offset_t file_size=0); 5.11
6.1 --- a/libfsserver/lib/files/ext2_file_opener.cc Thu Feb 17 00:37:13 2022 +0100 6.2 +++ b/libfsserver/lib/files/ext2_file_opener.cc Thu Feb 17 19:41:23 2022 +0100 6.3 @@ -52,6 +52,13 @@ 6.4 return _ops->is_file((ext2_ino_t) fileid); 6.5 } 6.6 6.7 +/* Test if a directory is empty. */ 6.8 + 6.9 +bool Ext2FileOpener::directory_is_empty(fileid_t fileid) 6.10 +{ 6.11 + return _ops->directory_is_empty(fileid); 6.12 +} 6.13 + 6.14 /* Return a file identifier for the given 'path'. */ 6.15 6.16 long Ext2FileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid)
7.1 --- a/libfsserver/lib/files/ext2_file_operations.cc Thu Feb 17 00:37:13 2022 +0100 7.2 +++ b/libfsserver/lib/files/ext2_file_operations.cc Thu Feb 17 19:41:23 2022 +0100 7.3 @@ -44,6 +44,17 @@ 7.4 return access_can_read(user, &inode); 7.5 } 7.6 7.7 +/* Assert that a directory is empty. */ 7.8 + 7.9 +bool Ext2FileOperations::directory_is_empty(ext2_ino_t ino) 7.10 +{ 7.11 + std::lock_guard<std::mutex> guard(_lock); 7.12 + 7.13 + return !image_dir_empty_by_inode(_fs, ino); 7.14 +} 7.15 + 7.16 +/* Test for a directory. */ 7.17 + 7.18 bool Ext2FileOperations::is_directory(ext2_ino_t ino_file) 7.19 { 7.20 std::lock_guard<std::mutex> guard(_lock); 7.21 @@ -51,6 +62,8 @@ 7.22 return _image_isdir(_fs, ino_file); 7.23 } 7.24 7.25 +/* Test for a file. */ 7.26 + 7.27 bool Ext2FileOperations::is_file(ext2_ino_t ino_file) 7.28 { 7.29 std::lock_guard<std::mutex> guard(_lock);
8.1 --- a/libfsserver/lib/files/host_file_opener.cc Thu Feb 17 00:37:13 2022 +0100 8.2 +++ b/libfsserver/lib/files/host_file_opener.cc Thu Feb 17 19:41:23 2022 +0100 8.3 @@ -19,7 +19,9 @@ 8.4 * Boston, MA 02110-1301, USA 8.5 */ 8.6 8.7 +#include <dirent.h> 8.8 #include <stdio.h> 8.9 +#include <string.h> 8.10 #include <sys/stat.h> 8.11 #include <unistd.h> 8.12 8.13 @@ -69,6 +71,34 @@ 8.14 return (st.st_mode & S_IFREG) ? true : false; 8.15 } 8.16 8.17 +/* Test if a directory is empty. */ 8.18 + 8.19 +bool HostFileOpener::directory_is_empty(fileid_t fileid) 8.20 +{ 8.21 + const char *path = _get_path(fileid); 8.22 + 8.23 + if (path == NULL) 8.24 + return false; 8.25 + 8.26 + DIR *dir = opendir(path); 8.27 + struct dirent *entry; 8.28 + 8.29 + if (dir == NULL) 8.30 + return false; 8.31 + 8.32 + while ((entry = readdir(dir)) != NULL) 8.33 + { 8.34 + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) 8.35 + { 8.36 + closedir(dir); 8.37 + return false; 8.38 + } 8.39 + } 8.40 + 8.41 + closedir(dir); 8.42 + return true; 8.43 +} 8.44 + 8.45 /* Return a file identifier for the given 'path'. */ 8.46 8.47 long HostFileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid)
9.1 --- a/libfsserver/lib/files/test_file_opener.cc Thu Feb 17 00:37:13 2022 +0100 9.2 +++ b/libfsserver/lib/files/test_file_opener.cc Thu Feb 17 19:41:23 2022 +0100 9.3 @@ -47,6 +47,14 @@ 9.4 return true; 9.5 } 9.6 9.7 +/* Test if a directory is empty. */ 9.8 + 9.9 +bool TestFileOpener::directory_is_empty(fileid_t fileid) 9.10 +{ 9.11 + (void) fileid; 9.12 + return false; 9.13 +} 9.14 + 9.15 /* Return a file identifier for the given 'path'. */ 9.16 9.17 long TestFileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid)
10.1 --- a/libfsserver/lib/generic/resource_registry.cc Thu Feb 17 00:37:13 2022 +0100 10.2 +++ b/libfsserver/lib/generic/resource_registry.cc Thu Feb 17 19:41:23 2022 +0100 10.3 @@ -207,6 +207,12 @@ 10.4 if (err) 10.5 return err; 10.6 10.7 + /* Test for an empty directory. 10.8 + NOTE: A descriptive error should be communicated. */ 10.9 + 10.10 + if (opening->accessing_directory(0, fileid) && !opening->directory_is_empty(fileid)) 10.11 + return -L4_EIO; 10.12 + 10.13 /* Unlink the object regardless of whether it will be removed. */ 10.14 10.15 err = opening->unlink_object(parent_fileid, fileid);