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
This commit is contained in:
Emery Hemingway 2016-03-02 14:32:43 +01:00 committed by Christian Helmuth
parent d0735b1734
commit 23c1d4c66d
6 changed files with 61 additions and 24 deletions

View File

@ -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;

View File

@ -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('/');

View File

@ -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<Directory*>(to_node))
if (dir->length() || (!dynamic_cast<Directory*>(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;
}

View File

@ -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

View File

@ -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; }

View File

@ -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