From 4053e1628bb476f2eafdc486f38fa57ee57527e1 Mon Sep 17 00:00:00 2001 From: Pirmin Duss Date: Tue, 23 Mar 2021 10:44:39 +0100 Subject: [PATCH] lx_fs: support for unlink This is based on the work of @ehmry and @sidhussmann. Issue #4070 --- repos/base-linux/run/lx_fs.run | 3 +- repos/libports/src/test/libc_vfs/main.cc | 4 +- repos/os/src/server/lx_fs/directory.h | 20 +++--- repos/os/src/server/lx_fs/lx_util.h | 51 +++++++++++++-- repos/os/src/server/lx_fs/main.cc | 79 +++++++++++++++++++++--- repos/os/src/server/lx_fs/node.h | 25 ++++++-- repos/os/src/server/lx_fs/symlink.h | 29 ++++++--- 7 files changed, 173 insertions(+), 38 deletions(-) diff --git a/repos/base-linux/run/lx_fs.run b/repos/base-linux/run/lx_fs.run index 8162b567f3..91d0094e88 100644 --- a/repos/base-linux/run/lx_fs.run +++ b/repos/base-linux/run/lx_fs.run @@ -51,9 +51,10 @@ install_config { } # -# Create test-directory structure +# Create test-directory structure and ensure it is empty # +exec rm -rf bin/libc_vfs exec mkdir -p bin/libc_vfs # diff --git a/repos/libports/src/test/libc_vfs/main.cc b/repos/libports/src/test/libc_vfs/main.cc index b3659705f1..7a3ecff8fb 100644 --- a/repos/libports/src/test/libc_vfs/main.cc +++ b/repos/libports/src/test/libc_vfs/main.cc @@ -119,10 +119,10 @@ static void test(Genode::Xml_node node) for (unsigned int i = 0; i < iterations; i++) { /* create directory given with a trailing slash */ - CALL_AND_CHECK(ret, mkdir(trailing_slash_dir_name, 0777), (ret == 0), "dir_name=%s", dir_name); + CALL_AND_CHECK(ret, mkdir(trailing_slash_dir_name, 0777), (ret == 0), "dir_name=%s", trailing_slash_dir_name); /* remove directory given with a trailing slash */ - CALL_AND_CHECK(ret, rmdir(trailing_slash_dir_name), (ret == 0), "dir_name=%s", dir_name); + CALL_AND_CHECK(ret, rmdir(trailing_slash_dir_name), (ret == 0), "dir_name=%s", trailing_slash_dir_name); /* create directory (short name) */ CALL_AND_CHECK(ret, mkdir(dir_name, 0777), ((ret == 0) || (errno == EEXIST)), "dir_name=%s", dir_name); diff --git a/repos/os/src/server/lx_fs/directory.h b/repos/os/src/server/lx_fs/directory.h index 14634f07c3..5305368990 100644 --- a/repos/os/src/server/lx_fs/directory.h +++ b/repos/os/src/server/lx_fs/directory.h @@ -2,6 +2,8 @@ * \brief File-system directory node * \author Norman Feske * \author Christian Helmuth + * \author Emery Hemingway + * \author Sid Hussmann * \date 2013-11-11 */ @@ -19,13 +21,14 @@ #include #include -/* local includes */ -#include -#include - -#include +/* libc includes */ #include +/* local includes */ +#include "file.h" +#include "lx_util.h" +#include "node.h" + namespace Lx_fs { using namespace Genode; @@ -44,8 +47,6 @@ class Lx_fs::Directory : public Node Directory(Directory const &); Directory &operator = (Directory const &); - typedef Genode::Path Path; - DIR *_fd; Path _path; Allocator &_alloc; @@ -261,6 +262,11 @@ class Lx_fs::Directory : public Node .modification_time = { st.st_mtime } }; } + + Path path() const override + { + return _path; + } }; #endif /* _DIRECTORY_H_ */ diff --git a/repos/os/src/server/lx_fs/lx_util.h b/repos/os/src/server/lx_fs/lx_util.h index a9ce4018f9..8c63c218c5 100644 --- a/repos/os/src/server/lx_fs/lx_util.h +++ b/repos/os/src/server/lx_fs/lx_util.h @@ -1,22 +1,33 @@ /* * \brief Linux utilities * \author Christian Helmuth + * \author Pirmin Duss * \date 2013-11-11 */ +/* + * Copyright (C) 2013-2020 Genode Labs GmbH + * Copyright (C) 2020 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + #ifndef _LX_UTIL_H_ #define _LX_UTIL_H_ /* Genode includes */ #include +#include /* Linux includes */ #define _FILE_OFFSET_BITS 64 -#include -#include -#include #include +#include +#include +#include #include +#include namespace File_system { @@ -24,6 +35,24 @@ namespace File_system { } +namespace Lx_fs { + + using namespace Genode; + + using Path_string = Genode::String; + + /* + * Calculate the absolute path that the root of a File_system session is + * located at. + * + * @param root_path root path specified in the policy of a File_system + * session. + * + */ + Path_string absolute_root_directory(char const *root_path); +} + + int File_system::access_mode(File_system::Mode const &mode) { switch (mode) { @@ -36,4 +65,18 @@ int File_system::access_mode(File_system::Mode const &mode) return O_RDONLY; } -#endif + +Lx_fs::Path_string Lx_fs::absolute_root_directory(char const *root_path) +{ + char cwd[PATH_MAX]; + char real_path[PATH_MAX]; + + getcwd(cwd, PATH_MAX); + + realpath(Path_string { cwd, "/", root_path }.string(), real_path); + + return Path_string { real_path }; +} + + +#endif /* _LX_UTIL_H_ */ diff --git a/repos/os/src/server/lx_fs/main.cc b/repos/os/src/server/lx_fs/main.cc index 5dea421fdd..79637c3bb8 100644 --- a/repos/os/src/server/lx_fs/main.cc +++ b/repos/os/src/server/lx_fs/main.cc @@ -1,28 +1,34 @@ /* - * \brief RAM file system + * \brief Linux host file system * \author Norman Feske + * \author Emery Hemingway + * \author Sid Hussmann + * \author Pirmin Duss * \date 2012-04-11 */ /* - * Copyright (C) 2012-2017 Genode Labs GmbH + * Copyright (C) 2013-2020 Genode Labs GmbH + * Copyright (C) 2020 gapfruit AG * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* Genode includes */ +#include #include #include -#include -#include #include #include +#include #include /* local includes */ -#include -#include +#include "directory.h" +#include "node.h" +#include "open_node.h" + namespace Lx_fs { @@ -47,6 +53,7 @@ class Lx_fs::Session_component : public Session_rpc_object Directory &_root; Id_space _open_node_registry { }; bool _writable; + Absolute_path const _root_dir; Signal_handler _process_packet_dispatcher; @@ -88,8 +95,6 @@ class Lx_fs::Session_component : public Session_rpc_object /* File system session can't handle partial writes */ if (res_length != length) { - Genode::error("partial write detected ", - res_length, " vs ", length); /* don't acknowledge */ return; } @@ -206,6 +211,7 @@ class Lx_fs::Session_component : public Session_rpc_object _md_alloc(md_alloc), _root(*new (&_md_alloc) Directory(_md_alloc, root_dir, false)), _writable(writable), + _root_dir(root_dir), _process_packet_dispatcher(env.ep(), *this, &Session_component::_process_packets) { /* @@ -263,6 +269,9 @@ class Lx_fs::Session_component : public Session_rpc_object Symlink_handle symlink(Dir_handle, Name const &, bool /* create */) override { + /* + * We do not support symbolic links for security reasons. + */ Genode::error(__func__, " not implemented"); throw Permission_denied(); } @@ -337,9 +346,59 @@ class Lx_fs::Session_component : public Session_rpc_object Genode::error(__func__, " not implemented"); } - void unlink(Dir_handle, Name const &) override + void unlink(Dir_handle dir_handle, Name const &name) override { - Genode::error(__func__, " not implemented"); + if (!valid_name(name.string())) + throw Invalid_name(); + + if (!_writable) + throw Permission_denied(); + + auto unlink_fn = [&] (Open_node &open_node) { + + Absolute_path absolute_path("/"); + + try { + absolute_path.append(open_node.node().path().string()); + absolute_path.append("/"); + absolute_path.append(name.string()); + } catch (Path_base::Path_too_long const &) { + Genode::error("Path too long. path=", absolute_path); + throw Invalid_name(); + } + + char const *path_str = absolute_path.string(); + _assert_valid_path(path_str); + + /* skip leading '/' */ + path_str++; + + struct stat s; + int ret = lstat(path_str, &s); + if (ret == -1) { + throw Lookup_failed(); + } + + if (S_ISDIR(s.st_mode)) { + ret = rmdir(path_str); + } else if (S_ISREG(s.st_mode) || S_ISLNK(s.st_mode)) { + ret = ::unlink(path_str); + } else { + throw Lookup_failed(); + } + + if (ret == -1) { + auto err = errno; + if (err == EACCES) + throw Permission_denied(); + } + }; + + try { + _open_node_registry.apply(dir_handle, unlink_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } void truncate(File_handle file_handle, file_size_t size) override diff --git a/repos/os/src/server/lx_fs/node.h b/repos/os/src/server/lx_fs/node.h index 67db592c48..06988cf9e1 100644 --- a/repos/os/src/server/lx_fs/node.h +++ b/repos/os/src/server/lx_fs/node.h @@ -2,11 +2,15 @@ * \brief File-system node * \author Norman Feske * \author Christian Helmuth + * \author Emery Hemingway + * \author Sid Hussmann + * \author Pirmin Duss * \date 2013-11-11 */ /* - * Copyright (C) 2013-2017 Genode Labs GmbH + * Copyright (C) 2013-2020 Genode Labs GmbH + * Copyright (C) 2020 gapfruit AG * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -20,7 +24,13 @@ namespace Lx_fs { + using namespace File_system; + + enum { MAX_ABSOLUTE_PATH_LEN = 2048 }; + + using Absolute_path = Genode::Path; + class Node; class File; } @@ -29,6 +39,7 @@ class Lx_fs::Node : public File_system::Node_base { public: + using Path = Genode::Path; typedef char Name[128]; private: @@ -38,10 +49,14 @@ class Lx_fs::Node : public File_system::Node_base public: - Node(unsigned long inode) : _inode(inode) { _name[0] = 0; } + Node(unsigned long inode) + : _inode { inode } + { + _name[0] = 0; + } - unsigned long inode() const { return _inode; } - char const *name() const { return _name; } + unsigned long inode() const { return _inode; } + char const *name() const { return _name; } /** * Assign name @@ -73,6 +88,8 @@ class Lx_fs::Node : public File_system::Node_base Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); return nullptr; } + + virtual Path path() const { return Path { }; } }; #endif /* _NODE_H_ */ diff --git a/repos/os/src/server/lx_fs/symlink.h b/repos/os/src/server/lx_fs/symlink.h index 1718ed6d2d..07b2188ed3 100644 --- a/repos/os/src/server/lx_fs/symlink.h +++ b/repos/os/src/server/lx_fs/symlink.h @@ -2,13 +2,17 @@ * \brief Symlink file-system node * \author Norman Feske * \author Christian Helmuth + * \author Emery Hemingway + * \author Sid Hussmann + * \author Pirmin Duss * \date 2013-11-11 * * FIXME unfinished */ /* - * Copyright (C) 2013-2017 Genode Labs GmbH + * Copyright (C) 2013-2020 Genode Labs GmbH + * Copyright (C) 2020 gapfruit AG * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -18,16 +22,16 @@ #define _SYMLINK_H_ /* local includes */ -#include -#include +#include "node.h" +#include "lx_util.h" -namespace File_system { +namespace Lx_fs { class Symlink; } -class File_system::Symlink : public Node +class Lx_fs::Symlink : public Node { private: @@ -37,11 +41,16 @@ class File_system::Symlink : public Node public: - Symlink(char const *name) { Node::name(name); } - - size_t read(char *dst, size_t len, seek_off_t seek_offset) override + Symlink(char const *name) + : + Node { 0 } { - size_t count = min(len, sizeof(_link_to) + 1); + Node::name(basename(name)); + } + + size_t read(char *dst, size_t len, seek_off_t /*seek_offset*/) override + { + size_t count = min(len, _length()); Genode::copy_cstring(dst, _link_to, count); return count; } @@ -51,7 +60,7 @@ class File_system::Symlink : public Node /* Ideal symlink operations are atomic. */ if (seek_offset) return 0; - size_t count = min(len, sizeof(_link_to) + 1); + size_t count = min(len, _length()); Genode::copy_cstring(_link_to, src, count); return count; }