From 23c1d4c66d81b6092a437e06386b53216dd4444c Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 2 Mar 2016 14:32:43 +0100 Subject: [PATCH] libc, vfs: rename improvements Perform POSIX rename checks at the libc VFS plugin. Clarify rename at VFS fs, ram, single, and tar file systems. Issue #1900 Fixes #1782 --- repos/libports/src/lib/libc/vfs_plugin.cc | 18 ++++++++++ repos/os/include/vfs/fs_file_system.h | 3 ++ repos/os/include/vfs/ram_file_system.h | 42 +++++++++++++--------- repos/os/include/vfs/single_file_system.h | 8 +++-- repos/os/include/vfs/symlink_file_system.h | 8 +++-- repos/os/include/vfs/tar_file_system.h | 6 ++-- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index 4a1117f9a..c40cc09a9 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -775,6 +775,24 @@ int Libc::Vfs_plugin::rename(char const *from_path, char const *to_path) { typedef Vfs::Directory_service::Rename_result Result; + if (_root_dir.leaf_path(to_path)) { + + if (_root_dir.is_directory(to_path)) { + if (!_root_dir.is_directory(from_path)) { + errno = EISDIR; return -1; + } + + if (_root_dir.num_dirent(to_path)) { + errno = ENOTEMPTY; return -1; + } + + } else { + if (_root_dir.is_directory(from_path)) { + errno = ENOTDIR; return -1; + } + } + } + switch (_root_dir.rename(from_path, to_path)) { case Result::RENAME_ERR_NO_ENTRY: errno = ENOENT; return -1; case Result::RENAME_ERR_CROSS_FS: errno = EXDEV; return -1; diff --git a/repos/os/include/vfs/fs_file_system.h b/repos/os/include/vfs/fs_file_system.h index b722507ba..b51c5d2d1 100644 --- a/repos/os/include/vfs/fs_file_system.h +++ b/repos/os/include/vfs/fs_file_system.h @@ -387,6 +387,9 @@ class Vfs::Fs_file_system : public File_system Rename_result rename(char const *from_path, char const *to_path) override { + if ((strcmp(from_path, to_path) == 0) && leaf_path(from_path)) + return RENAME_OK; + Absolute_path from_dir_path(from_path); from_dir_path.strip_last_element(); from_dir_path.remove_trailing('/'); diff --git a/repos/os/include/vfs/ram_file_system.h b/repos/os/include/vfs/ram_file_system.h index 7c7bd0bdf..c22c5ec14 100644 --- a/repos/os/include/vfs/ram_file_system.h +++ b/repos/os/include/vfs/ram_file_system.h @@ -353,7 +353,7 @@ class Vfs::Ram_file_system : public Vfs::File_system Directory *dir = &_root; char *name = &buf[0]; - for (size_t i = 0; i < MAX_NAME_LEN; ++i) { + for (size_t i = 0; i < MAX_PATH_LEN; ++i) { if (buf[i] == '/') { buf[i] = '\0'; @@ -498,6 +498,7 @@ class Vfs::Ram_file_system : public Vfs::File_system return STAT_OK; } + /* this should never happen */ return STAT_ERR_NO_ENTRY; } @@ -575,6 +576,9 @@ class Vfs::Ram_file_system : public Vfs::File_system { using namespace Vfs_ram; + if ((strcmp(from, to) == 0) && lookup(from)) + return RENAME_OK; + char const *new_name = basename(to); if (strlen(new_name) >= MAX_NAME_LEN) return RENAME_ERR_NO_PERM; @@ -586,28 +590,32 @@ class Vfs::Ram_file_system : public Vfs::File_system Directory *to_dir = lookup_parent(to); if (!to_dir) return RENAME_ERR_NO_ENTRY; - if (from_dir == to_dir) { + /* unlock the node so a second guard can be constructed */ + if (from_dir == to_dir) + from_dir->unlock(); - Node *node = from_dir->child(basename(from)); - if (!node) return RENAME_ERR_NO_ENTRY; - Node::Guard guard(node); + Node::Guard to_guard(to_dir); - if (from_dir->child(new_name)) return RENAME_ERR_NO_PERM; - node->name(new_name); + Node *from_node = from_dir->child(basename(from)); + if (!from_node) return RENAME_ERR_NO_ENTRY; + Node::Guard guard(from_node); - } else { + Node *to_node = to_dir->child(new_name); + if (to_node) { + to_node->lock(); - Node::Guard toguard(to_dir); + if (Directory *dir = dynamic_cast(to_node)) + if (dir->length() || (!dynamic_cast(from_node))) + return RENAME_ERR_NO_PERM; - if (to_dir->child(new_name)) return RENAME_ERR_NO_PERM; - - Node *node = from_dir->child(basename(from)); - if (!node) return RENAME_ERR_NO_ENTRY; - - node->name(new_name); - to_dir->adopt(node); - from_dir->release(node); + to_dir->release(to_node); + destroy(_alloc, to_node); } + + from_dir->release(from_node); + from_node->name(new_name); + to_dir->adopt(from_node); + return RENAME_OK; } diff --git a/repos/os/include/vfs/single_file_system.h b/repos/os/include/vfs/single_file_system.h index 6ffcf98fe..b2f5178bb 100644 --- a/repos/os/include/vfs/single_file_system.h +++ b/repos/os/include/vfs/single_file_system.h @@ -124,7 +124,7 @@ class Vfs::Single_file_system : public File_system char const *leaf_path(char const *path) override { - return path; + return _is_single_file(path) ? path : 0; } Open_result open(char const *path, unsigned, @@ -148,9 +148,11 @@ class Vfs::Single_file_system : public File_system return READLINK_ERR_NO_ENTRY; } - Rename_result rename(char const *, char const *) override + Rename_result rename(char const *from, char const *to) override { - return RENAME_ERR_NO_PERM; + if (_is_single_file(from) || _is_single_file(to)) + return RENAME_ERR_NO_PERM; + return RENAME_ERR_NO_ENTRY; } Mkdir_result mkdir(char const *, unsigned) override diff --git a/repos/os/include/vfs/symlink_file_system.h b/repos/os/include/vfs/symlink_file_system.h index 845216b11..82e248c72 100644 --- a/repos/os/include/vfs/symlink_file_system.h +++ b/repos/os/include/vfs/symlink_file_system.h @@ -138,8 +138,12 @@ class Vfs::Symlink_file_system : public File_system Unlink_result unlink(char const *) override { return UNLINK_ERR_NO_PERM; } - Rename_result rename(char const *, char const *) override { - return RENAME_ERR_NO_PERM; } + Rename_result rename(char const *from, char const *to) override + { + if (_is_single_file(from) || _is_single_file(to)) + return RENAME_ERR_NO_PERM; + return RENAME_ERR_NO_ENTRY; + } Mkdir_result mkdir(char const *, unsigned) override { return MKDIR_ERR_NO_PERM; } diff --git a/repos/os/include/vfs/tar_file_system.h b/repos/os/include/vfs/tar_file_system.h index 764bb1cc4..fa37287a2 100644 --- a/repos/os/include/vfs/tar_file_system.h +++ b/repos/os/include/vfs/tar_file_system.h @@ -528,9 +528,11 @@ class Vfs::Tar_file_system : public File_system return READLINK_OK; } - Rename_result rename(char const *, char const *) override + Rename_result rename(char const *from, char const *to) override { - return RENAME_ERR_NO_PERM; + if (_root_node.lookup(from) || _root_node.lookup(to)) + return RENAME_ERR_NO_PERM; + return RENAME_ERR_NO_ENTRY; } Mkdir_result mkdir(char const *, unsigned) override