From 5ab1505d43fe419ff4b59687a695b10018fa7725 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 25 Sep 2019 17:13:29 +0200 Subject: [PATCH] file system: enhanced file status info This patch extends the 'File_system::Status', 'File_system::Directory_entry', and the related 'Vfs' types with the following additional information: - Distinction between continuous and transactional files (Node_type) (issue #3507) - Readable, writeable, and executable attributes (Node_rwx), replacing the former 'mode' bits (issue #3030) The types 'Node_rwx', 'Node_type' are defined twice, once for the VFS (vfs/types.h) and once for the 'File_system' session (file_system_session/file_system_session.h). Similarly, there is a direct correspondance between 'Vfs::Directory_service::Dirent' and 'File_system::Directory_entry'. This duplication of types follows the existing pattern of keeping the VFS and file-system session independent from each other. --- repos/dde_linux/src/lib/vfs/lxip/vfs.cc | 137 +++++++++-------- repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc | 60 +++++--- repos/dde_rump/src/server/rump_fs/directory.h | 46 +++--- repos/dde_rump/src/server/rump_fs/file.h | 19 +-- repos/dde_rump/src/server/rump_fs/symlink.h | 16 +- repos/gems/include/gems/vfs.h | 56 ++++--- repos/gems/src/app/fs_query/main.cc | 6 +- repos/gems/src/lib/vfs/import/plugin.cc | 19 +-- .../src/lib/vfs/trace/value_file_system.h | 5 +- repos/gems/src/lib/vfs/trace/vfs.cc | 4 +- .../gems/src/lib/vfs/ttf/glyphs_file_system.h | 4 +- repos/libports/src/lib/libc/vfs_plugin.cc | 78 +++++++--- repos/libports/src/lib/vfs/fatfs/vfs_fatfs.cc | 40 +++-- .../lib/vfs/jitterentropy/vfs_jitterentropy.h | 3 +- repos/libports/src/lib/vfs/lwip/vfs.cc | 56 +++++-- .../libports/src/server/fatfs_fs/directory.h | 19 ++- repos/libports/src/server/fatfs_fs/main.cc | 17 ++- .../file_system_session/file_system_session.h | 54 +++++-- repos/os/include/vfs/dir_file_system.h | 43 ++++-- repos/os/include/vfs/directory_service.h | 69 +++++---- .../include/vfs/readonly_value_file_system.h | 5 +- repos/os/include/vfs/single_file_system.h | 79 +++++----- repos/os/include/vfs/types.h | 30 ++++ .../cli_monitor/subsystem_config_registry.h | 12 +- repos/os/src/lib/vfs/block_file_system.h | 3 +- repos/os/src/lib/vfs/fs_file_system.h | 102 ++++++++----- repos/os/src/lib/vfs/inline_file_system.h | 8 +- repos/os/src/lib/vfs/log_file_system.h | 3 +- repos/os/src/lib/vfs/null_file_system.h | 3 +- repos/os/src/lib/vfs/ram_file_system.h | 103 +++++++------ repos/os/src/lib/vfs/rom_file_system.h | 9 +- repos/os/src/lib/vfs/rtc_file_system.h | 8 +- repos/os/src/lib/vfs/symlink_file_system.h | 3 +- repos/os/src/lib/vfs/tar_file_system.h | 144 +++++++++++------- repos/os/src/lib/vfs/terminal_file_system.h | 3 +- repos/os/src/lib/vfs/zero_file_system.h | 3 +- repos/os/src/server/lx_fs/directory.h | 50 +++--- repos/os/src/server/lx_fs/file.h | 17 ++- repos/os/src/server/ram_fs/directory.h | 37 +++-- repos/os/src/server/ram_fs/file.h | 15 +- repos/os/src/server/ram_fs/symlink.h | 15 +- repos/os/src/server/vfs/main.cc | 55 ++++--- repos/os/src/server/vfs/node.h | 75 +++++---- repos/os/src/test/vfs_stress/main.cc | 8 +- repos/ports/include/noux_session/sysio.h | 42 +---- repos/ports/ports/gdb.hash | 2 +- repos/ports/src/lib/libc_noux/plugin.cc | 86 +++++++---- .../gdb/patches/gdbserver_genode.patch | 18 ++- repos/ports/src/noux/pipe_io_channel.h | 4 +- repos/ports/src/noux/syscall.cc | 3 - repos/ports/src/noux/terminal_io_channel.h | 7 +- repos/ports/src/noux/vfs_io_channel.h | 14 +- 52 files changed, 1049 insertions(+), 668 deletions(-) diff --git a/repos/dde_linux/src/lib/vfs/lxip/vfs.cc b/repos/dde_linux/src/lib/vfs/lxip/vfs.cc index 433bb2e27..e32c8ca23 100644 --- a/repos/dde_linux/src/lib/vfs/lxip/vfs.cc +++ b/repos/dde_linux/src/lib/vfs/lxip/vfs.cc @@ -1107,11 +1107,7 @@ class Vfs::Lxip_socket_dir final : public Lxip::Socket_dir Vfs::file_size index = seek_offset / sizeof(Dirent); - Dirent *out = (Dirent*)dst; - - out->fileno = index+1; - out->type = Directory_service::DIRENT_TYPE_END; - out->name[0] = '\0'; + Dirent &out = *(Dirent*)dst; Vfs::Node *node = nullptr; for (Vfs::File *n : _files) { @@ -1123,11 +1119,21 @@ class Vfs::Lxip_socket_dir final : public Lxip::Socket_dir --index; } } - if (!node) return -1; + if (!node) { + out = { + .fileno = index + 1, + .type = Directory_service::Dirent_type::END, + .rwx = { }, + .name = { } }; - out->type = Directory_service::DIRENT_TYPE_FILE; + return -1; + } - strncpy(out->name, node->name(), sizeof(out->name)); + out = { + .fileno = index + 1, + .type = Directory_service::Dirent_type::TRANSACTIONAL_FILE, + .rwx = Node_rwx::rw(), + .name = { node->name() } }; return sizeof(Dirent); } @@ -1435,11 +1441,7 @@ class Lxip::Protocol_dir_impl : public Protocol_dir Vfs::file_size index = seek_offset / sizeof(Dirent); - Dirent *out = (Dirent*)dst; - - out->fileno = index+1; - out->type = Vfs::Directory_service::DIRENT_TYPE_END; - out->name[0] = '\0'; + Dirent &out = *(Dirent*)dst; Vfs::Node *node = nullptr; for (Vfs::Node *n : _nodes) { @@ -1451,15 +1453,32 @@ class Lxip::Protocol_dir_impl : public Protocol_dir --index; } } - if (!node) return -1; + if (!node) { + out = { + .fileno = index + 1, + .type = Vfs::Directory_service::Dirent_type::END, + .rwx = { }, + .name = { } }; - if (dynamic_cast(node)) - out->type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY; + return -1; + } - if (dynamic_cast(node)) - out->type = Vfs::Directory_service::DIRENT_TYPE_FILE; + typedef Vfs::Directory_service::Dirent_type Dirent_type; - Genode::strncpy(out->name, node->name(), sizeof(out->name)); + Dirent_type const type = + dynamic_cast(node) ? Dirent_type::DIRECTORY : + dynamic_cast(node) ? Dirent_type::TRANSACTIONAL_FILE + : Dirent_type::END; + + Vfs::Node_rwx const rwx = (type == Dirent_type::DIRECTORY) + ? Vfs::Node_rwx::rwx() + : Vfs::Node_rwx::rw(); + + out = { + .fileno = index + 1, + .type = type, + .rwx = rwx, + .name = { node->name() } }; return sizeof(Dirent); } @@ -1692,44 +1711,38 @@ class Vfs::Lxip_file_system : public Vfs::File_system, if (len < sizeof(Dirent)) return -1; - file_size index = seek_offset / sizeof(Dirent); + file_size const index = seek_offset / sizeof(Dirent); - Dirent *out = (Dirent*)dst; + struct Entry + { + void const *fileno; + Dirent_type type; + char const *name; + }; - if (index == 0) { - out->fileno = (Genode::addr_t)&_tcp_dir; - out->type = Directory_service::DIRENT_TYPE_DIRECTORY; - Genode::strncpy(out->name, "tcp", sizeof(out->name)); - } else if (index == 1) { - out->fileno = (Genode::addr_t)&_udp_dir; - out->type = Directory_service::DIRENT_TYPE_DIRECTORY; - Genode::strncpy(out->name, "udp", sizeof(out->name)); - } else if (index == 2) { - out->fileno = (Genode::addr_t)&_address; - out->type = Directory_service::DIRENT_TYPE_FILE; - Genode::strncpy(out->name, "address", sizeof(out->name)); - } else if (index == 3) { - out->fileno = (Genode::addr_t)&_netmask; - out->type = Directory_service::DIRENT_TYPE_FILE; - Genode::strncpy(out->name, "netmask", sizeof(out->name)); - } else if (index == 4) { - out->fileno = (Genode::addr_t)&_gateway; - out->type = Directory_service::DIRENT_TYPE_FILE; - Genode::strncpy(out->name, "gateway", sizeof(out->name)); - } else if (index == 5) { - out->fileno = (Genode::addr_t)&_nameserver; - out->type = Directory_service::DIRENT_TYPE_FILE; - Genode::strncpy(out->name, "nameserver", sizeof(out->name)); - } else if (index == 6) { - out->fileno = (Genode::addr_t)&_link_state; - out->type = Directory_service::DIRENT_TYPE_FILE; - Genode::strncpy(out->name, "link_state", sizeof(out->name)); - } else { - out->fileno = 0; - out->type = Directory_service::DIRENT_TYPE_END; - out->name[0] = '\0'; - } + enum { NUM_ENTRIES = 8U }; + static Entry const entries[NUM_ENTRIES] = { + { &_tcp_dir, Dirent_type::DIRECTORY, "tcp" }, + { &_udp_dir, Dirent_type::DIRECTORY, "udp" }, + { &_address, Dirent_type::TRANSACTIONAL_FILE, "address" }, + { &_netmask, Dirent_type::TRANSACTIONAL_FILE, "netmask" }, + { &_gateway, Dirent_type::TRANSACTIONAL_FILE, "gateway" }, + { &_nameserver, Dirent_type::TRANSACTIONAL_FILE, "nameserver" }, + { &_link_state, Dirent_type::TRANSACTIONAL_FILE, "link_state" }, + { nullptr, Dirent_type::END, "" } + }; + Entry const &entry = entries[min(index, NUM_ENTRIES - 1U)]; + + Dirent &out = *(Dirent*)dst; + + out = { + .fileno = (Genode::addr_t)entry.fileno, + .type = entry.type, + .rwx = entry.type == Dirent_type::DIRECTORY + ? Node_rwx::rwx() : Node_rwx::rw(), + .name = { entry.name } + }; return sizeof(Dirent); } @@ -1746,23 +1759,27 @@ class Vfs::Lxip_file_system : public Vfs::File_system, Stat_result stat(char const *path, Stat &out) override { - Vfs::Node *node = _lookup(path); + Node *node = _lookup(path); if (!node) return STAT_ERR_NO_ENTRY; - Vfs::Directory *dir = dynamic_cast(node); - if (dir) { - out.mode = STAT_MODE_DIRECTORY | 0777; + out = { }; + + if (dynamic_cast(node)) { + out.type = Node_type::DIRECTORY; + out.rwx = Node_rwx::rwx(); return STAT_OK; } if (dynamic_cast(node)) { - out.mode = STAT_MODE_FILE | 0666; + out.type = Node_type::TRANSACTIONAL_FILE; + out.rwx = Node_rwx::rw(); out.size = 0; return STAT_OK; } if (dynamic_cast(node)) { - out.mode = STAT_MODE_FILE | 0666; + out.type = Node_type::TRANSACTIONAL_FILE; + out.rwx = Node_rwx::rw(); out.size = 0x1000; /* there may be something to read */ return STAT_OK; } diff --git a/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc b/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc index d18b529c9..33c30c53e 100644 --- a/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc +++ b/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc @@ -197,25 +197,28 @@ class Vfs::Rump_file_system : public File_system struct stat s; rump_sys_lstat(path, &s); - vfs_dir.fileno = s.st_ino; + auto dirent_type = [] (unsigned mode) + { + if (S_ISREG (mode)) return Dirent_type::CONTINUOUS_FILE; + if (S_ISDIR (mode)) return Dirent_type::DIRECTORY; + if (S_ISLNK (mode)) return Dirent_type::SYMLINK; + if (S_ISBLK (mode)) return Dirent_type::CONTINUOUS_FILE; + if (S_ISCHR (mode)) return Dirent_type::CONTINUOUS_FILE; + if (S_ISFIFO(mode)) return Dirent_type::CONTINUOUS_FILE; - if (S_ISREG(s.st_mode)) - vfs_dir.type = Dirent_type::DIRENT_TYPE_FILE; - else if (S_ISDIR(s.st_mode)) - vfs_dir.type = Dirent_type::DIRENT_TYPE_DIRECTORY; - else if (S_ISLNK(s.st_mode)) - vfs_dir.type = Dirent_type::DIRENT_TYPE_SYMLINK; - else if (S_ISBLK(s.st_mode)) - vfs_dir.type = Dirent_type::DIRENT_TYPE_BLOCKDEV; - else if (S_ISCHR(s.st_mode)) - vfs_dir.type = Dirent_type::DIRENT_TYPE_CHARDEV; - else if (S_ISFIFO(s.st_mode)) - vfs_dir.type = Dirent_type::DIRENT_TYPE_FIFO; - else - vfs_dir.type = Dirent_type::DIRENT_TYPE_FILE; + return Dirent_type::END; + }; - strncpy(vfs_dir.name, dent->d_name, sizeof(Dirent::name)); + Node_rwx const rwx { .readable = (s.st_mode & S_IRUSR), + .writeable = (s.st_mode & S_IWUSR), + .executable = (s.st_mode & S_IXUSR) }; + vfs_dir = { + .fileno = s.st_ino, + .type = dirent_type(s.st_mode), + .rwx = rwx, + .name = { dent->d_name } + }; return READ_OK; } @@ -699,12 +702,25 @@ class Vfs::Rump_file_system : public File_system struct stat sb; if (rump_sys_lstat(path, &sb) != 0) return STAT_ERR_NO_ENTRY; - stat.size = sb.st_size; - stat.mode = sb.st_mode; - stat.uid = sb.st_uid; - stat.gid = sb.st_gid; - stat.inode = sb.st_ino; - stat.device = sb.st_dev; + auto type = [] (unsigned mode) + { + if (S_ISDIR(mode)) return Node_type::DIRECTORY; + if (S_ISLNK(mode)) return Node_type::SYMLINK; + + return Node_type::CONTINUOUS_FILE; + }; + + stat = { + .size = (file_size)sb.st_size, + .type = type(sb.st_mode), + .rwx = { .readable = (sb.st_mode & S_IRUSR), + .writeable = (sb.st_mode & S_IWUSR), + .executable = (sb.st_mode & S_IXUSR) }, + .inode = sb.st_ino, + .device = sb.st_dev, + + .modification_time = { 0 } + }; return STAT_OK; } diff --git a/repos/dde_rump/src/server/rump_fs/directory.h b/repos/dde_rump/src/server/rump_fs/directory.h index 185717386..d426bb927 100644 --- a/repos/dde_rump/src/server/rump_fs/directory.h +++ b/repos/dde_rump/src/server/rump_fs/directory.h @@ -218,18 +218,26 @@ class Rump_fs::Directory : public Node struct stat s; rump_sys_lstat(path, &s); - Directory_entry *e = (Directory_entry *)(dst); - if (S_ISDIR(s.st_mode)) - e->type = Directory_entry::TYPE_DIRECTORY; - else if (S_ISREG(s.st_mode)) - e->type = Directory_entry::TYPE_FILE; - else if (S_ISLNK(s.st_mode)) - e->type = Directory_entry::TYPE_SYMLINK; - else - return 0; + auto type = [] (unsigned mode) + { + if (S_ISDIR(mode)) return Node_type::DIRECTORY; + else if (S_ISREG(mode)) return Node_type::CONTINUOUS_FILE; + else if (S_ISLNK(mode)) return Node_type::SYMLINK; + else return Node_type::CONTINUOUS_FILE; + }; + + Node_rwx const rwx { .readable = (s.st_mode & S_IRUSR), + .writeable = (s.st_mode & S_IWUSR), + .executable = (s.st_mode & S_IXUSR) }; + + Directory_entry &e = *(Directory_entry *)(dst); + e = { + .inode = s.st_ino, + .type = type(s.st_mode), + .rwx = rwx, + .name = { dent->d_name } + }; - e->inode = s.st_ino; - strncpy(e->name, dent->d_name, dent->d_namlen + 1); return sizeof(Directory_entry); } @@ -245,13 +253,15 @@ class Rump_fs::Directory : public Node if (rump_sys_fstat(_fd, &st) < 0) st.st_mtime = 0; - Status s; - s.inode = inode(); - s.size = num_entries() * sizeof (Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; - s.modification_time = { (int64_t)st.st_mtime }; - - return s; + return { + .size = num_entries() * sizeof (Directory_entry), + .type = File_system::Node_type::DIRECTORY, + .rwx = { .readable = (st.st_mode & S_IRUSR), + .writeable = (st.st_mode & S_IWUSR), + .executable = (st.st_mode & S_IXUSR) }, + .inode = inode(), + .modification_time = { (int64_t)st.st_mtime } + }; } size_t num_entries() const diff --git a/repos/dde_rump/src/server/rump_fs/file.h b/repos/dde_rump/src/server/rump_fs/file.h index b935e2750..409438ec9 100644 --- a/repos/dde_rump/src/server/rump_fs/file.h +++ b/repos/dde_rump/src/server/rump_fs/file.h @@ -153,20 +153,21 @@ class Rump_fs::File : public Node virtual Status status() override { - struct stat st; + struct stat st { }; if (rump_sys_fstat(_fd, &st) < 0) { st.st_size = 0; st.st_mtime = 0; } - Status s; - - s.inode = inode(); - s.size = st.st_size; - s.mode = File_system::Status::MODE_FILE; - s.modification_time = { (int64_t)st.st_mtime }; - - return s; + return { + .size = (file_size_t)st.st_size, + .type = File_system::Node_type::CONTINUOUS_FILE, + .rwx = { .readable = (st.st_mode & S_IRUSR), + .writeable = (st.st_mode & S_IWUSR), + .executable = (st.st_mode & S_IXUSR) }, + .inode = inode(), + .modification_time = { (int64_t)st.st_mtime } + }; } void truncate(file_size_t size) override diff --git a/repos/dde_rump/src/server/rump_fs/symlink.h b/repos/dde_rump/src/server/rump_fs/symlink.h index 3b500aa2e..bd0c0cf71 100644 --- a/repos/dde_rump/src/server/rump_fs/symlink.h +++ b/repos/dde_rump/src/server/rump_fs/symlink.h @@ -78,13 +78,15 @@ class Rump_fs::Symlink : public Node st.st_mtime = 0; } - Status s; - s.inode = inode(); - s.size = length(); - s.mode = File_system::Status::MODE_SYMLINK; - s.modification_time = { (int64_t)st.st_mtime }; - - return s; + return { + .size = length(), + .type = File_system::Node_type::SYMLINK, + .rwx = { .readable = true, + .writeable = true, + .executable = true }, + .inode = inode(), + .modification_time = { (int64_t)st.st_mtime } + }; } file_size_t length() diff --git a/repos/gems/include/gems/vfs.h b/repos/gems/include/gems/vfs.h index 49823cba9..952c98aa4 100644 --- a/repos/gems/include/gems/vfs.h +++ b/repos/gems/include/gems/vfs.h @@ -56,20 +56,22 @@ struct Genode::Directory : Noncopyable, Interface { using Genode::print; using Vfs::Directory_service; + using Dirent_type = Directory_service::Dirent_type; - print(out, _dirent.name, " ("); + print(out, _dirent.name.buf, " ("); switch (_dirent.type) { - case Directory_service::DIRENT_TYPE_FILE: print(out, "file"); break; - case Directory_service::DIRENT_TYPE_DIRECTORY: print(out, "dir"); break; - case Directory_service::DIRENT_TYPE_SYMLINK: print(out, "symlink"); break; - default: print(out, "other"); break; + case Dirent_type::TRANSACTIONAL_FILE: print(out, "file"); break; + case Dirent_type::CONTINUOUS_FILE: print(out, "file"); break; + case Dirent_type::DIRECTORY: print(out, "dir"); break; + case Dirent_type::SYMLINK: print(out, "symlink"); break; + default: print(out, "other"); break; } print(out, ")"); } - typedef String Name; + typedef String Name; - Name name() const { return Name(Cstring(_dirent.name)); } + Name name() const { return Name(Cstring(_dirent.name.buf)); } Vfs::Directory_service::Dirent_type type() const { return _dirent.type; } }; @@ -118,16 +120,10 @@ struct Genode::Directory : Noncopyable, Interface return const_cast(_fs); } - Vfs::Directory_service::Stat _stat(Path const &rel_path) const + Vfs::Directory_service::Stat_result _stat(Path const &rel_path, + Vfs::Directory_service::Stat &out) const { - Vfs::Directory_service::Stat stat; - - /* - * Ignore return value as the validity of the result is can be - * checked by the caller via 'stat.mode != 0'. - */ - _nonconst_fs().stat(join(_path, rel_path).string(), stat); - return stat; + return _nonconst_fs().stat(join(_path, rel_path).string(), out); } public: @@ -199,7 +195,7 @@ struct Genode::Directory : Noncopyable, Interface throw Read_dir_failed(); } - if (entry._dirent.type == Vfs::Directory_service::DIRENT_TYPE_END) + if (entry._dirent.type == Vfs::Directory_service::Dirent_type::END) return; fn(entry); @@ -215,12 +211,23 @@ struct Genode::Directory : Noncopyable, Interface bool file_exists(Path const &rel_path) const { - return _stat(rel_path).mode & Vfs::Directory_service::STAT_MODE_FILE; + Vfs::Directory_service::Stat stat { }; + + if (_stat(rel_path, stat) != Vfs::Directory_service::STAT_OK) + return false; + + return stat.type == Vfs::Node_type::TRANSACTIONAL_FILE + || stat.type == Vfs::Node_type::CONTINUOUS_FILE; } bool directory_exists(Path const &rel_path) const { - return _stat(rel_path).mode & Vfs::Directory_service::STAT_MODE_DIRECTORY; + Vfs::Directory_service::Stat stat { }; + + if (_stat(rel_path, stat) != Vfs::Directory_service::STAT_OK) + return false; + + return stat.type == Vfs::Node_type::DIRECTORY; } /** @@ -232,11 +239,16 @@ struct Genode::Directory : Noncopyable, Interface */ Vfs::file_size file_size(Path const &rel_path) const { - Vfs::Directory_service::Stat stat = _stat(rel_path); + Vfs::Directory_service::Stat stat { }; - if (!(stat.mode & Vfs::Directory_service::STAT_MODE_FILE)) + if (_stat(rel_path, stat) != Vfs::Directory_service::STAT_OK) throw Nonexistent_file(); - return stat.size; + + if (stat.type == Vfs::Node_type::TRANSACTIONAL_FILE + || stat.type == Vfs::Node_type::CONTINUOUS_FILE) + return stat.size; + + throw Nonexistent_file(); } /** diff --git a/repos/gems/src/app/fs_query/main.cc b/repos/gems/src/app/fs_query/main.cc index 859105110..1ad222bf9 100644 --- a/repos/gems/src/app/fs_query/main.cc +++ b/repos/gems/src/app/fs_query/main.cc @@ -104,7 +104,11 @@ struct Fs_query::Watched_directory _dir(other, rel_path), _watcher(other, rel_path, handler) { _dir.for_each_entry([&] (Directory::Entry const &entry) { - if (entry.type() == Vfs::Directory_service::DIRENT_TYPE_FILE) { + + using Dirent_type = Vfs::Directory_service::Dirent_type; + bool const file = (entry.type() == Dirent_type::CONTINUOUS_FILE) + || (entry.type() == Dirent_type::TRANSACTIONAL_FILE); + if (file) { try { new (_alloc) Registered(_files, _dir, entry.name(), handler); } catch (...) { } diff --git a/repos/gems/src/lib/vfs/import/plugin.cc b/repos/gems/src/lib/vfs/import/plugin.cc index a2218090a..e2acb94e9 100644 --- a/repos/gems/src/lib/vfs/import/plugin.cc +++ b/repos/gems/src/lib/vfs/import/plugin.cc @@ -189,19 +189,20 @@ class Vfs_import::File_system : public Vfs::File_system dir.for_each_entry([&] (Directory::Entry const &e) { auto entry_path = Directory::join(path, e.name()); switch (e.type()) { - case DIRENT_TYPE_FILE: + case Dirent_type::TRANSACTIONAL_FILE: + case Dirent_type::CONTINUOUS_FILE: copy_file(env, src, entry_path, alloc, overwrite); - break; - case DIRENT_TYPE_DIRECTORY: + return; + case Dirent_type::DIRECTORY: copy_dir(env, src, entry_path, alloc, overwrite); - break; - case DIRENT_TYPE_SYMLINK: + return; + case Dirent_type::SYMLINK: copy_symlink(env, src, entry_path, alloc, overwrite); - break; - default: - Genode::warning("skipping copy of ", e); - break; + return; + case Dirent_type::END: + return; } + Genode::warning("skipping copy of ", e); }); } } diff --git a/repos/gems/src/lib/vfs/trace/value_file_system.h b/repos/gems/src/lib/vfs/trace/value_file_system.h index 6c62c48c4..f498fde05 100644 --- a/repos/gems/src/lib/vfs/trace/value_file_system.h +++ b/repos/gems/src/lib/vfs/trace/value_file_system.h @@ -128,8 +128,8 @@ class Vfs::Value_file_system : public Vfs::Single_file_system Value_file_system(Name const &name, Buffer const &initial_value) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, type(), - Xml_node(_config(name).string())), + Single_file_system(Node_type::TRANSACTIONAL_FILE, type(), + Node_rwx::rw(), Xml_node(_config(name).string())), _file_name(name) { value(initial_value); @@ -196,7 +196,6 @@ class Vfs::Value_file_system : public Vfs::Single_file_system Stat_result stat(char const *path, Stat &out) override { Stat_result result = Single_file_system::stat(path, out); - out.mode |= 0666; out.size = BUF_SIZE + 1; return result; } diff --git a/repos/gems/src/lib/vfs/trace/vfs.cc b/repos/gems/src/lib/vfs/trace/vfs.cc index aa19e90e9..7629049c6 100644 --- a/repos/gems/src/lib/vfs/trace/vfs.cc +++ b/repos/gems/src/lib/vfs/trace/vfs.cc @@ -155,8 +155,8 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system Trace::Connection &trace, Trace::Policy_id policy, Trace::Subject_id id) - : Single_file_system(NODE_TYPE_CHAR_DEVICE, - type_name(), Xml_node(_config().string())), + : Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(), + Node_rwx::rw(), Xml_node(_config().string())), _env(env), _trace(trace), _policy(policy), _id(id) { } diff --git a/repos/gems/src/lib/vfs/ttf/glyphs_file_system.h b/repos/gems/src/lib/vfs/ttf/glyphs_file_system.h index a6e99ac39..7e0ace54f 100644 --- a/repos/gems/src/lib/vfs/ttf/glyphs_file_system.h +++ b/repos/gems/src/lib/vfs/ttf/glyphs_file_system.h @@ -113,7 +113,8 @@ class Vfs::Glyphs_file_system : public Vfs::Single_file_system Glyphs_file_system(Font const &font) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, type(), Xml_node("")), + Single_file_system(Node_type::TRANSACTIONAL_FILE, type(), + Node_rwx::ro(), Xml_node("")), _font(font) { } @@ -145,7 +146,6 @@ class Vfs::Glyphs_file_system : public Vfs::Single_file_system Stat_result stat(char const *path, Stat &out) override { Stat_result result = Single_file_system::stat(path, out); - out.mode |= 0444; out.size = FILE_SIZE; return result; } diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index 00a9fb75b..3e5e8e5c7 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -98,11 +98,29 @@ static void vfs_stat_to_libc_stat_struct(Vfs::Directory_service::Stat const &src { enum { FS_BLOCK_SIZE = 4096 }; - Genode::memset(dst, 0, sizeof(*dst)); + unsigned const readable_bits = S_IRUSR, + writeable_bits = S_IWUSR, + executable_bits = S_IXUSR; - dst->st_uid = src.uid; - dst->st_gid = src.gid; - dst->st_mode = src.mode; + auto type = [] (Vfs::Node_type type) + { + switch (type) { + case Vfs::Node_type::DIRECTORY: return S_IFDIR; + case Vfs::Node_type::CONTINUOUS_FILE: return S_IFREG; + case Vfs::Node_type::TRANSACTIONAL_FILE: return S_IFSOCK; + case Vfs::Node_type::SYMLINK: return S_IFLNK; + } + return 0; + }; + + *dst = { }; + + dst->st_uid = 0; + dst->st_gid = 0; + dst->st_mode = (src.rwx.readable ? readable_bits : 0) + | (src.rwx.writeable ? writeable_bits : 0) + | (src.rwx.executable ? executable_bits : 0) + | type(src.type); dst->st_size = src.size; dst->st_blksize = FS_BLOCK_SIZE; dst->st_blocks = (dst->st_size + FS_BLOCK_SIZE - 1) / FS_BLOCK_SIZE; @@ -525,7 +543,18 @@ int Libc::Vfs_plugin::fstat(File_descriptor *fd, struct stat *buf) _vfs_sync(*handle); fd->modified = false; } - return stat(fd->fd_path, buf); + + int const result = stat(fd->fd_path, buf); + + /* + * The libc expects stdout to be a character device. + * If 'st_mode' is set to 'S_IFREG', 'printf' does not work. + */ + if (fd->libc_fd == 1) { + buf->st_mode &= ~S_IFMT; + buf->st_mode |= S_IFCHR; + } + return result; } @@ -830,6 +859,7 @@ ssize_t Libc::Vfs_plugin::getdirentries(File_descriptor *fd, char *buf, (char*)&dirent_out, sizeof(Dirent), out_count)); + dirent_out.sanitize(); /* suspend me if read is still queued */ @@ -851,29 +881,37 @@ ssize_t Libc::Vfs_plugin::getdirentries(File_descriptor *fd, char *buf, return 0; } + using Dirent_type = Vfs::Directory_service::Dirent_type; + + if (dirent_out.type == Dirent_type::END) + return 0; + /* * Convert dirent structure from VFS to libc */ - struct dirent *dirent = (struct dirent *)buf; - Genode::memset(dirent, 0, sizeof(struct dirent)); + auto dirent_type = [] (Dirent_type type) + { + switch (type) { + case Dirent_type::DIRECTORY: return DT_DIR; + case Dirent_type::CONTINUOUS_FILE: return DT_REG; + case Dirent_type::TRANSACTIONAL_FILE: return DT_SOCK; + case Dirent_type::SYMLINK: return DT_LNK; + case Dirent_type::END: return DT_UNKNOWN; + } + return DT_UNKNOWN; + }; - switch (dirent_out.type) { - case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: dirent->d_type = DT_DIR; break; - case Vfs::Directory_service::DIRENT_TYPE_FILE: dirent->d_type = DT_REG; break; - case Vfs::Directory_service::DIRENT_TYPE_SYMLINK: dirent->d_type = DT_LNK; break; - case Vfs::Directory_service::DIRENT_TYPE_FIFO: dirent->d_type = DT_FIFO; break; - case Vfs::Directory_service::DIRENT_TYPE_CHARDEV: dirent->d_type = DT_CHR; break; - case Vfs::Directory_service::DIRENT_TYPE_BLOCKDEV: dirent->d_type = DT_BLK; break; - case Vfs::Directory_service::DIRENT_TYPE_END: return 0; - } + dirent &dirent = *(struct dirent *)buf; + dirent = { }; - dirent->d_fileno = dirent_out.fileno; - dirent->d_reclen = sizeof(struct dirent); + dirent.d_type = dirent_type(dirent_out.type); + dirent.d_fileno = dirent_out.fileno; + dirent.d_reclen = sizeof(struct dirent); - Genode::strncpy(dirent->d_name, dirent_out.name, sizeof(dirent->d_name)); + Genode::strncpy(dirent.d_name, dirent_out.name.buf, sizeof(dirent.d_name)); - dirent->d_namlen = Genode::strlen(dirent->d_name); + dirent.d_namlen = Genode::strlen(dirent.d_name); /* * Keep track of VFS seek pointer and user-supplied basep. diff --git a/repos/libports/src/lib/vfs/fatfs/vfs_fatfs.cc b/repos/libports/src/lib/vfs/fatfs/vfs_fatfs.cc index 2c856ac9e..f507732d5 100644 --- a/repos/libports/src/lib/vfs/fatfs/vfs_fatfs.cc +++ b/repos/libports/src/lib/vfs/fatfs/vfs_fatfs.cc @@ -181,30 +181,39 @@ class Fatfs::File_system : public Vfs::File_system cur_index = 0; } - Dirent *vfs_dir = (Dirent*)buf; + Dirent &vfs_dirent = *(Dirent*)buf; FILINFO info; FRESULT res; - vfs_dir->fileno = 1; /* inode 0 is a pending unlink */ + + unsigned const fileno = 1; /* inode 0 is a pending unlink */ while (cur_index <= dir_index) { res = f_readdir (&dir, &info); if ((res != FR_OK) || (!info.fname[0])) { f_readdir(&dir, nullptr); cur_index = 0; - vfs_dir->type = DIRENT_TYPE_END; - vfs_dir->name[0] = '\0'; + + vfs_dirent = { + .fileno = fileno, + .type = Dirent_type::END, + .rwx = Node_rwx::rwx(), + .name = { } + }; out_count = sizeof(Dirent); return READ_OK; } cur_index++; } - vfs_dir->type = (info.fattrib & AM_DIR) ? - DIRENT_TYPE_DIRECTORY : DIRENT_TYPE_FILE; - Genode::strncpy(vfs_dir->name, (const char*)info.fname, - sizeof(vfs_dir->name)); - + vfs_dirent = { + .fileno = fileno, + .type = (info.fattrib & AM_DIR) + ? Dirent_type::DIRECTORY + : Dirent_type::CONTINUOUS_FILE, + .rwx = Node_rwx::rwx(), + .name = { (char const *)info.fname } + }; out_count = sizeof(Dirent); return READ_OK; } @@ -607,19 +616,22 @@ class Fatfs::File_system : public Vfs::File_system Stat_result stat(char const *path, Stat &stat) override { - stat = Stat(); + stat = Stat { }; FILINFO info; FRESULT const err = f_stat((const TCHAR*)path, &info); switch (err) { case FR_OK: - stat.inode = 1; + stat.inode = 1; stat.device = (Genode::addr_t)this; - stat.mode = (info.fattrib & AM_DIR) ? - STAT_MODE_DIRECTORY : STAT_MODE_FILE; + stat.type = (info.fattrib & AM_DIR) + ? Vfs::Node_type::DIRECTORY + : Vfs::Node_type::CONTINUOUS_FILE; + stat.rwx = Vfs::Node_rwx::rwx(); + /* XXX: size in f_stat is always zero */ - if ((stat.mode == STAT_MODE_FILE) && (info.fsize == 0)) { + if ((stat.type == Vfs::Node_type::CONTINUOUS_FILE) && (info.fsize == 0)) { File *file = _opened_file(path); if (file) { stat.size = f_size(&file->fil); diff --git a/repos/libports/src/lib/vfs/jitterentropy/vfs_jitterentropy.h b/repos/libports/src/lib/vfs/jitterentropy/vfs_jitterentropy.h index 766ac24ef..a4d0f5a39 100644 --- a/repos/libports/src/lib/vfs/jitterentropy/vfs_jitterentropy.h +++ b/repos/libports/src/lib/vfs/jitterentropy/vfs_jitterentropy.h @@ -102,7 +102,8 @@ class Jitterentropy_file_system : public Vfs::Single_file_system Jitterentropy_file_system(Genode::Allocator &alloc, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config), + Single_file_system(Vfs::Node_type::CONTINUOUS_FILE, name(), + Vfs::Node_rwx::ro(), config), _ec_stir(0), _initialized(_init_jitterentropy(alloc)) { } diff --git a/repos/libports/src/lib/vfs/lwip/vfs.cc b/repos/libports/src/lib/vfs/lwip/vfs.cc index 810099b71..1acb6bfa3 100644 --- a/repos/libports/src/lib/vfs/lwip/vfs.cc +++ b/repos/libports/src/lib/vfs/lwip/vfs.cc @@ -603,35 +603,51 @@ class Lwip::Protocol_dir_impl final : public Protocol_dir Path subpath(path); if (subpath == "/") { - st.size = 1; - st.mode = Directory_service::STAT_MODE_DIRECTORY; - st.inode = (Genode::addr_t)this; + st = { .size = 1, + .type = Node_type::DIRECTORY, + .rwx = Node_rwx::rwx(), + .inode = (Genode::addr_t)this, + .device = 0, + .modification_time = { 0 } }; return Directory_service::STAT_OK; } if (subpath == "/new_socket") { - st.size = 1; - st.mode = Directory_service::STAT_MODE_FILE | 0777; - st.inode = ((Genode::addr_t)this)+1; + st = { .size = 1, + .type = Node_type::TRANSACTIONAL_FILE, + .rwx = Node_rwx::rw(), + .inode = (Genode::addr_t)this + 1, + .device = 0, + .modification_time = { 0 } }; return Directory_service::STAT_OK; } if (!subpath.has_single_element()) subpath.strip_last_element(); + if (SOCKET_DIR *dir = lookup(subpath.string())) { Path filename(path); filename.keep_only_last_element(); if (filename == subpath.base()) { - st.size = Lwip_file_handle::INVALID; - st.mode = Directory_service::STAT_MODE_DIRECTORY; - st.inode = (Genode::addr_t)dir; + st = { .size = 0, + .type = Node_type::DIRECTORY, + .rwx = Node_rwx::rwx(), + .inode = (Genode::addr_t)dir, + .device = 0, + .modification_time = { 0 } }; return Directory_service::STAT_OK; } Lwip_file_handle::Kind k = Lwip_file_handle::kind_from_name(filename); if (k != Lwip_file_handle::INVALID) { - st.mode = Directory_service::STAT_MODE_CHARDEV; - st.inode = ((Genode::addr_t)dir)+k; + st = { .size = 0, + .type = (filename == "/data") + ? Node_type::CONTINUOUS_FILE + : Node_type::TRANSACTIONAL_FILE, + .rwx = Node_rwx::rw(), + .inode = (Genode::addr_t)dir + k, + .device = 0, + .modification_time = { 0 } }; return Directory_service::STAT_OK; } } @@ -1795,18 +1811,26 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory Stat_result stat(char const *path, Stat &st) override { if (*path == '/') ++path; - st = Stat(); + st = Stat { }; st.device = (Genode::addr_t)this; if (match_address(path) || match_netmask(path)) { - st.size = ADDRESS_FILE_SIZE; - st.mode = STAT_MODE_FILE; + st = { .size = ADDRESS_FILE_SIZE, + .type = Node_type::TRANSACTIONAL_FILE, + .rwx = Node_rwx::rw(), + .inode = (Genode::addr_t)this, + .device = 0, + .modification_time = { 0 } }; return STAT_OK; } if (match_nameserver(path)) { - st.size = IPADDR_STRLEN_MAX; - st.mode = STAT_MODE_FILE; + st = { .size = IPADDR_STRLEN_MAX, + .type = Node_type::TRANSACTIONAL_FILE, + .rwx = Node_rwx::rw(), + .inode = 0, + .device = 0, + .modification_time = { 0 } }; return STAT_OK; } diff --git a/repos/libports/src/server/fatfs_fs/directory.h b/repos/libports/src/server/fatfs_fs/directory.h index 500e747fc..656743146 100644 --- a/repos/libports/src/server/fatfs_fs/directory.h +++ b/repos/libports/src/server/fatfs_fs/directory.h @@ -56,8 +56,6 @@ class Fatfs_fs::Directory : public Node return 0; } - Directory_entry *e = (Directory_entry *)(dst); - using namespace Fatfs; FILINFO fatfs_file_info; @@ -99,12 +97,17 @@ class Fatfs_fs::Directory : public Node return 0; } - strncpy(e->name, fatfs_file_info.fname, sizeof(e->name)); - - if ((fatfs_file_info.fattrib & AM_DIR) == AM_DIR) - e->type = Directory_entry::TYPE_DIRECTORY; - else - e->type = Directory_entry::TYPE_FILE; + Directory_entry &e = *(Directory_entry *)(dst); + e = { + .inode = 0, + .type = ((fatfs_file_info.fattrib & AM_DIR) == AM_DIR) + ? Node_type::DIRECTORY + : Node_type::CONTINUOUS_FILE, + .rwx = { .readable = true, + .writeable = true, + .executable = true }, + .name = { fatfs_file_info.fname } + }; return sizeof(Directory_entry); } diff --git a/repos/libports/src/server/fatfs_fs/main.cc b/repos/libports/src/server/fatfs_fs/main.cc index 74e61c5a7..888f51b53 100644 --- a/repos/libports/src/server/fatfs_fs/main.cc +++ b/repos/libports/src/server/fatfs_fs/main.cc @@ -133,6 +133,10 @@ class Fatfs_fs::Session_component : public Session_rpc_object succeeded = true; /* not supported */ break; + + case Packet_descriptor::WRITE_TIMESTAMP: + succeeded = false; + break; } packet.length(res_length); @@ -537,8 +541,9 @@ class Fatfs_fs::Session_component : public Session_rpc_object Status status; status.inode = 1; status.size = 0; - status.mode = 0; - + status.rwx = { .readable = true, + .writeable = true, + .executable = true }; Node &node = open_node.node(); using namespace Fatfs; @@ -587,17 +592,17 @@ class Fatfs_fs::Session_component : public Session_rpc_object } if ((fatfs_file_info.fattrib & AM_DIR) == AM_DIR) { - status.mode = File_system::Status::MODE_DIRECTORY; } + status.type = File_system::Node_type::DIRECTORY; } else { - status.mode = File_system::Status::MODE_FILE; + status.type = File_system::Node_type::CONTINUOUS_FILE; status.size = fatfs_file_info.fsize; } } else { - status.mode = File_system::Status::MODE_DIRECTORY; + status.type = File_system::Node_type::DIRECTORY; } - if (status.mode == File_system::Status::MODE_DIRECTORY) { + if (status.type == File_system::Node_type::DIRECTORY) { /* determine the number of directory entries */ 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 55ace3dcd..1b5911b70 100644 --- a/repos/os/include/file_system_session/file_system_session.h +++ b/repos/os/include/file_system_session/file_system_session.h @@ -16,6 +16,7 @@ #ifndef _INCLUDE__FILE_SYSTEM_SESSION__FILE_SYSTEM_SESSION_H_ #define _INCLUDE__FILE_SYSTEM_SESSION__FILE_SYSTEM_SESSION_H_ +#include #include #include #include @@ -66,6 +67,20 @@ namespace File_system { typedef Symlink::Id Symlink_handle; typedef Watch::Id Watch_handle; + enum class Node_type { + DIRECTORY, + SYMLINK, + CONTINUOUS_FILE, + TRANSACTIONAL_FILE + }; + + struct Node_rwx + { + bool readable; + bool writeable; + bool executable; + }; + using Genode::size_t; typedef Genode::uint64_t seek_off_t; @@ -250,30 +265,21 @@ class File_system::Packet_descriptor : public Genode::Packet_descriptor struct File_system::Status { - enum { - MODE_SYMLINK = 0020000, - MODE_FILE = 0100000, - MODE_DIRECTORY = 0040000, - }; - - /* - * XXX add executable bit - */ - file_size_t size; - unsigned mode; + Node_type type; + Node_rwx rwx; unsigned long inode; Timestamp modification_time; /** * Return true if node is a directory */ - bool directory() const { return mode & MODE_DIRECTORY; } + bool directory() const { return type == Node_type::DIRECTORY; } /** * Return true if node is a symbolic link */ - bool symlink() const { return mode & MODE_SYMLINK; } + bool symlink() const { return type == Node_type::SYMLINK; } }; @@ -285,11 +291,27 @@ struct File_system::Control { /* to manipulate the executable bit */ }; */ struct File_system::Directory_entry { - enum Type { TYPE_FILE, TYPE_DIRECTORY, TYPE_SYMLINK }; + struct Name + { + char buf[MAX_NAME_LEN] { }; + + Name() { }; + Name(char const *name) { Genode::strncpy(buf, name, sizeof(buf)); } + }; unsigned long inode; - Type type; - char name[MAX_NAME_LEN]; + Node_type type; + Node_rwx rwx; + Name name; + + /** + * Sanitize object received from a file-system server as plain bytes + */ + void sanitize() + { + /* enforce null termination */ + name.buf[MAX_NAME_LEN - 1] = 0; + } }; diff --git a/repos/os/include/vfs/dir_file_system.h b/repos/os/include/vfs/dir_file_system.h index d99e94c21..a7c240538 100644 --- a/repos/os/include/vfs/dir_file_system.h +++ b/repos/os/include/vfs/dir_file_system.h @@ -343,8 +343,8 @@ class Vfs::Dir_file_system : public File_system if (count < sizeof(Dirent)) return READ_ERR_INVALID; - Dirent *dirent = (Dirent*)dst; - *dirent = Dirent(); + Dirent &dirent = *(Dirent*)dst; + dirent = Dirent { }; out_count = sizeof(Dirent); @@ -456,13 +456,14 @@ class Vfs::Dir_file_system : public File_system * current directory. */ if (strlen(path) == 0 || _top_dir(path)) { - out.size = 0; - out.mode = STAT_MODE_DIRECTORY | 0755; - out.uid = 0; - out.gid = 0; - out.inode = 1; - out.device = (Genode::addr_t)this; - out.modification_time = { Vfs::Timestamp::INVALID }; + out = { + .size = 0, + .type = Node_type::DIRECTORY, + .rwx = Node_rwx::rwx(), + .inode = 1, + .device = (Genode::addr_t)this, + .modification_time = { Vfs::Timestamp::INVALID }, + }; return STAT_OK; } @@ -903,16 +904,28 @@ class Vfs::Dir_file_system : public File_system return _complete_read_of_file_systems(dir_vfs_handle, dst, count, out_count); if (_top_dir(dir_vfs_handle->path.base())) { - Dirent *dirent = (Dirent*)dst; - file_offset index = vfs_handle->seek() / sizeof(Dirent); + + Dirent &dirent = *(Dirent*)dst; + + file_offset const index = vfs_handle->seek() / sizeof(Dirent); if (index == 0) { - strncpy(dirent->name, _name.string(), sizeof(dirent->name)); - dirent->type = DIRENT_TYPE_DIRECTORY; - dirent->fileno = 1; + dirent = { + .fileno = 1, + .type = Dirent_type::DIRECTORY, + .rwx = Node_rwx::rwx(), + .name = { _name.string() } + }; + } else { - dirent->type = DIRENT_TYPE_END; + + dirent = { + .fileno = 0, + .type = Dirent_type::END, + .rwx = { }, + .name = { } + }; } out_count = sizeof(Dirent); diff --git a/repos/os/include/vfs/directory_service.h b/repos/os/include/vfs/directory_service.h index 155413e57..8f994a740 100644 --- a/repos/os/include/vfs/directory_service.h +++ b/repos/os/include/vfs/directory_service.h @@ -141,26 +141,14 @@ struct Vfs::Directory_service : Interface ** Stat ** **********/ - /** - * These values are the same as in the FreeBSD libc - */ - enum { - STAT_MODE_SYMLINK = 0120000, - STAT_MODE_FILE = 0100000, - STAT_MODE_DIRECTORY = 0040000, - STAT_MODE_CHARDEV = 0020000, - STAT_MODE_BLOCKDEV = 0060000, - }; - struct Stat { - file_size size = 0; - unsigned mode = 0; - unsigned uid = 0; - unsigned gid = 0; - unsigned long inode = 0; - unsigned long device = 0; - Timestamp modification_time { Timestamp::INVALID }; + file_size size; + Node_type type; + Node_rwx rwx; + unsigned long inode; + unsigned long device; + Timestamp modification_time; }; enum Stat_result { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS, @@ -177,23 +165,42 @@ struct Vfs::Directory_service : Interface ** Dirent ** ************/ - enum { DIRENT_MAX_NAME_LEN = 128 }; - - enum Dirent_type { - DIRENT_TYPE_FILE, - DIRENT_TYPE_DIRECTORY, - DIRENT_TYPE_FIFO, - DIRENT_TYPE_CHARDEV, - DIRENT_TYPE_BLOCKDEV, - DIRENT_TYPE_SYMLINK, - DIRENT_TYPE_END + enum class Dirent_type + { + END, + DIRECTORY, + SYMLINK, + CONTINUOUS_FILE, + TRANSACTIONAL_FILE, }; struct Dirent { - unsigned long fileno = 0; - Dirent_type type = DIRENT_TYPE_END; - char name[DIRENT_MAX_NAME_LEN] = { 0 }; + struct Name + { + enum { MAX_LEN = 128 }; + char buf[MAX_LEN] { }; + + Name() { }; + Name(char const *name) { strncpy(buf, name, sizeof(buf)); } + }; + + unsigned long fileno; + Dirent_type type; + Node_rwx rwx; + Name name; + + /** + * Sanitize dirent members + * + * This method must be called after receiving a 'Dirent' as + * a plain data copy. + */ + void sanitize() + { + /* enforce null termination */ + name.buf[Name::MAX_LEN - 1] = 0; + } }; diff --git a/repos/os/include/vfs/readonly_value_file_system.h b/repos/os/include/vfs/readonly_value_file_system.h index 7f0184086..d4971a149 100644 --- a/repos/os/include/vfs/readonly_value_file_system.h +++ b/repos/os/include/vfs/readonly_value_file_system.h @@ -88,8 +88,8 @@ class Vfs::Readonly_value_file_system : public Vfs::Single_file_system Readonly_value_file_system(Name const &name, T const &initial_value) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, type(), - Xml_node(_config(name).string())), + Single_file_system(Node_type::TRANSACTIONAL_FILE, type(), + Node_rwx::ro(), Xml_node(_config(name).string())), _file_name(name) { value(initial_value); @@ -131,7 +131,6 @@ class Vfs::Readonly_value_file_system : public Vfs::Single_file_system Stat_result stat(char const *path, Stat &out) override { Stat_result result = Single_file_system::stat(path, out); - out.mode |= 0444; out.size = _buffer.length(); return result; } diff --git a/repos/os/include/vfs/single_file_system.h b/repos/os/include/vfs/single_file_system.h index a06a6856b..ba5db3b3f 100644 --- a/repos/os/include/vfs/single_file_system.h +++ b/repos/os/include/vfs/single_file_system.h @@ -22,16 +22,10 @@ namespace Vfs { class Single_file_system; } class Vfs::Single_file_system : public File_system { - public: - - enum Node_type { - NODE_TYPE_FILE, NODE_TYPE_SYMLINK, - NODE_TYPE_CHAR_DEVICE, NODE_TYPE_BLOCK_DEVICE - }; - private: - Node_type const _node_type; + Node_type const _type; + Node_rwx const _rwx; typedef String<64> Filename; @@ -61,8 +55,10 @@ class Vfs::Single_file_system : public File_system { private: - Node_type _node_type; - char const *_filename; + Node_type const _type; + Node_rwx const _rwx; + + Filename const &_filename; /* * Noncopyable @@ -75,12 +71,12 @@ class Vfs::Single_file_system : public File_system Single_vfs_dir_handle(Directory_service &ds, File_io_service &fs, Genode::Allocator &alloc, - Node_type node_type, - char const *filename) + Node_type type, + Node_rwx rwx, + Filename const &filename) : Single_vfs_handle(ds, fs, alloc, 0), - _node_type(node_type), - _filename(filename) + _type(type), _rwx(rwx), _filename(filename) { } Read_result read(char *dst, file_size count, @@ -93,19 +89,33 @@ class Vfs::Single_file_system : public File_system file_size index = seek() / sizeof(Dirent); - Dirent *out = (Dirent*)dst; + Dirent &out = *(Dirent*)dst; + + auto dirent_type = [&] () + { + switch (_type) { + case Node_type::DIRECTORY: return Dirent_type::DIRECTORY; + case Node_type::SYMLINK: return Dirent_type::SYMLINK; + case Node_type::CONTINUOUS_FILE: return Dirent_type::CONTINUOUS_FILE; + case Node_type::TRANSACTIONAL_FILE: return Dirent_type::TRANSACTIONAL_FILE; + } + return Dirent_type::END; + }; if (index == 0) { - out->fileno = (Genode::addr_t)this; - switch (_node_type) { - case NODE_TYPE_FILE: out->type = DIRENT_TYPE_FILE; break; - case NODE_TYPE_SYMLINK: out->type = DIRENT_TYPE_SYMLINK; break; - case NODE_TYPE_CHAR_DEVICE: out->type = DIRENT_TYPE_CHARDEV; break; - case NODE_TYPE_BLOCK_DEVICE: out->type = DIRENT_TYPE_BLOCKDEV; break; - } - strncpy(out->name, _filename, sizeof(out->name)); + out = { + .fileno = (Genode::addr_t)this, + .type = dirent_type(), + .rwx = _rwx, + .name = { _filename.string() } + }; } else { - out->type = DIRENT_TYPE_END; + out = { + .fileno = (Genode::addr_t)this, + .type = Dirent_type::END, + .rwx = { }, + .name = { } + }; } out_count = sizeof(Dirent); @@ -134,9 +144,12 @@ class Vfs::Single_file_system : public File_system public: - Single_file_system(Node_type node_type, char const *type_name, Xml_node config) + Single_file_system(Node_type node_type, + char const *type_name, + Node_rwx rwx, + Xml_node config) : - _node_type(node_type), + _type(node_type), _rwx(rwx), _filename(config.attribute_value("name", Filename(type_name))) { } @@ -154,19 +167,15 @@ class Vfs::Single_file_system : public File_system Stat_result stat(char const *path, Stat &out) override { - out = Stat(); + out = Stat { }; out.device = (Genode::addr_t)this; if (_root(path)) { - out.mode = STAT_MODE_DIRECTORY; + out.type = Node_type::DIRECTORY; } else if (_single_file(path)) { - switch (_node_type) { - case NODE_TYPE_FILE: out.mode = STAT_MODE_FILE; break; - case NODE_TYPE_SYMLINK: out.mode = STAT_MODE_SYMLINK; break; - case NODE_TYPE_CHAR_DEVICE: out.mode = STAT_MODE_CHARDEV; break; - case NODE_TYPE_BLOCK_DEVICE: out.mode = STAT_MODE_BLOCKDEV; break; - } + out.type = _type; + out.rwx = _rwx; out.inode = 1; } else { return STAT_ERR_NO_ENTRY; @@ -208,7 +217,7 @@ class Vfs::Single_file_system : public File_system try { *out_handle = new (alloc) Single_vfs_dir_handle(*this, *this, alloc, - _node_type, _filename.string()); + _type, _rwx, _filename); return OPENDIR_OK; } catch (Genode::Out_of_ram) { return OPENDIR_ERR_OUT_OF_RAM; } diff --git a/repos/os/include/vfs/types.h b/repos/os/include/vfs/types.h index 2dac626c4..f2733966b 100644 --- a/repos/os/include/vfs/types.h +++ b/repos/os/include/vfs/types.h @@ -55,6 +55,36 @@ namespace Vfs { long long value; }; + enum class Node_type { + DIRECTORY, + SYMLINK, + CONTINUOUS_FILE, + TRANSACTIONAL_FILE + }; + + struct Node_rwx + { + bool readable; + bool writeable; + bool executable; + + static Node_rwx ro() { return { .readable = true, + .writeable = false, + .executable = false }; } + + static Node_rwx rw() { return { .readable = true, + .writeable = true, + .executable = false }; } + + static Node_rwx rx() { return { .readable = true, + .writeable = false, + .executable = true }; } + + static Node_rwx rwx() { return { .readable = true, + .writeable = false, + .executable = true }; } + }; + typedef Genode::Path Absolute_path; } diff --git a/repos/os/src/app/cli_monitor/subsystem_config_registry.h b/repos/os/src/app/cli_monitor/subsystem_config_registry.h index f94c522e4..3477b8ea6 100644 --- a/repos/os/src/app/cli_monitor/subsystem_config_registry.h +++ b/repos/os/src/app/cli_monitor/subsystem_config_registry.h @@ -50,8 +50,8 @@ class Cli_monitor::Subsystem_config_registry unsigned _subsystem_suffix(Vfs::Directory_service::Dirent const &dirent) { unsigned found = 0; - for (unsigned i = 0; i < sizeof(dirent.name) && dirent.name[i]; i++) - if (Genode::strcmp(_subsystem_suffix(), &dirent.name[i]) == 0) + for (unsigned i = 0; i < sizeof(dirent.name.buf) && dirent.name.buf[i]; i++) + if (Genode::strcmp(_subsystem_suffix(), &dirent.name.buf[i]) == 0) found = i; return found; @@ -155,7 +155,7 @@ class Cli_monitor::Subsystem_config_registry /* iterate over the directory entries */ for (unsigned i = 0;; i++) { - Vfs::Directory_service::Dirent dirent; + Vfs::Directory_service::Dirent dirent { }; dir_handle->seek(i * sizeof(dirent)); dir_handle->fs().queue_read(dir_handle, sizeof(dirent)); @@ -168,7 +168,7 @@ class Cli_monitor::Subsystem_config_registry Vfs::File_io_service::READ_QUEUED) _ep.wait_and_dispatch_one_io_signal(); - if (dirent.type == Vfs::Directory_service::DIRENT_TYPE_END) { + if (dirent.type == Vfs::Directory_service::Dirent_type::END) { _fs.close(dir_handle); return; } @@ -179,8 +179,8 @@ class Cli_monitor::Subsystem_config_registry if (subsystem_suffix) { /* subsystem name is file name without the suffix */ - char name[sizeof(dirent.name)]; - Genode::strncpy(name, dirent.name, subsystem_suffix + 1); + char name[sizeof(dirent.name.buf)]; + Genode::strncpy(name, dirent.name.buf, subsystem_suffix + 1); try { for_config(name, fn); diff --git a/repos/os/src/lib/vfs/block_file_system.h b/repos/os/src/lib/vfs/block_file_system.h index df8417cc8..ff485e77b 100644 --- a/repos/os/src/lib/vfs/block_file_system.h +++ b/repos/os/src/lib/vfs/block_file_system.h @@ -326,7 +326,8 @@ class Vfs::Block_file_system : public Single_file_system Block_file_system(Vfs::Env &env, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_BLOCK_DEVICE, name(), config), + Single_file_system(Node_type::CONTINUOUS_FILE, name(), + Node_rwx::rw(), config), _env(env), _label(config.attribute_value("label", Label())), _block_buffer(0), diff --git a/repos/os/src/lib/vfs/fs_file_system.h b/repos/os/src/lib/vfs/fs_file_system.h index d0051528c..ea9341d38 100644 --- a/repos/os/src/lib/vfs/fs_file_system.h +++ b/repos/os/src/lib/vfs/fs_file_system.h @@ -69,6 +69,50 @@ class Vfs::Fs_file_system : public File_system struct Fs_vfs_handle; typedef Genode::Fifo Fs_vfs_handle_queue; + /** + * Convert 'File_system::Node_type' to 'Dirent_type' + */ + static Dirent_type _dirent_type(::File_system::Node_type type) + { + using ::File_system::Node_type; + + switch (type) { + case Node_type::DIRECTORY: return Dirent_type::DIRECTORY; + case Node_type::CONTINUOUS_FILE: return Dirent_type::CONTINUOUS_FILE; + case Node_type::TRANSACTIONAL_FILE: return Dirent_type::TRANSACTIONAL_FILE; + case Node_type::SYMLINK: return Dirent_type::SYMLINK; + } + return Dirent_type::END; + } + + /** + * Convert 'File_system::Node_type' to 'Vfs::Node_type' + */ + static Node_type _node_type(::File_system::Node_type type) + { + using Type = ::File_system::Node_type; + + switch (type) { + case Type::DIRECTORY: return Node_type::DIRECTORY; + case Type::CONTINUOUS_FILE: return Node_type::CONTINUOUS_FILE; + case Type::TRANSACTIONAL_FILE: return Node_type::TRANSACTIONAL_FILE; + case Type::SYMLINK: return Node_type::SYMLINK; + } + + Genode::error("invalid File_system::Node_type"); + return Node_type::CONTINUOUS_FILE; + } + + /** + * Convert 'File_system::Node_rwx' to 'Vfs::Node_rwx' + */ + static Node_rwx _node_rwx(::File_system::Node_rwx rwx) + { + return { .readable = rwx.readable, + .writeable = rwx.writeable, + .executable = rwx.executable }; + } + struct Fs_vfs_handle : Vfs_handle, private ::File_system::Node, private Handle_space::Element, @@ -295,41 +339,38 @@ class Vfs::Fs_file_system : public File_system using ::File_system::Directory_entry; - Directory_entry entry; - file_size entry_out_count; + Directory_entry entry { }; + file_size entry_out_count = 0; - Read_result read_result = + Read_result const read_result = _complete_read(&entry, DIRENT_SIZE, entry_out_count); if (read_result != READ_OK) return read_result; - Dirent *dirent = (Dirent*)dst; + entry.sanitize(); + + Dirent &dirent = *(Dirent*)dst; if (entry_out_count < DIRENT_SIZE) { + /* no entry found for the given index, or error */ - *dirent = Dirent(); + dirent = Dirent { + .fileno = 0, + .type = Dirent_type::END, + .rwx = { }, + .name = { } + }; out_count = sizeof(Dirent); return READ_OK; } - /* - * The default value has no meaning because the switch below - * assigns a value in each possible branch. But it is needed to - * keep the compiler happy. - */ - Dirent_type type = DIRENT_TYPE_END; - - /* copy-out payload into destination buffer */ - switch (entry.type) { - case Directory_entry::TYPE_DIRECTORY: type = DIRENT_TYPE_DIRECTORY; break; - case Directory_entry::TYPE_FILE: type = DIRENT_TYPE_FILE; break; - case Directory_entry::TYPE_SYMLINK: type = DIRENT_TYPE_SYMLINK; break; - } - - dirent->fileno = entry.inode; - dirent->type = type; - strncpy(dirent->name, entry.name, sizeof(dirent->name)); + dirent = Dirent { + .fileno = entry.inode, + .type = _dirent_type(entry.type), + .rwx = _node_rwx(entry.rwx), + .name = { entry.name.buf } + }; out_count = sizeof(Dirent); @@ -646,20 +687,13 @@ class Vfs::Fs_file_system : public File_system out = Stat(); - out.size = status.size; - out.mode = STAT_MODE_FILE | 0777; - - if (status.symlink()) - out.mode = STAT_MODE_SYMLINK | 0777; - - if (status.directory()) - out.mode = STAT_MODE_DIRECTORY | 0777; - - out.uid = 0; - out.gid = 0; - out.inode = status.inode; + out.size = status.size; + out.type = _node_type(status.type); + out.rwx = _node_rwx(status.rwx); + out.inode = status.inode; out.device = (Genode::addr_t)this; out.modification_time.value = status.modification_time.value; + return STAT_OK; } diff --git a/repos/os/src/lib/vfs/inline_file_system.h b/repos/os/src/lib/vfs/inline_file_system.h index 6554c0beb..ae541bf68 100644 --- a/repos/os/src/lib/vfs/inline_file_system.h +++ b/repos/os/src/lib/vfs/inline_file_system.h @@ -103,7 +103,9 @@ class Vfs::Inline_file_system : public Single_file_system */ Inline_file_system(Vfs::Env&, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_FILE, name(), config), _node(config) + Single_file_system(Node_type::CONTINUOUS_FILE, name(), + Node_rwx::rx(), config), + _node(config) { } static char const *name() { return "inline"; } @@ -140,9 +142,11 @@ class Vfs::Inline_file_system : public Single_file_system Stat_result stat(char const *path, Stat &out) override { - Stat_result result = Single_file_system::stat(path, out); + Stat_result const result = Single_file_system::stat(path, out); + _node.with_raw_content([&] (char const *, Genode::size_t size) { out.size = size; }); + return result; } }; diff --git a/repos/os/src/lib/vfs/log_file_system.h b/repos/os/src/lib/vfs/log_file_system.h index a9e9c46ef..757290fbf 100644 --- a/repos/os/src/lib/vfs/log_file_system.h +++ b/repos/os/src/lib/vfs/log_file_system.h @@ -141,7 +141,8 @@ class Vfs::Log_file_system : public Single_file_system Log_file_system(Vfs::Env &env, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config), + Single_file_system(Node_type::CONTINUOUS_FILE, name(), + Node_rwx::ro(), config), _label(config.attribute_value("label", Label())), _log(_log_session(env.env())) { } diff --git a/repos/os/src/lib/vfs/null_file_system.h b/repos/os/src/lib/vfs/null_file_system.h index e9ddd1505..fd790c214 100644 --- a/repos/os/src/lib/vfs/null_file_system.h +++ b/repos/os/src/lib/vfs/null_file_system.h @@ -24,7 +24,8 @@ struct Vfs::Null_file_system : Single_file_system { Null_file_system(Vfs::Env&, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config) + Single_file_system(Node_type::CONTINUOUS_FILE, name(), + Node_rwx::rw(), config) { } static char const *name() { return "null"; } diff --git a/repos/os/src/lib/vfs/ram_file_system.h b/repos/os/src/lib/vfs/ram_file_system.h index 1f6719394..c41e2d535 100644 --- a/repos/os/src/lib/vfs/ram_file_system.h +++ b/repos/os/src/lib/vfs/ram_file_system.h @@ -169,6 +169,13 @@ class Vfs_ram::Node : private Genode::Avl_node, private Genode::Lock Vfs::Timestamp modification_time() const { return _modification_time; } + Vfs::Node_rwx rwx() const + { + return { .readable = true, + .writeable = true, + .executable = true }; + } + virtual size_t read(char*, size_t, file_size) { Genode::error("Vfs_ram::Node::read() called"); @@ -450,39 +457,43 @@ class Vfs_ram::Directory : public Vfs_ram::Node file_offset index = seek_offset / sizeof(Dirent); - Dirent *dirent = (Dirent*)dst; - *dirent = Dirent(); + Dirent &dirent = *(Dirent*)dst; + + using Dirent_type = Vfs::Directory_service::Dirent_type; + out_count = sizeof(Dirent); - Node *node = _entries.first(); - if (node) node = node->index(index); - if (!node) { - dirent->type = Directory_service::DIRENT_TYPE_END; + Node *node_ptr = _entries.first(); + if (node_ptr) node_ptr = node_ptr->index(index); + if (!node_ptr) { + dirent.type = Dirent_type::END; return Vfs::File_io_service::READ_OK; } - dirent->fileno = node->inode; - strncpy(dirent->name, node->name(), sizeof(dirent->name)); + Node &node = *node_ptr; - File *file = dynamic_cast(node); - if (file) { - dirent->type = Directory_service::DIRENT_TYPE_FILE; - return Vfs::File_io_service::READ_OK; - } + auto dirent_type = [&] () + { + if (dynamic_cast(node_ptr)) return Dirent_type::CONTINUOUS_FILE; + if (dynamic_cast(node_ptr)) return Dirent_type::DIRECTORY; + if (dynamic_cast(node_ptr)) return Dirent_type::SYMLINK; - Directory *dir = dynamic_cast(node); - if (dir) { - dirent->type = Directory_service::DIRENT_TYPE_DIRECTORY; - return Vfs::File_io_service::READ_OK; - } + return Dirent_type::END; + }; - Symlink *symlink = dynamic_cast(node); - if (symlink) { - dirent->type = Directory_service::DIRENT_TYPE_SYMLINK; - return Vfs::File_io_service::READ_OK; - } + Dirent_type const type = dirent_type(); - return Vfs::File_io_service::READ_ERR_INVALID; + if (type == Dirent_type::END) + return Vfs::File_io_service::READ_ERR_INVALID; + + dirent = { + .fileno = node.inode, + .type = type, + .rwx = node.rwx(), + .name = { node.name() } + }; + + return Vfs::File_io_service::READ_OK; } }; @@ -780,35 +791,31 @@ class Vfs::Ram_file_system : public Vfs::File_system { using namespace Vfs_ram; - Node *node = lookup(path); - if (!node) return STAT_ERR_NO_ENTRY; - Node::Guard guard(node); + Node *node_ptr = lookup(path); + if (!node_ptr) return STAT_ERR_NO_ENTRY; - stat.size = node->length(); - stat.inode = node->inode; - stat.device = (Genode::addr_t)this; - stat.modification_time = node->modification_time(); + Node::Guard guard(node_ptr); - File *file = dynamic_cast(node); - if (file) { - stat.mode = STAT_MODE_FILE | 0777; - return STAT_OK; - } + Node &node = *node_ptr; - Directory *dir = dynamic_cast(node); - if (dir) { - stat.mode = STAT_MODE_DIRECTORY | 0777; - return STAT_OK; - } + auto node_type = [&] () + { + if (dynamic_cast(node_ptr)) return Node_type::DIRECTORY; + if (dynamic_cast(node_ptr)) return Node_type::SYMLINK; - Symlink *symlink = dynamic_cast(node); - if (symlink) { - stat.mode = STAT_MODE_SYMLINK | 0777; - return STAT_OK; - } + return Node_type::CONTINUOUS_FILE; + }; - /* this should never happen */ - return STAT_ERR_NO_ENTRY; + stat = { + .size = node.length(), + .type = node_type(), + .rwx = node.rwx(), + .inode = node.inode, + .device = (Genode::addr_t)this, + .modification_time = node.modification_time() + }; + + return STAT_OK; } Rename_result rename(char const *from, char const *to) override diff --git a/repos/os/src/lib/vfs/rom_file_system.h b/repos/os/src/lib/vfs/rom_file_system.h index 9ede4e7a3..50496fd54 100644 --- a/repos/os/src/lib/vfs/rom_file_system.h +++ b/repos/os/src/lib/vfs/rom_file_system.h @@ -107,7 +107,8 @@ class Vfs::Rom_file_system : public Single_file_system Rom_file_system(Vfs::Env &env, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_FILE, name(), config), + Single_file_system(Node_type::CONTINUOUS_FILE, name(), + Node_rwx::ro(), config), /* use 'label' attribute if present, fall back to 'name' if not */ _label(config.attribute_value("label", @@ -161,10 +162,12 @@ class Vfs::Rom_file_system : public Single_file_system * found a file), obtain the size of the most current ROM module * version. */ - if (out.mode == STAT_MODE_FILE) { + if (out.type == Node_type::CONTINUOUS_FILE) { _rom.update(); out.size = _rom.valid() ? _rom.size() : 0; - out.mode |= 0555; + out.rwx = { .readable = true, + .writeable = false, + .executable = true }; } return result; diff --git a/repos/os/src/lib/vfs/rtc_file_system.h b/repos/os/src/lib/vfs/rtc_file_system.h index da7db4e63..c1af968a8 100644 --- a/repos/os/src/lib/vfs/rtc_file_system.h +++ b/repos/os/src/lib/vfs/rtc_file_system.h @@ -103,7 +103,8 @@ class Vfs::Rtc_file_system : public Single_file_system Rtc_file_system(Vfs::Env &env, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config), + Single_file_system(Node_type::TRANSACTIONAL_FILE, name(), + Node_rwx::ro(), config), _rtc(env.env()), _set_signal_handler(env.env().ep(), *this, &Rtc_file_system::_handle_set_signal) @@ -136,10 +137,7 @@ class Vfs::Rtc_file_system : public Single_file_system Stat_result stat(char const *path, Stat &out) override { - Stat_result result = Single_file_system::stat(path, out); - out.mode |= 0444; - - return result; + return Single_file_system::stat(path, out); } Watch_result watch(char const *path, diff --git a/repos/os/src/lib/vfs/symlink_file_system.h b/repos/os/src/lib/vfs/symlink_file_system.h index 57562b088..63d44fcd6 100644 --- a/repos/os/src/lib/vfs/symlink_file_system.h +++ b/repos/os/src/lib/vfs/symlink_file_system.h @@ -60,7 +60,8 @@ class Vfs::Symlink_file_system : public Single_file_system Symlink_file_system(Vfs::Env&, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_SYMLINK, "symlink", config), + Single_file_system(Node_type::SYMLINK, "symlink", + Node_rwx::rw(), config), _target(config.attribute_value("target", Target())) { } diff --git a/repos/os/src/lib/vfs/tar_file_system.h b/repos/os/src/lib/vfs/tar_file_system.h index f00900dc2..e149f8218 100644 --- a/repos/os/src/lib/vfs/tar_file_system.h +++ b/repos/os/src/lib/vfs/tar_file_system.h @@ -110,12 +110,22 @@ class Vfs::Tar_file_system : public File_system TYPE_LONG_LINK = 75, TYPE_LONG_NAME = 76 }; - file_size size() const { return _long_name() ? _next()->size() : _read(_size); } - unsigned uid() const { return _long_name() ? _next()->uid() : _read(_uid); } - unsigned gid() const { return _long_name() ? _next()->gid() : _read(_gid); } - unsigned mode() const { return _long_name() ? _next()->mode() : _read(_mode); } - unsigned type() const { return _long_name() ? _next()->type() : _read(_type); } - void *data() const { return _long_name() ? _next()->data() : (void *)_data_begin(); } + file_size size() const { return _long_name() ? _next()->size() : _read(_size); } + long long mtime() const { return _long_name() ? _next()->mtime() : _read(_mtime); } + unsigned uid() const { return _long_name() ? _next()->uid() : _read(_uid); } + unsigned gid() const { return _long_name() ? _next()->gid() : _read(_gid); } + unsigned mode() const { return _long_name() ? _next()->mode() : _read(_mode); } + unsigned type() const { return _long_name() ? _next()->type() : _read(_type); } + void *data() const { return _long_name() ? _next()->data() : (void *)_data_begin(); } + + Node_rwx rwx() const + { + unsigned const mode_bits = mode(); + + return { .readable = (mode_bits & 0400) != 0, + .writeable = (mode_bits & 0200) != 0, + .executable = (mode_bits & 0100) != 0 }; + } char const *name() const { return _long_name() ? _data_begin() : _name; } unsigned max_name_len() const { return _long_name() ? MAX_PATH_LEN : 100; } @@ -193,50 +203,67 @@ class Vfs::Tar_file_system : public File_system if (count < sizeof(Dirent)) return READ_ERR_INVALID; - Dirent *dirent = (Dirent*)dst; + Dirent &dirent = *(Dirent*)dst; - /* initialize */ - *dirent = Dirent(); + file_offset const index = seek() / sizeof(Dirent); - file_offset index = seek() / sizeof(Dirent); + Node const *node_ptr = _node->lookup_child(index); - Node const *node = _node->lookup_child(index); - - if (!node) + if (!node_ptr) { + dirent = Dirent { }; + out_count = 0; return READ_OK; + } - dirent->fileno = (Genode::addr_t)node; + Node const &node = *node_ptr; - Record const *record = node->record; + Record const *record_ptr = node.record; - while (record && (record->type() == Record::TYPE_HARDLINK)) { + while (record_ptr && (record_ptr->type() == Record::TYPE_HARDLINK)) { Tar_file_system &tar_fs = static_cast(fs()); - Node const *target = tar_fs.dereference(record->linked_name()); - record = target ? target->record : 0; + Node const *target = tar_fs.dereference(record_ptr->linked_name()); + record_ptr = target ? target->record : 0; } - if (record) { - switch (record->type()) { - case Record::TYPE_FILE: - dirent->type = DIRENT_TYPE_FILE; break; - case Record::TYPE_SYMLINK: - dirent->type = DIRENT_TYPE_SYMLINK; break; - case Record::TYPE_DIR: - dirent->type = DIRENT_TYPE_DIRECTORY; break; + using Dirent_type = Vfs::Directory_service::Dirent_type; - default: - Genode::error("unhandled record type ", record->type(), " " - "for ", node->name); - } - } else { - /* If no record exists, assume it is a directory */ - dirent->type = DIRENT_TYPE_DIRECTORY; + /* if no record exists, assume it is a directory */ + if (!record_ptr) { + dirent = { + .fileno = (Genode::addr_t)node_ptr, + .type = Dirent_type::DIRECTORY, + .rwx = Node_rwx::rx(), + .name = { node.name } + }; + out_count = sizeof(Dirent); + return READ_OK; } - strncpy(dirent->name, node->name, sizeof(dirent->name)); + Record const &record = *record_ptr; + auto node_type = [&] () + { + switch (record.type()) { + case Record::TYPE_FILE: return Dirent_type::CONTINUOUS_FILE; + case Record::TYPE_SYMLINK: return Dirent_type::SYMLINK; + case Record::TYPE_DIR: return Dirent_type::DIRECTORY; + }; + + Genode::warning("unhandled record type ", record.type(), " " + "for ", node.name); + + return Dirent_type::END; + }; + + dirent = { + .fileno = (Genode::addr_t)node_ptr, + .type = node_type(), + .rwx = { .readable = true, + .writeable = false, + .executable = record.rwx().executable }, + .name = { node.name } + }; out_count = sizeof(Dirent); - return READ_OK; } }; @@ -576,35 +603,40 @@ class Vfs::Tar_file_system : public File_system Stat_result stat(char const *path, Stat &out) override { - out = Stat(); + out = Stat { }; - Node const *node = dereference(path); - if (!node) + Node const *node_ptr = dereference(path); + if (!node_ptr) return STAT_ERR_NO_ENTRY; - if (!node->record) { - out.mode = STAT_MODE_DIRECTORY; + if (!node_ptr->record) { + out.type = Node_type::DIRECTORY; + out.rwx = Node_rwx::rx(); return STAT_OK; } - Record const *record = node->record; + Record const &record = *node_ptr->record; - /* convert TAR record modes to stat modes */ - unsigned mode = record->mode(); - switch (record->type()) { - case Record::TYPE_FILE: mode |= STAT_MODE_FILE; break; - case Record::TYPE_SYMLINK: mode |= STAT_MODE_SYMLINK; break; - case Record::TYPE_DIR: mode |= STAT_MODE_DIRECTORY; break; + auto node_type = [&] () + { + switch (record.type()) { + case Record::TYPE_FILE: return Node_type::CONTINUOUS_FILE; + case Record::TYPE_SYMLINK: return Node_type::SYMLINK; + case Record::TYPE_DIR: return Node_type::DIRECTORY; + }; + return Node_type::DIRECTORY; + }; - default: break; - } - - out.mode = mode; - out.size = record->size(); - out.uid = record->uid(); - out.gid = record->gid(); - out.inode = (Genode::addr_t)node; - out.device = (Genode::addr_t)this; + out = { + .size = record.size(), + .type = node_type(), + .rwx = { .readable = true, + .writeable = false, + .executable = record.rwx().executable }, + .inode = (Genode::addr_t)node_ptr, + .device = (Genode::addr_t)this, + .modification_time = { record.mtime() } + }; return STAT_OK; } diff --git a/repos/os/src/lib/vfs/terminal_file_system.h b/repos/os/src/lib/vfs/terminal_file_system.h index d47fc9eac..c970e3ca0 100644 --- a/repos/os/src/lib/vfs/terminal_file_system.h +++ b/repos/os/src/lib/vfs/terminal_file_system.h @@ -101,7 +101,8 @@ class Vfs::Terminal_file_system : public Single_file_system Terminal_file_system(Vfs::Env &env, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config), + Single_file_system(Node_type::TRANSACTIONAL_FILE, name(), + Node_rwx::rw(), config), _label(config.attribute_value("label", Label())), _env(env.env()) { diff --git a/repos/os/src/lib/vfs/zero_file_system.h b/repos/os/src/lib/vfs/zero_file_system.h index 541113a15..0332512c5 100644 --- a/repos/os/src/lib/vfs/zero_file_system.h +++ b/repos/os/src/lib/vfs/zero_file_system.h @@ -24,7 +24,8 @@ struct Vfs::Zero_file_system : Single_file_system { Zero_file_system(Vfs::Env&, Genode::Xml_node config) : - Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config) + Single_file_system(Node_type::CONTINUOUS_FILE, name(), + Node_rwx::rw(), config) { } static char const *name() { return "zero"; } diff --git a/repos/os/src/server/lx_fs/directory.h b/repos/os/src/server/lx_fs/directory.h index eefbf8eda..6eca4fa97 100644 --- a/repos/os/src/server/lx_fs/directory.h +++ b/repos/os/src/server/lx_fs/directory.h @@ -69,7 +69,7 @@ class Lx_fs::Directory : public Node } } - struct stat s; + struct stat s { }; ret = lstat(path, &s); if (ret == -1) @@ -203,19 +203,30 @@ class Lx_fs::Directory : public Node if (!dent) return 0; - Directory_entry *e = (Directory_entry *)(dst); + Path dent_path(dent->d_name, _path.base()); - switch (dent->d_type) { - case DT_REG: e->type = Directory_entry::TYPE_FILE; break; - case DT_DIR: e->type = Directory_entry::TYPE_DIRECTORY; break; - case DT_LNK: e->type = Directory_entry::TYPE_SYMLINK; break; - default: - return 0; - } + struct stat st { }; + lstat(dent_path.base(), &st); - e->inode = dent->d_ino; + auto type = [] (unsigned char type) + { + switch (type) { + case DT_REG: return Node_type::CONTINUOUS_FILE; + case DT_DIR: return Node_type::DIRECTORY; + case DT_LNK: return Node_type::SYMLINK; + default: return Node_type::CONTINUOUS_FILE; + } + }; - strncpy(e->name, dent->d_name, sizeof(e->name)); + Directory_entry &e = *(Directory_entry *)(dst); + e = { + .inode = (unsigned long)dent->d_ino, + .type = type(dent->d_type), + .rwx = { .readable = (st.st_mode & S_IRUSR), + .writeable = (st.st_mode & S_IWUSR), + .executable = (st.st_mode & S_IXUSR) }, + .name = { dent->d_name } + }; return sizeof(Directory_entry); } @@ -228,18 +239,21 @@ class Lx_fs::Directory : public Node Status status() override { - struct stat st; + struct stat st { }; int fd = dirfd(_fd); if (fd == -1 || fstat(fd, &st) < 0) st.st_mtime = 0; - Status s; - s.inode = inode(); - s.size = _num_entries() * sizeof(File_system::Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; - s.modification_time = { st.st_mtime }; - return s; + return { + .size = _num_entries() * sizeof(File_system::Directory_entry), + .type = Node_type::DIRECTORY, + .rwx = { .readable = (st.st_mode & S_IRUSR), + .writeable = (st.st_mode & S_IWUSR), + .executable = (st.st_mode & S_IXUSR) }, + .inode = inode(), + .modification_time = { st.st_mtime } + }; } }; diff --git a/repos/os/src/server/lx_fs/file.h b/repos/os/src/server/lx_fs/file.h index db33dd143..fa94192fe 100644 --- a/repos/os/src/server/lx_fs/file.h +++ b/repos/os/src/server/lx_fs/file.h @@ -143,19 +143,22 @@ class Lx_fs::File : public Node Status status() override { - struct stat st; + struct stat st { }; if (fstat(_fd, &st) < 0) { st.st_size = 0; st.st_mtime = 0; } - Status s; - s.inode = inode(); - s.size = st.st_size; - s.mode = File_system::Status::MODE_FILE; - s.modification_time = { st.st_mtime }; - return s; + return { + .size = (file_size_t)st.st_size, + .type = File_system::Node_type::CONTINUOUS_FILE, + .rwx = { .readable = (st.st_mode & S_IRUSR), + .writeable = (st.st_mode & S_IWUSR), + .executable = (st.st_mode & S_IXUSR) }, + .inode = inode(), + .modification_time = { st.st_mtime } + }; } void truncate(file_size_t size) override diff --git a/repos/os/src/server/ram_fs/directory.h b/repos/os/src/server/ram_fs/directory.h index eca6f9513..c07835c9c 100644 --- a/repos/os/src/server/ram_fs/directory.h +++ b/repos/os/src/server/ram_fs/directory.h @@ -203,15 +203,25 @@ class Ram_fs::Directory : public Node if (!node) return 0; - Directory_entry *e = (Directory_entry *)(dst); + auto type = [&] () + { + using Node_type = File_system::Node_type; - e->inode = node->inode(); + if (dynamic_cast(node)) return Node_type::DIRECTORY; + if (dynamic_cast(node)) return Node_type::SYMLINK; + return Node_type::CONTINUOUS_FILE; + }; - 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; + Directory_entry &e = *(Directory_entry *)(dst); - strncpy(e->name, node->name(), sizeof(e->name)); + e = { + .inode = node->inode(), + .type = type(), + .rwx = { .readable = true, + .writeable = true, + .executable = true }, + .name = { node->name() } + }; return sizeof(Directory_entry); } @@ -224,12 +234,15 @@ class Ram_fs::Directory : public Node Status status() override { - Status s; - s.inode = inode(); - s.size = _num_entries * sizeof(File_system::Directory_entry); - s.mode = File_system::Status::MODE_DIRECTORY; - s.modification_time = modification_time(); - return s; + return { + .size = _num_entries * sizeof(File_system::Directory_entry), + .type = File_system::Node_type::DIRECTORY, + .rwx = { .readable = true, + .writeable = true, + .executable = true }, + .inode = inode(), + .modification_time = modification_time() + }; } }; diff --git a/repos/os/src/server/ram_fs/file.h b/repos/os/src/server/ram_fs/file.h index 0f339560c..1c8ee2dfe 100644 --- a/repos/os/src/server/ram_fs/file.h +++ b/repos/os/src/server/ram_fs/file.h @@ -112,12 +112,15 @@ class Ram_fs::File : public Node Status status() override { - Status s { }; - s.inode = inode(); - s.size = _length; - s.mode = File_system::Status::MODE_FILE; - s.modification_time = modification_time(); - return s; + return { + .size = _length, + .type = File_system::Node_type::CONTINUOUS_FILE, + .rwx = { .readable = true, + .writeable = true, + .executable = true }, + .inode = inode(), + .modification_time = modification_time() + }; } void truncate(file_size_t size) override diff --git a/repos/os/src/server/ram_fs/symlink.h b/repos/os/src/server/ram_fs/symlink.h index 0f830bc70..23689a4ff 100644 --- a/repos/os/src/server/ram_fs/symlink.h +++ b/repos/os/src/server/ram_fs/symlink.h @@ -67,12 +67,15 @@ class Ram_fs::Symlink : public Node Status status() override { - Status s; - s.inode = inode(); - s.size = _len; - s.mode = File_system::Status::MODE_SYMLINK; - s.modification_time = modification_time(); - return s; + return { + .size = _len, + .type = File_system::Node_type::SYMLINK, + .rwx = { .readable = true, + .writeable = true, + .executable = true }, + .inode = inode(), + .modification_time = modification_time() + }; } }; diff --git a/repos/os/src/server/vfs/main.cc b/repos/os/src/server/vfs/main.cc index 6543a7980..6b4534921 100644 --- a/repos/os/src/server/vfs/main.cc +++ b/repos/os/src/server/vfs/main.cc @@ -485,35 +485,54 @@ class Vfs_server::Session_component : private Session_resources, ::File_system::Status fs_stat; _apply_node(node_handle, [&] (Node &node) { + Directory_service::Stat vfs_stat; if (_vfs.stat(node.path(), vfs_stat) != Directory_service::STAT_OK) throw Invalid_handle(); - fs_stat.inode = vfs_stat.inode; + auto fs_node_type = [&] (Vfs::Node_type type) + { + using To = ::File_system::Node_type; - switch (vfs_stat.mode & ( - Directory_service::STAT_MODE_DIRECTORY | - Directory_service::STAT_MODE_SYMLINK | - ::File_system::Status::MODE_FILE)) { + switch (type) { + case Vfs::Node_type::DIRECTORY: return To::DIRECTORY; + case Vfs::Node_type::SYMLINK: return To::SYMLINK; + case Vfs::Node_type::CONTINUOUS_FILE: return To::CONTINUOUS_FILE; + case Vfs::Node_type::TRANSACTIONAL_FILE: return To::TRANSACTIONAL_FILE; + }; + return To::CONTINUOUS_FILE; + }; - case Directory_service::STAT_MODE_DIRECTORY: - fs_stat.mode = ::File_system::Status::MODE_DIRECTORY; - fs_stat.size = _vfs.num_dirent(node.path()) * sizeof(Directory_entry); - return; + auto fs_node_size = [&] (Vfs::Directory_service::Stat const &vfs_stat) + { + switch (vfs_stat.type) { + case Vfs::Node_type::DIRECTORY: + return _vfs.num_dirent(node.path()) * sizeof(Directory_entry); - case Directory_service::STAT_MODE_SYMLINK: - fs_stat.mode = ::File_system::Status::MODE_SYMLINK; - break; + case Vfs::Node_type::SYMLINK: + return 0ULL; - default: /* Directory_service::STAT_MODE_FILE */ - fs_stat.mode = ::File_system::Status::MODE_FILE; - break; - } + case Vfs::Node_type::CONTINUOUS_FILE: + case Vfs::Node_type::TRANSACTIONAL_FILE: + return vfs_stat.size; + }; + return 0ULL; + }; - fs_stat.size = vfs_stat.size; - fs_stat.modification_time.value = vfs_stat.modification_time.value; + fs_stat = ::File_system::Status { + .size = fs_node_size(vfs_stat), + .type = fs_node_type(vfs_stat.type), + .rwx = { + .readable = vfs_stat.rwx.readable, + .writeable = vfs_stat.rwx.writeable, + .executable = vfs_stat.rwx.executable }, + + .inode = vfs_stat.inode, + .modification_time = { vfs_stat.modification_time.value } + }; }); + return fs_stat; } diff --git a/repos/os/src/server/vfs/node.h b/repos/os/src/server/vfs/node.h index c99199155..2e4eb3c88 100644 --- a/repos/os/src/server/vfs/node.h +++ b/repos/os/src/server/vfs/node.h @@ -726,17 +726,21 @@ struct Vfs_server::Directory : Io_node return true; } - seek_off_t seek_offset = _packet.position(); + seek_off_t const seek_offset = _packet.position(); - Directory_service::Dirent vfs_dirent; - size_t blocksize = sizeof(::File_system::Directory_entry); + size_t const blocksize = sizeof(::File_system::Directory_entry); - unsigned index = (seek_offset / blocksize); + unsigned const index = (seek_offset / blocksize); file_size out_count = 0; - bool result = _vfs_read( - (char*)&vfs_dirent, sizeof(vfs_dirent), - index * sizeof(vfs_dirent), out_count); + + Directory_service::Dirent vfs_dirent { }; + + bool const result = _vfs_read((char*)&vfs_dirent, + sizeof(vfs_dirent), + index * sizeof(vfs_dirent), + out_count); + vfs_dirent.sanitize(); if (result) { if (out_count != sizeof(vfs_dirent)) { @@ -744,30 +748,47 @@ struct Vfs_server::Directory : Io_node return true; } - ::File_system::Directory_entry *fs_dirent = - (Directory_entry *)_stream.packet_content(_packet); - fs_dirent->inode = vfs_dirent.fileno; + auto fs_dirent_type = [&] (Vfs::Directory_service::Dirent_type type) + { + using From = Vfs::Directory_service::Dirent_type; + using To = ::File_system::Node_type; - switch (vfs_dirent.type) { - case Vfs::Directory_service::DIRENT_TYPE_END: + /* + * This should never be taken because 'END' is checked as a + * precondition prior the call to of this function. + */ + To const default_result = To::CONTINUOUS_FILE; + + switch (type) { + case From::END: return default_result; + case From::DIRECTORY: return To::DIRECTORY; + case From::SYMLINK: return To::SYMLINK; + case From::CONTINUOUS_FILE: return To::CONTINUOUS_FILE; + case From::TRANSACTIONAL_FILE: return To::TRANSACTIONAL_FILE; + } + return default_result; + }; + + if (vfs_dirent.type == Vfs::Directory_service::Dirent_type::END) { _ack_packet(0); - return true; - case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: - fs_dirent->type = ::File_system::Directory_entry::TYPE_DIRECTORY; - break; - case Vfs::Directory_service::DIRENT_TYPE_SYMLINK: - fs_dirent->type = ::File_system::Directory_entry::TYPE_SYMLINK; - break; - case Vfs::Directory_service::DIRENT_TYPE_FILE: - default: - fs_dirent->type = ::File_system::Directory_entry::TYPE_FILE; - break; + } else { + + ::File_system::Directory_entry &fs_dirent = + *(Directory_entry *)_stream.packet_content(_packet); + + fs_dirent = { + .inode = vfs_dirent.fileno, + .type = fs_dirent_type(vfs_dirent.type), + .rwx = { + .readable = vfs_dirent.rwx.readable, + .writeable = vfs_dirent.rwx.writeable, + .executable = vfs_dirent.rwx.executable }, + .name = { vfs_dirent.name.buf } + }; + + _ack_packet(sizeof(Directory_entry)); } - - strncpy(fs_dirent->name, vfs_dirent.name, MAX_NAME_LEN); - - _ack_packet(sizeof(Directory_entry)); return true; } return false; diff --git a/repos/os/src/test/vfs_stress/main.cc b/repos/os/src/test/vfs_stress/main.cc index cc325dd87..4fffac447 100644 --- a/repos/os/src/test/vfs_stress/main.cc +++ b/repos/os/src/test/vfs_stress/main.cc @@ -442,7 +442,7 @@ struct Unlink_test : public Stress_test Vfs::Vfs_handle *dir_handle; assert_opendir(vfs.opendir(path, false, &dir_handle, alloc)); - Vfs::Directory_service::Dirent dirent; + Vfs::Directory_service::Dirent dirent { }; for (Vfs::file_size i = vfs.num_dirent(path); i;) { dir_handle->seek(--i * sizeof(dirent)); dir_handle->fs().queue_read(dir_handle, sizeof(dirent)); @@ -453,13 +453,13 @@ struct Unlink_test : public Stress_test Vfs::File_io_service::READ_QUEUED) _ep.wait_and_dispatch_one_io_signal(); - subpath.append(dirent.name); + subpath.append(dirent.name.buf); switch (dirent.type) { - case Vfs::Directory_service::DIRENT_TYPE_END: + case Vfs::Directory_service::Dirent_type::END: error("reached the end prematurely"); throw Exception(); - case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: + case Vfs::Directory_service::Dirent_type::DIRECTORY: empty_dir(subpath.base()); default: diff --git a/repos/ports/include/noux_session/sysio.h b/repos/ports/include/noux_session/sysio.h index f9d9fe846..9ec3f8d54 100644 --- a/repos/ports/include/noux_session/sysio.h +++ b/repos/ports/include/noux_session/sysio.h @@ -74,43 +74,7 @@ struct Noux::Sysio OPEN_MODE_CREATE = 0x0800, /* libc O_EXCL */ }; - /** - * These values are the same as in the FreeBSD libc - */ - enum { - STAT_MODE_SYMLINK = 0120000, - STAT_MODE_FILE = 0100000, - STAT_MODE_DIRECTORY = 0040000, - STAT_MODE_CHARDEV = 0020000, - STAT_MODE_BLOCKDEV = 0060000, - }; - - /* - * Must be POD (in contrast to the VFS type) because it's used in a union - */ - struct Stat - { - Vfs::file_size size; - unsigned mode; - unsigned uid; - unsigned gid; - unsigned long inode; - unsigned long device; - long long mtime; - - Stat & operator= (Vfs::Directory_service::Stat const &stat) - { - size = stat.size; - mode = stat.mode; - uid = stat.uid; - gid = stat.gid; - inode = stat.inode; - device = stat.device; - mtime = stat.modification_time.value; - - return *this; - } - }; + typedef Vfs::Directory_service::Stat Stat; /** * Argument structure used for ioctl syscall @@ -132,7 +96,7 @@ struct Noux::Sysio enum Lseek_whence { LSEEK_SET, LSEEK_CUR, LSEEK_END }; - enum { DIRENT_MAX_NAME_LEN = Vfs::Directory_service::DIRENT_MAX_NAME_LEN }; + enum { DIRENT_MAX_NAME_LEN = Vfs::Directory_service::Dirent::Name::MAX_LEN }; typedef Vfs::Directory_service::Dirent_type Dirent_type; @@ -149,7 +113,7 @@ struct Noux::Sysio { fileno = dirent.fileno; type = dirent.type; - memcpy(name, dirent.name, DIRENT_MAX_NAME_LEN); + memcpy(name, dirent.name.buf, DIRENT_MAX_NAME_LEN); return *this; } diff --git a/repos/ports/ports/gdb.hash b/repos/ports/ports/gdb.hash index 354ec23b9..614248f95 100644 --- a/repos/ports/ports/gdb.hash +++ b/repos/ports/ports/gdb.hash @@ -1 +1 @@ -b82025f7f85938ce713b6c442c693afe465dd83a +8eddf0d249a22993e57b3242112fb62f503101c9 diff --git a/repos/ports/src/lib/libc_noux/plugin.cc b/repos/ports/src/lib/libc_noux/plugin.cc index 41e489c7b..d0cf513dd 100644 --- a/repos/ports/src/lib/libc_noux/plugin.cc +++ b/repos/ports/src/lib/libc_noux/plugin.cc @@ -388,18 +388,39 @@ extern "C" int getrlimit(int resource, struct rlimit *rlim) */ static void _sysio_to_stat_struct(Noux::Sysio const *sysio, struct stat *buf) { - Genode::memset(buf, 0, sizeof(*buf)); - buf->st_uid = sysio->stat_out.st.uid; - buf->st_gid = sysio->stat_out.st.gid; - buf->st_mode = sysio->stat_out.st.mode; - buf->st_size = sysio->stat_out.st.size; - buf->st_blksize = FS_BLOCK_SIZE; - buf->st_blocks = (buf->st_size + FS_BLOCK_SIZE - 1) / FS_BLOCK_SIZE; - buf->st_ino = sysio->stat_out.st.inode; - buf->st_dev = sysio->stat_out.st.device; + unsigned const readable_bits = S_IRUSR, + writeable_bits = S_IWUSR, + executable_bits = S_IXUSR; - if (sysio->stat_out.st.mtime >= 0) - buf->st_mtime = sysio->stat_out.st.mtime; + auto type = [] (Vfs::Node_type type) + { + switch (type) { + case Vfs::Node_type::DIRECTORY: return S_IFDIR; + case Vfs::Node_type::CONTINUOUS_FILE: return S_IFREG; + case Vfs::Node_type::TRANSACTIONAL_FILE: return S_IFSOCK; + case Vfs::Node_type::SYMLINK: return S_IFLNK; + } + return 0; + }; + + Vfs::Directory_service::Stat const &src = sysio->stat_out.st; + + *buf = { }; + + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_mode = (src.rwx.readable ? readable_bits : 0) + | (src.rwx.writeable ? writeable_bits : 0) + | (src.rwx.executable ? executable_bits : 0) + | type(src.type); + buf->st_size = src.size; + buf->st_blksize = FS_BLOCK_SIZE; + buf->st_blocks = (src.size + FS_BLOCK_SIZE - 1) / FS_BLOCK_SIZE; + buf->st_ino = src.inode; + buf->st_dev = src.device; + + if (src.modification_time.value >= 0) + buf->st_mtime = src.modification_time.value; } @@ -1693,9 +1714,6 @@ namespace { sysio()->dirent_in.fd = noux_fd(fd->context); - struct dirent *dirent = (struct dirent *)buf; - Genode::memset(dirent, 0, sizeof(struct dirent)); - if (!noux_syscall(Noux::Session::SYSCALL_DIRENT)) { switch (sysio()->error.general) { @@ -1708,23 +1726,35 @@ namespace { } } - switch (sysio()->dirent_out.entry.type) { - case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: dirent->d_type = DT_DIR; break; - case Vfs::Directory_service::DIRENT_TYPE_FILE: dirent->d_type = DT_REG; break; - case Vfs::Directory_service::DIRENT_TYPE_SYMLINK: dirent->d_type = DT_LNK; break; - case Vfs::Directory_service::DIRENT_TYPE_FIFO: dirent->d_type = DT_FIFO; break; - case Vfs::Directory_service::DIRENT_TYPE_CHARDEV: dirent->d_type = DT_CHR; break; - case Vfs::Directory_service::DIRENT_TYPE_BLOCKDEV: dirent->d_type = DT_BLK; break; - case Vfs::Directory_service::DIRENT_TYPE_END: return 0; - } + using Dirent_type = Vfs::Directory_service::Dirent_type; - dirent->d_fileno = sysio()->dirent_out.entry.fileno; - dirent->d_reclen = sizeof(struct dirent); + if (sysio()->dirent_out.entry.type == Dirent_type::END) + return 0; - Genode::strncpy(dirent->d_name, sysio()->dirent_out.entry.name, - sizeof(dirent->d_name)); + auto d_type = [] (Dirent_type const &type) + { + switch (sysio()->dirent_out.entry.type) { + case Dirent_type::DIRECTORY: return DT_DIR; + case Dirent_type::CONTINUOUS_FILE: return DT_REG; + case Dirent_type::TRANSACTIONAL_FILE: return DT_REG; + case Dirent_type::SYMLINK: return DT_LNK; + case Dirent_type::END: return 0; + } + return 0; + }; - dirent->d_namlen = Genode::strlen(dirent->d_name); + struct dirent &dirent = *(struct dirent *)buf; + + dirent = { }; + + dirent.d_type = d_type(sysio()->dirent_out.entry.type); + dirent.d_fileno = sysio()->dirent_out.entry.fileno; + dirent.d_reclen = sizeof(struct dirent); + + Genode::strncpy(dirent.d_name, sysio()->dirent_out.entry.name, + sizeof(dirent.d_name)); + + dirent.d_namlen = Genode::strlen(dirent.d_name); *basep += sizeof(struct dirent); return sizeof(struct dirent); diff --git a/repos/ports/src/noux-pkg/gdb/patches/gdbserver_genode.patch b/repos/ports/src/noux-pkg/gdb/patches/gdbserver_genode.patch index 3ec38f164..508b2ebf0 100644 --- a/repos/ports/src/noux-pkg/gdb/patches/gdbserver_genode.patch +++ b/repos/ports/src/noux-pkg/gdb/patches/gdbserver_genode.patch @@ -14,14 +14,14 @@ From: Christian Prochaska gdb/gdbserver/linux-x86-low.c | 111 +++++++++++++++++++- gdb/gdbserver/linux-x86-tdesc-selftest.c | 31 ++++++ gdb/gdbserver/linux-x86-tdesc.c | 8 + - gdb/gdbserver/remote-utils.c | 11 ++ + gdb/gdbserver/remote-utils.c | 15 +++ gdb/gdbserver/server.c | 36 ++++++ gdb/gdbserver/server.h | 4 + gdb/nat/fork-inferior.c | 4 - gdb/nat/gdb_ptrace.h | 2 gdb/nat/linux-ptrace.c | 17 +++ gdb/nat/linux-ptrace.h | 4 + - 17 files changed, 418 insertions(+), 15 deletions(-) + 17 files changed, 422 insertions(+), 15 deletions(-) diff --git a/gdb/common/common-defs.h b/gdb/common/common-defs.h index eb0ec21..4dc07ce 100644 @@ -1071,7 +1071,7 @@ index c3aa20c..e5a57c0 100644 init_target_desc (*tdesc, amd64_expedite_regs); } diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c -index 45d5c8d..7b6b1be 100644 +index 45d5c8d..b246402 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -27,6 +27,12 @@ @@ -1099,6 +1099,18 @@ index 45d5c8d..7b6b1be 100644 static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR; /* FIXME headerize? */ +@@ -312,7 +321,11 @@ remote_open (const char *name) + struct stat statbuf; + + if (stat (name, &statbuf) == 0 ++#ifndef __GENODE__ + && (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))) ++#else ++ ) ++#endif + remote_desc = open (name, O_RDWR); + else + { diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index bf6302b..b6a9494 100644 --- a/gdb/gdbserver/server.c diff --git a/repos/ports/src/noux/pipe_io_channel.h b/repos/ports/src/noux/pipe_io_channel.h index 662b3ffae..9d7f8d449 100644 --- a/repos/ports/src/noux/pipe_io_channel.h +++ b/repos/ports/src/noux/pipe_io_channel.h @@ -271,7 +271,7 @@ class Noux::Pipe_sink_io_channel : public Io_channel bool fstat(Sysio &sysio) override { - sysio.fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; + sysio.fstat_out.st.type = Vfs::Node_type::CONTINUOUS_FILE; return true; } }; @@ -345,7 +345,7 @@ class Noux::Pipe_source_io_channel : public Io_channel bool fstat(Sysio &sysio) override { - sysio.fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; + sysio.fstat_out.st.type = Vfs::Node_type::CONTINUOUS_FILE; return true; } }; diff --git a/repos/ports/src/noux/syscall.cc b/repos/ports/src/noux/syscall.cc index 093674a2d..2547a0170 100644 --- a/repos/ports/src/noux/syscall.cc +++ b/repos/ports/src/noux/syscall.cc @@ -121,9 +121,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) * we use the ones specificed in the config. */ if (result) { - stat_out.uid = _user_info.uid(); - stat_out.gid = _user_info.gid(); - stat_out.inode = path_hash; } diff --git a/repos/ports/src/noux/terminal_io_channel.h b/repos/ports/src/noux/terminal_io_channel.h index 76ad18cb7..71937f4b8 100644 --- a/repos/ports/src/noux/terminal_io_channel.h +++ b/repos/ports/src/noux/terminal_io_channel.h @@ -151,12 +151,7 @@ struct Noux::Terminal_io_channel : Io_channel bool fstat(Sysio &sysio) override { - /* - * Supply stat values such that libc is happy. I.e., the libc - * is checking for the file descriptor 1 being a character - * device. - */ - sysio.fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV; + sysio.fstat_out.st.type = Vfs::Node_type::CONTINUOUS_FILE; return true; } diff --git a/repos/ports/src/noux/vfs_io_channel.h b/repos/ports/src/noux/vfs_io_channel.h index e8fb0f2d9..3c57774f3 100644 --- a/repos/ports/src/noux/vfs_io_channel.h +++ b/repos/ports/src/noux/vfs_io_channel.h @@ -269,7 +269,7 @@ struct Noux::Vfs_io_channel : Io_channel */ unsigned const index = _fh.seek() / sizeof(Sysio::Dirent); if (index < 2) { - sysio.dirent_out.entry.type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY; + sysio.dirent_out.entry.type = Vfs::Directory_service::Dirent_type::DIRECTORY; strncpy(sysio.dirent_out.entry.name, index ? ".." : ".", sizeof(sysio.dirent_out.entry.name)); @@ -284,12 +284,10 @@ struct Noux::Vfs_io_channel : Io_channel * Align index range to zero when calling the directory service. */ - Vfs::Directory_service::Dirent dirent; - Vfs::file_size noux_dirent_seek = _fh.seek(); - _fh.seek((index - 2) * sizeof(dirent)); + _fh.seek((index - 2) * sizeof(Vfs::Directory_service::Dirent)); - Vfs::file_size const count = sizeof(dirent); + Vfs::file_size const count = sizeof(Vfs::Directory_service::Dirent); Registered_no_delete vfs_io_waiter(_vfs_io_waiter_registry); @@ -298,10 +296,10 @@ struct Noux::Vfs_io_channel : Io_channel vfs_io_waiter.wait_for_io(); Vfs::File_io_service::Read_result read_result; - Vfs::file_size out_count = 0; + Vfs::file_size out_count = 0; + Vfs::Directory_service::Dirent dirent { }; for (;;) { - read_result = _fh.fs().complete_read(&_fh, (char*)&dirent, count, out_count); @@ -318,7 +316,7 @@ struct Noux::Vfs_io_channel : Io_channel if ((read_result != Vfs::File_io_service::READ_OK) || (out_count != sizeof(dirent))) { - dirent = Vfs::Directory_service::Dirent(); + dirent = { }; } _fh.seek(noux_dirent_seek);