From 6a43f3c11a2c01a7bca9e1232e7ba252c5f775ad Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Tue, 20 Jun 2017 14:23:22 +0200 Subject: [PATCH] file system: use Id_space instead of Node_handle_registry Fixes #2436 --- repos/base/include/base/id_space.h | 5 +- repos/dde_rump/src/server/rump_fs/directory.h | 26 +- repos/dde_rump/src/server/rump_fs/file.h | 21 +- repos/dde_rump/src/server/rump_fs/main.cc | 253 ++-- repos/dde_rump/src/server/rump_fs/node.h | 45 +- repos/dde_rump/src/server/rump_fs/symlink.h | 18 +- repos/libports/src/server/ffat_fs/directory.h | 179 +-- repos/libports/src/server/ffat_fs/file.h | 371 +++-- repos/libports/src/server/ffat_fs/main.cc | 1225 ++++++++--------- repos/libports/src/server/ffat_fs/node.h | 82 +- repos/libports/src/server/fuse_fs/directory.h | 18 +- repos/libports/src/server/fuse_fs/file.h | 19 +- .../src/server/fuse_fs/fuse_fs_main.cc | 279 ++-- repos/libports/src/server/fuse_fs/node.h | 55 +- repos/libports/src/server/fuse_fs/symlink.h | 17 +- repos/os/include/file_system/listener.h | 19 +- repos/os/include/file_system/node.h | 24 +- .../file_system/node_handle_registry.h | 218 --- repos/os/include/file_system/open_node.h | 79 ++ .../file_system_session/file_system_session.h | 110 +- repos/os/include/ram_fs/node.h | 67 - repos/os/src/app/rom_to_file/main.cc | 12 +- repos/os/src/app/usb_report_filter/main.cc | 11 +- repos/os/src/lib/vfs/fs_file_system.h | 27 +- repos/os/src/server/fs_log/main.cc | 14 +- repos/os/src/server/fs_rom/main.cc | 135 +- repos/os/src/server/lx_fs/directory.h | 44 +- repos/os/src/server/lx_fs/file.h | 41 +- repos/os/src/server/lx_fs/main.cc | 150 +- repos/os/src/server/lx_fs/node.h | 87 +- repos/os/src/server/lx_fs/symlink.h | 22 +- .../server}/ram_fs/directory.h | 87 +- .../os/{include => src/server}/ram_fs/file.h | 28 +- repos/os/src/server/ram_fs/main.cc | 346 +++-- repos/os/src/server/ram_fs/node.h | 120 ++ .../{include => src/server}/ram_fs/symlink.h | 21 +- repos/os/src/server/trace_fs/directory.h | 340 ++--- repos/os/src/server/trace_fs/file.h | 381 ++--- .../os/src/server/trace_fs/followed_subject.h | 509 +++---- repos/os/src/server/trace_fs/main.cc | 214 +-- repos/os/src/server/trace_fs/node.h | 109 +- repos/os/src/server/trace_fs/symlink.h | 44 +- repos/os/src/server/trace_fs/trace_files.h | 818 +++++------ repos/os/src/server/vfs/main.cc | 33 +- 44 files changed, 3623 insertions(+), 3100 deletions(-) delete mode 100644 repos/os/include/file_system/node_handle_registry.h create mode 100644 repos/os/include/file_system/open_node.h delete mode 100644 repos/os/include/ram_fs/node.h rename repos/os/{include => src/server}/ram_fs/directory.h (70%) rename repos/os/{include => src/server}/ram_fs/file.h (84%) create mode 100644 repos/os/src/server/ram_fs/node.h rename repos/os/{include => src/server}/ram_fs/symlink.h (71%) diff --git a/repos/base/include/base/id_space.h b/repos/base/include/base/id_space.h index 52ce180ae..84c012caa 100644 --- a/repos/base/include/base/id_space.h +++ b/repos/base/include/base/id_space.h @@ -188,7 +188,8 @@ class Genode::Id_space : public Noncopyable * \throw Unknown_id */ template - void apply(Id id, FUNC const &fn) + auto apply(Id id, FUNC const &fn) + -> typename Trait::Functor::Return_type { T *obj = nullptr; { @@ -201,7 +202,7 @@ class Genode::Id_space : public Noncopyable obj = &e->_obj; } if (obj) - fn(static_cast(*obj)); + return fn(static_cast(*obj)); else throw Unknown_id(); } diff --git a/repos/dde_rump/src/server/rump_fs/directory.h b/repos/dde_rump/src/server/rump_fs/directory.h index 588a6440c..68ee57307 100644 --- a/repos/dde_rump/src/server/rump_fs/directory.h +++ b/repos/dde_rump/src/server/rump_fs/directory.h @@ -26,11 +26,11 @@ #include "file.h" #include "symlink.h" -namespace File_system { +namespace Rump_fs { class Directory; } -class File_system::Directory : public Node +class Rump_fs::Directory : public Node { private: @@ -106,14 +106,14 @@ class File_system::Directory : public Node rump_sys_close(_fd); } - int fd() const { return _fd; } + int fd() const override { return _fd; } - File * file(char const *name, Mode mode, bool create) + File * file(char const *name, Mode mode, bool create) override { return new (&_alloc) File(_fd, name, mode, create); } - Symlink * symlink(char const *name, bool create) + Symlink * symlink(char const *name, bool create) override { return new (&_alloc) Symlink(_path.base(), name, create); } @@ -148,7 +148,7 @@ class File_system::Directory : public Node return node; } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { if (len < sizeof(Directory_entry)) { Genode::error("read buffer too small for directory entry"); @@ -222,12 +222,22 @@ class File_system::Directory : public Node return sizeof(Directory_entry); } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* writing to directory nodes is not supported */ return 0; } + Status status() override + { + Status s; + s.inode = inode(); + s.size = num_entries() * sizeof (Directory_entry); + s.mode = File_system::Status::MODE_DIRECTORY; + + return s; + } + size_t num_entries() const { int bytes = 0; @@ -247,7 +257,7 @@ class File_system::Directory : public Node return count; } - void unlink(char const *path) + void unlink(char const *path) override { Path node_path(path, _path.base()); diff --git a/repos/dde_rump/src/server/rump_fs/file.h b/repos/dde_rump/src/server/rump_fs/file.h index ded500fe1..67b6114e5 100644 --- a/repos/dde_rump/src/server/rump_fs/file.h +++ b/repos/dde_rump/src/server/rump_fs/file.h @@ -21,11 +21,11 @@ #include "node.h" -namespace File_system { +namespace Rump_fs { class File; } -class File_system::File : public Node +class Rump_fs::File : public Node { private: @@ -114,7 +114,7 @@ class File_system::File : public Node virtual ~File() { rump_sys_close(_fd); } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { ssize_t ret; @@ -127,7 +127,7 @@ class File_system::File : public Node return ret == -1 ? 0 : ret; } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { ssize_t ret; @@ -140,6 +140,17 @@ class File_system::File : public Node return ret == -1 ? 0 : ret; } + virtual Status status() override + { + Status s; + + s.inode = inode(); + s.size = length(); + s.mode = File_system::Status::MODE_FILE; + + return s; + } + file_size_t length() const { struct stat s; @@ -150,7 +161,7 @@ class File_system::File : public Node return s.st_size; } - void truncate(file_size_t size) + void truncate(file_size_t size) override { rump_sys_ftruncate(_fd, size); diff --git a/repos/dde_rump/src/server/rump_fs/main.cc b/repos/dde_rump/src/server/rump_fs/main.cc index ca9b94d9d..a4da67926 100644 --- a/repos/dde_rump/src/server/rump_fs/main.cc +++ b/repos/dde_rump/src/server/rump_fs/main.cc @@ -13,7 +13,7 @@ */ /* Genode includes */ -#include +#include #include #include #include @@ -30,20 +30,26 @@ #include "file_system.h" #include "directory.h" -namespace File_system { +namespace Rump_fs { + + using File_system::Packet_descriptor; + using File_system::Path; + struct Main; struct Root; struct Session_component; } -class File_system::Session_component : public Session_rpc_object +class Rump_fs::Session_component : public Session_rpc_object { private: - Allocator &_md_alloc; - Directory &_root; - Node_handle_registry _handle_registry; - bool _writable; + typedef File_system::Open_node Open_node; + + Allocator &_md_alloc; + Directory &_root; + Id_space _open_node_registry; + bool _writable; Signal_handler _process_packet_handler; @@ -57,7 +63,7 @@ class File_system::Session_component : public Session_rpc_object * * \return true on success, false on failure */ - void _process_packet_op(Packet_descriptor &packet, Node &node) + void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) { void * const content = tx_sink()->packet_content(packet); size_t const length = packet.length(); @@ -69,18 +75,18 @@ class File_system::Session_component : public Session_rpc_object case Packet_descriptor::READ: if (content && (packet.length() <= packet.size())) - res_length = node.read((char *)content, length, packet.position()); + res_length = open_node.node().read((char *)content, length, packet.position()); break; case Packet_descriptor::WRITE: if (content && (packet.length() <= packet.size())) - res_length = node.write((char const *)content, length, packet.position()); + res_length = open_node.node().write((char const *)content, length, packet.position()); break; case Packet_descriptor::CONTENT_CHANGED: - _handle_registry.register_notify(*tx_sink(), packet.handle()); + open_node.register_notify(*tx_sink()); /* notify_listeners may bounce the packet back*/ - node.notify_listeners(); + open_node.node().notify_listeners(); /* otherwise defer acknowledgement of this packet */ return; @@ -101,12 +107,16 @@ class File_system::Session_component : public Session_rpc_object /* assume failure by default */ packet.succeeded(false); - try { - Node *node = _handle_registry.lookup(packet.handle()); + auto process_packet_fn = [&] (Open_node &open_node) { + _process_packet_op(packet, open_node); + }; - _process_packet_op(packet, *node); + try { + _open_node_registry.apply(packet.handle(), process_packet_fn); + } catch (Id_space::Unknown_id const &) { + Genode::error("Invalid_handle"); + tx_sink()->acknowledge_packet(packet); } - catch (Invalid_handle) { Genode::error("Invalid_handle"); } } /** @@ -189,14 +199,29 @@ class File_system::Session_component : public Session_rpc_object if (!valid_name(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup(dir_handle); + auto file_fn = [&] (Open_node &open_node) { - if (!_writable) - if (create || (mode != STAT_ONLY && mode != READ_ONLY)) - throw Permission_denied(); + Node &dir = open_node.node(); - File *file = dir->file(name.string(), mode, create); - return _handle_registry.alloc(file); + if (!_writable) + if (create || (mode != STAT_ONLY && mode != READ_ONLY)) + throw Permission_denied(); + + File *file = dir.file(name.string(), mode, create); + + Open_node *open_file = + new (_md_alloc) Open_node(*file, _open_node_registry); + + return open_file->id(); + }; + + try { + return File_handle { + _open_node_registry.apply(dir_handle, file_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) @@ -207,13 +232,28 @@ class File_system::Session_component : public Session_rpc_object if (!valid_name(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup(dir_handle); + auto symlink_fn = [&] (Open_node &open_node) { - if (create && !_writable) - throw Permission_denied(); + Node &dir = open_node.node(); - Symlink *link = dir->symlink(name.string(), create); - return _handle_registry.alloc(link); + if (create && !_writable) + throw Permission_denied(); + + Symlink *link = dir.symlink(name.string(), create); + + Open_node *open_symlink = + new (_md_alloc) Open_node(*link, _open_node_registry); + + return open_symlink->id(); + }; + + try { + return Symlink_handle { + _open_node_registry.apply(dir_handle, symlink_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Dir_handle dir(Path const &path, bool create) @@ -231,7 +271,11 @@ class File_system::Session_component : public Session_rpc_object throw Name_too_long(); Directory *dir = _root.subdir(path_str, create); - return _handle_registry.alloc(dir); + + Open_node *open_dir = + new (_md_alloc) Open_node(*dir, _open_node_registry); + + return Dir_handle { open_dir->id().value }; } Node_handle node(Path const &path) @@ -240,55 +284,39 @@ class File_system::Session_component : public Session_rpc_object _assert_valid_path(path_str); Node *node = _root.node(path_str + 1); - Node_handle h = _handle_registry.alloc(node); - return h; + + Open_node *open_node = + new (_md_alloc) Open_node(*node, _open_node_registry); + + return open_node->id(); } void close(Node_handle handle) { - Node *node = 0; - - try { - node = _handle_registry.lookup(handle); - } catch (Invalid_handle) { return; } + auto close_fn = [&] (Open_node &open_node) { + Node &node = open_node.node(); + destroy(_md_alloc, &open_node); + destroy(_md_alloc, &node); + }; - _handle_registry.free(handle); - /* destruct node */ - if (node) - destroy(&_md_alloc, node); + try { + _open_node_registry.apply(handle, close_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Status status(Node_handle node_handle) { - Node *node = _handle_registry.lookup(node_handle); - Status s; - s.inode = node->inode(); - s.size = 0; - s.mode = 0; + auto status_fn = [&] (Open_node &open_node) { + return open_node.node().status(); + }; - - File *file = dynamic_cast(node); - if (file) { - s.size = file->length(); - s.mode = File_system::Status::MODE_FILE; - return s; + try { + return _open_node_registry.apply(node_handle, status_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - - Directory *dir = dynamic_cast(node); - if (dir) { - s.size = dir->num_entries()*sizeof(Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; - return s; - } - - Symlink *link = dynamic_cast(node); - if (link) { - s.size = link->length(); - s.mode = File_system::Status::MODE_SYMLINK; - return s; - } - - return Status(); } void control(Node_handle, Control) override { } @@ -301,8 +329,16 @@ class File_system::Session_component : public Session_rpc_object if (!_writable) throw Permission_denied(); - Directory *dir = _handle_registry.lookup(dir_handle); - dir->unlink(name.string()); + auto unlink_fn = [&] (Open_node &open_node) { + Node &dir = open_node.node(); + dir.unlink(name.string()); + }; + + 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) @@ -310,8 +346,15 @@ class File_system::Session_component : public Session_rpc_object if (!_writable) throw Permission_denied(); - File *file = _handle_registry.lookup(file_handle); - file->truncate(size); + auto truncate_fn = [&] (Open_node &open_node) { + open_node.node().truncate(size); + }; + + try { + _open_node_registry.apply(file_handle, truncate_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } void move(Dir_handle from_dir_handle, Name const &from_name, @@ -320,41 +363,59 @@ class File_system::Session_component : public Session_rpc_object if (!_writable) throw Permission_denied(); - char const *from_str = from_name.string(); - char const *to_str = to_name.string(); + auto move_fn = [&] (Open_node &open_from_dir_node) { - if (!(valid_name(from_str) && valid_name(to_str))) - throw Lookup_failed(); + auto inner_move_fn = [&] (Open_node &open_to_dir_node) { - Directory *from_dir = _handle_registry.lookup(from_dir_handle); - Directory *to_dir = _handle_registry.lookup( to_dir_handle); + Node &from_dir = open_from_dir_node.node(); + Node &to_dir = open_to_dir_node.node(); - if (rump_sys_renameat(from_dir->fd(), from_str, - to_dir->fd(), to_str) == 0) { - from_dir->mark_as_updated(); - from_dir->notify_listeners(); - if (!_handle_registry.refer_to_same_node(from_dir_handle, - to_dir_handle)) { - to_dir->mark_as_updated(); - to_dir->notify_listeners(); + char const *from_str = from_name.string(); + char const *to_str = to_name.string(); + + if (!(valid_name(from_str) && valid_name(to_str))) + throw Lookup_failed(); + + if (rump_sys_renameat(from_dir.fd(), from_str, + to_dir.fd(), to_str) == 0) { + from_dir.mark_as_updated(); + from_dir.notify_listeners(); + if (&from_dir != &to_dir) { + to_dir.mark_as_updated(); + to_dir.notify_listeners(); + } + + return; + } + + switch (errno) { + case ENOTEMPTY: throw Node_already_exists(); + case ENOENT: throw Lookup_failed(); + } + + Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str); + throw Permission_denied(); + + }; + + try { + _open_node_registry.apply(to_dir_handle, inner_move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } + }; - return; + try { + _open_node_registry.apply(from_dir_handle, move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - - switch (errno) { - case ENOTEMPTY: throw Node_already_exists(); - case ENOENT: throw Lookup_failed(); - } - - Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str); - throw Permission_denied(); } void sync(Node_handle) override { rump_sys_sync(); } }; -class File_system::Root : public Root_component +class Rump_fs::Root : public Root_component { private: @@ -453,7 +514,7 @@ class File_system::Root : public Root_component }; -struct File_system::Main +struct Rump_fs::Main { Genode::Env &env; @@ -516,5 +577,5 @@ void Component::construct(Genode::Env &env) /* XXX execute constructors of global statics (uses shared objects) */ env.exec_static_constructors(); - static File_system::Main inst(env); + static Rump_fs::Main inst(env); } diff --git a/repos/dde_rump/src/server/rump_fs/node.h b/repos/dde_rump/src/server/rump_fs/node.h index 0572e606a..cfd8b3054 100644 --- a/repos/dde_rump/src/server/rump_fs/node.h +++ b/repos/dde_rump/src/server/rump_fs/node.h @@ -18,16 +18,20 @@ /* Genode includes */ #include -#include #include -namespace File_system { +namespace Rump_fs { + using namespace File_system; using namespace Genode; + using Genode::size_t; class Node; + class File; + class Directory; + class Symlink; } -class File_system::Node : public Node_base, public List::Element +class Rump_fs::Node : public Node_base { public: @@ -52,6 +56,41 @@ class File_system::Node : public Node_base, public List::Element virtual size_t read(char *dst, size_t len, seek_off_t) = 0; virtual size_t write(char const *src, size_t len, seek_off_t) = 0; + virtual Status status() = 0; + + /* + * Directory functionality + */ + virtual int fd() const + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return -1; + } + + virtual File *file(char const *name, Mode mode, bool create) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return nullptr; + } + + virtual Symlink *symlink(char const *name, bool create) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return nullptr; + } + + virtual void unlink(char const *path) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + } + + /* + * File functionality + */ + virtual void truncate(file_size_t size) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); + } }; #endif /* _NODE_H_ */ diff --git a/repos/dde_rump/src/server/rump_fs/symlink.h b/repos/dde_rump/src/server/rump_fs/symlink.h index f0ac316c5..49b12001a 100644 --- a/repos/dde_rump/src/server/rump_fs/symlink.h +++ b/repos/dde_rump/src/server/rump_fs/symlink.h @@ -20,11 +20,11 @@ #include "node.h" -namespace File_system { +namespace Rump_fs { class Symlink; } -class File_system::Symlink : public Node +class Rump_fs::Symlink : public Node { private: @@ -47,7 +47,7 @@ class File_system::Symlink : public Node Node::name(basename(path)); } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* Ideal symlink operations are atomic. */ if (!_create || seek_offset) @@ -60,12 +60,22 @@ class File_system::Symlink : public Node return ret == -1 ? 0 : ret; } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { int ret = rump_sys_readlink(_path.base(), dst, len); return ret == -1 ? 0 : ret; } + Status status() override + { + Status s; + s.inode = inode(); + s.size = length(); + s.mode = File_system::Status::MODE_SYMLINK; + + return s; + } + file_size_t length() { char link_to[MAX_PATH_LEN]; diff --git a/repos/libports/src/server/ffat_fs/directory.h b/repos/libports/src/server/ffat_fs/directory.h index 7d7730fd9..10d89c1e0 100644 --- a/repos/libports/src/server/ffat_fs/directory.h +++ b/repos/libports/src/server/ffat_fs/directory.h @@ -4,6 +4,13 @@ * \date 2012-07-04 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _DIRECTORY_H_ #define _DIRECTORY_H_ @@ -16,101 +23,101 @@ namespace Ffat { extern "C" { #include -namespace File_system { - +namespace Ffat_fs { using namespace Genode; + class Directory; +} - class Directory : public Node - { - private: +class Ffat_fs::Directory : public Node +{ + private: - Ffat::DIR _ffat_dir; - int64_t _prev_index; + Ffat::DIR _ffat_dir; + int64_t _prev_index; - public: + public: - Directory(const char *name) - : Node(name), - _prev_index(-1) { } + Directory(const char *name) + : Node(name), + _prev_index(-1) { } - void ffat_dir(Ffat::DIR ffat_dir) { _ffat_dir = ffat_dir; } - Ffat::DIR *ffat_dir() { return &_ffat_dir; } + void ffat_dir(Ffat::DIR ffat_dir) { _ffat_dir = ffat_dir; } + Ffat::DIR *ffat_dir() { return &_ffat_dir; } - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - if (len < sizeof(Directory_entry)) { - error("read buffer too small for directory entry"); - return 0; - } - - if (seek_offset % sizeof(Directory_entry)) { - error("seek offset not alighed to sizeof(Directory_entry)"); - return 0; - } - - Directory_entry *e = (Directory_entry *)(dst); - - using namespace Ffat; - - FILINFO ffat_file_info; - ffat_file_info.lfname = e->name; - ffat_file_info.lfsize = sizeof(e->name); - - int64_t index = seek_offset / sizeof(Directory_entry); - - if (index != (_prev_index + 1)) { - /* rewind and iterate from the beginning */ - f_readdir(&_ffat_dir, 0); - for (int i = 0; i < index; i++) - f_readdir(&_ffat_dir, &ffat_file_info); - } - - _prev_index = index; - - FRESULT res = f_readdir(&_ffat_dir, &ffat_file_info); - switch(res) { - case FR_OK: - break; - case FR_INVALID_OBJECT: - error("f_readdir() failed with error code FR_INVALID_OBJECT"); - return 0; - case FR_DISK_ERR: - error("f_readdir() failed with error code FR_DISK_ERR"); - return 0; - case FR_INT_ERR: - error("f_readdir() failed with error code FR_INT_ERR"); - return 0; - case FR_NOT_READY: - error("f_readdir() failed with error code FR_NOT_READY"); - return 0; - default: - /* not supposed to occur according to the libffat documentation */ - error("f_readdir() returned an unexpected error code"); - return 0; - } - - if (ffat_file_info.fname[0] == 0) { /* no (more) entries */ - return 0; - } - - if (e->name[0] == 0) /* use short file name */ - strncpy(e->name, ffat_file_info.fname, sizeof(e->name)); - - if ((ffat_file_info.fattrib & AM_DIR) == AM_DIR) - e->type = Directory_entry::TYPE_DIRECTORY; - else - e->type = Directory_entry::TYPE_FILE; - - return sizeof(Directory_entry); - } - - size_t write(char const *src, size_t len, seek_off_t) - { - /* writing to directory nodes is not supported */ + size_t read(char *dst, size_t len, seek_off_t seek_offset) + { + if (len < sizeof(Directory_entry)) { + error("read buffer too small for directory entry"); return 0; } - }; -} + if (seek_offset % sizeof(Directory_entry)) { + error("seek offset not alighed to sizeof(Directory_entry)"); + return 0; + } + + Directory_entry *e = (Directory_entry *)(dst); + + using namespace Ffat; + + FILINFO ffat_file_info; + ffat_file_info.lfname = e->name; + ffat_file_info.lfsize = sizeof(e->name); + + int64_t index = seek_offset / sizeof(Directory_entry); + + if (index != (_prev_index + 1)) { + /* rewind and iterate from the beginning */ + f_readdir(&_ffat_dir, 0); + for (int i = 0; i < index; i++) + f_readdir(&_ffat_dir, &ffat_file_info); + } + + _prev_index = index; + + FRESULT res = f_readdir(&_ffat_dir, &ffat_file_info); + switch(res) { + case FR_OK: + break; + case FR_INVALID_OBJECT: + error("f_readdir() failed with error code FR_INVALID_OBJECT"); + return 0; + case FR_DISK_ERR: + error("f_readdir() failed with error code FR_DISK_ERR"); + return 0; + case FR_INT_ERR: + error("f_readdir() failed with error code FR_INT_ERR"); + return 0; + case FR_NOT_READY: + error("f_readdir() failed with error code FR_NOT_READY"); + return 0; + default: + /* not supposed to occur according to the libffat documentation */ + error("f_readdir() returned an unexpected error code"); + return 0; + } + + if (ffat_file_info.fname[0] == 0) { /* no (more) entries */ + return 0; + } + + if (e->name[0] == 0) /* use short file name */ + strncpy(e->name, ffat_file_info.fname, sizeof(e->name)); + + if ((ffat_file_info.fattrib & AM_DIR) == AM_DIR) + e->type = Directory_entry::TYPE_DIRECTORY; + else + e->type = Directory_entry::TYPE_FILE; + + return sizeof(Directory_entry); + } + + size_t write(char const *src, size_t len, seek_off_t) + { + /* writing to directory nodes is not supported */ + return 0; + } + +}; #endif /* _DIRECTORY_H_ */ diff --git a/repos/libports/src/server/ffat_fs/file.h b/repos/libports/src/server/ffat_fs/file.h index aa8a4eb78..2e578b036 100644 --- a/repos/libports/src/server/ffat_fs/file.h +++ b/repos/libports/src/server/ffat_fs/file.h @@ -4,6 +4,13 @@ * \date 2012-07-04 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _FILE_H_ #define _FILE_H_ @@ -16,140 +23,236 @@ namespace Ffat { extern "C" { #include -namespace File_system { - - class File : public Node - { - private: - - Ffat::FIL _ffat_fil; - - public: - - File(const char *name) : Node(name) { } - - void ffat_fil(Ffat::FIL ffat_fil) { _ffat_fil = ffat_fil; } - Ffat::FIL *ffat_fil() { return &_ffat_fil; } - - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - using namespace Ffat; - - UINT result; - - if (seek_offset == (seek_off_t)(~0)) - seek_offset = _ffat_fil.fsize; - - FRESULT res = f_lseek(&_ffat_fil, seek_offset); - - switch(res) { - case FR_OK: - break; - case FR_INVALID_OBJECT: - Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT"); - return 0; - case FR_DISK_ERR: - Genode::error("f_lseek() failed with error code FR_DISK_ERR"); - return 0; - case FR_INT_ERR: - Genode::error("f_lseek() failed with error code FR_INT_ERR"); - return 0; - case FR_NOT_READY: - Genode::error("f_lseek() failed with error code FR_NOT_READY"); - return 0; - default: - /* not supposed to occur according to the libffat documentation */ - Genode::error("f_lseek() returned an unexpected error code"); - return 0; - } - - res = f_read(&_ffat_fil, dst, len, &result); - - switch(res) { - case FR_OK: - return result; - case FR_DENIED: - Genode::warning("f_read() failed with error code FR_DENIED"); - return 0; - case FR_INVALID_OBJECT: - Genode::error("f_read() failed with error code FR_INVALID_OBJECT"); - return 0; - case FR_DISK_ERR: - Genode::error("f_read() failed with error code FR_DISK_ERR"); - return 0; - case FR_INT_ERR: - Genode::error("f_read() failed with error code FR_INT_ERR"); - return 0; - case FR_NOT_READY: - Genode::error("f_read() failed with error code FR_NOT_READY"); - return 0; - default: - /* not supposed to occur according to the libffat documentation */ - Genode::error("f_read() returned an unexpected error code"); - return 0; - } - } - - size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - using namespace Ffat; - - UINT result; - - if (seek_offset == (seek_off_t)(~0)) - seek_offset = _ffat_fil.fsize; - - FRESULT res = f_lseek(&_ffat_fil, seek_offset); - - switch(res) { - case FR_OK: - break; - case FR_INVALID_OBJECT: - Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT"); - return 0; - case FR_DISK_ERR: - Genode::error("f_lseek() failed with error code FR_DISK_ERR"); - return 0; - case FR_INT_ERR: - Genode::error("f_lseek() failed with error code FR_INT_ERR"); - return 0; - case FR_NOT_READY: - Genode::error("f_lseek() failed with error code FR_NOT_READY"); - return 0; - default: - /* not supposed to occur according to the libffat documentation */ - Genode::error("f_lseek() returned an unexpected error code"); - return 0; - } - - res = f_write(&_ffat_fil, src, len, &result); - - switch(res) { - case FR_OK: - return result; - case FR_DENIED: - Genode::error("f_write() failed with error code FR_DENIED"); - return 0; - case FR_INVALID_OBJECT: - Genode::error("f_write() failed with error code FR_INVALID_OBJECT"); - return 0; - case FR_DISK_ERR: - Genode::error("f_write() failed with error code FR_DISK_ERR"); - return 0; - case FR_INT_ERR: - Genode::error("f_write() failed with error code FR_INT_ERR"); - return 0; - case FR_NOT_READY: - Genode::error("f_write() failed with error code FR_NOT_READY"); - return 0; - default: - /* not supposed to occur according to the libffat documentation */ - Genode::error("f_write() returned an unexpected error code"); - return 0; - } - } - - }; +namespace Ffat_fs { + class File; } +class Ffat_fs::File : public Node +{ + private: + + Ffat::FIL _ffat_fil; + + public: + + File(const char *name) : Node(name) { } + + ~File() + { + using namespace Ffat; + + FRESULT res = f_close(&_ffat_fil); + + switch(res) { + case FR_OK: + return; + case FR_INVALID_OBJECT: + error("f_close() failed with error code FR_INVALID_OBJECT"); + return; + case FR_DISK_ERR: + error("f_close() failed with error code FR_DISK_ERR"); + return; + case FR_INT_ERR: + error("f_close() failed with error code FR_INT_ERR"); + return; + case FR_NOT_READY: + error("f_close() failed with error code FR_NOT_READY"); + return; + default: + /* not supposed to occur according to the libffat documentation */ + error("f_close() returned an unexpected error code"); + return; + } + } + + void ffat_fil(Ffat::FIL ffat_fil) { _ffat_fil = ffat_fil; } + Ffat::FIL *ffat_fil() { return &_ffat_fil; } + + size_t read(char *dst, size_t len, seek_off_t seek_offset) override + { + using namespace Ffat; + + UINT result; + + if (seek_offset == (seek_off_t)(~0)) + seek_offset = _ffat_fil.fsize; + + FRESULT res = f_lseek(&_ffat_fil, seek_offset); + + switch(res) { + case FR_OK: + break; + case FR_INVALID_OBJECT: + Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT"); + return 0; + case FR_DISK_ERR: + Genode::error("f_lseek() failed with error code FR_DISK_ERR"); + return 0; + case FR_INT_ERR: + Genode::error("f_lseek() failed with error code FR_INT_ERR"); + return 0; + case FR_NOT_READY: + Genode::error("f_lseek() failed with error code FR_NOT_READY"); + return 0; + default: + /* not supposed to occur according to the libffat documentation */ + Genode::error("f_lseek() returned an unexpected error code"); + return 0; + } + + res = f_read(&_ffat_fil, dst, len, &result); + + switch(res) { + case FR_OK: + return result; + case FR_DENIED: + Genode::warning("f_read() failed with error code FR_DENIED"); + return 0; + case FR_INVALID_OBJECT: + Genode::error("f_read() failed with error code FR_INVALID_OBJECT"); + return 0; + case FR_DISK_ERR: + Genode::error("f_read() failed with error code FR_DISK_ERR"); + return 0; + case FR_INT_ERR: + Genode::error("f_read() failed with error code FR_INT_ERR"); + return 0; + case FR_NOT_READY: + Genode::error("f_read() failed with error code FR_NOT_READY"); + return 0; + default: + /* not supposed to occur according to the libffat documentation */ + Genode::error("f_read() returned an unexpected error code"); + return 0; + } + } + + size_t write(char const *src, size_t len, seek_off_t seek_offset) override + { + using namespace Ffat; + + UINT result; + + if (seek_offset == (seek_off_t)(~0)) + seek_offset = _ffat_fil.fsize; + + FRESULT res = f_lseek(&_ffat_fil, seek_offset); + + switch(res) { + case FR_OK: + break; + case FR_INVALID_OBJECT: + Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT"); + return 0; + case FR_DISK_ERR: + Genode::error("f_lseek() failed with error code FR_DISK_ERR"); + return 0; + case FR_INT_ERR: + Genode::error("f_lseek() failed with error code FR_INT_ERR"); + return 0; + case FR_NOT_READY: + Genode::error("f_lseek() failed with error code FR_NOT_READY"); + return 0; + default: + /* not supposed to occur according to the libffat documentation */ + Genode::error("f_lseek() returned an unexpected error code"); + return 0; + } + + res = f_write(&_ffat_fil, src, len, &result); + + switch(res) { + case FR_OK: + return result; + case FR_DENIED: + Genode::error("f_write() failed with error code FR_DENIED"); + return 0; + case FR_INVALID_OBJECT: + Genode::error("f_write() failed with error code FR_INVALID_OBJECT"); + return 0; + case FR_DISK_ERR: + Genode::error("f_write() failed with error code FR_DISK_ERR"); + return 0; + case FR_INT_ERR: + Genode::error("f_write() failed with error code FR_INT_ERR"); + return 0; + case FR_NOT_READY: + Genode::error("f_write() failed with error code FR_NOT_READY"); + return 0; + default: + /* not supposed to occur according to the libffat documentation */ + Genode::error("f_write() returned an unexpected error code"); + return 0; + } + } + + void truncate(file_size_t size) override + { + using namespace Ffat; + + /* + * This macro is defined in later versions of the FatFs lib, but not in the + * one currently used for Genode. + */ + #define f_tell(fp) ((fp)->fptr) + + /* 'f_truncate()' truncates to the current seek pointer */ + + FRESULT res = f_lseek(&_ffat_fil, size); + + switch(res) { + case FR_OK: + /* according to the FatFs documentation this can happen */ + if (f_tell(&_ffat_fil) != size) { + error("f_lseek() could not seek to offset ", size); + return; + } + break; + case FR_DISK_ERR: + error("f_lseek() failed with error code FR_DISK_ERR"); + return; + case FR_INT_ERR: + error("f_lseek() failed with error code FR_INT_ERR"); + return; + case FR_NOT_READY: + error("f_lseek() failed with error code FR_NOT_READY"); + return; + case FR_INVALID_OBJECT: + error("f_lseek() failed with error code FR_INVALID_OBJECT"); + throw Invalid_handle(); + default: + /* not supposed to occur according to the libffat documentation */ + error("f_lseek() returned an unexpected error code"); + return; + } + + res = f_truncate(&_ffat_fil); + + switch(res) { + case FR_OK: + return; + case FR_INVALID_OBJECT: + error("f_truncate() failed with error code FR_INVALID_OBJECT"); + throw Invalid_handle(); + case FR_DISK_ERR: + error("f_truncate() failed with error code FR_DISK_ERR"); + return; + case FR_INT_ERR: + error("f_truncate() failed with error code FR_INT_ERR"); + return; + case FR_NOT_READY: + error("f_truncate() failed with error code FR_NOT_READY"); + return; + case FR_TIMEOUT: + error("f_truncate() failed with error code FR_TIMEOUT"); + return; + default: + /* not supposed to occur according to the libffat documentation */ + error("f_truncate() returned an unexpected error code"); + return; + } + } + +}; + #endif /* _FILE_H_ */ diff --git a/repos/libports/src/server/ffat_fs/main.cc b/repos/libports/src/server/ffat_fs/main.cc index 70c9d2c03..8925ba720 100644 --- a/repos/libports/src/server/ffat_fs/main.cc +++ b/repos/libports/src/server/ffat_fs/main.cc @@ -13,7 +13,7 @@ /* Genode includes */ #include -#include +#include #include #include #include @@ -35,186 +35,192 @@ namespace Ffat { extern "C" { #include } } -/* - * This macro is defined in later versions of the FatFs lib, but not in the - * one currently used for Genode. - */ -#define f_tell(fp) ((fp)->fptr) - - -using namespace Genode; - - -static Lock _ffat_lock; -typedef Lock_guard Ffat_lock_guard; - /************************* ** File-system service ** *************************/ -namespace File_system { +namespace Ffat_fs { - class Session_component : public Session_rpc_object - { - private: + using namespace Genode; + using File_system::Exception; + using File_system::Packet_descriptor; + using File_system::Path; - Genode::Env &_env; - Genode::Allocator &_heap; + class Session_component; + class Root; + struct Main; +} - Directory &_root; - Node_handle_registry _handle_registry; - bool _writable; +class Ffat_fs::Session_component : public Session_rpc_object +{ + private: - Signal_handler _process_packet_dispatcher; + typedef File_system::Open_node Open_node; - /****************************** - ** Packet-stream processing ** - ******************************/ + Genode::Env &_env; + Genode::Allocator &_heap; - /** - * Perform packet operation - * - * \return true on success, false on failure - */ - void _process_packet_op(Packet_descriptor &packet, Node &node) - { - void * const content = tx_sink()->packet_content(packet); - size_t const length = packet.length(); - seek_off_t const offset = packet.position(); + Directory &_root; + Id_space _open_node_registry; + bool _writable; - if (!content || (packet.length() > packet.size())) { - packet.succeeded(false); - return; - } + Signal_handler _process_packet_dispatcher; - /* resulting length */ - size_t res_length = 0; + /****************************** + ** Packet-stream processing ** + ******************************/ - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + /** + * Perform packet operation + * + * \return true on success, false on failure + */ + void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) + { + void * const content = tx_sink()->packet_content(packet); + size_t const length = packet.length(); + seek_off_t const offset = packet.position(); - switch (packet.operation()) { - - case Packet_descriptor::READ: - res_length = node.read((char *)content, length, offset); - break; - - case Packet_descriptor::WRITE: - res_length = node.write((char const *)content, length, offset); - break; - - case Packet_descriptor::READ_READY: - /* not supported */ - break; - } - - packet.length(res_length); - packet.succeeded(res_length > 0); - } - - void _process_packet() - { - Packet_descriptor packet = tx_sink()->get_packet(); - - /* assume failure by default */ + if (!content || (packet.length() > packet.size())) { packet.succeeded(false); + return; + } - try { - Node *node = _handle_registry.lookup(packet.handle()); - _process_packet_op(packet, *node); - } - catch (Invalid_handle) { error("Invalid_handle"); } + /* resulting length */ + size_t res_length = 0; + + switch (packet.operation()) { + + case Packet_descriptor::READ: + res_length = open_node.node().read((char *)content, length, offset); + break; + + case Packet_descriptor::WRITE: + res_length = open_node.node().write((char const *)content, length, offset); + break; + + case Packet_descriptor::CONTENT_CHANGED: + open_node.register_notify(*tx_sink()); + open_node.node().notify_listeners(); + return; + + case Packet_descriptor::READ_READY: + /* not supported */ + break; + } + + packet.length(res_length); + packet.succeeded(res_length > 0); + } + + void _process_packet() + { + Packet_descriptor packet = tx_sink()->get_packet(); + + /* assume failure by default */ + packet.succeeded(false); + + auto process_packet_fn = [&] (Open_node &open_node) { + _process_packet_op(packet, open_node); + }; + + try { + _open_node_registry.apply(packet.handle(), process_packet_fn); + } catch (Id_space::Unknown_id const &) { + Genode::error("Invalid_handle"); + } + + /* + * The 'acknowledge_packet' function cannot block because we + * checked for 'ready_to_ack' in '_process_packets'. + */ + tx_sink()->acknowledge_packet(packet); + } + + /** + * Called by signal dispatcher, executed in the context of the main + * thread (not serialized with the RPC functions) + */ + void _process_packets() + { + while (tx_sink()->packet_avail()) { /* - * The 'acknowledge_packet' function cannot block because we - * checked for 'ready_to_ack' in '_process_packets'. + * Make sure that the '_process_packet' function does not + * block. + * + * If the acknowledgement queue is full, we defer packet + * processing until the client processed pending + * acknowledgements and thereby emitted a ready-to-ack + * signal. Otherwise, the call of 'acknowledge_packet()' + * in '_process_packet' would infinitely block the context + * of the main thread. The main thread is however needed + * for receiving any subsequent 'ready-to-ack' signals. */ - tx_sink()->acknowledge_packet(packet); - } + if (!tx_sink()->ready_to_ack()) + return; - /** - * Called by signal dispatcher, executed in the context of the main - * thread (not serialized with the RPC functions) + _process_packet(); + } + } + + /** + * Check if string represents a valid path (most start with '/') + */ + static void _assert_valid_path(char const *path) + { + if (!valid_path(path)) { + warning("malformed path '", path, "'"); + throw Lookup_failed(); + } + } + + public: + + /** + * Constructor + */ + Session_component(Genode::Env &env, + Genode::Allocator &heap, + size_t tx_buf_size, + Directory &root, + bool writable) + : + Session_rpc_object(env.ram().alloc(tx_buf_size), + env.rm(), env.ep().rpc_ep()), + _env(env), _heap(heap), _root(root), _writable(writable), + _process_packet_dispatcher(env.ep(), *this, + &Session_component::_process_packets) + { + /* + * Register '_process_packets' dispatch function as signal + * handler for packet-avail and ready-to-ack signals. */ - void _process_packets() - { - while (tx_sink()->packet_avail()) { + _tx.sigh_packet_avail(_process_packet_dispatcher); + _tx.sigh_ready_to_ack(_process_packet_dispatcher); + } - /* - * Make sure that the '_process_packet' function does not - * block. - * - * If the acknowledgement queue is full, we defer packet - * processing until the client processed pending - * acknowledgements and thereby emitted a ready-to-ack - * signal. Otherwise, the call of 'acknowledge_packet()' - * in '_process_packet' would infinitely block the context - * of the main thread. The main thread is however needed - * for receiving any subsequent 'ready-to-ack' signals. - */ - if (!tx_sink()->ready_to_ack()) - return; + /** + * Destructor + */ + ~Session_component() + { + Dataspace_capability ds = tx_sink()->dataspace(); + _env.ram().free(static_cap_cast(ds)); + } - _process_packet(); - } - } + /*************************** + ** File_system interface ** + ***************************/ - /** - * Check if string represents a valid path (most start with '/') - */ - static void _assert_valid_path(char const *path) - { - if (!valid_path(path)) { - warning("malformed path '", path, "'"); - throw Lookup_failed(); - } - } + File_handle file(Dir_handle dir_handle, Name const &name, + Mode mode, bool create) + { + if (!valid_filename(name.string())) + throw Invalid_name(); - public: - - /** - * Constructor - */ - Session_component(Genode::Env &env, - Genode::Allocator &heap, - size_t tx_buf_size, - Directory &root, - bool writable) - : - Session_rpc_object(env.ram().alloc(tx_buf_size), - env.rm(), env.ep().rpc_ep()), - _env(env), _heap(heap), _root(root), _writable(writable), - _process_packet_dispatcher(env.ep(), *this, - &Session_component::_process_packets) - { - /* - * Register '_process_packets' dispatch function as signal - * handler for packet-avail and ready-to-ack signals. - */ - _tx.sigh_packet_avail(_process_packet_dispatcher); - _tx.sigh_ready_to_ack(_process_packet_dispatcher); - } - - /** - * Destructor - */ - ~Session_component() - { - Dataspace_capability ds = tx_sink()->dataspace(); - _env.ram().free(static_cap_cast(ds)); - } - - /*************************** - ** File_system interface ** - ***************************/ - - File_handle file(Dir_handle dir_handle, Name const &name, - Mode mode, bool create) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); - - if (!valid_filename(name.string())) - throw Invalid_name(); + auto file_fn = [&] (Open_node &open_node) { using namespace Ffat; @@ -237,7 +243,7 @@ namespace File_system { Absolute_path absolute_path(_root.name()); try { - absolute_path.append(_handle_registry.lookup(dir_handle)->name()); + absolute_path.append(open_node.node().name()); absolute_path.append("/"); absolute_path.append(name.string()); } catch (Path_base::Path_too_long) { @@ -250,7 +256,11 @@ namespace File_system { case FR_OK: { File *file_node = new (&_heap) File(absolute_path.base()); file_node->ffat_fil(ffat_fil); - return _handle_registry.alloc(file_node); + + Open_node *open_file = + new (_heap) Open_node(*file_node, _open_node_registry); + + return open_file->id(); } case FR_NO_FILE: case FR_NO_PATH: @@ -283,120 +293,87 @@ namespace File_system { error("f_open() returned an unexpected error code"); throw Lookup_failed(); } - } + }; - Symlink_handle symlink(Dir_handle, Name const &name, bool create) - { - /* not supported */ + try { + return File_handle { + _open_node_registry.apply(dir_handle, file_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + Symlink_handle symlink(Dir_handle, Name const &name, bool create) + { + /* not supported */ + throw Permission_denied(); + } + + Dir_handle dir(Path const &path, bool create) + { + if (create && !_writable) throw Permission_denied(); + + _assert_valid_path(path.string()); + + /* + * The 'Directory' constructor removes trailing slashes, + * except for "/" + */ + Directory *dir_node = new (&_heap) Directory(path.string()); + + using namespace Ffat; + + Absolute_path absolute_path(_root.name()); + + try { + absolute_path.append(dir_node->name()); + absolute_path.remove_trailing('/'); + } catch (Path_base::Path_too_long) { + throw Name_too_long(); } - Dir_handle dir(Path const &path, bool create) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + if (create) { - if (create && !_writable) - throw Permission_denied(); + if (is_root(dir_node->name())) + throw Node_already_exists(); - _assert_valid_path(path.string()); - - /* - * The 'Directory' constructor removes trailing slashes, - * except for "/" - */ - Directory *dir_node = new (&_heap) Directory(path.string()); - - using namespace Ffat; - - Absolute_path absolute_path(_root.name()); + FRESULT res = f_mkdir(absolute_path.base()); try { - absolute_path.append(dir_node->name()); - absolute_path.remove_trailing('/'); - } catch (Path_base::Path_too_long) { - throw Name_too_long(); - } - - if (create) { - - if (is_root(dir_node->name())) - throw Node_already_exists(); - - FRESULT res = f_mkdir(absolute_path.base()); - - try { - switch(res) { - case FR_OK: - break; - case FR_NO_PATH: - throw Lookup_failed(); - case FR_INVALID_NAME: - throw Name_too_long(); - case FR_INVALID_DRIVE: - throw Name_too_long(); - case FR_DENIED: - case FR_WRITE_PROTECTED: - throw Permission_denied(); - case FR_EXIST: - throw Node_already_exists(); - case FR_NOT_READY: - error("f_mkdir() failed with error code FR_NOT_READY"); - throw Lookup_failed(); - case FR_DISK_ERR: - error("f_mkdir() failed with error code FR_DISK_ERR"); - throw Lookup_failed(); - case FR_INT_ERR: - error("f_mkdir() failed with error code FR_INT_ERR"); - throw Lookup_failed(); - case FR_NOT_ENABLED: - error("f_mkdir() failed with error code FR_NOT_ENABLED"); - throw Lookup_failed(); - case FR_NO_FILESYSTEM: - error("f_mkdir() failed with error code FR_NO_FILESYSTEM"); - throw Lookup_failed(); - default: - /* not supposed to occur according to the libffat documentation */ - error("f_mkdir() returned an unexpected error code"); - throw Lookup_failed(); - } - } catch (Exception e) { - destroy(&_heap, dir_node); - throw e; - } - } - - Ffat::DIR ffat_dir; - FRESULT f_opendir_res = f_opendir(&ffat_dir, absolute_path.base()); - - try { - switch(f_opendir_res) { + switch(res) { case FR_OK: - dir_node->ffat_dir(ffat_dir); - return _handle_registry.alloc(dir_node); + break; case FR_NO_PATH: throw Lookup_failed(); case FR_INVALID_NAME: throw Name_too_long(); case FR_INVALID_DRIVE: throw Name_too_long(); + case FR_DENIED: + case FR_WRITE_PROTECTED: + throw Permission_denied(); + case FR_EXIST: + throw Node_already_exists(); case FR_NOT_READY: - error("f_opendir() failed with error code FR_NOT_READY"); + error("f_mkdir() failed with error code FR_NOT_READY"); throw Lookup_failed(); case FR_DISK_ERR: - error("f_opendir() failed with error code FR_DISK_ERR"); + error("f_mkdir() failed with error code FR_DISK_ERR"); throw Lookup_failed(); case FR_INT_ERR: - error("f_opendir() failed with error code FR_INT_ERR"); + error("f_mkdir() failed with error code FR_INT_ERR"); throw Lookup_failed(); case FR_NOT_ENABLED: - error("f_opendir() failed with error code FR_NOT_ENABLED"); + error("f_mkdir() failed with error code FR_NOT_ENABLED"); throw Lookup_failed(); case FR_NO_FILESYSTEM: - error("f_opendir() failed with error code FR_NO_FILESYSTEM"); + error("f_mkdir() failed with error code FR_NO_FILESYSTEM"); throw Lookup_failed(); default: /* not supposed to occur according to the libffat documentation */ - error("f_opendir() returned an unexpected error code"); + error("f_mkdir() returned an unexpected error code"); throw Lookup_failed(); } } catch (Exception e) { @@ -405,145 +382,158 @@ namespace File_system { } } - Node_handle node(Path const &path) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + Ffat::DIR ffat_dir; + FRESULT f_opendir_res = f_opendir(&ffat_dir, absolute_path.base()); - if (!valid_path(path.string())) - throw Lookup_failed(); + try { + switch(f_opendir_res) { + case FR_OK: { + dir_node->ffat_dir(ffat_dir); - Absolute_path absolute_path(_root.name()); + Open_node *open_dir = + new (_heap) Open_node(*dir_node, _open_node_registry); - try { - absolute_path.append(path.string()); - absolute_path.remove_trailing('/'); - } catch (Path_base::Path_too_long) { - throw Lookup_failed(); - } - - Node *node = new (&_heap) Node(absolute_path.base()); - - /* f_stat() does not work for "/" */ - if (!is_root(node->name())) { - - using namespace Ffat; - - FILINFO file_info; - /* the long file name is not used in this function */ - file_info.lfname = 0; - file_info.lfsize = 0; - - FRESULT res = f_stat(node->name(), &file_info); - - try { - switch(res) { - case FR_OK: - break; - case FR_NO_FILE: - case FR_NO_PATH: - throw Lookup_failed(); - case FR_INVALID_NAME: - case FR_INVALID_DRIVE: - throw Lookup_failed(); - case FR_DISK_ERR: - error("f_stat() failed with error code FR_DISK_ERR"); - throw Lookup_failed(); - case FR_INT_ERR: - error("f_stat() failed with error code FR_INT_ERR"); - throw Lookup_failed(); - case FR_NOT_READY: - error("f_stat() failed with error code FR_NOT_READY"); - throw Lookup_failed(); - case FR_NOT_ENABLED: - error("f_stat() failed with error code FR_NOT_ENABLED"); - throw Lookup_failed(); - case FR_NO_FILESYSTEM: - error("f_stat() failed with error code FR_NO_FILESYSTEM"); - throw Lookup_failed(); - default: - /* not supposed to occur according to the libffat documentation */ - error("f_stat() returned an unexpected error code"); - throw Lookup_failed(); - } - } catch (Exception e) { - destroy(&_heap, node); - throw e; + return Dir_handle { open_dir->id().value }; } + case FR_NO_PATH: + throw Lookup_failed(); + case FR_INVALID_NAME: + throw Name_too_long(); + case FR_INVALID_DRIVE: + throw Name_too_long(); + case FR_NOT_READY: + error("f_opendir() failed with error code FR_NOT_READY"); + throw Lookup_failed(); + case FR_DISK_ERR: + error("f_opendir() failed with error code FR_DISK_ERR"); + throw Lookup_failed(); + case FR_INT_ERR: + error("f_opendir() failed with error code FR_INT_ERR"); + throw Lookup_failed(); + case FR_NOT_ENABLED: + error("f_opendir() failed with error code FR_NOT_ENABLED"); + throw Lookup_failed(); + case FR_NO_FILESYSTEM: + error("f_opendir() failed with error code FR_NO_FILESYSTEM"); + throw Lookup_failed(); + default: + /* not supposed to occur according to the libffat documentation */ + error("f_opendir() returned an unexpected error code"); + throw Lookup_failed(); } + } catch (Exception e) { + destroy(&_heap, dir_node); + throw e; + } + } - return _handle_registry.alloc(node); + Node_handle node(Path const &path) + { + if (!valid_path(path.string())) + throw Lookup_failed(); + + Absolute_path absolute_path(_root.name()); + + try { + absolute_path.append(path.string()); + absolute_path.remove_trailing('/'); + } catch (Path_base::Path_too_long) { + throw Lookup_failed(); } - void close(Node_handle handle) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + Node *node = new (&_heap) Node(absolute_path.base()); - Node *node; + /* f_stat() does not work for "/" */ + if (!is_root(node->name())) { + + using namespace Ffat; + + FILINFO file_info; + /* the long file name is not used in this function */ + file_info.lfname = 0; + file_info.lfsize = 0; + + FRESULT res = f_stat(node->name(), &file_info); try { - node = _handle_registry.lookup(handle); - } catch(Invalid_handle) { - error("close() called with invalid handle"); - return; - } - - /* free the handle */ - _handle_registry.free(handle); - - File *file = dynamic_cast(node); - if (file) { - using namespace Ffat; - - FRESULT res = f_close(file->ffat_fil()); - - /* free the node */ - destroy(&_heap, file); - switch(res) { case FR_OK: - return; - case FR_INVALID_OBJECT: - error("f_close() failed with error code FR_INVALID_OBJECT"); - return; + break; + case FR_NO_FILE: + case FR_NO_PATH: + throw Lookup_failed(); + case FR_INVALID_NAME: + case FR_INVALID_DRIVE: + throw Lookup_failed(); case FR_DISK_ERR: - error("f_close() failed with error code FR_DISK_ERR"); - return; + error("f_stat() failed with error code FR_DISK_ERR"); + throw Lookup_failed(); case FR_INT_ERR: - error("f_close() failed with error code FR_INT_ERR"); - return; + error("f_stat() failed with error code FR_INT_ERR"); + throw Lookup_failed(); case FR_NOT_READY: - error("f_close() failed with error code FR_NOT_READY"); - return; + error("f_stat() failed with error code FR_NOT_READY"); + throw Lookup_failed(); + case FR_NOT_ENABLED: + error("f_stat() failed with error code FR_NOT_ENABLED"); + throw Lookup_failed(); + case FR_NO_FILESYSTEM: + error("f_stat() failed with error code FR_NO_FILESYSTEM"); + throw Lookup_failed(); default: /* not supposed to occur according to the libffat documentation */ - error("f_close() returned an unexpected error code"); - return; + error("f_stat() returned an unexpected error code"); + throw Lookup_failed(); } + } catch (Exception e) { + destroy(&_heap, node); + throw e; } } - Status status(Node_handle node_handle) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + Open_node *open_node = + new (_heap) Open_node(*node, _open_node_registry); + + return open_node->id(); + } + + void close(Node_handle handle) + { + auto close_fn = [&] (Open_node &open_node) { + Node &node = open_node.node(); + destroy(_heap, &open_node); + destroy(_heap, &node); + }; + + try { + _open_node_registry.apply(handle, close_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + Status status(Node_handle node_handle) + { + auto status_fn = [&] (Open_node &open_node) { Status status; status.inode = 1; status.size = 0; status.mode = 0; - Node *node = _handle_registry.lookup(node_handle); + Node &node = open_node.node(); using namespace Ffat; /* f_stat() does not work for the '/' directory */ - if (!is_root(node->name())) { + if (!is_root(node.name())) { FILINFO ffat_file_info; /* the long file name is not used in this function */ ffat_file_info.lfname = 0; ffat_file_info.lfsize = 0; - FRESULT res = f_stat(node->name(), &ffat_file_info); + FRESULT res = f_stat(node.name(), &ffat_file_info); switch(res) { case FR_OK: @@ -597,7 +587,7 @@ namespace File_system { /* determine the number of directory entries */ Ffat::DIR ffat_dir; - FRESULT f_opendir_res = f_opendir(&ffat_dir, node->name()); + FRESULT f_opendir_res = f_opendir(&ffat_dir, node.name()); if (f_opendir_res != FR_OK) return status; @@ -619,26 +609,33 @@ namespace File_system { } return status; + }; + + try { + return _open_node_registry.apply(node_handle, status_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } + } - void control(Node_handle, Control) { } + void control(Node_handle, Control) { } - void unlink(Dir_handle dir_handle, Name const &name) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + void unlink(Dir_handle dir_handle, Name const &name) + { + if (!valid_filename(name.string())) + throw Invalid_name(); - if (!valid_filename(name.string())) - throw Invalid_name(); + if (!_writable) + throw Permission_denied(); - if (!_writable) - throw Permission_denied(); + auto unlink_fn = [&] (Open_node &open_node) { using namespace Ffat; Absolute_path absolute_path(_root.name()); try { - absolute_path.append(_handle_registry.lookup(dir_handle)->name()); + absolute_path.append(open_node.node().name()); absolute_path.append("/"); absolute_path.append(name.string()); } catch (Path_base::Path_too_long) { @@ -679,308 +676,278 @@ namespace File_system { error("f_unlink() returned an unexpected error code"); return; } + }; + + 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) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + void truncate(File_handle file_handle, file_size_t size) + { + if (!_writable) + throw Permission_denied(); - if (!_writable) - throw Permission_denied(); + auto truncate_fn = [&] (Open_node &open_node) { + open_node.node().truncate(size); + }; - File *file = _handle_registry.lookup(file_handle); - - using namespace Ffat; - - /* 'f_truncate()' truncates to the current seek pointer */ - - FRESULT res = f_lseek(file->ffat_fil(), size); - - switch(res) { - case FR_OK: - /* according to the FatFs documentation this can happen */ - if (f_tell(file->ffat_fil()) != size) { - error("f_lseek() could not seek to offset ", size); - return; - } - break; - case FR_DISK_ERR: - error("f_lseek() failed with error code FR_DISK_ERR"); - return; - case FR_INT_ERR: - error("f_lseek() failed with error code FR_INT_ERR"); - return; - case FR_NOT_READY: - error("f_lseek() failed with error code FR_NOT_READY"); - return; - case FR_INVALID_OBJECT: - error("f_lseek() failed with error code FR_INVALID_OBJECT"); - throw Invalid_handle(); - default: - /* not supposed to occur according to the libffat documentation */ - error("f_lseek() returned an unexpected error code"); - return; - } - - res = f_truncate(file->ffat_fil()); - - switch(res) { - case FR_OK: - return; - case FR_INVALID_OBJECT: - error("f_truncate() failed with error code FR_INVALID_OBJECT"); - throw Invalid_handle(); - case FR_DISK_ERR: - error("f_truncate() failed with error code FR_DISK_ERR"); - return; - case FR_INT_ERR: - error("f_truncate() failed with error code FR_INT_ERR"); - return; - case FR_NOT_READY: - error("f_truncate() failed with error code FR_NOT_READY"); - return; - case FR_TIMEOUT: - error("f_truncate() failed with error code FR_TIMEOUT"); - return; - default: - /* not supposed to occur according to the libffat documentation */ - error("f_truncate() returned an unexpected error code"); - return; - } + try { + _open_node_registry.apply(file_handle, truncate_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } + } - void move(Dir_handle from_dir_handle, Name const &from_name, - Dir_handle to_dir_handle, Name const &to_name) - { - Ffat_lock_guard ffat_lock_guard(_ffat_lock); + void move(Dir_handle from_dir_handle, Name const &from_name, + Dir_handle to_dir_handle, Name const &to_name) + { + if (!_writable) + throw Permission_denied(); - if (!_writable) - throw Permission_denied(); + if (!valid_filename(from_name.string())) + throw Lookup_failed(); - if (!valid_filename(from_name.string())) - throw Lookup_failed(); + if (!valid_filename(to_name.string())) + throw Invalid_name(); - if (!valid_filename(to_name.string())) - throw Invalid_name(); + auto move_fn = [&] (Open_node &open_from_dir_node) { - Absolute_path absolute_from_path(_root.name()); - Absolute_path absolute_to_path(_root.name()); + auto inner_move_fn = [&] (Open_node &open_to_dir_node) { - try { - absolute_from_path.append(_handle_registry.lookup(from_dir_handle)->name()); - absolute_from_path.append("/"); - absolute_from_path.append(from_name.string()); - absolute_to_path.append(_handle_registry.lookup(to_dir_handle)->name()); - absolute_to_path.append("/"); - absolute_to_path.append(to_name.string()); - } catch (Path_base::Path_too_long) { - throw Invalid_name(); - } + Absolute_path absolute_from_path(_root.name()); + Absolute_path absolute_to_path(_root.name()); - using namespace Ffat; - - FRESULT res = f_rename(absolute_from_path.base(), absolute_to_path.base()); - - switch(res) { - case FR_OK: - break; - case FR_NO_FILE: - case FR_NO_PATH: - throw Lookup_failed(); - case FR_INVALID_NAME: - case FR_INVALID_DRIVE: - throw Invalid_name(); - case FR_EXIST: - error("f_rename() failed with error code FR_EXIST"); - throw Invalid_name(); - case FR_DENIED: - case FR_WRITE_PROTECTED: - throw Permission_denied(); - case FR_DISK_ERR: - error("f_rename() failed with error code FR_DISK_ERR"); - throw Lookup_failed(); - case FR_INT_ERR: - error("f_rename() failed with error code FR_INT_ERR"); - throw Lookup_failed(); - case FR_NOT_READY: - error("f_rename() failed with error code FR_NOT_READY"); - throw Lookup_failed(); - case FR_NOT_ENABLED: - error("f_rename() failed with error code FR_NOT_ENABLED"); - throw Lookup_failed(); - case FR_NO_FILESYSTEM: - error("f_rename() failed with error code FR_NO_FILESYSTEM"); - throw Lookup_failed(); - default: - /* not supposed to occur according to the libffat documentation */ - error("f_rename() returned an unexpected error code"); - throw Lookup_failed(); - } - } - - void sigh(Node_handle, Genode::Signal_context_capability) - { - error("File_system::Session::sigh not supported"); - } - }; - - - class Root : public Root_component - { - private: - - Genode::Env &_env; - Genode::Allocator &_md_alloc; - Genode::Allocator &_heap; - Genode::Attached_rom_dataspace _config { _env, "config" }; - Directory &_root_dir; - - protected: - - Session_component *_create_session(const char *args) - { - /* - * Determine client-specific policy defined implicitly by - * the client's label. - */ - Directory *session_root_dir = 0; - bool writeable = false; - - enum { ROOT_MAX_LEN = 256 }; - char root[ROOT_MAX_LEN]; - root[0] = 0; - - Session_label const label = label_from_args(args); - try { - Session_policy policy(label, _config.xml()); - - /* - * Determine directory that is used as root directory of - * the session. - */ try { - policy.attribute("root").value(root, sizeof(root)); - if (is_root(root)) { - session_root_dir = &_root_dir; - } else { - /* - * Make sure the root path is specified with a - * leading path delimiter. For performing the - * lookup, we skip the first character. - */ - if (root[0] != '/') - throw Lookup_failed(); - - /* Check if the root path exists */ - - using namespace Ffat; - - FRESULT res = f_chdir(root); - - switch(res) { - case FR_OK: - break; - case FR_NO_PATH: - throw Lookup_failed(); - case FR_INVALID_NAME: - case FR_INVALID_DRIVE: - throw Lookup_failed(); - case FR_NOT_READY: - error("f_chdir() failed with error code FR_NOT_READY"); - throw Service_denied(); - case FR_DISK_ERR: - error("f_chdir() failed with error code FR_DISK_ERR"); - throw Service_denied(); - case FR_INT_ERR: - error("f_chdir() failed with error code FR_INT_ERR"); - throw Service_denied(); - case FR_NOT_ENABLED: - error("f_chdir() failed with error code FR_NOT_ENABLED"); - throw Service_denied(); - case FR_NO_FILESYSTEM: - error("f_chdir() failed with error code FR_NO_FILESYSTEM"); - throw Service_denied(); - default: - /* not supposed to occur according to the libffat documentation */ - error("f_chdir() returned an unexpected error code"); - throw Service_denied(); - } - - session_root_dir = new (&_md_alloc) Directory(root); - } - } - catch (Xml_node::Nonexistent_attribute) { - error("missing \"root\" attribute in policy definition"); - throw Service_denied(); - } - catch (Lookup_failed) { - error("session root directory \"", Cstring(root), "\" does not exist"); - throw Service_denied(); + absolute_from_path.append(open_from_dir_node.node().name()); + absolute_from_path.append("/"); + absolute_from_path.append(from_name.string()); + absolute_to_path.append(open_to_dir_node.node().name()); + absolute_to_path.append("/"); + absolute_to_path.append(to_name.string()); + } catch (Path_base::Path_too_long) { + throw Invalid_name(); } - /* - * Determine if write access is permitted for the session. - */ - writeable = policy.attribute_value("writeable", false); - } - catch (Session_policy::No_policy_defined) { - error("Invalid session request, no matching policy"); - throw Service_denied(); - } + using namespace Ffat; - size_t ram_quota = - Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); - size_t tx_buf_size = - Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + FRESULT res = f_rename(absolute_from_path.base(), absolute_to_path.base()); - if (!tx_buf_size) { - error(label, " requested a session with a zero length transmission buffer"); - throw Service_denied(); - } + switch(res) { + case FR_OK: + break; + case FR_NO_FILE: + case FR_NO_PATH: + throw Lookup_failed(); + case FR_INVALID_NAME: + case FR_INVALID_DRIVE: + throw Invalid_name(); + case FR_EXIST: + error("f_rename() failed with error code FR_EXIST"); + throw Invalid_name(); + case FR_DENIED: + case FR_WRITE_PROTECTED: + throw Permission_denied(); + case FR_DISK_ERR: + error("f_rename() failed with error code FR_DISK_ERR"); + throw Lookup_failed(); + case FR_INT_ERR: + error("f_rename() failed with error code FR_INT_ERR"); + throw Lookup_failed(); + case FR_NOT_READY: + error("f_rename() failed with error code FR_NOT_READY"); + throw Lookup_failed(); + case FR_NOT_ENABLED: + error("f_rename() failed with error code FR_NOT_ENABLED"); + throw Lookup_failed(); + case FR_NO_FILESYSTEM: + error("f_rename() failed with error code FR_NO_FILESYSTEM"); + throw Lookup_failed(); + default: + /* not supposed to occur according to the libffat documentation */ + error("f_rename() returned an unexpected error code"); + throw Lookup_failed(); + } + }; - /* - * Check if donated ram quota suffices for session data, - * and communication buffer. - */ - size_t session_size = sizeof(Session_component) + tx_buf_size; - if (max((size_t)4096, session_size) > ram_quota) { - error("insufficient 'ram_quota', got ", ram_quota, ", " - "need ", session_size); - throw Insufficient_ram_quota(); + try { + _open_node_registry.apply(to_dir_handle, inner_move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - return new (md_alloc()) - Session_component(_env, _heap, tx_buf_size, - *session_root_dir, writeable); + }; + + try { + _open_node_registry.apply(from_dir_handle, move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } + } - public: - - /** - * Constructor - * - * \param env reference to Genode environment - * \param heap meta-data allocator - * \param root normal root directory if root in policy starts - * at root - */ - Root(Genode::Env &env, Allocator &md_alloc, Genode::Allocator &heap, - Directory &root) - : - Root_component(&env.ep().rpc_ep(), &md_alloc), - _env(env), _md_alloc(md_alloc), _heap(heap), _root_dir(root) - { } - }; + void sigh(Node_handle, Genode::Signal_context_capability) + { + error("File_system::Session::sigh not supported"); + } }; -struct Main +class Ffat_fs::Root : public Root_component +{ + private: + + Genode::Env &_env; + Genode::Allocator &_md_alloc; + Genode::Allocator &_heap; + Genode::Attached_rom_dataspace _config { _env, "config" }; + Directory &_root_dir; + + protected: + + Session_component *_create_session(const char *args) + { + /* + * Determine client-specific policy defined implicitly by + * the client's label. + */ + Directory *session_root_dir = 0; + bool writeable = false; + + enum { ROOT_MAX_LEN = 256 }; + char root[ROOT_MAX_LEN]; + root[0] = 0; + + Session_label const label = label_from_args(args); + try { + Session_policy policy(label, _config.xml()); + + /* + * Determine directory that is used as root directory of + * the session. + */ + try { + policy.attribute("root").value(root, sizeof(root)); + if (is_root(root)) { + session_root_dir = &_root_dir; + } else { + /* + * Make sure the root path is specified with a + * leading path delimiter. For performing the + * lookup, we skip the first character. + */ + if (root[0] != '/') + throw Lookup_failed(); + + /* Check if the root path exists */ + + using namespace Ffat; + + FRESULT res = f_chdir(root); + + switch(res) { + case FR_OK: + break; + case FR_NO_PATH: + throw Lookup_failed(); + case FR_INVALID_NAME: + case FR_INVALID_DRIVE: + throw Lookup_failed(); + case FR_NOT_READY: + error("f_chdir() failed with error code FR_NOT_READY"); + throw Service_denied(); + case FR_DISK_ERR: + error("f_chdir() failed with error code FR_DISK_ERR"); + throw Service_denied(); + case FR_INT_ERR: + error("f_chdir() failed with error code FR_INT_ERR"); + throw Service_denied(); + case FR_NOT_ENABLED: + error("f_chdir() failed with error code FR_NOT_ENABLED"); + throw Service_denied(); + case FR_NO_FILESYSTEM: + error("f_chdir() failed with error code FR_NO_FILESYSTEM"); + throw Service_denied(); + default: + /* not supposed to occur according to the libffat documentation */ + error("f_chdir() returned an unexpected error code"); + throw Service_denied(); + } + + session_root_dir = new (&_md_alloc) Directory(root); + } + } + catch (Xml_node::Nonexistent_attribute) { + error("missing \"root\" attribute in policy definition"); + throw Service_denied(); + } + catch (Lookup_failed) { + error("session root directory \"", Cstring(root), "\" does not exist"); + throw Service_denied(); + } + + /* + * Determine if write access is permitted for the session. + */ + writeable = policy.attribute_value("writeable", false); + } + catch (Session_policy::No_policy_defined) { + error("Invalid session request, no matching policy"); + throw Service_denied(); + } + + size_t ram_quota = + Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = + Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + + if (!tx_buf_size) { + error(label, " requested a session with a zero length transmission buffer"); + throw Service_denied(); + } + + /* + * Check if donated ram quota suffices for session data, + * and communication buffer. + */ + size_t session_size = sizeof(Session_component) + tx_buf_size; + if (max((size_t)4096, session_size) > ram_quota) { + error("insufficient 'ram_quota', got ", ram_quota, ", " + "need ", session_size); + throw Insufficient_ram_quota(); + } + return new (md_alloc()) + Session_component(_env, _heap, tx_buf_size, + *session_root_dir, writeable); + } + + public: + + /** + * Constructor + * + * \param env reference to Genode environment + * \param heap meta-data allocator + * \param root normal root directory if root in policy starts + * at root + */ + Root(Genode::Env &env, Allocator &md_alloc, Genode::Allocator &heap, + Directory &root) + : + Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), _md_alloc(md_alloc), _heap(heap), _root_dir(root) + { } +}; + + +struct Ffat_fs::Main { Genode::Env &_env; Genode::Heap _heap { _env.ram(), _env.rm() }; Genode::Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; - File_system::Directory _root_dir { "/" }; - File_system::Root _root { _env, _sliced_heap, _heap, _root_dir }; + Directory _root_dir { "/" }; + Root _root { _env, _sliced_heap, _heap, _root_dir }; Ffat::FATFS _fatfs; @@ -1011,5 +978,5 @@ void Component::construct(Genode::Env &env) /* XXX execute constructors of global statics */ env.exec_static_constructors(); - static Main main(env); + static Ffat_fs::Main main(env); } diff --git a/repos/libports/src/server/ffat_fs/node.h b/repos/libports/src/server/ffat_fs/node.h index e9a71a9d4..619b1f9a4 100644 --- a/repos/libports/src/server/ffat_fs/node.h +++ b/repos/libports/src/server/ffat_fs/node.h @@ -4,6 +4,13 @@ * \date 2012-07-04 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _NODE_H_ #define _NODE_H_ @@ -17,41 +24,52 @@ namespace Ffat { extern "C" { #include } } -namespace File_system { +namespace Ffat_fs { + using namespace File_system; typedef Genode::Path<_MAX_LFN + 1> Absolute_path; - class Node : public Node_base - { - protected: - - Absolute_path _name; - - public: - - Node(const char *name) : _name(name) { } - - char const *name() { return _name.base(); } - - /* - * A generic Node object can be created to represent a file or - * directory by its name without opening it, so the functions - * of this class must not be abstract. - */ - - virtual size_t read(char *dst, size_t len, seek_off_t) - { - Genode::error("read() called on generic Node object"); - return 0; - } - - virtual size_t write(char const *src, size_t len, seek_off_t) - { - Genode::error("write() called on generic Node object"); - return 0; - } - }; - + class Node; } + +class Ffat_fs::Node : public Node_base +{ + protected: + + Absolute_path _name; + + public: + + Node(const char *name) : _name(name) { } + + char const *name() { return _name.base(); } + + /* + * A generic Node object can be created to represent a file or + * directory by its name without opening it, so the functions + * of this class must not be abstract. + */ + + virtual size_t read(char *dst, size_t len, seek_off_t) + { + Genode::error("read() called on generic Node object"); + return 0; + } + + virtual size_t write(char const *src, size_t len, seek_off_t) + { + Genode::error("write() called on generic Node object"); + return 0; + } + + /* + * File functionality + */ + virtual void truncate(file_size_t size) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); + } +}; + #endif /* _NODE_H_ */ diff --git a/repos/libports/src/server/fuse_fs/directory.h b/repos/libports/src/server/fuse_fs/directory.h index d8ad53494..abf43e5f9 100644 --- a/repos/libports/src/server/fuse_fs/directory.h +++ b/repos/libports/src/server/fuse_fs/directory.h @@ -6,6 +6,13 @@ * \date 2013-11-11 */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _DIRECTORY_H_ #define _DIRECTORY_H_ @@ -30,12 +37,12 @@ #include -namespace File_system { +namespace Fuse_fs { class Directory; } -class File_system::Directory : public Node +class Fuse_fs::Directory : public Node { private: @@ -181,13 +188,12 @@ class File_system::Directory : public Node else throw Lookup_failed(); - node->lock(); return node; } struct fuse_file_info *file_info() { return &_file_info; } - Status status() + Status status() override { struct stat s; int res = Fuse::fuse()->op.getattr(_path.base(), &s); @@ -202,7 +208,7 @@ class File_system::Directory : public Node return status; } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { if (len < sizeof(Directory_entry)) { Genode::error("read buffer too small for directory entry"); @@ -277,7 +283,7 @@ class File_system::Directory : public Node return sizeof(Directory_entry); } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* writing to directory nodes is not supported */ return 0; diff --git a/repos/libports/src/server/fuse_fs/file.h b/repos/libports/src/server/fuse_fs/file.h index afb7f589e..d654c9c80 100644 --- a/repos/libports/src/server/fuse_fs/file.h +++ b/repos/libports/src/server/fuse_fs/file.h @@ -6,6 +6,13 @@ * \date 2013-11-26 */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _FILE_H_ #define _FILE_H_ @@ -16,12 +23,12 @@ #include #include -namespace File_system { +namespace Fuse_fs { class File; } -class File_system::File : public Node +class Fuse_fs::File : public Node { private: @@ -104,7 +111,7 @@ class File_system::File : public Node struct fuse_file_info *file_info() { return &_file_info; } - Status status() + Status status() override { struct stat s; int res = Fuse::fuse()->op.getattr(_path.base(), &s); @@ -118,7 +125,7 @@ class File_system::File : public Node return status; } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { /* append mode, use actual length as offset */ if (seek_offset == ~0ULL) @@ -129,7 +136,7 @@ class File_system::File : public Node return ret < 0 ? 0 : ret; } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* append mode, use actual length as offset */ if (seek_offset == ~0ULL) @@ -140,7 +147,7 @@ class File_system::File : public Node return ret < 0 ? 0 : ret; } - void truncate(file_size_t size) + void truncate(file_size_t size) override { int res = Fuse::fuse()->op.ftruncate(_path.base(), size, &_file_info); diff --git a/repos/libports/src/server/fuse_fs/fuse_fs_main.cc b/repos/libports/src/server/fuse_fs/fuse_fs_main.cc index 18808882f..7c9b5eb97 100644 --- a/repos/libports/src/server/fuse_fs/fuse_fs_main.cc +++ b/repos/libports/src/server/fuse_fs/fuse_fs_main.cc @@ -13,7 +13,7 @@ /* Genode includes */ #include -#include +#include #include #include #include @@ -29,22 +29,29 @@ #include -namespace File_system { +namespace Fuse_fs { + + using namespace Genode; + using File_system::Packet_descriptor; + using File_system::Path; + struct Main; struct Session_component; struct Root; } -class File_system::Session_component : public Session_rpc_object +class Fuse_fs::Session_component : public Session_rpc_object { private: - Genode::Env &_env; - Allocator &_md_alloc; - Directory &_root; - Node_handle_registry _handle_registry; - bool _writeable; + typedef File_system::Open_node Open_node; + + Genode::Env &_env; + Allocator &_md_alloc; + Directory &_root; + Id_space _open_node_registry; + bool _writeable; Signal_handler _process_packet_handler; @@ -58,7 +65,7 @@ class File_system::Session_component : public Session_rpc_object * * \return true on success, false on failure */ - void _process_packet_op(Packet_descriptor &packet, Node &node) + void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) { void * const content = tx_sink()->packet_content(packet); size_t const length = packet.length(); @@ -70,18 +77,18 @@ class File_system::Session_component : public Session_rpc_object case Packet_descriptor::READ: if (content && (packet.length() <= packet.size())) - res_length = node.read((char *)content, length, packet.position()); + res_length = open_node.node().read((char *)content, length, packet.position()); break; case Packet_descriptor::WRITE: if (content && (packet.length() <= packet.size())) - res_length = node.write((char const *)content, length, packet.position()); + res_length = open_node.node().write((char const *)content, length, packet.position()); break; case Packet_descriptor::CONTENT_CHANGED: - _handle_registry.register_notify(*tx_sink(), packet.handle()); + open_node.register_notify(*tx_sink()); /* notify_listeners may bounce the packet back*/ - node.notify_listeners(); + open_node.node().notify_listeners(); /* otherwise defer acknowledgement of this packet */ return; @@ -102,13 +109,16 @@ class File_system::Session_component : public Session_rpc_object /* assume failure by default */ packet.succeeded(false); - try { - Node *node = _handle_registry.lookup_and_lock(packet.handle()); - Node_lock_guard guard(node); + auto process_packet_fn = [&] (Open_node &open_node) { + _process_packet_op(packet, open_node); + }; - _process_packet_op(packet, *node); + try { + _open_node_registry.apply(packet.handle(), process_packet_fn); + } catch (Id_space::Unknown_id const &) { + Genode::error("Invalid_handle"); + tx_sink()->acknowledge_packet(packet); } - catch (Invalid_handle) { Genode::error("Invalid_handle"); } } /** @@ -193,38 +203,60 @@ class File_system::Session_component : public Session_rpc_object if (!valid_filename(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup_and_lock(dir_handle); - Node_lock_guard dir_guard(dir); + auto file_fn = [&] (Open_node &open_node) { - if (create && !_writeable) - throw Permission_denied(); + Node &dir = open_node.node(); - File *file = new (&_md_alloc) File(dir, name.string(), mode, create); - Node_lock_guard file_guard(file); + if (create && !_writeable) + throw Permission_denied(); - return _handle_registry.alloc(file); + File *file = new (&_md_alloc) File(&dir, name.string(), mode, create); + + Open_node *open_file = + new (_md_alloc) Open_node(*file, _open_node_registry); + + return open_file->id(); + }; + + try { + return File_handle { + _open_node_registry.apply(dir_handle, file_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) { if (! Fuse::support_symlinks()) { Genode::error("FUSE file system does not support symlinks"); - return Symlink_handle(); + throw Permission_denied(); } if (!valid_filename(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup_and_lock(dir_handle); - Node_lock_guard dir_guard(dir); + auto symlink_fn = [&] (Open_node &open_node) { - if (create && !_writeable) - throw Permission_denied(); + Node &dir = open_node.node(); - Symlink *symlink = new (&_md_alloc) Symlink(dir, name.string(), create); - Node_lock_guard symlink_guard(symlink); + if (create && !_writeable) + throw Permission_denied(); - return _handle_registry.alloc(symlink); + Symlink *symlink = new (&_md_alloc) Symlink(&dir, name.string(), create); + + Open_node *open_symlink = + new (_md_alloc) Open_node(*symlink, _open_node_registry); + + return Symlink_handle { open_symlink->id().value }; + }; + + try { + return _open_node_registry.apply(dir_handle, symlink_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Dir_handle dir(Path const &path, bool create) @@ -241,8 +273,10 @@ class File_system::Session_component : public Session_rpc_object Directory *dir_node = new (&_md_alloc) Directory(_md_alloc, path_str, create); - Node_lock_guard guard(dir_node); - return _handle_registry.alloc(dir_node); + Open_node *open_dir = + new (_md_alloc) Open_node(*dir_node, _open_node_registry); + + return Dir_handle { open_dir->id().value }; } Node_handle node(Path const &path) @@ -257,48 +291,38 @@ class File_system::Session_component : public Session_rpc_object */ Node *node = _root.node(path_str + 1); - Node_lock_guard guard(node); - return _handle_registry.alloc(node); + Open_node *open_node = + new (_md_alloc) Open_node(*node, _open_node_registry); + + return open_node->id(); } void close(Node_handle handle) { - Node *node; + auto close_fn = [&] (Open_node &open_node) { + Node &node = open_node.node(); + destroy(_md_alloc, &open_node); + destroy(_md_alloc, &node); + }; try { - node = _handle_registry.lookup_and_lock(handle); - /** - * We need to call unlock() here because the handle registry - * calls lock() itself on the node. - */ - node->unlock(); - } catch (Invalid_handle) { - Genode::error("close() called with invalid handle"); - return; + _open_node_registry.apply(handle, close_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - - _handle_registry.free(handle); - destroy(&_md_alloc, node); } Status status(Node_handle node_handle) { - Node *node = _handle_registry.lookup_and_lock(node_handle); - Node_lock_guard guard(node); + auto status_fn = [&] (Open_node &open_node) { + return open_node.node().status(); + }; - File *file = dynamic_cast(node); - if (file) - return file->status(); - - Directory *dir = dynamic_cast(node); - if (dir) - return dir->status(); - - Symlink *symlink = dynamic_cast(node); - if (symlink) - return symlink->status(); - - return Status(); + try { + return _open_node_registry.apply(node_handle, status_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } void control(Node_handle, Control) @@ -311,25 +335,33 @@ class File_system::Session_component : public Session_rpc_object if (!_writeable) throw Permission_denied(); - Directory *dir = _handle_registry.lookup_and_lock(dir_handle); - Node_lock_guard dir_guard(dir); + auto unlink_fn = [&] (Open_node &open_node) { - Absolute_path absolute_path(_root.name()); + Node &dir = open_node.node(); + + Absolute_path absolute_path(_root.name()); + + try { + absolute_path.append(dir.name()); + absolute_path.append("/"); + absolute_path.append(name.string()); + } catch (Path_base::Path_too_long) { + throw Invalid_name(); + } + + /* XXX remove direct use of FUSE operations */ + int res = Fuse::fuse()->op.unlink(absolute_path.base()); + + if (res != 0) { + Genode::error("fuse()->op.unlink() returned unexpected error code: ", res); + return; + } + }; try { - absolute_path.append(dir->name()); - absolute_path.append("/"); - absolute_path.append(name.string()); - } catch (Path_base::Path_too_long) { - throw Invalid_name(); - } - - /* XXX remove direct use of FUSE operations */ - int res = Fuse::fuse()->op.unlink(absolute_path.base()); - - if (res != 0) { - Genode::error("fuse()->op.unlink() returned unexpected error code: ", res); - return; + _open_node_registry.apply(dir_handle, unlink_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } } @@ -338,12 +370,15 @@ class File_system::Session_component : public Session_rpc_object if (!_writeable) throw Permission_denied(); - File *file; - try { file = _handle_registry.lookup_and_lock(file_handle); } - catch (Invalid_handle) { throw Lookup_failed(); } + auto truncate_fn = [&] (Open_node &open_node) { + open_node.node().truncate(size); + }; - Node_lock_guard file_guard(file); - file->truncate(size); + try { + _open_node_registry.apply(file_handle, truncate_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } void move(Dir_handle from_dir_handle, Name const &from_name, @@ -352,40 +387,48 @@ class File_system::Session_component : public Session_rpc_object if (!_writeable) throw Permission_denied(); - Directory *from_dir, *to_dir; - try { from_dir = _handle_registry.lookup_and_lock(from_dir_handle); } - catch (Invalid_handle) { throw Lookup_failed(); } + auto move_fn = [&] (Open_node &open_from_dir_node) { - try { to_dir = _handle_registry.lookup_and_lock(to_dir_handle); } - catch (Invalid_handle) { - from_dir->unlock(); - throw Lookup_failed(); - } + auto inner_move_fn = [&] (Open_node &open_to_dir_node) { - Node_lock_guard from_dir_guard(from_dir); - Node_lock_guard to_dir_guard(to_dir); + Node &from_dir = open_from_dir_node.node(); + Node &to_dir = open_to_dir_node.node(); - Absolute_path absolute_from_path(_root.name()); - Absolute_path absolute_to_path(_root.name()); + Absolute_path absolute_from_path(_root.name()); + Absolute_path absolute_to_path(_root.name()); + + try { + absolute_from_path.append(from_dir.name()); + absolute_from_path.append("/"); + absolute_from_path.append(from_name.string()); + absolute_to_path.append(to_dir.name()); + absolute_to_path.append("/"); + absolute_to_path.append(to_name.string()); + } catch (Path_base::Path_too_long) { + throw Invalid_name(); + } + + /* XXX remove direct use of FUSE operations */ + int res = Fuse::fuse()->op.rename(absolute_to_path.base(), + absolute_from_path.base()); + + if (res != 0) { + Genode::error("fuse()->op.rename() returned unexpected error code: ", res); + return; + } + }; + + try { + _open_node_registry.apply(to_dir_handle, inner_move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + }; try { - absolute_from_path.append(from_dir->name()); - absolute_from_path.append("/"); - absolute_from_path.append(from_name.string()); - absolute_to_path.append(to_dir->name()); - absolute_to_path.append("/"); - absolute_to_path.append(to_name.string()); - } catch (Path_base::Path_too_long) { - throw Invalid_name(); - } - - /* XXX remove direct use of FUSE operations */ - int res = Fuse::fuse()->op.rename(absolute_to_path.base(), - absolute_from_path.base()); - - if (res != 0) { - Genode::error("fuse()->op.rename() returned unexpected error code: ", res); - return; + _open_node_registry.apply(from_dir_handle, move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } } @@ -396,7 +439,7 @@ class File_system::Session_component : public Session_rpc_object }; -class File_system::Root : public Root_component +class Fuse_fs::Root : public Root_component { private: @@ -500,7 +543,7 @@ class File_system::Root : public Root_component }; -struct File_system::Main +struct Fuse_fs::Main { Genode::Env & env; Sliced_heap sliced_heap { env.ram(), env.rm() }; @@ -531,6 +574,6 @@ struct File_system::Main void Libc::Component::construct(Libc::Env &env) { - static File_system::Main inst(env); + static Fuse_fs::Main inst(env); } diff --git a/repos/libports/src/server/fuse_fs/node.h b/repos/libports/src/server/fuse_fs/node.h index 056d4e604..c4330f72f 100644 --- a/repos/libports/src/server/fuse_fs/node.h +++ b/repos/libports/src/server/fuse_fs/node.h @@ -6,40 +6,57 @@ * \date 2013-11-11 */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _NODE_H_ #define _NODE_H_ /* Genode includes */ #include -#include #include #include #include -namespace File_system { +namespace Fuse_fs { using namespace Genode; + using namespace File_system; typedef Genode::Path Absolute_path; - class Node : public Node_base, public List::Element - { - protected: - - unsigned long _inode; - Absolute_path _name; - - public: - - Node(char const *name) : _name(name) { } - - char const *name() const { return _name.base(); } - - virtual size_t read(char *dst, size_t len, seek_off_t) = 0; - virtual size_t write(char const *src, size_t len, seek_off_t) = 0; - }; - + class Node; } +class Fuse_fs::Node : public Node_base +{ + protected: + + unsigned long _inode; + Absolute_path _name; + + public: + + Node(char const *name) : _name(name) { } + + char const *name() const { return _name.base(); } + + virtual size_t read(char *dst, size_t len, seek_off_t) = 0; + virtual size_t write(char const *src, size_t len, seek_off_t) = 0; + virtual Status status() = 0; + + /* + * File functionality + */ + virtual void truncate(file_size_t size) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); + } +}; + #endif /* _NODE_H_ */ diff --git a/repos/libports/src/server/fuse_fs/symlink.h b/repos/libports/src/server/fuse_fs/symlink.h index 590f6198e..61a96c4eb 100644 --- a/repos/libports/src/server/fuse_fs/symlink.h +++ b/repos/libports/src/server/fuse_fs/symlink.h @@ -6,6 +6,13 @@ * \date 2013-11-26 */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _SYMLINK_H_ #define _SYMLINK_H_ @@ -13,12 +20,12 @@ #include -namespace File_system { +namespace Fuse_fs { class Symlink; } -class File_system::Symlink : public Node +class Fuse_fs::Symlink : public Node { private: @@ -45,7 +52,7 @@ class File_system::Symlink : public Node _path(name, parent->name()) { } - Status status() + Status status() override { struct stat s; int res = Fuse::fuse()->op.getattr(_path.base(), &s); @@ -59,7 +66,7 @@ class File_system::Symlink : public Node return status; } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { int res = Fuse::fuse()->op.readlink(_path.base(), dst, len); if (res != 0) @@ -68,7 +75,7 @@ class File_system::Symlink : public Node return Genode::strlen(dst); } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* Ideal symlink operations are atomic. */ if (seek_offset) return 0; diff --git a/repos/os/include/file_system/listener.h b/repos/os/include/file_system/listener.h index 4e2486833..8daf013e5 100644 --- a/repos/os/include/file_system/listener.h +++ b/repos/os/include/file_system/listener.h @@ -4,6 +4,13 @@ * \date 2012-04-11 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _FILE_SYSTEM__LISTENER_H_ #define _FILE_SYSTEM__LISTENER_H_ @@ -23,23 +30,21 @@ namespace File_system { private: Genode::Lock _lock; - Sink *_sink = nullptr; + Sink &_sink; Node_handle _handle; bool _marked_as_updated; public: - Listener() : _marked_as_updated(false) { } - Listener(Sink &sink, Node_handle handle) - : _sink(&sink), _handle(handle), _marked_as_updated(false) { } + : _sink(sink), _handle(handle), _marked_as_updated(false) { } void notify() { Genode::Lock::Guard guard(_lock); - if (_marked_as_updated && _sink && _sink->ready_to_ack()) { - _sink->acknowledge_packet(Packet_descriptor( + if (_marked_as_updated && _sink.ready_to_ack()) { + _sink.acknowledge_packet(Packet_descriptor( _handle, Packet_descriptor::CONTENT_CHANGED)); _marked_as_updated = false; } @@ -51,8 +56,6 @@ namespace File_system { _marked_as_updated = true; } - - bool valid() const { return _sink != nullptr; } }; } diff --git a/repos/os/include/file_system/node.h b/repos/os/include/file_system/node.h index b26aaee66..bf2ab687b 100644 --- a/repos/os/include/file_system/node.h +++ b/repos/os/include/file_system/node.h @@ -4,6 +4,13 @@ * \date 2012-04-11 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _FILE_SYSTEM__NODE_H_ #define _FILE_SYSTEM__NODE_H_ @@ -19,7 +26,6 @@ namespace File_system { { private: - Genode::Lock _lock; Genode::List _listeners; public: @@ -34,9 +40,6 @@ namespace File_system { _listeners.remove(_listeners.first()); } - void lock() { _lock.lock(); } - void unlock() { _lock.unlock(); } - void add_listener(Listener *listener) { _listeners.insert(listener); @@ -59,19 +62,6 @@ namespace File_system { curr->mark_as_updated(); } }; - - - /** - * Guard used for properly releasing node locks - */ - struct Node_lock_guard - { - Node_base *node; - - Node_lock_guard(Node_base *node) : node(node) { node = node; } - - ~Node_lock_guard() { node->unlock(); } - }; } #endif /* _FILE_SYSTEM__NODE_H_ */ diff --git a/repos/os/include/file_system/node_handle_registry.h b/repos/os/include/file_system/node_handle_registry.h deleted file mode 100644 index cb8ceb26d..000000000 --- a/repos/os/include/file_system/node_handle_registry.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * \brief Facility for managing the session-local node-handle namespace - * \author Norman Feske - * \date 2012-04-11 - */ - -#ifndef _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_ -#define _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_ - -#include - -namespace File_system { - - class Node; - class Directory; - class File; - class Symlink; - - /** - * Type trait for determining the node type for a given handle type - */ - template struct Node_type; - template<> struct Node_type { typedef Node Type; }; - template<> struct Node_type { typedef Directory Type; }; - template<> struct Node_type { typedef File Type; }; - template<> struct Node_type { typedef Symlink Type; }; - - - /** - * Type trait for determining the handle type for a given node type - */ - template struct Handle_type; - template<> struct Handle_type { typedef Node_handle Type; }; - template<> struct Handle_type { typedef Dir_handle Type; }; - template<> struct Handle_type { typedef File_handle Type; }; - template<> struct Handle_type { typedef Symlink_handle Type; }; - - - class Node_handle_registry - { - public: - - class Out_of_node_handles : public Exception { }; - - private: - - /* maximum number of open nodes per session */ - enum { MAX_NODE_HANDLES = 128U }; - - Genode::Lock mutable _lock; - - Node_base *_nodes[MAX_NODE_HANDLES]; - - /** - * Each open node handle can act as a listener to be informed about - * node changes. - */ - Listener _listeners[MAX_NODE_HANDLES]; - - /** - * Allocate node handle - * - * \throw Out_of_node_handles - */ - int _alloc(Node_base *node) - { - Genode::Lock::Guard guard(_lock); - - for (unsigned i = 0; i < MAX_NODE_HANDLES; i++) - if (!_nodes[i]) { - _nodes[i] = node; - return i; - } - - throw Out_of_node_handles(); - } - - bool _in_range(int handle) const - { - return ((handle >= 0) && (handle < MAX_NODE_HANDLES)); - } - - public: - - Node_handle_registry() - { - for (unsigned i = 0; i < MAX_NODE_HANDLES; i++) - _nodes[i] = 0; - } - - template - typename Handle_type::Type alloc(NODE_TYPE *node) - { - typedef typename Handle_type::Type Handle; - return Handle(_alloc(node)); - } - - /** - * Release node handle - */ - void free(Node_handle handle) - { - Genode::Lock::Guard guard(_lock); - - if (!_in_range(handle.value)) - return; - - /* - * Notify listeners about the changed file. - */ - Node_base *node = dynamic_cast(_nodes[handle.value]); - if (!node) { return; } - - node->lock(); - node->notify_listeners(); - - /* - * De-allocate handle - */ - Listener &listener = _listeners[handle.value]; - - if (listener.valid()) - node->remove_listener(&listener); - - _nodes[handle.value] = 0; - listener = Listener(); - - node->unlock(); - } - - /** - * Lookup node using its handle as key - * - * \throw Invalid_handle - */ - template - typename Node_type::Type *lookup(HANDLE_TYPE handle) - { - Genode::Lock::Guard guard(_lock); - - if (!_in_range(handle.value)) - throw Invalid_handle(); - - typedef typename Node_type::Type Node; - Node *node = dynamic_cast(_nodes[handle.value]); - if (!node) - throw Invalid_handle(); - - return node; - } - - /** - * Lookup node using its handle as key - * - * The node returned by this function is in a locked state. - * - * \throw Invalid_handle - */ - template - typename Node_type::Type *lookup_and_lock(HANDLE_TYPE handle) - { - Genode::Lock::Guard guard(_lock); - - if (!_in_range(handle.value)) - throw Invalid_handle(); - - typedef typename Node_type::Type Node_base; - Node_base *node = dynamic_cast(_nodes[handle.value]); - if (!node) - throw Invalid_handle(); - - node->lock(); - return node; - } - - bool refer_to_same_node(Node_handle h1, Node_handle h2) const - { - Genode::Lock::Guard guard(_lock); - - if (!_in_range(h1.value) || !_in_range(h2.value)) - throw Invalid_handle(); - - return _nodes[h1.value] == _nodes[h2.value]; - } - - /** - * Register signal handler to be notified of node changes - */ - void register_notify(Sink &sink, Node_handle handle) - { - Genode::Lock::Guard guard(_lock); - - if (!_in_range(handle.value)) - throw Invalid_handle(); - - Node_base *node = dynamic_cast(_nodes[handle.value]); - if (!node) - throw Invalid_handle(); - - Listener &listener = _listeners[handle.value]; - - /* - * If there was already a handler registered for the node, - * remove the old handler. - */ - if (listener.valid()) - node->remove_listener(&listener); - - /* - * Register new handler - */ - listener = Listener(sink, handle); - node->add_listener(&listener); - } - }; -} - -#endif /* _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_ */ diff --git a/repos/os/include/file_system/open_node.h b/repos/os/include/file_system/open_node.h new file mode 100644 index 000000000..efb7bbf95 --- /dev/null +++ b/repos/os/include/file_system/open_node.h @@ -0,0 +1,79 @@ +/* + * \brief Representation of an open file system node within the component + * \author Christian Prochaska + * \date 2017-06-09 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * 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 _OPEN_NODE_H_ +#define _OPEN_NODE_H_ + +/* Genode includes */ +#include +#include + +namespace File_system { + /* + * \param NODE component-specific node type + */ + template class Open_node; +} + +template +class File_system::Open_node : public File_system::Node +{ + private: + + Genode::Id_space::Element _element; + + NODE &_node; + Genode::Constructible _listener; + + public: + + Open_node(NODE &node, Genode::Id_space &id_space) + : _element(*this, id_space), + _node(node) { } + + ~Open_node() + { + if (_listener.constructed()) { + _node.remove_listener(&*_listener); + _listener.destruct(); + } + } + + NODE &node() { return _node; } + File_system::Listener &listener() { return *_listener; } + + Genode::Id_space::Id id() { return _element.id(); } + + /** + * Register packet stream sink to be notified of node changes + */ + void register_notify(File_system::Sink &sink) + { + /* + * If there was already a handler registered for the node, + * remove the old handler. + */ + if (_listener.constructed()) { + _node.remove_listener(&*_listener); + _listener.destruct(); + } + + /* + * Register new handler + */ + _listener.construct(sink, id()); + _node.add_listener(&*_listener); + } +}; + +#endif /* _OPEN_NODE_H_ */ diff --git a/repos/os/include/file_system_session/file_system_session.h b/repos/os/include/file_system_session/file_system_session.h index 383be6632..e5f303268 100644 --- a/repos/os/include/file_system_session/file_system_session.h +++ b/repos/os/include/file_system_session/file_system_session.h @@ -23,10 +23,39 @@ namespace File_system { - struct Node_handle; - struct File_handle; - struct Dir_handle; - struct Symlink_handle; + struct Node + { + typedef Genode::Id_space::Id Id; + }; + + struct File : Node + { + struct Id : Node::Id + { + explicit Id(unsigned long value) : Node::Id { value } { }; + }; + }; + + struct Directory : Node + { + struct Id : Node::Id + { + explicit Id(unsigned long value) : Node::Id { value } { }; + }; + }; + + struct Symlink : Node + { + struct Id : Node::Id + { + explicit Id(unsigned long value) : Node::Id { value } { }; + }; + }; + + typedef Node::Id Node_handle; + typedef File::Id File_handle; + typedef Directory::Id Dir_handle; + typedef Symlink::Id Symlink_handle; using Genode::size_t; @@ -81,42 +110,6 @@ namespace File_system { } -struct File_system::Node_handle -{ - unsigned long value; - - Node_handle() : value(~0UL) { } - Node_handle(int v) : value(v) { } - - bool valid() const { return value != ~0UL; } - - bool operator == (Node_handle const &other) const { return other.value == value; } - bool operator != (Node_handle const &other) const { return other.value != value; } - -}; - - -struct File_system::File_handle : Node_handle -{ - File_handle() { } - File_handle(unsigned long v) : Node_handle(v) { } -}; - - -struct File_system::Dir_handle : Node_handle -{ - Dir_handle() { } - Dir_handle(unsigned long v) : Node_handle(v) { } -}; - - -struct File_system::Symlink_handle : Node_handle -{ - Symlink_handle() { } - Symlink_handle(unsigned long v) : Node_handle(v) { } -}; - - class File_system::Packet_descriptor : public Genode::Packet_descriptor { public: @@ -125,11 +118,11 @@ class File_system::Packet_descriptor : public Genode::Packet_descriptor private: - Node_handle _handle; /* node handle */ - Opcode _op; /* requested operation */ - seek_off_t _position; /* file seek offset in bytes */ - size_t _length; /* transaction length in bytes */ - bool _success; /* indicates success of operation */ + Node_handle _handle { 0 }; /* node handle */ + Opcode _op; /* requested operation */ + seek_off_t _position; /* file seek offset in bytes */ + size_t _length; /* transaction length in bytes */ + bool _success; /* indicates success of operation */ public: @@ -139,7 +132,7 @@ class File_system::Packet_descriptor : public Genode::Packet_descriptor Packet_descriptor(Genode::off_t buf_offset = 0, Genode::size_t buf_size = 0) : - Genode::Packet_descriptor(buf_offset, buf_size), _handle(-1), + Genode::Packet_descriptor(buf_offset, buf_size), _op(READ), _position(0), _length(0), _success(false) { } /** @@ -330,16 +323,22 @@ struct File_system::Session : public Genode::Session /** * Close file + * + * \throw Invalid_handle node handle is invalid */ virtual void close(Node_handle) = 0; /** * Request information about an open file or directory + * + * \throw Invalid_handle node handle is invalid */ virtual Status status(Node_handle) = 0; /** * Set information about an open file or directory + * + * \throw Invalid_handle node handle is invalid */ virtual void control(Node_handle, Control) = 0; @@ -380,6 +379,9 @@ struct File_system::Session : public Genode::Session * * This is only needed by file systems that maintain an internal * cache, which needs to be flushed on certain occasions. + * + * \throw Invalid_handle node handle is invalid + * */ virtual void sync(Node_handle) { } @@ -409,9 +411,15 @@ struct File_system::Session : public Genode::Session GENODE_RPC_THROW(Rpc_node, Node_handle, node, GENODE_TYPE_LIST(Lookup_failed, Out_of_ram, Out_of_caps), Path const &); - GENODE_RPC(Rpc_close, void, close, Node_handle); - GENODE_RPC(Rpc_status, Status, status, Node_handle); - GENODE_RPC(Rpc_control, void, control, Node_handle, Control); + GENODE_RPC_THROW(Rpc_close, void, close, + GENODE_TYPE_LIST(Invalid_handle), + Node_handle); + GENODE_RPC_THROW(Rpc_status, Status, status, + GENODE_TYPE_LIST(Invalid_handle), + Node_handle); + GENODE_RPC_THROW(Rpc_control, void, control, + GENODE_TYPE_LIST(Invalid_handle), + Node_handle, Control); GENODE_RPC_THROW(Rpc_unlink, void, unlink, GENODE_TYPE_LIST(Invalid_handle, Invalid_name, Lookup_failed, Not_empty, @@ -425,7 +433,9 @@ struct File_system::Session : public Genode::Session GENODE_TYPE_LIST(Invalid_handle, Invalid_name, Lookup_failed, Permission_denied), Dir_handle, Name const &, Dir_handle, Name const &); - GENODE_RPC(Rpc_sync, void, sync, Node_handle); + GENODE_RPC_THROW(Rpc_sync, void, sync, + GENODE_TYPE_LIST(Invalid_handle), + Node_handle); GENODE_RPC_INTERFACE(Rpc_tx_cap, Rpc_file, Rpc_symlink, Rpc_dir, Rpc_node, Rpc_close, Rpc_status, Rpc_control, Rpc_unlink, diff --git a/repos/os/include/ram_fs/node.h b/repos/os/include/ram_fs/node.h deleted file mode 100644 index c53ac76a0..000000000 --- a/repos/os/include/ram_fs/node.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * \brief File-system node - * \author Norman Feske - * \date 2012-04-11 - */ - -/* - * Copyright (C) 2012-2017 Genode Labs GmbH - * - * 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 _INCLUDE__RAM_FS__NODE_H_ -#define _INCLUDE__RAM_FS__NODE_H_ - -/* Genode includes */ -#include -#include -#include - -namespace File_system { - using namespace Genode; - class Node; -} - - -class File_system::Node : public Node_base, public List::Element -{ - public: - - typedef char Name[128]; - - private: - - int _ref_count; - Name _name; - unsigned long const _inode; - - /** - * Generate unique inode number - */ - static unsigned long _unique_inode() - { - static unsigned long inode_count; - return ++inode_count; - } - - public: - - Node() - : _ref_count(0), _inode(_unique_inode()) - { _name[0] = 0; } - - unsigned long inode() const { return _inode; } - char const *name() const { return _name; } - - /** - * Assign name - */ - void name(char const *name) { strncpy(_name, name, sizeof(_name)); } - - virtual size_t read(char *dst, size_t len, seek_off_t) = 0; - virtual size_t write(char const *src, size_t len, seek_off_t) = 0; -}; - -#endif /* _INCLUDE__RAM_FS__NODE_H_ */ diff --git a/repos/os/src/app/rom_to_file/main.cc b/repos/os/src/app/rom_to_file/main.cc index b1f8db2f6..da3f48601 100644 --- a/repos/os/src/app/rom_to_file/main.cc +++ b/repos/os/src/app/rom_to_file/main.cc @@ -122,24 +122,24 @@ void Rom_to_file::Main::_handle_update() try { Dir_handle dir_handle = ensure_dir(_fs, dir_path); Handle_guard dir_guard(_fs, dir_handle); - File_handle handle; + Constructible handle; try { - handle = _fs.file(dir_handle, file_name, File_system::WRITE_ONLY, true); + handle.construct(_fs.file(dir_handle, file_name, File_system::WRITE_ONLY, true)); } catch (Node_already_exists) { - handle = _fs.file(dir_handle, file_name, File_system::WRITE_ONLY, false); + handle.construct(_fs.file(dir_handle, file_name, File_system::WRITE_ONLY, false)); } - _fs.truncate(handle, 0); + _fs.truncate(*handle, 0); size_t len = max(strlen(_rom_ds->local_addr()), _rom_ds->size()); - size_t written = write(_fs, handle, _rom_ds->local_addr(), len, 0); + size_t written = write(_fs, *handle, _rom_ds->local_addr(), len, 0); if (written < len) { warning(written, " of ", len, " bytes have been written"); } - _fs.close(handle); + _fs.close(*handle); } catch (Permission_denied) { error(Cstring(dir_path), file_name, ": permission denied"); diff --git a/repos/os/src/app/usb_report_filter/main.cc b/repos/os/src/app/usb_report_filter/main.cc index 5d779160a..54ede7cf0 100644 --- a/repos/os/src/app/usb_report_filter/main.cc +++ b/repos/os/src/app/usb_report_filter/main.cc @@ -58,7 +58,6 @@ class Usb_filter::Device_registry Genode::Allocator_avl _fs_packet_alloc { &_alloc }; File_system::Connection _fs { _env, _fs_packet_alloc, "usb_drv.config" }; - File_system::File_handle _file; struct Entry : public Genode::List::Element { @@ -154,16 +153,18 @@ class Usb_filter::Device_registry { using namespace Genode; + Constructible file; + try { File_system::Dir_handle root_dir = _fs.dir("/", false); - _file = _fs.file(root_dir, config_file, File_system::READ_WRITE, false); + file.construct(_fs.file(root_dir, config_file, File_system::READ_WRITE, false)); } catch (...) { error("could not open '", config_file, "'"); return; } char old_file[1024]; - size_t n = File_system::read(_fs, _file, old_file, + size_t n = File_system::read(_fs, *file, old_file, sizeof(old_file)); if (n == 0) { error("could not read '", config_file, "'"); @@ -216,11 +217,11 @@ class Usb_filter::Device_registry if (verbose) log("new usb_drv configuration:\n", Cstring(new_file)); - n = File_system::write(_fs, _file, new_file, xml.used()); + n = File_system::write(_fs, *file, new_file, xml.used()); if (n == 0) error("could not write '", config_file, "'"); - _fs.close(_file); + _fs.close(*file); } Genode::Signal_handler _devices_handler = diff --git a/repos/os/src/lib/vfs/fs_file_system.h b/repos/os/src/lib/vfs/fs_file_system.h index 6fa57296d..0403c81f8 100644 --- a/repos/os/src/lib/vfs/fs_file_system.h +++ b/repos/os/src/lib/vfs/fs_file_system.h @@ -51,16 +51,7 @@ class Vfs::Fs_file_system : public File_system ::File_system::Connection _fs; - struct Fs_vfs_handle; - - struct Handle_space : Genode::Id_space - { - struct Id : Genode::Id_space::Id - { - Id(unsigned long v) { value = v; } - Id(::File_system::Node_handle h) { value = h.value; } - }; - }; + typedef Genode::Id_space<::File_system::Node> Handle_space; Handle_space _handle_space; @@ -77,19 +68,17 @@ class Vfs::Fs_file_system : public File_system ::File_system::Packet_descriptor queued_write_packet; }; - struct Fs_vfs_handle : Vfs_handle, Handle_space::Element, Handle_state + struct Fs_vfs_handle : Vfs_handle, ::File_system::Node, Handle_space::Element, Handle_state { - Handle_space::Id const id; - Fs_vfs_handle(File_system &fs, Allocator &alloc, int status_flags, Handle_space &space, Handle_space::Id id) : Vfs_handle(fs, fs, alloc, status_flags), - Handle_space::Element(*this, space, id), - id(id) + Handle_space::Element(*this, space, id) { } - ::File_system::File_handle file_handle() const { return id.value; } + ::File_system::File_handle file_handle() const + { return ::File_system::File_handle { id().value }; } }; /** @@ -400,13 +389,13 @@ class Vfs::Fs_file_system : public File_system if (strcmp(path, "") == 0) path = "/"; - ::File_system::Dir_handle dir_handle; - try { dir_handle = _fs.dir(path, false); } + Genode::Constructible<::File_system::Dir_handle> dir_handle; + try { dir_handle.construct(_fs.dir(path, false)); } catch (::File_system::Lookup_failed) { return DIRENT_ERR_INVALID_PATH; } catch (::File_system::Name_too_long) { return DIRENT_ERR_INVALID_PATH; } catch (...) { return DIRENT_ERR_NO_PERM; } - Fs_handle_guard dir_guard(*this, _fs, dir_handle, _handle_space); + Fs_handle_guard dir_guard(*this, _fs, *dir_handle, _handle_space); Directory_entry entry; enum { DIRENT_SIZE = sizeof(Directory_entry) }; diff --git a/repos/os/src/server/fs_log/main.cc b/repos/os/src/server/fs_log/main.cc index 012064fef..6d5b570ea 100644 --- a/repos/os/src/server/fs_log/main.cc +++ b/repos/os/src/server/fs_log/main.cc @@ -133,22 +133,22 @@ class Fs_log::Root_component : Dir_handle dir_handle = ensure_dir(_fs, dir_path.base()); Handle_guard dir_guard(_fs, dir_handle); - File_handle handle; + Genode::Constructible handle; try { - handle = _fs.file(dir_handle, file_name, - File_system::WRITE_ONLY, false); + handle.construct(_fs.file(dir_handle, file_name, + File_system::WRITE_ONLY, false)); /* don't truncate at every new child session */ if (truncate && (strcmp(label_prefix, "") == 0)) - _fs.truncate(handle, 0); + _fs.truncate(*handle, 0); } catch (File_system::Lookup_failed) { - handle = _fs.file(dir_handle, file_name, - File_system::WRITE_ONLY, true); + handle.construct(_fs.file(dir_handle, file_name, + File_system::WRITE_ONLY, true)); } - return new (md_alloc()) Session_component(_fs, handle, label_prefix); + return new (md_alloc()) Session_component(_fs, *handle, label_prefix); } catch (Permission_denied) { errstr = "permission denied"; } diff --git a/repos/os/src/server/fs_rom/main.cc b/repos/os/src/server/fs_rom/main.cc index 281d08c66..3089878c9 100755 --- a/repos/os/src/server/fs_rom/main.cc +++ b/repos/os/src/server/fs_rom/main.cc @@ -65,7 +65,7 @@ class Fs_rom::Rom_session_component : /** * Handle of associated file */ - File_system::File_handle _file_handle; + Genode::Constructible _file_handle; /** * Size of current version of the file @@ -83,7 +83,7 @@ class Fs_rom::Rom_session_component : * The compund directory is watched only if the requested file could * not be looked up. */ - File_system::Node_handle _compound_dir_handle; + Genode::Constructible _compound_dir_handle; /** * Dataspace exposed as ROM module to the client @@ -95,6 +95,11 @@ class Fs_rom::Rom_session_component : */ Genode::Signal_context_capability _sigh; + /* + * Exception + */ + struct Open_compound_dir_failed { }; + /** * Open compound directory of specified file * @@ -130,9 +135,14 @@ class Fs_rom::Rom_session_component : */ if (!walk_up) break; } - return Dir_handle(); /* invalid */ + throw Open_compound_dir_failed(); } + /* + * Exception + */ + struct Open_file_failed { }; + /** * Open file with specified name at the file system */ @@ -141,25 +151,30 @@ class Fs_rom::Rom_session_component : { using namespace File_system; - File_system::File_handle file_handle; - try { Dir_handle dir = _open_compound_dir(fs, path, false); - Handle_guard guard(fs, dir); - /* open file */ - Genode::Path file_name(path.base()); - file_name.keep_only_last_element(); - file_handle = fs.file(dir, file_name.base() + 1, - File_system::READ_ONLY, false); + try { + + Handle_guard guard(fs, dir); + + /* open file */ + Genode::Path file_name(path.base()); + file_name.keep_only_last_element(); + return fs.file(dir, file_name.base() + 1, + File_system::READ_ONLY, false); + } + catch (Invalid_handle) { Genode::error(_file_path, ": Invalid_handle"); } + catch (Invalid_name) { Genode::error(_file_path, ": invalid_name"); } + catch (Lookup_failed) { Genode::error(_file_path, ": lookup_failed"); } + catch (...) { Genode::error(_file_path, ": unhandled error"); }; + + throw Open_file_failed(); + + } catch (Open_compound_dir_failed) { + throw Open_file_failed(); } - catch (Invalid_handle) { Genode::error(_file_path, ": Invalid_handle"); } - catch (Invalid_name) { Genode::error(_file_path, ": invalid_name"); } - catch (Lookup_failed) { Genode::error(_file_path, ": lookup_failed"); } - catch (...) { Genode::error(_file_path, ": unhandled error"); }; - - return file_handle; } void _register_for_compound_dir_changes() @@ -167,18 +182,22 @@ class Fs_rom::Rom_session_component : using namespace File_system; /* forget about the previously watched compound directory */ - if (_compound_dir_handle.valid()) - _fs.close(_compound_dir_handle); + if (_compound_dir_handle.constructed()) { + _fs.close(*_compound_dir_handle); + _compound_dir_handle.destruct(); + } - _compound_dir_handle = _open_compound_dir(_fs, _file_path, true); + try { + _compound_dir_handle.construct(_open_compound_dir(_fs, _file_path, true)); - /* register for changes in compound directory */ - if (_compound_dir_handle.valid()) + /* register for changes in compound directory */ _fs.tx()->submit_packet(File_system::Packet_descriptor( - _compound_dir_handle, + *_compound_dir_handle, File_system::Packet_descriptor::CONTENT_CHANGED)); - else + + } catch (Open_compound_dir_failed) { Genode::warning("could not track compound dir, giving up"); + } } /** @@ -194,42 +213,46 @@ class Fs_rom::Rom_session_component : * content. The dataspace is re-allocated if the new version * of the file has become bigger. */ - { + try { File_handle const file_handle = _open_file(_fs, _file_path); - if (file_handle.valid()) { - File_system::file_size_t const new_file_size = - _fs.status(file_handle).size; + File_system::file_size_t const new_file_size = + _fs.status(file_handle).size; - if (_file_ds.size() && (new_file_size > _file_size)) { - /* mark as invalid */ - _file_ds.realloc(&_env.ram(), 0); - _file_size = 0; - _file_seek = 0; - } + if (_file_ds.size() && (new_file_size > _file_size)) { + /* mark as invalid */ + _file_ds.realloc(&_env.ram(), 0); + _file_size = 0; + _file_seek = 0; } _fs.close(file_handle); - } + } catch (Open_file_failed) { } /* close and then re-open the file */ - if (_file_handle.valid()) - _fs.close(_file_handle); + if (_file_handle.constructed()) { + _fs.close(*_file_handle); + _file_handle.destruct(); + } - _file_handle = _open_file(_fs, _file_path); + try { + _file_handle.construct(_open_file(_fs, _file_path)); + } catch (Open_file_failed) { } /* * If we got the file, we can stop paying attention to the * compound directory. */ - if (_file_handle.valid() && _compound_dir_handle.valid()) - _fs.close(_compound_dir_handle); + if (_file_handle.constructed() && _compound_dir_handle.constructed()) { + _fs.close(*_compound_dir_handle); + _compound_dir_handle.destruct(); + } /* register for file changes */ - if (_file_handle.valid()) + if (_file_handle.constructed()) _fs.tx()->submit_packet(File_system::Packet_descriptor( - _file_handle, File_system::Packet_descriptor::CONTENT_CHANGED)); + *_file_handle, File_system::Packet_descriptor::CONTENT_CHANGED)); - size_t const file_size = _file_handle.valid() - ? _fs.status(_file_handle).size : 0; + size_t const file_size = _file_handle.constructed() + ? _fs.status(*_file_handle).size : 0; /* allocate new RAM dataspace according to file size */ if (file_size > 0) { @@ -255,7 +278,7 @@ class Fs_rom::Rom_session_component : source.bulk_buffer_size() / 2); File_system::Packet_descriptor packet(source.alloc_packet(chunk_size), - _file_handle, + *_file_handle, File_system::Packet_descriptor::READ, chunk_size, _file_seek); @@ -284,11 +307,13 @@ class Fs_rom::Rom_session_component : : _env(env), _fs(fs), _file_path(file_path), - _file_handle(_open_file(_fs, _file_path)), _file_ds(env.ram(), env.rm(), 0) /* realloc later */ { - if (!_file_handle.valid()) - _register_for_compound_dir_changes(); + try { + _file_handle.construct(_open_file(_fs, _file_path)); + } catch (Open_file_failed) { } + + _register_for_compound_dir_changes(); } /** @@ -297,11 +322,11 @@ class Fs_rom::Rom_session_component : ~Rom_session_component() { /* close re-open the file */ - if (_file_handle.valid()) - _fs.close(_file_handle); + if (_file_handle.constructed()) + _fs.close(*_file_handle); - if (_compound_dir_handle.valid()) - _fs.close(_compound_dir_handle); + if (_compound_dir_handle.constructed()) + _fs.close(*_compound_dir_handle); } /** @@ -327,8 +352,8 @@ class Fs_rom::Rom_session_component : switch (packet.operation()) { case File_system::Packet_descriptor::CONTENT_CHANGED: - if (_file_handle == packet.handle() || - _compound_dir_handle == packet.handle()) + if ((_file_handle.constructed() && (*_file_handle == packet.handle())) || + (_compound_dir_handle.constructed() && (*_compound_dir_handle == packet.handle()))) { if (_sigh.valid()) Genode::Signal_transmitter(_sigh).submit(); @@ -337,7 +362,7 @@ class Fs_rom::Rom_session_component : return false; case File_system::Packet_descriptor::READ: { - if (_file_handle != packet.handle()) + if (!(_file_handle.constructed() && (*_file_handle == packet.handle()))) return false; if (packet.position() > _file_seek || _file_seek >= _file_size) { diff --git a/repos/os/src/server/lx_fs/directory.h b/repos/os/src/server/lx_fs/directory.h index 5ae4172b7..7ba6d7e3c 100644 --- a/repos/os/src/server/lx_fs/directory.h +++ b/repos/os/src/server/lx_fs/directory.h @@ -5,6 +5,13 @@ * \date 2013-11-11 */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _DIRECTORY_H_ #define _DIRECTORY_H_ @@ -19,13 +26,14 @@ #include -namespace File_system { +namespace Lx_fs { using namespace Genode; + using namespace File_system; class Directory; } -class File_system::Directory : public Node +class Lx_fs::Directory : public Node { private: @@ -72,6 +80,16 @@ class File_system::Directory : public Node return fd; } + size_t _num_entries() const + { + unsigned num = 0; + + rewinddir(_fd); + while (readdir(_fd)) ++num; + + return num; + } + public: Directory(Allocator &alloc, char const *path, bool create) @@ -90,11 +108,10 @@ class File_system::Directory : public Node } /* FIXME returned file node must be locked */ - File * file(char const *name, Mode mode, bool create) + File * file(char const *name, Mode mode, bool create) override { File *file = new (&_alloc) File(dirfd(_fd), name, mode, create); - file->lock(); return file; } @@ -105,7 +122,6 @@ class File_system::Directory : public Node Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create); - dir->lock(); return dir; } @@ -134,11 +150,10 @@ class File_system::Directory : public Node else throw Lookup_failed(); - node->lock(); return node; } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { if (len < sizeof(Directory_entry)) { Genode::error("read buffer too small for directory entry"); @@ -177,20 +192,19 @@ class File_system::Directory : public Node return sizeof(Directory_entry); } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* writing to directory nodes is not supported */ return 0; } - size_t num_entries() const + Status status() override { - unsigned num = 0; - - rewinddir(_fd); - while (readdir(_fd)) ++num; - - return num; + Status s; + s.inode = inode(); + s.size = _num_entries() * sizeof(File_system::Directory_entry); + s.mode = File_system::Status::MODE_DIRECTORY; + return s; } }; diff --git a/repos/os/src/server/lx_fs/file.h b/repos/os/src/server/lx_fs/file.h index 406fa455d..9e3d13c4a 100644 --- a/repos/os/src/server/lx_fs/file.h +++ b/repos/os/src/server/lx_fs/file.h @@ -5,6 +5,13 @@ * \date 2013-11-11 */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _FILE_H_ #define _FILE_H_ @@ -13,12 +20,13 @@ #include -namespace File_system { +namespace Lx_fs { + using namespace File_system; class File; } -class File_system::File : public Node +class Lx_fs::File : public Node { private: @@ -74,6 +82,16 @@ class File_system::File : public Node return fd; } + file_size_t _length() const + { + struct stat s; + + if (fstat(_fd, &s) < 0) + return 0; + + return s.st_size; + } + public: File(int dir, @@ -95,14 +113,14 @@ class File_system::File : public Node Node::name(basename(path)); } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { int ret = pread(_fd, dst, len, seek_offset); return ret == -1 ? 0 : ret; } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* should we append? */ if (seek_offset == ~0ULL) { @@ -117,17 +135,16 @@ class File_system::File : public Node return ret == -1 ? 0 : ret; } - file_size_t length() const + Status status() override { - struct stat s; - - if (fstat(_fd, &s) < 0) - return 0; - - return s.st_size; + Status s; + s.inode = inode(); + s.size = _length(); + s.mode = File_system::Status::MODE_FILE; + return s; } - void truncate(file_size_t size) + void truncate(file_size_t size) override { if (ftruncate(_fd, size)) /* nothing */; diff --git a/repos/os/src/server/lx_fs/main.cc b/repos/os/src/server/lx_fs/main.cc index 9da9c7d66..76f1d4323 100644 --- a/repos/os/src/server/lx_fs/main.cc +++ b/repos/os/src/server/lx_fs/main.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,22 +25,29 @@ #include -namespace File_system { +namespace Lx_fs { + + using namespace File_system; + using File_system::Packet_descriptor; + using File_system::Path; + struct Main; struct Session_component; struct Root; } -class File_system::Session_component : public Session_rpc_object +class Lx_fs::Session_component : public Session_rpc_object { private: - Genode::Env &_env; - Allocator &_md_alloc; - Directory &_root; - Node_handle_registry _handle_registry; - bool _writable; + typedef File_system::Open_node Open_node; + + Genode::Env &_env; + Allocator &_md_alloc; + Directory &_root; + Id_space _open_node_registry; + bool _writable; Signal_handler _process_packet_dispatcher; @@ -54,7 +61,7 @@ class File_system::Session_component : public Session_rpc_object * * \return true on success, false on failure */ - void _process_packet_op(Packet_descriptor &packet, Node &node) + void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) { void * const content = tx_sink()->packet_content(packet); size_t const length = packet.length(); @@ -66,18 +73,18 @@ class File_system::Session_component : public Session_rpc_object case Packet_descriptor::READ: if (content && (packet.length() <= packet.size())) - res_length = node.read((char *)content, length, packet.position()); + res_length = open_node.node().read((char *)content, length, packet.position()); break; case Packet_descriptor::WRITE: if (content && (packet.length() <= packet.size())) - res_length = node.write((char const *)content, length, packet.position()); + res_length = open_node.node().write((char const *)content, length, packet.position()); break; case Packet_descriptor::CONTENT_CHANGED: - _handle_registry.register_notify(*tx_sink(), packet.handle()); + open_node.register_notify(*tx_sink()); /* notify_listeners may bounce the packet back*/ - node.notify_listeners(); + open_node.node().notify_listeners(); /* otherwise defer acknowledgement of this packet */ return; @@ -98,13 +105,16 @@ class File_system::Session_component : public Session_rpc_object /* assume failure by default */ packet.succeeded(false); - try { - Node *node = _handle_registry.lookup_and_lock(packet.handle()); - Node_lock_guard guard(node); + auto process_packet_fn = [&] (Open_node &open_node) { + _process_packet_op(packet, open_node); + }; - _process_packet_op(packet, *node); + try { + _open_node_registry.apply(packet.handle(), process_packet_fn); + } catch (Id_space::Unknown_id const &) { + Genode::error("Invalid_handle"); + tx_sink()->acknowledge_packet(packet); } - catch (Invalid_handle) { Genode::error("Invalid_handle"); } } /** @@ -191,23 +201,35 @@ class File_system::Session_component : public Session_rpc_object if (!valid_name(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup_and_lock(dir_handle); - Node_lock_guard dir_guard(dir); + auto file_fn = [&] (Open_node &open_node) { - if (!_writable) - if (create || (mode != STAT_ONLY && mode != READ_ONLY)) - throw Permission_denied(); + Node &dir = open_node.node(); - File *file = dir->file(name.string(), mode, create); + if (!_writable) + if (create || (mode != STAT_ONLY && mode != READ_ONLY)) + throw Permission_denied(); - Node_lock_guard file_guard(file); - return _handle_registry.alloc(file); + File *file = dir.file(name.string(), mode, create); + + Open_node *open_file = + new (_md_alloc) Open_node(*file, _open_node_registry); + + return open_file->id(); + }; + + try { + return File_handle { + _open_node_registry.apply(dir_handle, file_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) { Genode::error(__func__, " not implemented"); - return Symlink_handle(); + throw Permission_denied(); } Dir_handle dir(Path const &path, bool create) @@ -226,8 +248,11 @@ class File_system::Session_component : public Session_rpc_object throw Name_too_long(); Directory *dir = _root.subdir(path_str, create); - Node_lock_guard guard(dir); - return _handle_registry.alloc(dir); + + Open_node *open_dir = + new (_md_alloc) Open_node(*dir, _open_node_registry); + + return Dir_handle { open_dir->id().value }; } Node_handle node(Path const &path) @@ -238,43 +263,38 @@ class File_system::Session_component : public Session_rpc_object Node *node = _root.node(path_str + 1); - Node_lock_guard guard(node); - return _handle_registry.alloc(node); + Open_node *open_node = + new (_md_alloc) Open_node(*node, _open_node_registry); + + return open_node->id(); } void close(Node_handle handle) { - /* FIXME when to destruct node? */ - _handle_registry.free(handle); + auto close_fn = [&] (Open_node &open_node) { + Node &node = open_node.node(); + destroy(_md_alloc, &open_node); + destroy(_md_alloc, &node); + }; + + try { + _open_node_registry.apply(handle, close_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Status status(Node_handle node_handle) { - Node *node = _handle_registry.lookup_and_lock(node_handle); - Node_lock_guard guard(node); + auto status_fn = [&] (Open_node &open_node) { + return open_node.node().status(); + }; - Status s; - s.inode = node->inode(); - s.size = 0; - s.mode = 0; - - File *file = dynamic_cast(node); - if (file) { - s.size = file->length(); - s.mode = File_system::Status::MODE_FILE; - return s; + try { + return _open_node_registry.apply(node_handle, status_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - - Directory *dir = dynamic_cast(node); - if (dir) { - s.size = dir->num_entries()*sizeof(Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; - return s; - } - - Genode::error(__func__, " for symlinks not implemented"); - - return Status(); } void control(Node_handle, Control) @@ -292,9 +312,15 @@ class File_system::Session_component : public Session_rpc_object if (!_writable) throw Permission_denied(); - File *file = _handle_registry.lookup_and_lock(file_handle); - Node_lock_guard file_guard(file); - file->truncate(size); + auto truncate_fn = [&] (Open_node &open_node) { + open_node.node().truncate(size); + }; + + try { + _open_node_registry.apply(file_handle, truncate_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } void move(Dir_handle, Name const &, Dir_handle, Name const &) @@ -311,7 +337,7 @@ class File_system::Session_component : public Session_rpc_object }; -class File_system::Root : public Root_component +class Lx_fs::Root : public Root_component { private: @@ -419,7 +445,7 @@ class File_system::Root : public Root_component }; -struct File_system::Main +struct Lx_fs::Main { Genode::Env &env; @@ -434,4 +460,4 @@ struct File_system::Main }; -void Component::construct(Genode::Env &env) { static File_system::Main inst(env); } +void Component::construct(Genode::Env &env) { static Lx_fs::Main inst(env); } diff --git a/repos/os/src/server/lx_fs/node.h b/repos/os/src/server/lx_fs/node.h index 96133a884..5dc7e5bdf 100644 --- a/repos/os/src/server/lx_fs/node.h +++ b/repos/os/src/server/lx_fs/node.h @@ -5,43 +5,70 @@ * \date 2013-11-11 */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _NODE_H_ #define _NODE_H_ /* Genode includes */ -#include #include -namespace File_system { - - class Node : public Node_base - { - public: - - typedef char Name[128]; - - private: - - Name _name; - unsigned long const _inode; - - public: - - Node(unsigned long inode) : _inode(inode) { _name[0] = 0; } - - unsigned long inode() const { return _inode; } - char const *name() const { return _name; } - - /** - * Assign name - */ - void name(char const *name) { Genode::strncpy(_name, name, sizeof(_name)); } - - virtual size_t read(char *dst, size_t len, seek_off_t) = 0; - virtual size_t write(char const *src, size_t len, seek_off_t) = 0; - }; - +namespace Lx_fs { + using namespace File_system; + class Node; + class File; } +class Lx_fs::Node : public File_system::Node_base +{ + public: + + typedef char Name[128]; + + private: + + Name _name; + unsigned long const _inode; + + public: + + Node(unsigned long inode) : _inode(inode) { _name[0] = 0; } + + unsigned long inode() const { return _inode; } + char const *name() const { return _name; } + + /** + * Assign name + */ + void name(char const *name) { Genode::strncpy(_name, name, sizeof(_name)); } + + virtual size_t read(char *dst, size_t len, seek_off_t) = 0; + virtual size_t write(char const *src, size_t len, seek_off_t) = 0; + + virtual Status status() = 0; + + /* + * File functionality + */ + virtual void truncate(file_size_t size) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); + } + + /* + * Directory functionality + */ + virtual File *file(char const *name, Mode mode, bool create) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return nullptr; + } +}; + #endif /* _NODE_H_ */ diff --git a/repos/os/src/server/lx_fs/symlink.h b/repos/os/src/server/lx_fs/symlink.h index e0c466b73..4f1b4ed67 100644 --- a/repos/os/src/server/lx_fs/symlink.h +++ b/repos/os/src/server/lx_fs/symlink.h @@ -7,6 +7,13 @@ * FIXME unfinished */ +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * 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 _SYMLINK_H_ #define _SYMLINK_H_ @@ -26,18 +33,20 @@ class File_system::Symlink : public Node char _link_to[MAX_PATH_LEN]; + file_size_t _length() const { return strlen(_link_to) + 1; } + public: Symlink(char const *name) { Node::name(name); } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { size_t count = min(len, sizeof(_link_to) + 1); Genode::strncpy(dst, _link_to, count); return count; } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* Ideal symlink operations are atomic. */ if (seek_offset) return 0; @@ -47,7 +56,14 @@ class File_system::Symlink : public Node return count; } - file_size_t length() const { return strlen(_link_to) + 1; } + Status status() override + { + Status s; + s.inode = inode(); + s.size = _length(); + s.mode = File_system::Status::MODE_SYMLINK; + return s; + } }; #endif /* _SYMLINK_H_ */ diff --git a/repos/os/include/ram_fs/directory.h b/repos/os/src/server/ram_fs/directory.h similarity index 70% rename from repos/os/include/ram_fs/directory.h rename to repos/os/src/server/ram_fs/directory.h index ba8e2b60b..a47ee7dfe 100644 --- a/repos/os/include/ram_fs/directory.h +++ b/repos/os/src/server/ram_fs/directory.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2017 Genode Labs GmbH + * Copyright (C) 2012-2017 Genode Labs GmbH * * 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,32 +18,32 @@ #include /* local includes */ -#include -#include -#include +#include "node.h" +#include "file.h" +#include "symlink.h" -namespace File_system { class Directory; } +namespace Ram_fs { class Directory; } -class File_system::Directory : public Node +class Ram_fs::Directory : public Node { private: List _entries; size_t _num_entries; - public: - - Directory(char const *name) : _num_entries(0) { Node::name(name); } - - Node *entry_unsynchronized(size_t index) + Node *_entry_unsynchronized(size_t index) { Node *node = _entries.first(); for (unsigned i = 0; i < index && node; node = node->next(), i++); return node; } - bool has_sub_node_unsynchronized(char const *name) const + public: + + Directory(char const *name) : _num_entries(0) { Node::name(name); } + + bool has_sub_node_unsynchronized(char const *name) const override { Node const *sub_node = _entries.first(); for (; sub_node; sub_node = sub_node->next()) @@ -53,7 +53,7 @@ class File_system::Directory : public Node return false; } - void adopt_unsynchronized(Node *node) + void adopt_unsynchronized(Node *node) override { /* * XXX inc ref counter @@ -64,7 +64,7 @@ class File_system::Directory : public Node mark_as_updated(); } - void discard_unsynchronized(Node *node) + void discard(Node *node) override { _entries.remove(node); _num_entries--; @@ -72,15 +72,14 @@ class File_system::Directory : public Node mark_as_updated(); } - Node *lookup_and_lock(char const *path, bool return_parent = false) + Node *lookup(char const *path, bool return_parent = false) override { if (strcmp(path, "") == 0) { - lock(); return this; } if (!path || path[0] == '/') - throw Lookup_failed(); + throw File_system::Lookup_failed(); /* find first path delimiter */ unsigned i = 0; @@ -91,7 +90,6 @@ class File_system::Directory : public Node * specified path. */ if (path[i] == 0 && return_parent) { - lock(); return this; } @@ -109,16 +107,15 @@ class File_system::Directory : public Node break; if (!sub_node) - throw Lookup_failed(); + throw File_system::Lookup_failed(); - if (!contains_path_delimiter(path)) { + if (!File_system::contains_path_delimiter(path)) { /* * Because 'path' is a basename that corresponds to an * existing sub_node, we have found what we were looking * for. */ - sub_node->lock(); return sub_node; } @@ -134,59 +131,58 @@ class File_system::Directory : public Node */ Directory *sub_dir = dynamic_cast(sub_node); if (!sub_dir) - throw Lookup_failed(); + throw File_system::Lookup_failed(); - return sub_dir->lookup_and_lock(path + i + 1, return_parent); + return sub_dir->lookup(path + i + 1, return_parent); } - Directory *lookup_and_lock_dir(char const *path) + Directory *lookup_dir(char const *path) { - Node *node = lookup_and_lock(path); + Node *node = lookup(path); Directory *dir = dynamic_cast(node); if (dir) return dir; - node->unlock(); - throw Lookup_failed(); + throw File_system::Lookup_failed(); } - File *lookup_and_lock_file(char const *path) + File *lookup_file(char const *path) override { - Node *node = lookup_and_lock(path); + Node *node = lookup(path); File *file = dynamic_cast(node); if (file) return file; - node->unlock(); - throw Lookup_failed(); + throw File_system::Lookup_failed(); } - Symlink *lookup_and_lock_symlink(char const *path) + Symlink *lookup_symlink(char const *path) { - Node *node = lookup_and_lock(path); + Node *node = lookup(path); Symlink *symlink = dynamic_cast(node); if (symlink) return symlink; - node->unlock(); - throw Lookup_failed(); + throw File_system::Lookup_failed(); } /** * Lookup parent directory of the specified path * - * \throw Lookup_failed + * \throw File_system::Lookup_failed */ - Directory *lookup_and_lock_parent(char const *path) + Directory *lookup_parent(char const *path) { - return static_cast(lookup_and_lock(path, true)); + return static_cast(lookup(path, true)); } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { + using File_system::Directory_entry; + if (len < sizeof(Directory_entry)) { Genode::error("read buffer too small for directory entry"); return 0; @@ -199,7 +195,7 @@ class File_system::Directory : public Node return 0; } - Node *node = entry_unsynchronized(index); + Node *node = _entry_unsynchronized(index); /* index out of range */ if (!node) @@ -218,13 +214,20 @@ class File_system::Directory : public Node return sizeof(Directory_entry); } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* writing to directory nodes is not supported */ return 0; } - size_t num_entries() const { return _num_entries; } + Status status() override + { + Status s; + s.inode = inode(); + s.size = _num_entries * sizeof(File_system::Directory_entry); + s.mode = File_system::Status::MODE_DIRECTORY; + return s; + } }; #endif /* _INCLUDE__RAM_FS__DIRECTORY_H_ */ diff --git a/repos/os/include/ram_fs/file.h b/repos/os/src/server/ram_fs/file.h similarity index 84% rename from repos/os/include/ram_fs/file.h rename to repos/os/src/server/ram_fs/file.h index 988fd9157..a1cfc9e82 100644 --- a/repos/os/include/ram_fs/file.h +++ b/repos/os/src/server/ram_fs/file.h @@ -19,13 +19,20 @@ #include /* local includes */ -#include #include +#include "node.h" -namespace File_system { class File; } +namespace Ram_fs +{ + using File_system::Chunk; + using File_system::Chunk_index; + using File_system::file_size_t; + using File_system::SEEK_TAIL; + class File; +} -class File_system::File : public Node +class Ram_fs::File : public Node { private: @@ -43,7 +50,7 @@ class File_system::File : public Node File(Allocator &alloc, char const *name) : _chunk(alloc, 0), _length(0) { Node::name(name); } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { file_size_t const chunk_used_size = _chunk.used_size(); @@ -79,7 +86,7 @@ class File_system::File : public Node return len; } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { if (seek_offset == SEEK_TAIL) seek_offset = _length; @@ -102,9 +109,16 @@ class File_system::File : public Node return len; } - file_size_t length() const { return _length; } + Status status() override + { + Status s; + s.inode = inode(); + s.size = _length; + s.mode = File_system::Status::MODE_FILE; + return s; + } - void truncate(file_size_t size) + void truncate(file_size_t size) override { if (size < _chunk.used_size()) _chunk.truncate(size); diff --git a/repos/os/src/server/ram_fs/main.cc b/repos/os/src/server/ram_fs/main.cc index d006f1f46..6f1cfc32e 100644 --- a/repos/os/src/server/ram_fs/main.cc +++ b/repos/os/src/server/ram_fs/main.cc @@ -12,7 +12,7 @@ */ /* Genode includes */ -#include +#include #include #include #include @@ -21,14 +21,18 @@ #include /* local includes */ -#include +#include "directory.h" /************************* ** File-system service ** *************************/ -namespace File_system { +namespace Ram_fs { + + using namespace File_system; + using File_system::Packet_descriptor; + using File_system::Path; class Session_component; class Root; @@ -36,16 +40,18 @@ namespace File_system { }; -class File_system::Session_component : public Session_rpc_object +class Ram_fs::Session_component : public File_system::Session_rpc_object { private: - Genode::Entrypoint &_ep; - Genode::Ram_session &_ram; - Genode::Allocator &_alloc; - Directory &_root; - Node_handle_registry _handle_registry; - bool _writable; + typedef File_system::Open_node Open_node; + + Genode::Entrypoint &_ep; + Genode::Ram_session &_ram; + Genode::Allocator &_alloc; + Directory &_root; + Id_space _open_node_registry; + bool _writable; Signal_handler _process_packet_handler; @@ -59,7 +65,7 @@ class File_system::Session_component : public Session_rpc_object * * \return true on success, false on failure */ - void _process_packet_op(Packet_descriptor &packet, Node &node) + void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) { void * const content = tx_sink()->packet_content(packet); size_t const length = packet.length(); @@ -71,17 +77,17 @@ class File_system::Session_component : public Session_rpc_object case Packet_descriptor::READ: if (content && (packet.length() <= packet.size())) - res_length = node.read((char *)content, length, packet.position()); + res_length = open_node.node().read((char *)content, length, packet.position()); break; case Packet_descriptor::WRITE: if (content && (packet.length() <= packet.size())) - res_length = node.write((char const *)content, length, packet.position()); + res_length = open_node.node().write((char const *)content, length, packet.position()); break; case Packet_descriptor::CONTENT_CHANGED: - _handle_registry.register_notify(*tx_sink(), packet.handle()); - node.notify_listeners(); + open_node.register_notify(*tx_sink()); + open_node.node().notify_listeners(); return; case Packet_descriptor::READ_READY: @@ -101,13 +107,13 @@ class File_system::Session_component : public Session_rpc_object /* assume failure by default */ packet.succeeded(false); - try { - Node *node = _handle_registry.lookup_and_lock(packet.handle()); - Node_lock_guard guard(node); + auto process_packet_fn = [&] (Open_node &open_node) { + _process_packet_op(packet, open_node); + }; - _process_packet_op(packet, *node); - } - catch (Invalid_handle) { + try { + _open_node_registry.apply(packet.handle(), process_packet_fn); + } catch (Id_space::Unknown_id const &) { Genode::error("Invalid_handle"); tx_sink()->acknowledge_packet(packet); } @@ -193,33 +199,46 @@ class File_system::Session_component : public Session_rpc_object if (!valid_name(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup_and_lock(dir_handle); - Node_lock_guard dir_guard(dir); + auto file_fn = [&] (Open_node &open_node) { - if (!_writable) - if (mode != STAT_ONLY && mode != READ_ONLY) - throw Permission_denied(); - - if (create) { + Node &dir = open_node.node(); if (!_writable) - throw Permission_denied(); + if (mode != STAT_ONLY && mode != READ_ONLY) + throw Permission_denied(); - if (dir->has_sub_node_unsynchronized(name.string())) - throw Node_already_exists(); + if (create) { - try { - File * const file = new (_alloc) - File(_alloc, name.string()); + if (!_writable) + throw Permission_denied(); - dir->adopt_unsynchronized(file); + if (dir.has_sub_node_unsynchronized(name.string())) + throw Node_already_exists(); + + try { + File * const file = new (_alloc) + File(_alloc, name.string()); + + dir.adopt_unsynchronized(file); + } + catch (Allocator::Out_of_memory) { throw No_space(); } } - catch (Allocator::Out_of_memory) { throw No_space(); } - } - File *file = dir->lookup_and_lock_file(name.string()); - Node_lock_guard file_guard(file); - return _handle_registry.alloc(file); + File *file = dir.lookup_file(name.string()); + + Open_node *open_file = + new (_alloc) Open_node(*file, _open_node_registry); + + return open_file->id(); + }; + + try { + return File_handle { + _open_node_registry.apply(dir_handle, file_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) @@ -227,29 +246,42 @@ class File_system::Session_component : public Session_rpc_object if (!valid_name(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup_and_lock(dir_handle); - Node_lock_guard dir_guard(dir); + auto symlink_fn = [&] (Open_node &open_node) { - if (create) { + Node &dir = open_node.node(); - if (!_writable) - throw Permission_denied(); + if (create) { - if (dir->has_sub_node_unsynchronized(name.string())) - throw Node_already_exists(); + if (!_writable) + throw Permission_denied(); - try { - Symlink * const symlink = new (_alloc) - Symlink(name.string()); + if (dir.has_sub_node_unsynchronized(name.string())) + throw Node_already_exists(); - dir->adopt_unsynchronized(symlink); + try { + Symlink * const symlink = new (_alloc) + Symlink(name.string()); + + dir.adopt_unsynchronized(symlink); + } + catch (Allocator::Out_of_memory) { throw No_space(); } } - catch (Allocator::Out_of_memory) { throw No_space(); } - } - Symlink *symlink = dir->lookup_and_lock_symlink(name.string()); - Node_lock_guard file_guard(symlink); - return _handle_registry.alloc(symlink); + Symlink *symlink = dir.lookup_symlink(name.string()); + + Open_node *open_symlink = + new (_alloc) Open_node(*symlink, _open_node_registry); + + return open_symlink->id(); + }; + + try { + return Symlink_handle { + _open_node_registry.apply(dir_handle, symlink_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Dir_handle dir(Path const &path, bool create) @@ -269,9 +301,7 @@ class File_system::Session_component : public Session_rpc_object if (!path.valid_string()) throw Name_too_long(); - Directory *parent = _root.lookup_and_lock_parent(path_str); - - Node_lock_guard guard(parent); + Directory *parent = _root.lookup_parent(path_str); char const *name = basename(path_str); @@ -285,55 +315,61 @@ class File_system::Session_component : public Session_rpc_object } } - Directory *dir = _root.lookup_and_lock_dir(path_str); - Node_lock_guard guard(dir); - return _handle_registry.alloc(dir); + Directory *dir = _root.lookup_dir(path_str); + + Open_node *open_dir = + new (_alloc) Open_node(*dir, _open_node_registry); + + return Dir_handle { open_dir->id().value }; } Node_handle node(Path const &path) { _assert_valid_path(path.string()); - Node *node = _root.lookup_and_lock(path.string() + 1); + Node *node = _root.lookup(path.string() + 1); - Node_lock_guard guard(node); - return _handle_registry.alloc(node); + Open_node *open_node = + new (_alloc) Open_node(*node, _open_node_registry); + + return open_node->id(); } void close(Node_handle handle) { - _handle_registry.free(handle); + auto close_fn = [&] (Open_node &open_node) { + + Node &node = open_node.node(); + + /* + * Notify listeners about the changed file. + */ + node.notify_listeners(); + + /* + * De-allocate handle + */ + destroy(_alloc, &open_node); + }; + + try { + _open_node_registry.apply(handle, close_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Status status(Node_handle node_handle) { - Node *node = _handle_registry.lookup_and_lock(node_handle); - Node_lock_guard guard(node); + auto status_fn = [&] (Open_node &open_node) { + return open_node.node().status(); + }; - Status s; - s.inode = node->inode(); - s.size = 0; - s.mode = 0; - - File *file = dynamic_cast(node); - if (file) { - s.size = file->length(); - s.mode = File_system::Status::MODE_FILE; - return s; + try { + return _open_node_registry.apply(node_handle, status_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - Directory *dir = dynamic_cast(node); - if (dir) { - s.size = dir->num_entries()*sizeof(Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; - return s; - } - Symlink *symlink = dynamic_cast(node); - if (symlink) { - s.size = symlink->length(); - s.mode = File_system::Status::MODE_SYMLINK; - return s; - } - return Status(); } void control(Node_handle, Control) { } @@ -346,18 +382,25 @@ class File_system::Session_component : public Session_rpc_object if (!_writable) throw Permission_denied(); - Directory *dir = _handle_registry.lookup_and_lock(dir_handle); - Node_lock_guard dir_guard(dir); + auto unlink_fn = [&] (Open_node &open_node) { - Node *node = dir->lookup_and_lock(name.string()); + Node &dir = open_node.node(); - dir->discard_unsynchronized(node); + Node *node = dir.lookup(name.string()); - // XXX implement ref counting, do not destroy node that is - // is still referenced by a node handle + dir.discard(node); - node->unlock(); - destroy(_alloc, node); + // XXX implement ref counting, do not destroy node that is + // is still referenced by a node handle + + destroy(_alloc, node); + }; + + 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) @@ -365,9 +408,15 @@ class File_system::Session_component : public Session_rpc_object if (!_writable) throw Permission_denied(); - File *file = _handle_registry.lookup_and_lock(file_handle); - Node_lock_guard file_guard(file); - file->truncate(size); + auto truncate_fn = [&] (Open_node &open_node) { + open_node.node().truncate(size); + }; + + try { + _open_node_registry.apply(file_handle, truncate_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } void move(Dir_handle from_dir_handle, Name const &from_name, @@ -382,47 +431,69 @@ class File_system::Session_component : public Session_rpc_object if (!valid_name(to_name.string())) throw Invalid_name(); - Directory *from_dir = _handle_registry.lookup_and_lock(from_dir_handle); - Node_lock_guard from_dir_guard(from_dir); + auto move_fn = [&] (Open_node &open_from_dir_node) { - Node *node = from_dir->lookup_and_lock(from_name.string()); - Node_lock_guard node_guard(node); - node->name(to_name.string()); + auto inner_move_fn = [&] (Open_node &open_to_dir_node) { - if (!_handle_registry.refer_to_same_node(from_dir_handle, to_dir_handle)) { - Directory *to_dir = _handle_registry.lookup_and_lock(to_dir_handle); - Node_lock_guard to_dir_guard(to_dir); + Node &from_dir = open_from_dir_node.node(); - from_dir->discard_unsynchronized(node); - to_dir->adopt_unsynchronized(node); + Node *node = from_dir.lookup(from_name.string()); + node->name(to_name.string()); - /* - * If the file was moved from one directory to another we - * need to inform the new directory 'to_dir'. The original - * directory 'from_dir' will always get notified (i.e., - * when just the file name was changed) below. - */ - to_dir->mark_as_updated(); - to_dir->notify_listeners(); + Node &to_dir = open_to_dir_node.node(); + + if (&to_dir != &from_dir) { + + from_dir.discard(node); + to_dir.adopt_unsynchronized(node); + + /* + * If the file was moved from one directory to another we + * need to inform the new directory 'to_dir'. The original + * directory 'from_dir' will always get notified (i.e., + * when just the file name was changed) below. + */ + to_dir.mark_as_updated(); + to_dir.notify_listeners(); + + from_dir.mark_as_updated(); + from_dir.notify_listeners(); + + node->mark_as_updated(); + node->notify_listeners(); + } + }; + + try { + _open_node_registry.apply(to_dir_handle, inner_move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + }; + + try { + _open_node_registry.apply(from_dir_handle, move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - - from_dir->mark_as_updated(); - from_dir->notify_listeners(); - - node->mark_as_updated(); - node->notify_listeners(); } void sync(Node_handle handle) override { - Node *node = _handle_registry.lookup_and_lock(handle); - Node_lock_guard guard(node); - node->notify_listeners(); + auto sync_fn = [&] (Open_node &open_node) { + open_node.node().notify_listeners(); + }; + + try { + _open_node_registry.apply(handle, sync_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } }; -class File_system::Root : public Root_component +class Ram_fs::Root : public Root_component { private: @@ -493,9 +564,8 @@ class File_system::Root : public Root_component * delimiter. For performing the lookup, we skip the first * character. */ - session_root_dir = _root_dir.lookup_and_lock_dir( + session_root_dir = _root_dir.lookup_dir( session_root.base() + 1); - session_root_dir->unlock(); } catch (Lookup_failed) { throw Service_denied(); } } @@ -588,7 +658,7 @@ struct Attribute_string static void preload_content(Genode::Env &env, Genode::Allocator &alloc, Genode::Xml_node node, - File_system::Directory &dir) + Ram_fs::Directory &dir) { using namespace File_system; @@ -606,7 +676,7 @@ static void preload_content(Genode::Env &env, */ if (sub_node.has_type("dir")) { - Directory *sub_dir = new (&alloc) Directory(name); + Ram_fs::Directory *sub_dir = new (&alloc) Ram_fs::Directory(name); /* traverse into the new directory */ preload_content(env, alloc, sub_node, *sub_dir); @@ -626,7 +696,7 @@ static void preload_content(Genode::Env &env, try { Attached_rom_dataspace rom(env, name); - File *file = new (&alloc) File(alloc, as); + Ram_fs::File *file = new (&alloc) Ram_fs::File(alloc, as); file->write(rom.local_addr(), rom.size(), 0); dir.adopt_unsynchronized(file); } @@ -641,7 +711,7 @@ static void preload_content(Genode::Env &env, */ if (sub_node.has_type("inline")) { - File *file = new (&alloc) File(alloc, name); + Ram_fs::File *file = new (&alloc) Ram_fs::File(alloc, name); file->write(sub_node.content_addr(), sub_node.content_size(), 0); dir.adopt_unsynchronized(file); } @@ -649,7 +719,7 @@ static void preload_content(Genode::Env &env, } -struct File_system::Main +struct Ram_fs::Main { Genode::Env &_env; @@ -679,4 +749,4 @@ struct File_system::Main }; -void Component::construct(Genode::Env &env) { static File_system::Main inst(env); } +void Component::construct(Genode::Env &env) { static Ram_fs::Main inst(env); } diff --git a/repos/os/src/server/ram_fs/node.h b/repos/os/src/server/ram_fs/node.h new file mode 100644 index 000000000..4de356486 --- /dev/null +++ b/repos/os/src/server/ram_fs/node.h @@ -0,0 +1,120 @@ +/* + * \brief File-system node + * \author Norman Feske + * \date 2012-04-11 + */ + +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _INCLUDE__RAM_FS__NODE_H_ +#define _INCLUDE__RAM_FS__NODE_H_ + +/* Genode includes */ +#include +#include +#include + +namespace Ram_fs { + using namespace Genode; + using File_system::seek_off_t; + using File_system::Status; + class Node; + class File; + class Symlink; +} + + +class Ram_fs::Node : public File_system::Node_base, public List::Element +{ + public: + + typedef char Name[128]; + + private: + + int _ref_count; + Name _name; + unsigned long const _inode; + + /** + * Generate unique inode number + */ + static unsigned long _unique_inode() + { + static unsigned long inode_count; + return ++inode_count; + } + + public: + + Node() + : _ref_count(0), _inode(_unique_inode()) + { _name[0] = 0; } + + unsigned long inode() const { return _inode; } + char const *name() const { return _name; } + + /** + * Assign name + */ + void name(char const *name) { strncpy(_name, name, sizeof(_name)); } + + virtual size_t read(char *dst, size_t len, seek_off_t) = 0; + virtual size_t write(char const *src, size_t len, seek_off_t) = 0; + + virtual Status status() = 0; + + + /* File functionality */ + + virtual void truncate(File_system::file_size_t size) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); + } + + + /* Directory functionality */ + + virtual bool has_sub_node_unsynchronized(char const *name) const + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return false; + } + + virtual void adopt_unsynchronized(Node *node) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + } + + virtual File *lookup_file(char const *path) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return nullptr; + } + + virtual Symlink *lookup_symlink(char const *path) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return nullptr; + } + + virtual Node *lookup(char const *path, bool return_parent = false) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return nullptr; + } + + virtual void discard(Node *node) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + } + + +}; + +#endif /* _INCLUDE__RAM_FS__NODE_H_ */ diff --git a/repos/os/include/ram_fs/symlink.h b/repos/os/src/server/ram_fs/symlink.h similarity index 71% rename from repos/os/include/ram_fs/symlink.h rename to repos/os/src/server/ram_fs/symlink.h index cd3ac76df..aead571c1 100644 --- a/repos/os/include/ram_fs/symlink.h +++ b/repos/os/src/server/ram_fs/symlink.h @@ -15,30 +15,30 @@ #define _INCLUDE__RAM_FS__SYMLINK_H_ /* local includes */ -#include +#include "node.h" -namespace File_system { class Symlink; } +namespace Ram_fs { class Symlink; } -class File_system::Symlink : public Node +class Ram_fs::Symlink : public Node { private: - char _link_to[MAX_PATH_LEN]; + char _link_to[File_system::MAX_PATH_LEN]; size_t _len; public: Symlink(char const *name): _len(0) { Node::name(name); } - size_t read(char *dst, size_t len, seek_off_t seek_offset) + size_t read(char *dst, size_t len, seek_off_t seek_offset) override { size_t count = min(len, _len-seek_offset); Genode::memcpy(dst, _link_to+seek_offset, count); return count; } - size_t write(char const *src, size_t len, seek_off_t seek_offset) + size_t write(char const *src, size_t len, seek_off_t seek_offset) override { /* Ideal symlink operations are atomic. */ if (seek_offset) return 0; @@ -48,7 +48,14 @@ class File_system::Symlink : public Node return _len; } - file_size_t length() const { return _len; } + Status status() override + { + Status s; + s.inode = inode(); + s.size = _len; + s.mode = File_system::Status::MODE_SYMLINK; + return s; + } }; #endif /* _INCLUDE__RAM_FS__SYMLINK_H_ */ diff --git a/repos/os/src/server/trace_fs/directory.h b/repos/os/src/server/trace_fs/directory.h index 9e0c2c1a4..dfcda613a 100644 --- a/repos/os/src/server/trace_fs/directory.h +++ b/repos/os/src/server/trace_fs/directory.h @@ -4,6 +4,13 @@ * \date 2012-04-11 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _DIRECTORY_H_ #define _DIRECTORY_H_ @@ -15,200 +22,201 @@ #include #include -namespace File_system { +namespace Trace_fs { + class Directory; +} - class Directory : public Node - { - private: +class Trace_fs::Directory : public Node +{ + private: - List _entries; - size_t _num_entries; + List _entries; + size_t _num_entries; - public: + public: - Directory(char const *name) : _num_entries(0) { Node::name(name); } + Directory(char const *name) : _num_entries(0) { Node::name(name); } - /** - * Check if the directory has the specified subnode - * - * \param name name of the searched subnode - * - * \return true if the subnode was found, either false + /** + * Check if the directory has the specified subnode + * + * \param name name of the searched subnode + * + * \return true if the subnode was found, either false + */ + bool has_sub_node_unsynchronized(char const *name) const + { + Node const *sub_node = _entries.first(); + for (; sub_node; sub_node = sub_node->next()) + if (strcmp(sub_node->name(), name) == 0) + return true; + + return false; + } + + + /** + * Add node to the list of subnodes + * + * \param pointer to node + */ + void adopt_unsynchronized(Node *node) + { + /* + * XXX inc ref counter */ - bool has_sub_node_unsynchronized(char const *name) const - { - Node const *sub_node = _entries.first(); - for (; sub_node; sub_node = sub_node->next()) - if (strcmp(sub_node->name(), name) == 0) - return true; + _entries.insert(node); + _num_entries++; - return false; + mark_as_updated(); + } + + /** + * Remove the node from the list of subnodes + * + * \param node pointer to node + */ + void discard_unsynchronized(Node *node) + { + _entries.remove(node); + _num_entries--; + + mark_as_updated(); + } + + /** + * Lookup node which belongs to the specified path + * + * \param path path to lookup + * \param return_parent if true return parent node, otherwise + * actual path node + * + * \return node node founc + * \throws Lookup_failed + */ + Node *lookup(char const *path, bool return_parent = false) override + { + if (strcmp(path, "") == 0) { + return this; } + if (!path || path[0] == '/') + throw Lookup_failed(); - /** - * Add node to the list of subnodes - * - * \param pointer to node + /* find first path delimiter */ + unsigned i = 0; + for (; path[i] && path[i] != '/'; i++); + + /* + * If no path delimiter was found, we are the parent of the + * specified path. */ - void adopt_unsynchronized(Node *node) - { - /* - * XXX inc ref counter - */ - _entries.insert(node); - _num_entries++; - - mark_as_updated(); + if (path[i] == 0 && return_parent) { + return this; } - /** - * Remove the node from the list of subnodes - * - * \param node pointer to node + /* + * The offset 'i' corresponds to the end of the first path + * element, which can be either the end of the string or the + * first '/' character. */ - void discard_unsynchronized(Node *node) - { - _entries.remove(node); - _num_entries--; - mark_as_updated(); + /* try to find entry that matches the first path element */ + Node *sub_node = _entries.first(); + for (; sub_node; sub_node = sub_node->next()) + if ((strlen(sub_node->name()) == i) && + (strcmp(sub_node->name(), path, i) == 0)) + break; + + if (!sub_node) + throw Lookup_failed(); + + if (!contains_path_delimiter(path)) { + + /* + * Because 'path' is a basename that corresponds to an + * existing sub_node, we have found what we were looking + * for. + */ + return sub_node; } - /** - * Lookup node which belongs to the specified path - * - * \param path path to lookup - * \param return_parent if true return parent node, otherwise - * actual path node - * - * \return node node founc - * \throws Lookup_failed + /* + * As 'path' contains one or more path delimiters, traverse + * into the sub directory names after the first path element. */ - Node *lookup(char const *path, bool return_parent = false) - { - if (strcmp(path, "") == 0) { - return this; - } - if (!path || path[0] == '/') - throw Lookup_failed(); - - /* find first path delimiter */ - unsigned i = 0; - for (; path[i] && path[i] != '/'; i++); - - /* - * If no path delimiter was found, we are the parent of the - * specified path. - */ - if (path[i] == 0 && return_parent) { - return this; - } - - /* - * The offset 'i' corresponds to the end of the first path - * element, which can be either the end of the string or the - * first '/' character. - */ - - /* try to find entry that matches the first path element */ - Node *sub_node = _entries.first(); - for (; sub_node; sub_node = sub_node->next()) - if ((strlen(sub_node->name()) == i) && - (strcmp(sub_node->name(), path, i) == 0)) - break; - - if (!sub_node) - throw Lookup_failed(); - - if (!contains_path_delimiter(path)) { - - /* - * Because 'path' is a basename that corresponds to an - * existing sub_node, we have found what we were looking - * for. - */ - return sub_node; - } - - /* - * As 'path' contains one or more path delimiters, traverse - * into the sub directory names after the first path element. - */ - - /* - * We cannot traverse into anything other than a directory. - * - * XXX we might follow symlinks here - */ - Directory *sub_dir = dynamic_cast(sub_node); - if (!sub_dir) - throw Lookup_failed(); - - return sub_dir->lookup(path + i + 1, return_parent); - } - - /** - * Return number of subnodes + /* + * We cannot traverse into anything other than a directory. + * + * XXX we might follow symlinks here */ - size_t num_entries() const { return _num_entries; } + Directory *sub_dir = dynamic_cast(sub_node); + if (!sub_dir) + throw Lookup_failed(); + + return sub_dir->lookup(path + i + 1, return_parent); + } + + /** + * Return number of subnodes + */ + size_t num_entries() const { return _num_entries; } - /******************** - ** Node interface ** - ********************/ + /******************** + ** Node interface ** + ********************/ - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - if (len < sizeof(Directory_entry)) { - Genode::error("read buffer too small for directory entry"); - return 0; - } - - seek_off_t index = seek_offset / sizeof(Directory_entry); - - if (seek_offset % sizeof(Directory_entry)) { - Genode::error("seek offset not alighed to sizeof(Directory_entry)"); - return 0; - } - - /* find list element */ - Node *node = _entries.first(); - for (unsigned i = 0; i < index && node; node = node->next(), i++); - - /* index out of range */ - if (!node) - return 0; - - Directory_entry *e = (Directory_entry *)(dst); - - if (dynamic_cast(node)) e->type = Directory_entry::TYPE_FILE; - if (dynamic_cast(node)) e->type = Directory_entry::TYPE_DIRECTORY; - if (dynamic_cast(node)) e->type = Directory_entry::TYPE_SYMLINK; - - strncpy(e->name, node->name(), sizeof(e->name)); - - return sizeof(Directory_entry); - } - - size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - /* writing to directory nodes is not supported */ + size_t read(char *dst, size_t len, seek_off_t seek_offset) + { + if (len < sizeof(Directory_entry)) { + Genode::error("read buffer too small for directory entry"); return 0; } - Status status() const - { - Status s; - s.inode = inode(); - s.size = _num_entries * sizeof (Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; + seek_off_t index = seek_offset / sizeof(Directory_entry); - return s; + if (seek_offset % sizeof(Directory_entry)) { + Genode::error("seek offset not alighed to sizeof(Directory_entry)"); + return 0; } - }; -} + + /* find list element */ + Node *node = _entries.first(); + for (unsigned i = 0; i < index && node; node = node->next(), i++); + + /* index out of range */ + if (!node) + return 0; + + Directory_entry *e = (Directory_entry *)(dst); + + if (dynamic_cast(node)) e->type = Directory_entry::TYPE_FILE; + if (dynamic_cast(node)) e->type = Directory_entry::TYPE_DIRECTORY; + if (dynamic_cast(node)) e->type = Directory_entry::TYPE_SYMLINK; + + strncpy(e->name, node->name(), sizeof(e->name)); + + return sizeof(Directory_entry); + } + + size_t write(char const *src, size_t len, seek_off_t seek_offset) + { + /* writing to directory nodes is not supported */ + return 0; + } + + Status status() const + { + Status s; + s.inode = inode(); + s.size = _num_entries * sizeof (Directory_entry); + s.mode = File_system::Status::MODE_DIRECTORY; + + return s; + } +}; #endif /* _DIRECTORY_H_ */ diff --git a/repos/os/src/server/trace_fs/file.h b/repos/os/src/server/trace_fs/file.h index 16096db7e..07a3fba21 100644 --- a/repos/os/src/server/trace_fs/file.h +++ b/repos/os/src/server/trace_fs/file.h @@ -23,195 +23,198 @@ #include #include -namespace File_system { - - /** - * - * - */ - class Changeable_content - { - protected: - - /** - * This member is used to communicate the state and - * must be set true by classes using this class in case - * the content has changed. - */ - bool _changed; - - /** - * This method is called when the content change is - * acknowledged. It may be overriden by any class using - * this particular class. - */ - virtual void _refresh_content() { } - - public: - - Changeable_content() : _changed(false) { } - - /** - * Check if the content was changed - * - * This evaluation has to be made by classes using this - * particular class. - * - * \return true if changed, otherwise false - */ - bool changed() const { return _changed; } - - - /** - * Acknowledge the content has changed - */ - void acknowledge_change() - { - _changed = false; - - _refresh_content(); - } - }; - - - /** - * File interface - */ - - class File : public Node - { - public: - - File(char const *name) - { - Node::name(name); - } - - virtual ~File() { } - - /******************** - ** Node interface ** - ********************/ - - virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) = 0; - - virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) = 0; - - virtual Status status() const = 0; - - /******************** - ** File interface ** - ********************/ - - virtual file_size_t length() const = 0; - - virtual void truncate(file_size_t size) = 0; - }; - - /** - * Memory buffered file - * - * This file merely exists in memory and grows automatically. - */ - - class Buffered_file : public File - { - private: - - typedef Chunk<4096> Chunk_level_3; - typedef Chunk_index<128, Chunk_level_3> Chunk_level_2; - typedef Chunk_index<64, Chunk_level_2> Chunk_level_1; - typedef Chunk_index<64, Chunk_level_1> Chunk_level_0; - - Chunk_level_0 _chunk; - - file_size_t _length; - - public: - - Buffered_file(Allocator &alloc, char const *name) - : File(name), _chunk(alloc, 0), _length(0) { } - - virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - file_size_t const chunk_used_size = _chunk.used_size(); - - if (seek_offset >= _length) - return 0; - - /* - * Constrain read transaction to available chunk data - * - * Note that 'chunk_used_size' may be lower than '_length' - * because 'Chunk' may have truncated tailing zeros. - */ - if (seek_offset + len >= _length) - len = _length - seek_offset; - - file_size_t read_len = len; - - if (seek_offset + read_len > chunk_used_size) { - if (chunk_used_size >= seek_offset) - read_len = chunk_used_size - seek_offset; - else - read_len = 0; - } - - _chunk.read(dst, read_len, seek_offset); - - /* add zero padding if needed */ - if (read_len < len) - memset(dst + read_len, 0, len - read_len); - - return len; - } - - virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - if (seek_offset == (seek_off_t)(~0)) - seek_offset = _chunk.used_size(); - - if (seek_offset + len >= Chunk_level_0::SIZE) { - len = (Chunk_level_0::SIZE-1) - seek_offset; - Genode::error(name(), ": size limit ", (long)Chunk_level_0::SIZE, " reached"); - } - - _chunk.write(src, len, (size_t)seek_offset); - - /* - * Keep track of file length. We cannot use 'chunk.used_size()' - * as file length because trailing zeros may by represented - * by zero chunks, which do not contribute to 'used_size()'. - */ - _length = max(_length, seek_offset + len); - - mark_as_updated(); - return len; - } - - virtual Status status() const - { - Status s; - - s.inode = inode(); - s.size = _length; - s.mode = File_system::Status::MODE_FILE; - - return s; - } - - virtual file_size_t length() const { return _length; } - - void truncate(file_size_t size) - { - if (size < _chunk.used_size()) - _chunk.truncate(size); - - _length = size; - - mark_as_updated(); - } - }; +namespace Trace_fs { + class Changeable_content; + class File; + class Buffered_file; } +/** + * + * + */ +class Trace_fs::Changeable_content +{ + protected: + + /** + * This member is used to communicate the state and + * must be set true by classes using this class in case + * the content has changed. + */ + bool _changed; + + /** + * This method is called when the content change is + * acknowledged. It may be overriden by any class using + * this particular class. + */ + virtual void _refresh_content() { } + + public: + + Changeable_content() : _changed(false) { } + + /** + * Check if the content was changed + * + * This evaluation has to be made by classes using this + * particular class. + * + * \return true if changed, otherwise false + */ + bool changed() const { return _changed; } + + + /** + * Acknowledge the content has changed + */ + void acknowledge_change() + { + _changed = false; + + _refresh_content(); + } +}; + + +/** + * File interface + */ + +class Trace_fs::File : public Node +{ + public: + + File(char const *name) + { + Node::name(name); + } + + virtual ~File() { } + + /******************** + ** Node interface ** + ********************/ + + virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) = 0; + + virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) = 0; + + virtual Status status() const = 0; + + /******************** + ** File interface ** + ********************/ + + virtual file_size_t length() const = 0; + + virtual void truncate(file_size_t size) = 0; +}; + +/** + * Memory buffered file + * + * This file merely exists in memory and grows automatically. + */ + +class Trace_fs::Buffered_file : public File +{ + private: + + typedef Chunk<4096> Chunk_level_3; + typedef Chunk_index<128, Chunk_level_3> Chunk_level_2; + typedef Chunk_index<64, Chunk_level_2> Chunk_level_1; + typedef Chunk_index<64, Chunk_level_1> Chunk_level_0; + + Chunk_level_0 _chunk; + + file_size_t _length; + + public: + + Buffered_file(Allocator &alloc, char const *name) + : File(name), _chunk(alloc, 0), _length(0) { } + + virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) + { + file_size_t const chunk_used_size = _chunk.used_size(); + + if (seek_offset >= _length) + return 0; + + /* + * Constrain read transaction to available chunk data + * + * Note that 'chunk_used_size' may be lower than '_length' + * because 'Chunk' may have truncated tailing zeros. + */ + if (seek_offset + len >= _length) + len = _length - seek_offset; + + file_size_t read_len = len; + + if (seek_offset + read_len > chunk_used_size) { + if (chunk_used_size >= seek_offset) + read_len = chunk_used_size - seek_offset; + else + read_len = 0; + } + + _chunk.read(dst, read_len, seek_offset); + + /* add zero padding if needed */ + if (read_len < len) + memset(dst + read_len, 0, len - read_len); + + return len; + } + + virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) + { + if (seek_offset == (seek_off_t)(~0)) + seek_offset = _chunk.used_size(); + + if (seek_offset + len >= Chunk_level_0::SIZE) { + len = (Chunk_level_0::SIZE-1) - seek_offset; + Genode::error(name(), ": size limit ", (long)Chunk_level_0::SIZE, " reached"); + } + + _chunk.write(src, len, (size_t)seek_offset); + + /* + * Keep track of file length. We cannot use 'chunk.used_size()' + * as file length because trailing zeros may by represented + * by zero chunks, which do not contribute to 'used_size()'. + */ + _length = max(_length, seek_offset + len); + + mark_as_updated(); + return len; + } + + virtual Status status() const + { + Status s; + + s.inode = inode(); + s.size = _length; + s.mode = File_system::Status::MODE_FILE; + + return s; + } + + virtual file_size_t length() const { return _length; } + + void truncate(file_size_t size) override + { + if (size < _chunk.used_size()) + _chunk.truncate(size); + + _length = size; + + mark_as_updated(); + } +}; + #endif /* _FILE_H_ */ diff --git a/repos/os/src/server/trace_fs/followed_subject.h b/repos/os/src/server/trace_fs/followed_subject.h index 0171a1519..8a5d0fed9 100644 --- a/repos/os/src/server/trace_fs/followed_subject.h +++ b/repos/os/src/server/trace_fs/followed_subject.h @@ -22,261 +22,262 @@ #include namespace Trace_fs { - typedef Genode::size_t size_t; - - struct Followed_subject : public File_system::Directory - { - public: - - /** - * This class manages the access to the trace subject's trace buffer - */ - class Trace_buffer_manager - { - public: - - class Already_managed { }; - class Not_managed { }; - - struct Process_entry - { - virtual size_t operator()(Genode::Trace::Buffer::Entry&) = 0; - }; - - private: - - Genode::Trace::Buffer *buffer; - Genode::Trace::Buffer::Entry current_entry; - - - public: - - Trace_buffer_manager(Genode::Region_map &rm, - Genode::Dataspace_capability ds_cap) - : - buffer(rm.attach(ds_cap)), - current_entry(buffer->first()) - { } - - size_t dump_entry(Process_entry &process) - { - size_t len = process(current_entry); - - current_entry = buffer->next(current_entry); - return len; - } - - bool last_entry() const - { - return current_entry.last(); - } - - void rewind() { current_entry = buffer->first(); } - }; - - - private: - - Genode::Allocator &_md_alloc; - - Genode::Region_map &_rm; - - int _handle; - - Genode::Trace::Subject_id _id; - Genode::Trace::Policy_id _policy_id; - - bool _was_traced; - - Trace_buffer_manager *_buffer_manager; - - public: - - File_system::Active_file active_file; - File_system::Buffer_size_file buffer_size_file; - File_system::Cleanup_file cleanup_file; - File_system::Enable_file enable_file; - File_system::Events_file events_file; - File_system::Policy_file policy_file; - - Followed_subject(Genode::Allocator &md_alloc, char const *name, - Genode::Region_map &rm, - Genode::Trace::Subject_id &id, int handle) - : - Directory(name), - _md_alloc(md_alloc), - _rm(rm), - _handle(handle), - _id(id), - _was_traced(false), - _buffer_manager(0), - active_file(_id), - buffer_size_file(), - cleanup_file(_id), - enable_file(_id), - events_file(_id, _md_alloc), - policy_file(_id, _md_alloc) - { - adopt_unsynchronized(&active_file); - adopt_unsynchronized(&cleanup_file); - adopt_unsynchronized(&enable_file); - adopt_unsynchronized(&events_file); - adopt_unsynchronized(&buffer_size_file); - adopt_unsynchronized(&policy_file); - } - - ~Followed_subject() - { - discard_unsynchronized(&active_file); - discard_unsynchronized(&cleanup_file); - discard_unsynchronized(&enable_file); - discard_unsynchronized(&events_file); - discard_unsynchronized(&buffer_size_file); - discard_unsynchronized(&policy_file); - } - - bool marked_for_cleanup() const { return cleanup_file.cleanup(); } - bool was_traced() const { return _was_traced; } - - Trace_buffer_manager* trace_buffer_manager() { return _buffer_manager; } - - void manage_trace_buffer(Genode::Dataspace_capability ds_cap) - { - if (_buffer_manager != 0) - throw Trace_buffer_manager::Already_managed(); - - _buffer_manager = new (&_md_alloc) Trace_buffer_manager(_rm, ds_cap); - } - - void unmanage_trace_buffer() - { - if (_buffer_manager == 0) - throw Trace_buffer_manager::Not_managed(); - - destroy(&_md_alloc, _buffer_manager); - _buffer_manager = 0; - } - - const Genode::Trace::Subject_id id() const { return _id; } - - const Genode::Trace::Policy_id policy_id() const { return _policy_id; } - void policy_id(Genode::Trace::Policy_id &id) { _policy_id.id = id.id; } - bool policy_valid() const { return (_policy_id.id != 0); } - void invalidate_policy() { _policy_id = Genode::Trace::Policy_id(); } - - int handle() const { return _handle; } - }; - - - /** - * This registry contains all current followed trace subjects - */ - class Followed_subject_registry - { - public: - - class Invalid_subject { }; - class Out_of_subject_handles { }; - - private: - - /* XXX abitrary limit - needs to be revisited when highly - * dynamic scenarios are executed */ - enum { MAX_SUBJECTS = 1024U }; - - Followed_subject *_subjects[MAX_SUBJECTS]; - - Genode::Allocator &_md_alloc; - - /** - * Find free subject handle - * - * \throw Out_of_subject_handles - */ - int _find_free_handle() - { - for (unsigned i = 0; i < MAX_SUBJECTS; i++) - if (!_subjects[i]) { - return i; - } - - throw Out_of_subject_handles(); - } - - bool _in_range(int handle) const - { - return ((handle >= 0) && (handle < MAX_SUBJECTS)); - } - - public: - - Followed_subject_registry(Genode::Allocator &md_alloc) - : - _md_alloc(md_alloc) - { - for (unsigned i = 0; i < MAX_SUBJECTS; i++) - _subjects[i] = 0; - } - - /** - * Return maximal number of subject that can be stored in the registry - * - * \return maximal number of subjects - */ - unsigned max_subjects() const { return MAX_SUBJECTS; } - - /** - * Allocate new subject - * - * \param name name of subject - * \param id subject id of tracre subject - */ - Followed_subject *alloc(char const *name, Genode::Trace::Subject_id &id, - Genode::Region_map &rm) - { - int handle = _find_free_handle(); - - _subjects[handle] = new (&_md_alloc) Followed_subject(_md_alloc, name, rm, id, handle); - - return _subjects[handle]; - } - - /** - * Free subject - * - * \param subject pointer to subject - */ - void free(Followed_subject *subject) - { - int handle = subject->handle(); - - if (!_in_range(handle)) - return; - - if(!_subjects[handle]) - return; - - _subjects[handle] = 0; - destroy(&_md_alloc, subject); - } - - /** - * Lookup subject by using the id - * - * \throw Invalid_subject(); - */ - Followed_subject *lookup(Genode::Trace::Subject_id const &sid) - { - for (unsigned i = 0; i < MAX_SUBJECTS; i++) - if (_subjects[i]) { - if (_subjects[i]->id().id == sid.id) - return _subjects[i]; - } - - throw Invalid_subject(); - } - }; + class Followed_subject; + class Followed_subject_registry; } +class Trace_fs::Followed_subject : public Directory +{ + public: + + /** + * This class manages the access to the trace subject's trace buffer + */ + class Trace_buffer_manager + { + public: + + class Already_managed { }; + class Not_managed { }; + + struct Process_entry + { + virtual size_t operator()(Genode::Trace::Buffer::Entry&) = 0; + }; + + private: + + Genode::Trace::Buffer *buffer; + Genode::Trace::Buffer::Entry current_entry; + + + public: + + Trace_buffer_manager(Genode::Region_map &rm, + Genode::Dataspace_capability ds_cap) + : + buffer(rm.attach(ds_cap)), + current_entry(buffer->first()) + { } + + size_t dump_entry(Process_entry &process) + { + size_t len = process(current_entry); + + current_entry = buffer->next(current_entry); + return len; + } + + bool last_entry() const + { + return current_entry.last(); + } + + void rewind() { current_entry = buffer->first(); } + }; + + + private: + + Genode::Allocator &_md_alloc; + + Genode::Region_map &_rm; + + int _handle; + + Genode::Trace::Subject_id _id; + Genode::Trace::Policy_id _policy_id; + + bool _was_traced; + + Trace_buffer_manager *_buffer_manager; + + public: + + Active_file active_file; + Buffer_size_file buffer_size_file; + Cleanup_file cleanup_file; + Enable_file enable_file; + Events_file events_file; + Policy_file policy_file; + + Followed_subject(Genode::Allocator &md_alloc, char const *name, + Genode::Region_map &rm, + Genode::Trace::Subject_id &id, int handle) + : + Directory(name), + _md_alloc(md_alloc), + _rm(rm), + _handle(handle), + _id(id), + _was_traced(false), + _buffer_manager(0), + active_file(_id), + buffer_size_file(), + cleanup_file(_id), + enable_file(_id), + events_file(_id, _md_alloc), + policy_file(_id, _md_alloc) + { + adopt_unsynchronized(&active_file); + adopt_unsynchronized(&cleanup_file); + adopt_unsynchronized(&enable_file); + adopt_unsynchronized(&events_file); + adopt_unsynchronized(&buffer_size_file); + adopt_unsynchronized(&policy_file); + } + + ~Followed_subject() + { + discard_unsynchronized(&active_file); + discard_unsynchronized(&cleanup_file); + discard_unsynchronized(&enable_file); + discard_unsynchronized(&events_file); + discard_unsynchronized(&buffer_size_file); + discard_unsynchronized(&policy_file); + } + + bool marked_for_cleanup() const { return cleanup_file.cleanup(); } + bool was_traced() const { return _was_traced; } + + Trace_buffer_manager* trace_buffer_manager() { return _buffer_manager; } + + void manage_trace_buffer(Genode::Dataspace_capability ds_cap) + { + if (_buffer_manager != 0) + throw Trace_buffer_manager::Already_managed(); + + _buffer_manager = new (&_md_alloc) Trace_buffer_manager(_rm, ds_cap); + } + + void unmanage_trace_buffer() + { + if (_buffer_manager == 0) + throw Trace_buffer_manager::Not_managed(); + + destroy(&_md_alloc, _buffer_manager); + _buffer_manager = 0; + } + + const Genode::Trace::Subject_id id() const { return _id; } + + const Genode::Trace::Policy_id policy_id() const { return _policy_id; } + void policy_id(Genode::Trace::Policy_id &id) { _policy_id.id = id.id; } + bool policy_valid() const { return (_policy_id.id != 0); } + void invalidate_policy() { _policy_id = Genode::Trace::Policy_id(); } + + int handle() const { return _handle; } +}; + + +/** + * This registry contains all current followed trace subjects + */ +class Trace_fs::Followed_subject_registry +{ + public: + + class Invalid_subject { }; + class Out_of_subject_handles { }; + + private: + + /* XXX abitrary limit - needs to be revisited when highly + * dynamic scenarios are executed */ + enum { MAX_SUBJECTS = 1024U }; + + Followed_subject *_subjects[MAX_SUBJECTS]; + + Genode::Allocator &_md_alloc; + + /** + * Find free subject handle + * + * \throw Out_of_subject_handles + */ + int _find_free_handle() + { + for (unsigned i = 0; i < MAX_SUBJECTS; i++) + if (!_subjects[i]) { + return i; + } + + throw Out_of_subject_handles(); + } + + bool _in_range(int handle) const + { + return ((handle >= 0) && (handle < MAX_SUBJECTS)); + } + + public: + + Followed_subject_registry(Genode::Allocator &md_alloc) + : + _md_alloc(md_alloc) + { + for (unsigned i = 0; i < MAX_SUBJECTS; i++) + _subjects[i] = 0; + } + + /** + * Return maximal number of subject that can be stored in the registry + * + * \return maximal number of subjects + */ + unsigned max_subjects() const { return MAX_SUBJECTS; } + + /** + * Allocate new subject + * + * \param name name of subject + * \param id subject id of tracre subject + */ + Followed_subject *alloc(char const *name, Genode::Trace::Subject_id &id, + Genode::Region_map &rm) + { + int handle = _find_free_handle(); + + _subjects[handle] = new (&_md_alloc) Followed_subject(_md_alloc, name, rm, id, handle); + + return _subjects[handle]; + } + + /** + * Free subject + * + * \param subject pointer to subject + */ + void free(Followed_subject *subject) + { + int handle = subject->handle(); + + if (!_in_range(handle)) + return; + + if(!_subjects[handle]) + return; + + _subjects[handle] = 0; + destroy(&_md_alloc, subject); + } + + /** + * Lookup subject by using the id + * + * \throw Invalid_subject(); + */ + Followed_subject *lookup(Genode::Trace::Subject_id const &sid) + { + for (unsigned i = 0; i < MAX_SUBJECTS; i++) + if (_subjects[i]) { + if (_subjects[i]->id().id == sid.id) + return _subjects[i]; + } + + throw Invalid_subject(); + } +}; + #endif /* _SUBJECT_REGISTRY_H_ */ diff --git a/repos/os/src/server/trace_fs/main.cc b/repos/os/src/server/trace_fs/main.cc index 54cd71228..fa994a4cc 100644 --- a/repos/os/src/server/trace_fs/main.cc +++ b/repos/os/src/server/trace_fs/main.cc @@ -13,7 +13,7 @@ /* Genode includes */ #include -#include +#include #include #include #include @@ -33,6 +33,18 @@ #include +namespace Trace_fs { + + using File_system::Packet_descriptor; + using File_system::Path; + + class Trace_file_system; + struct Main; + struct Session_component; + struct Root; +} + + /** * Return true if 'str' is a valid file name */ @@ -59,7 +71,7 @@ static inline bool valid_filename(char const *str) * needed, refreshing their content or deleting them if they are no * longer of any use. */ -class Trace_file_system +class Trace_fs::Trace_file_system { private: @@ -70,13 +82,6 @@ class Trace_file_system typedef Genode::Trace::Subject_info Subject_info; typedef Genode::Trace::Connection Trace; - typedef Trace_fs::Followed_subject_registry Followed_subject_registry; - typedef Trace_fs::Followed_subject Followed_subject; - - typedef File_system::Directory Directory; - typedef File_system::Node Node; - - /** * Simple node list * @@ -95,9 +100,9 @@ class Trace_file_system */ struct Node_list_entry : public Genode::List::Element { - File_system::Node *node; + Node *node; - Node_list_entry(File_system::Node *n) : node(n) { } + Node_list_entry(Node *n) : node(n) { } }; Genode::Allocator &_md_alloc; @@ -598,23 +603,18 @@ class Trace_file_system }; -namespace File_system { - struct Main; - struct Session_component; - struct Root; -} - - -class File_system::Session_component : public Session_rpc_object +class Trace_fs::Session_component : public Session_rpc_object { private: - Genode::Entrypoint &_ep; - Ram_session &_ram; - Allocator &_md_alloc; - Directory &_root_dir; - Node_handle_registry _handle_registry; - bool _writeable; + typedef File_system::Open_node Open_node; + + Genode::Entrypoint &_ep; + Ram_session &_ram; + Allocator &_md_alloc; + Directory &_root_dir; + Id_space _open_node_registry; + bool _writeable; unsigned _subject_limit; unsigned _poll_interval; @@ -647,7 +647,7 @@ class File_system::Session_component : public Session_rpc_object /** * Perform packet operation */ - void _process_packet_op(Packet_descriptor &packet, Node &node) + void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) { void * const content = tx_sink()->packet_content(packet); size_t const length = packet.length(); @@ -659,18 +659,18 @@ class File_system::Session_component : public Session_rpc_object case Packet_descriptor::READ: if (content && (packet.length() <= packet.size())) - res_length = node.read((char *)content, length, packet.position()); + res_length = open_node.node().read((char *)content, length, packet.position()); break; case Packet_descriptor::WRITE: if (content && (packet.length() <= packet.size())) - res_length = node.write((char const *)content, length, packet.position()); + res_length = open_node.node().write((char const *)content, length, packet.position()); break; case Packet_descriptor::CONTENT_CHANGED: - _handle_registry.register_notify(*tx_sink(), packet.handle()); + open_node.register_notify(*tx_sink()); /* notify_listeners may bounce the packet back*/ - node.notify_listeners(); + open_node.node().notify_listeners(); /* otherwise defer acknowledgement of this packet */ return; @@ -691,11 +691,15 @@ class File_system::Session_component : public Session_rpc_object /* assume failure by default */ packet.succeeded(false); + auto process_packet_fn = [&] (Open_node &open_node) { + _process_packet_op(packet, open_node); + }; + try { - Node *node = _handle_registry.lookup(packet.handle()); - _process_packet_op(packet, *node); + _open_node_registry.apply(packet.handle(), process_packet_fn); + } catch (Id_space::Unknown_id const &) { + Genode::error("Invalid_handle"); } - catch (Invalid_handle) { Genode::error("Invalid_handle"); } /* * The 'acknowledge_packet' function cannot block because we @@ -748,20 +752,20 @@ class File_system::Session_component : public Session_rpc_object /** * Constructor */ - Session_component(size_t tx_buf_size, - Genode::Entrypoint &ep, - Genode::Ram_session &ram, - Genode::Region_map &rm, - Genode::Env &env, - File_system::Directory &root_dir, - Allocator &md_alloc, - unsigned subject_limit, - unsigned poll_interval, - size_t trace_quota, - size_t trace_meta_quota, - size_t trace_parent_levels, - size_t buffer_size, - size_t buffer_size_max) + Session_component(size_t tx_buf_size, + Genode::Entrypoint &ep, + Genode::Ram_session &ram, + Genode::Region_map &rm, + Genode::Env &env, + Directory &root_dir, + Allocator &md_alloc, + unsigned subject_limit, + unsigned poll_interval, + size_t trace_quota, + size_t trace_meta_quota, + size_t trace_parent_levels, + size_t buffer_size, + size_t buffer_size_max) : Session_rpc_object(ram.alloc(tx_buf_size), rm, ep.rpc_ep()), _ep(ep), @@ -814,22 +818,36 @@ class File_system::Session_component : public Session_rpc_object if (!valid_filename(name.string())) throw Invalid_name(); - Directory *dir = _handle_registry.lookup(dir_handle); + auto file_fn = [&] (Open_node &open_node) { - if (create) - throw Permission_denied(); + Node &dir = open_node.node(); - File *file = dynamic_cast(dir->lookup(name.string())); - if (!file) - throw Invalid_name(); + if (create) + throw Permission_denied(); - return _handle_registry.alloc(file); + File *file = dynamic_cast(dir.lookup(name.string())); + if (!file) + throw Invalid_name(); + + Open_node *open_file = + new (_md_alloc) Open_node(*file, _open_node_registry); + + return open_file->id(); + }; + + try { + return File_handle { + _open_node_registry.apply(dir_handle, file_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) { Genode::warning("symlinks not supported"); - return Symlink_handle(); + throw Permission_denied(); } Dir_handle dir(Path const &path, bool create) @@ -848,7 +866,10 @@ class File_system::Session_component : public Session_rpc_object if (!dir) throw Invalid_name(); - return _handle_registry.alloc(dir); + Open_node *open_dir = + new (_md_alloc) Open_node(*dir, _open_node_registry); + + return Dir_handle { open_dir->id().value }; } Node_handle node(Path const &path) @@ -859,40 +880,61 @@ class File_system::Session_component : public Session_rpc_object Node *node = _root_dir.lookup(path_str + 1); - return _handle_registry.alloc(node); + Open_node *open_node = + new (_md_alloc) Open_node(*node, _open_node_registry); + + return open_node->id(); } void close(Node_handle handle) { - Node *node; + auto close_fn = [&] (Open_node &open_node) { - try { node = _handle_registry.lookup(handle); } - catch (Invalid_handle) { - Genode::error("close() called with invalid handle"); - return; - } + Node &node = open_node.node(); - /** - * Acknowledge the change of the content of files which may be - * modified by the user of the file system. - */ - Changeable_content *changeable = dynamic_cast(node); - if (changeable) { - if (changeable->changed()) { - changeable->acknowledge_change(); + /** + * Acknowledge the change of the content of files which may be + * modified by the user of the file system. + */ + Changeable_content *changeable = dynamic_cast(&node); + if (changeable) { + if (changeable->changed()) { + changeable->acknowledge_change(); - /* let the trace fs perform the provoked actions */ - _trace_fs->handle_changed_node(node); + /* let the trace fs perform the provoked actions */ + _trace_fs->handle_changed_node(&node); + } } - } - _handle_registry.free(handle); + /* + * Notify listeners about the changed file. + */ + node.notify_listeners(); + + /* + * De-allocate handle + */ + destroy(_md_alloc, &open_node); + }; + + try { + _open_node_registry.apply(handle, close_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } Status status(Node_handle node_handle) { - Node *node = _handle_registry.lookup(node_handle); - return node->status(); + auto status_fn = [&] (Open_node &open_node) { + return open_node.node().status(); + }; + + try { + return _open_node_registry.apply(node_handle, status_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } } void control(Node_handle, Control) { } @@ -900,22 +942,22 @@ class File_system::Session_component : public Session_rpc_object void truncate(File_handle handle, file_size_t size) { - Node *node; + auto truncate_fn = [&] (Open_node &open_node) { + open_node.node().truncate(size); + }; try { - node = _handle_registry.lookup(handle); - - File *file = dynamic_cast(node); - if (file) { file->truncate(size); } + _open_node_registry.apply(handle, truncate_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); } - catch (Invalid_handle) { } } void move(Dir_handle, Name const &, Dir_handle, Name const &) { } }; -class File_system::Root : public Root_component +class Trace_fs::Root : public Root_component { private: @@ -1055,7 +1097,7 @@ class File_system::Root : public Root_component }; -struct File_system::Main +struct Trace_fs::Main { Env &_env; @@ -1074,4 +1116,4 @@ struct File_system::Main } }; -void Component::construct(Genode::Env &env) { static File_system::Main main(env); } +void Component::construct(Genode::Env &env) { static Trace_fs::Main main(env); } diff --git a/repos/os/src/server/trace_fs/node.h b/repos/os/src/server/trace_fs/node.h index ea17dd2f2..ed7d26380 100644 --- a/repos/os/src/server/trace_fs/node.h +++ b/repos/os/src/server/trace_fs/node.h @@ -4,6 +4,13 @@ * \date 2012-04-11 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _NODE_H_ #define _NODE_H_ @@ -13,49 +20,67 @@ #include #include -namespace File_system { - +namespace Trace_fs { + using namespace File_system; using namespace Genode; - - class Node : public Node_base, public List::Element - { - public: - - typedef char Name[128]; - - private: - - Name _name; - unsigned long const _inode; - - /** - * Generate unique inode number - */ - static unsigned long _unique_inode() - { - static unsigned long inode_count; - return ++inode_count; - } - - public: - - Node() - : _inode(_unique_inode()) - { _name[0] = 0; } - - unsigned long inode() const { return _inode; } - char const *name() const { return _name; } - - /** - * Assign name - */ - void name(char const *name) { strncpy(_name, name, sizeof(_name)); } - - virtual Status status() const = 0; - - virtual size_t read(char *dst, size_t len, seek_off_t) = 0; - virtual size_t write(char const *src, size_t len, seek_off_t) = 0; - }; + class Node; } +class Trace_fs::Node : public Node_base, public List::Element +{ + public: + + typedef char Name[128]; + + private: + + Name _name; + unsigned long const _inode; + + /** + * Generate unique inode number + */ + static unsigned long _unique_inode() + { + static unsigned long inode_count; + return ++inode_count; + } + + public: + + Node() + : _inode(_unique_inode()) + { _name[0] = 0; } + + unsigned long inode() const { return _inode; } + char const *name() const { return _name; } + + /** + * Assign name + */ + void name(char const *name) { strncpy(_name, name, sizeof(_name)); } + + virtual Status status() const = 0; + + virtual size_t read(char *dst, size_t len, seek_off_t) = 0; + virtual size_t write(char const *src, size_t len, seek_off_t) = 0; + + /* + * Directory functionality + */ + virtual Node *lookup(char const *path, bool return_parent = false) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node"); + return nullptr; + } + + /* + * File functionality + */ + virtual void truncate(file_size_t size) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); + } +}; + #endif /* _NODE_H_ */ diff --git a/repos/os/src/server/trace_fs/symlink.h b/repos/os/src/server/trace_fs/symlink.h index 833d896ae..84088ac41 100644 --- a/repos/os/src/server/trace_fs/symlink.h +++ b/repos/os/src/server/trace_fs/symlink.h @@ -4,30 +4,38 @@ * \date 2012-04-11 */ +/* + * Copyright (C) 2012-2017 Genode Labs GmbH + * + * 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 _SYMLINK_H_ #define _SYMLINK_H_ /* local includes */ #include -namespace File_system { - - class Symlink : public File - { - public: - - Symlink(char const *name) : File(name) { } - - size_t read(char *dst, size_t len, seek_off_t seek_offset) { - return 0; } - - size_t write(char const *src, size_t len, seek_off_t seek_offset) { - return 0; } - - file_size_t length() const { return 0; } - - void truncate(file_size_t) { } - }; +namespace Trace_fs { + class Symlink; } +class Trace_fs::Symlink : public File +{ + public: + + Symlink(char const *name) : File(name) { } + + size_t read(char *dst, size_t len, seek_off_t seek_offset) { + return 0; } + + size_t write(char const *src, size_t len, seek_off_t seek_offset) { + return 0; } + + file_size_t length() const { return 0; } + + void truncate(file_size_t) { } +}; + #endif /* _SYMLINK_H_ */ diff --git a/repos/os/src/server/trace_fs/trace_files.h b/repos/os/src/server/trace_fs/trace_files.h index da1cbf143..43d4b122b 100644 --- a/repos/os/src/server/trace_fs/trace_files.h +++ b/repos/os/src/server/trace_fs/trace_files.h @@ -21,412 +21,418 @@ #include -namespace File_system { - - /** - * The State_file is a stateful file that is used to implement - * files in the file system, which may trigger a action in the - * file system backend. - */ - - class State_file : public File, - public Changeable_content - { - protected: - - bool _state; - - - public: - - State_file(char const *name) - : File(name), _state(false) { } - - bool state() const { return _state; } - - - /******************** - ** Node interface ** - ********************/ - - virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - /* limit len */ - if (len > 2) - len = 2; - - switch (len) { - case 2: - dst[1] = '\n'; - case 1: - dst[0] = 0x30 + (char)_state; - break; - default: - /* zero length is useless */ - break; - } - - return len; - } - - virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - char buf[32]; - if (len >= sizeof buf) - return 0; - - using namespace Genode; - - strncpy(buf, src, min(len + 1, sizeof (buf))); - - /** - * For now, we only check the leading digit and do not care - * about the rest. - */ - if (!strcmp(buf, "1", 1)) { - _state = true; - } - else if (!strcmp(buf, "0", 1)) { - _state = false; - } else { - /* silently ignore bogus writes */ - return 0; - } - - Changeable_content::_changed = true; - - return len; - } - - Status status() const - { - Status s; - - s.inode = inode(); - s.size = 2; - s.mode = File_system::Status::MODE_FILE; - - return s; - } - - /******************** - ** File interface ** - ********************/ - - file_size_t length() const { return 2; } - void truncate(file_size_t size) { } - }; - - - /** - * The Active_file node shows the state of the tracing - */ - - class Active_file : public State_file - { - private: - - Genode::Trace::Subject_id &_id; - bool _active; - - - public: - - Active_file(Genode::Trace::Subject_id &id) - : State_file("active"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - bool active() const { return State_file::state(); } - - void set_active() { _state = true; } - void set_inactive() { _state = false; } - }; - - - /** - * The Cleanup_file is used to trigger the removal of files used by - * the traced subject and to free utilized memory. - */ - - class Cleanup_file : public State_file - { - private: - - Genode::Trace::Subject_id &_id; - - - public: - - Cleanup_file(Genode::Trace::Subject_id &id) - : State_file("cleanup"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - bool cleanup() const { return State_file::state(); } - }; - - - /** - * The Enable_file is used to initiate the tracing process - */ - - class Enable_file : public State_file - { - private: - - Genode::Trace::Subject_id &_id; - - - public: - - Enable_file(Genode::Trace::Subject_id &id) - : State_file("enable"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - bool enabled() const { return State_file::state(); } - }; - - - /** - * The Events_file encapsulates the trace buffer of traced thread - */ - - class Events_file : public Buffered_file - { - private: - - Genode::Trace::Subject_id &_id; - - - public: - - Events_file(Genode::Trace::Subject_id &id, - Allocator &md_alloc) - : Buffered_file(md_alloc, "events"), _id(id) { } - - Genode::Trace::Subject_id id() const { return _id; } - - size_t append(char const *src, size_t len) - { - Buffered_file::write(src, len, length()); - - return len; - } - - /******************** - ** File interface ** - ********************/ - - /* override to prevent the user from overriding the file */ - size_t write(char const *src, size_t len, seek_off_t seek_offset) { return 0; } - void truncate(file_size_t size) { } - }; - - - /** - * This file contains the size of the trace buffer - */ - - class Buffer_size_file : public File, - public Changeable_content - { - private: - - file_size_t _length; - unsigned long _size_limit; - unsigned long _size; - - char _content[32]; - Genode::size_t _content_filled; - - /** - * Check if new size honors the size limit - * - * \param size new size of the buffer - * \return size limit if new size is greater, otherwise new size - */ - size_t _check_size_limit(size_t size) - { - if (size > _size_limit) - return _size_limit; - else - return size; - } - - /** - * Evalute the current content of the buffer - */ - void _refresh_content() - { - unsigned long tmp = 0; - - _content[_content_filled - 1] = '\0'; - _content_filled = 0; - - _length = Genode::strlen(_content); - - /* account for \n when reading from the file */ - _length += 1; - - ascii_to(_content, tmp); - - _size = _check_size_limit(tmp); - } - - - public: - - /** - * Constructor - */ - Buffer_size_file() : File("buffer_size"), _size_limit(0), _size(0) { } - - /** - * Return current size of the trace buffer - */ - unsigned long size() const { return _size; } - - /** - * Set current size of the trace buffer - */ - void size(unsigned long size) - { - _size = _check_size_limit(size); - - /* update file content */ - _length = Genode::snprintf(_content, sizeof (_content), "%lu", _size); - - /* account for \n when reading from the file */ - _length += 1; - } - - /** - * Set max size of a trace buffer - */ - void size_limit(unsigned long limit) { _size_limit = limit; } - - /** - * Return maximal size of the trace buffer - */ - unsigned long size_limit() const { return _size_limit; } - - - /******************** - ** Node interface ** - ********************/ - - /** - * Read current maximal size of the trace buffer - */ - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - if (len > 32) { - Genode::error("len:'", len, "' to small"); - return 0; - } - - char buf[32]; - Genode::snprintf(buf, sizeof (buf), "%lu\n", _size); - memcpy(dst, buf, len); - - return len; - } - - /** - * Write new current maximal size of the trace buffer - */ - size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - if ((_content_filled + len) > sizeof (_content)) - return 0; - - Genode::memcpy(_content + _content_filled, src, len); - _content_filled += len; - - Changeable_content::_changed = true; - - return len; - } - - Status status() const - { - Status s; - - s.inode = inode(); - s.size = _length; - s.mode = File_system::Status::MODE_FILE; - - return s; - } - - - /******************** - ** File interface ** - ********************/ - - file_size_t length() const { return _length; } - - void truncate(file_size_t size) { } - }; - - - /** - * Policy file - */ - - class Policy_file : public Buffered_file, - public Changeable_content - { - private: - - Genode::Trace::Subject_id &_id; - file_size_t _length; - - - public: - - Policy_file(Genode::Trace::Subject_id &id, - Genode::Allocator &md_alloc) - : Buffered_file(md_alloc, "policy"), _id(id) { } - - Genode::Trace::Subject_id& id() const { return _id; } - - - /******************** - ** Node interface ** - ********************/ - - size_t read(char *dst, size_t len, seek_off_t seek_offset) - { - return Buffered_file::read(dst, len, seek_offset); - } - - size_t write(char const *src, size_t len, seek_off_t seek_offset) - { - size_t written = Buffered_file::write(src, len, seek_offset); - - if (written > 0) - _changed = true; - - return written; - } - - - /******************** - ** File interface ** - ********************/ - - void truncate(file_size_t size) - { - Buffered_file::truncate(size); - - _changed = true; - } - - }; - +namespace Trace_fs { + class State_file; + class Active_file; + class Cleanup_file; + class Enable_file; + class Events_file; + class Buffer_size_file; + class Policy_file; } +/** + * The State_file is a stateful file that is used to implement + * files in the file system, which may trigger a action in the + * file system backend. + */ + +class Trace_fs::State_file : public File, + public Changeable_content +{ + protected: + + bool _state; + + + public: + + State_file(char const *name) + : File(name), _state(false) { } + + bool state() const { return _state; } + + + /******************** + ** Node interface ** + ********************/ + + virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) + { + /* limit len */ + if (len > 2) + len = 2; + + switch (len) { + case 2: + dst[1] = '\n'; + case 1: + dst[0] = 0x30 + (char)_state; + break; + default: + /* zero length is useless */ + break; + } + + return len; + } + + virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) + { + char buf[32]; + if (len >= sizeof buf) + return 0; + + using namespace Genode; + + strncpy(buf, src, min(len + 1, sizeof (buf))); + + /** + * For now, we only check the leading digit and do not care + * about the rest. + */ + if (!strcmp(buf, "1", 1)) { + _state = true; + } + else if (!strcmp(buf, "0", 1)) { + _state = false; + } else { + /* silently ignore bogus writes */ + return 0; + } + + Changeable_content::_changed = true; + + return len; + } + + Status status() const + { + Status s; + + s.inode = inode(); + s.size = 2; + s.mode = File_system::Status::MODE_FILE; + + return s; + } + + /******************** + ** File interface ** + ********************/ + + file_size_t length() const { return 2; } + void truncate(file_size_t size) { } +}; + + +/** + * The Active_file node shows the state of the tracing + */ + +class Trace_fs::Active_file : public State_file +{ + private: + + Genode::Trace::Subject_id &_id; + bool _active; + + + public: + + Active_file(Genode::Trace::Subject_id &id) + : State_file("active"), _id(id) { } + + Genode::Trace::Subject_id& id() const { return _id; } + + bool active() const { return State_file::state(); } + + void set_active() { _state = true; } + void set_inactive() { _state = false; } +}; + + +/** + * The Cleanup_file is used to trigger the removal of files used by + * the traced subject and to free utilized memory. + */ + +class Trace_fs::Cleanup_file : public State_file +{ + private: + + Genode::Trace::Subject_id &_id; + + + public: + + Cleanup_file(Genode::Trace::Subject_id &id) + : State_file("cleanup"), _id(id) { } + + Genode::Trace::Subject_id& id() const { return _id; } + + bool cleanup() const { return State_file::state(); } +}; + + +/** + * The Enable_file is used to initiate the tracing process + */ + +class Trace_fs::Enable_file : public State_file +{ + private: + + Genode::Trace::Subject_id &_id; + + + public: + + Enable_file(Genode::Trace::Subject_id &id) + : State_file("enable"), _id(id) { } + + Genode::Trace::Subject_id& id() const { return _id; } + + bool enabled() const { return State_file::state(); } +}; + + +/** + * The Events_file encapsulates the trace buffer of traced thread + */ + +class Trace_fs::Events_file : public Buffered_file +{ + private: + + Genode::Trace::Subject_id &_id; + + + public: + + Events_file(Genode::Trace::Subject_id &id, + Allocator &md_alloc) + : Buffered_file(md_alloc, "events"), _id(id) { } + + Genode::Trace::Subject_id id() const { return _id; } + + size_t append(char const *src, size_t len) + { + Buffered_file::write(src, len, length()); + + return len; + } + + /******************** + ** File interface ** + ********************/ + + /* override to prevent the user from overriding the file */ + size_t write(char const *src, size_t len, seek_off_t seek_offset) { return 0; } + void truncate(file_size_t size) { } +}; + + +/** + * This file contains the size of the trace buffer + */ + +class Trace_fs::Buffer_size_file : public File, + public Changeable_content +{ + private: + + file_size_t _length; + unsigned long _size_limit; + unsigned long _size; + + char _content[32]; + Genode::size_t _content_filled; + + /** + * Check if new size honors the size limit + * + * \param size new size of the buffer + * \return size limit if new size is greater, otherwise new size + */ + size_t _check_size_limit(size_t size) + { + if (size > _size_limit) + return _size_limit; + else + return size; + } + + /** + * Evalute the current content of the buffer + */ + void _refresh_content() + { + unsigned long tmp = 0; + + _content[_content_filled - 1] = '\0'; + _content_filled = 0; + + _length = Genode::strlen(_content); + + /* account for \n when reading from the file */ + _length += 1; + + ascii_to(_content, tmp); + + _size = _check_size_limit(tmp); + } + + + public: + + /** + * Constructor + */ + Buffer_size_file() : File("buffer_size"), _size_limit(0), _size(0) { } + + /** + * Return current size of the trace buffer + */ + unsigned long size() const { return _size; } + + /** + * Set current size of the trace buffer + */ + void size(unsigned long size) + { + _size = _check_size_limit(size); + + /* update file content */ + _length = Genode::snprintf(_content, sizeof (_content), "%lu", _size); + + /* account for \n when reading from the file */ + _length += 1; + } + + /** + * Set max size of a trace buffer + */ + void size_limit(unsigned long limit) { _size_limit = limit; } + + /** + * Return maximal size of the trace buffer + */ + unsigned long size_limit() const { return _size_limit; } + + + /******************** + ** Node interface ** + ********************/ + + /** + * Read current maximal size of the trace buffer + */ + size_t read(char *dst, size_t len, seek_off_t seek_offset) + { + if (len > 32) { + Genode::error("len:'", len, "' to small"); + return 0; + } + + char buf[32]; + Genode::snprintf(buf, sizeof (buf), "%lu\n", _size); + memcpy(dst, buf, len); + + return len; + } + + /** + * Write new current maximal size of the trace buffer + */ + size_t write(char const *src, size_t len, seek_off_t seek_offset) + { + if ((_content_filled + len) > sizeof (_content)) + return 0; + + Genode::memcpy(_content + _content_filled, src, len); + _content_filled += len; + + Changeable_content::_changed = true; + + return len; + } + + Status status() const + { + Status s; + + s.inode = inode(); + s.size = _length; + s.mode = File_system::Status::MODE_FILE; + + return s; + } + + + /******************** + ** File interface ** + ********************/ + + file_size_t length() const { return _length; } + + void truncate(file_size_t size) { } +}; + + +/** + * Policy file + */ + +class Trace_fs::Policy_file : public Buffered_file, + public Changeable_content +{ + private: + + Genode::Trace::Subject_id &_id; + file_size_t _length; + + + public: + + Policy_file(Genode::Trace::Subject_id &id, + Genode::Allocator &md_alloc) + : Buffered_file(md_alloc, "policy"), _id(id) { } + + Genode::Trace::Subject_id& id() const { return _id; } + + + /******************** + ** Node interface ** + ********************/ + + size_t read(char *dst, size_t len, seek_off_t seek_offset) + { + return Buffered_file::read(dst, len, seek_offset); + } + + size_t write(char const *src, size_t len, seek_off_t seek_offset) + { + size_t written = Buffered_file::write(src, len, seek_offset); + + if (written > 0) + _changed = true; + + return written; + } + + + /******************** + ** File interface ** + ********************/ + + void truncate(file_size_t size) + { + Buffered_file::truncate(size); + + _changed = true; + } + +}; + #endif /* _TRACE_FILES_H_ */ diff --git a/repos/os/src/server/vfs/main.cc b/repos/os/src/server/vfs/main.cc index 08dbdf07b..6726daffa 100644 --- a/repos/os/src/server/vfs/main.cc +++ b/repos/os/src/server/vfs/main.cc @@ -94,16 +94,17 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object, * \throw Invalid_handle */ template - void _apply(HANDLE_TYPE handle, FUNC const &fn) + auto _apply(HANDLE_TYPE handle, FUNC const &fn) + -> typename Genode::Trait::Functor::Return_type { Node_space::Id id { handle.value }; - try { _node_space.apply(id, [&] (Node &node) { + try { return _node_space.apply(id, [&] (Node &node) { typedef typename Node_type::Type Typed_node; Typed_node *n = dynamic_cast(&node); if (!n) throw Invalid_handle(); - fn(*n); + return fn(*n); }); } catch (Node_space::Unknown_id) { throw Invalid_handle(); } } @@ -385,7 +386,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object, if (file.notify_read_ready() && file.read_ready() && tx_sink()->ready_to_ack()) { Packet_descriptor packet(Packet_descriptor(), - Node_handle(file.id().value), + Node_handle { file.id().value }, Packet_descriptor::READ_READY, 0, 0); tx_sink()->acknowledge_packet(packet); @@ -431,33 +432,29 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object, if ((create || (fs_mode & WRITE_ONLY)) && (!_writable)) throw Permission_denied(); - File_handle new_handle; - - _apply(dir_handle, [&] (Directory &dir) { + return _apply(dir_handle, [&] (Directory &dir) { char const *name_str = name.string(); _assert_valid_name(name_str); - new_handle = dir.file( - _node_space, _vfs, _alloc, *this, name_str, fs_mode, create).value; + return File_handle { + dir.file(_node_space, _vfs, _alloc, *this, name_str, fs_mode, create).value + }; }); - return new_handle; } Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) override { if (create && !_writable) throw Permission_denied(); - Symlink_handle new_handle; - - _apply(dir_handle, [&] (Directory &dir) { + return _apply(dir_handle, [&] (Directory &dir) { char const *name_str = name.string(); _assert_valid_name(name_str); - new_handle = dir.symlink( + return Symlink_handle {dir.symlink( _node_space, _vfs, _alloc, name_str, - _writable ? READ_WRITE : READ_ONLY, create).value; + _writable ? READ_WRITE : READ_ONLY, create).value + }; }); - return new_handle; } Node_handle node(File_system::Path const &path) override @@ -465,7 +462,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object, char const *path_str = path.string(); /* '/' is bound to '0' */ if (!strcmp(path_str, "/")) - return Node_handle(0); + return Node_handle { 0 }; _assert_valid_path(path_str); @@ -480,7 +477,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object, try { node = new (_alloc) Node(_node_space, path_str, STAT_ONLY); } catch (Out_of_memory) { throw Out_of_ram(); } - return Node_handle(node->id().value); + return Node_handle { node->id().value }; } void close(Node_handle handle) override