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.
This commit is contained in:
Norman Feske 2019-09-25 17:13:29 +02:00 committed by Christian Helmuth
parent 1297a8fb57
commit 5ab1505d43
52 changed files with 1049 additions and 668 deletions

View File

@ -1107,11 +1107,7 @@ class Vfs::Lxip_socket_dir final : public Lxip::Socket_dir
Vfs::file_size index = seek_offset / sizeof(Dirent); Vfs::file_size index = seek_offset / sizeof(Dirent);
Dirent *out = (Dirent*)dst; Dirent &out = *(Dirent*)dst;
out->fileno = index+1;
out->type = Directory_service::DIRENT_TYPE_END;
out->name[0] = '\0';
Vfs::Node *node = nullptr; Vfs::Node *node = nullptr;
for (Vfs::File *n : _files) { for (Vfs::File *n : _files) {
@ -1123,11 +1119,21 @@ class Vfs::Lxip_socket_dir final : public Lxip::Socket_dir
--index; --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); return sizeof(Dirent);
} }
@ -1435,11 +1441,7 @@ class Lxip::Protocol_dir_impl : public Protocol_dir
Vfs::file_size index = seek_offset / sizeof(Dirent); Vfs::file_size index = seek_offset / sizeof(Dirent);
Dirent *out = (Dirent*)dst; Dirent &out = *(Dirent*)dst;
out->fileno = index+1;
out->type = Vfs::Directory_service::DIRENT_TYPE_END;
out->name[0] = '\0';
Vfs::Node *node = nullptr; Vfs::Node *node = nullptr;
for (Vfs::Node *n : _nodes) { for (Vfs::Node *n : _nodes) {
@ -1451,15 +1453,32 @@ class Lxip::Protocol_dir_impl : public Protocol_dir
--index; --index;
} }
} }
if (!node) return -1; if (!node) {
out = {
.fileno = index + 1,
.type = Vfs::Directory_service::Dirent_type::END,
.rwx = { },
.name = { } };
if (dynamic_cast<Vfs::Directory*>(node)) return -1;
out->type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY; }
if (dynamic_cast<Vfs::File*>(node)) typedef Vfs::Directory_service::Dirent_type Dirent_type;
out->type = Vfs::Directory_service::DIRENT_TYPE_FILE;
Genode::strncpy(out->name, node->name(), sizeof(out->name)); Dirent_type const type =
dynamic_cast<Vfs::Directory*>(node) ? Dirent_type::DIRECTORY :
dynamic_cast<Vfs::File *>(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); return sizeof(Dirent);
} }
@ -1692,44 +1711,38 @@ class Vfs::Lxip_file_system : public Vfs::File_system,
if (len < sizeof(Dirent)) if (len < sizeof(Dirent))
return -1; 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) { enum { NUM_ENTRIES = 8U };
out->fileno = (Genode::addr_t)&_tcp_dir; static Entry const entries[NUM_ENTRIES] = {
out->type = Directory_service::DIRENT_TYPE_DIRECTORY; { &_tcp_dir, Dirent_type::DIRECTORY, "tcp" },
Genode::strncpy(out->name, "tcp", sizeof(out->name)); { &_udp_dir, Dirent_type::DIRECTORY, "udp" },
} else if (index == 1) { { &_address, Dirent_type::TRANSACTIONAL_FILE, "address" },
out->fileno = (Genode::addr_t)&_udp_dir; { &_netmask, Dirent_type::TRANSACTIONAL_FILE, "netmask" },
out->type = Directory_service::DIRENT_TYPE_DIRECTORY; { &_gateway, Dirent_type::TRANSACTIONAL_FILE, "gateway" },
Genode::strncpy(out->name, "udp", sizeof(out->name)); { &_nameserver, Dirent_type::TRANSACTIONAL_FILE, "nameserver" },
} else if (index == 2) { { &_link_state, Dirent_type::TRANSACTIONAL_FILE, "link_state" },
out->fileno = (Genode::addr_t)&_address; { nullptr, Dirent_type::END, "" }
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';
}
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); 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 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; if (!node) return STAT_ERR_NO_ENTRY;
Vfs::Directory *dir = dynamic_cast<Vfs::Directory*>(node); out = { };
if (dir) {
out.mode = STAT_MODE_DIRECTORY | 0777; if (dynamic_cast<Vfs::Directory*>(node)) {
out.type = Node_type::DIRECTORY;
out.rwx = Node_rwx::rwx();
return STAT_OK; return STAT_OK;
} }
if (dynamic_cast<Lxip_file*>(node)) { if (dynamic_cast<Lxip_file*>(node)) {
out.mode = STAT_MODE_FILE | 0666; out.type = Node_type::TRANSACTIONAL_FILE;
out.rwx = Node_rwx::rw();
out.size = 0; out.size = 0;
return STAT_OK; return STAT_OK;
} }
if (dynamic_cast<Vfs::File*>(node)) { if (dynamic_cast<Vfs::File*>(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 */ out.size = 0x1000; /* there may be something to read */
return STAT_OK; return STAT_OK;
} }

View File

@ -197,25 +197,28 @@ class Vfs::Rump_file_system : public File_system
struct stat s; struct stat s;
rump_sys_lstat(path, &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)) return Dirent_type::END;
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;
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; return READ_OK;
} }
@ -699,12 +702,25 @@ class Vfs::Rump_file_system : public File_system
struct stat sb; struct stat sb;
if (rump_sys_lstat(path, &sb) != 0) return STAT_ERR_NO_ENTRY; if (rump_sys_lstat(path, &sb) != 0) return STAT_ERR_NO_ENTRY;
stat.size = sb.st_size; auto type = [] (unsigned mode)
stat.mode = sb.st_mode; {
stat.uid = sb.st_uid; if (S_ISDIR(mode)) return Node_type::DIRECTORY;
stat.gid = sb.st_gid; if (S_ISLNK(mode)) return Node_type::SYMLINK;
stat.inode = sb.st_ino;
stat.device = sb.st_dev; 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; return STAT_OK;
} }

View File

@ -218,18 +218,26 @@ class Rump_fs::Directory : public Node
struct stat s; struct stat s;
rump_sys_lstat(path, &s); rump_sys_lstat(path, &s);
Directory_entry *e = (Directory_entry *)(dst); auto type = [] (unsigned mode)
if (S_ISDIR(s.st_mode)) {
e->type = Directory_entry::TYPE_DIRECTORY; if (S_ISDIR(mode)) return Node_type::DIRECTORY;
else if (S_ISREG(s.st_mode)) else if (S_ISREG(mode)) return Node_type::CONTINUOUS_FILE;
e->type = Directory_entry::TYPE_FILE; else if (S_ISLNK(mode)) return Node_type::SYMLINK;
else if (S_ISLNK(s.st_mode)) else return Node_type::CONTINUOUS_FILE;
e->type = Directory_entry::TYPE_SYMLINK; };
else
return 0; 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); return sizeof(Directory_entry);
} }
@ -245,13 +253,15 @@ class Rump_fs::Directory : public Node
if (rump_sys_fstat(_fd, &st) < 0) if (rump_sys_fstat(_fd, &st) < 0)
st.st_mtime = 0; st.st_mtime = 0;
Status s; return {
s.inode = inode(); .size = num_entries() * sizeof (Directory_entry),
s.size = num_entries() * sizeof (Directory_entry); .type = File_system::Node_type::DIRECTORY,
s.mode = File_system::Status::MODE_DIRECTORY; .rwx = { .readable = (st.st_mode & S_IRUSR),
s.modification_time = { (int64_t)st.st_mtime }; .writeable = (st.st_mode & S_IWUSR),
.executable = (st.st_mode & S_IXUSR) },
return s; .inode = inode(),
.modification_time = { (int64_t)st.st_mtime }
};
} }
size_t num_entries() const size_t num_entries() const

View File

@ -153,20 +153,21 @@ class Rump_fs::File : public Node
virtual Status status() override virtual Status status() override
{ {
struct stat st; struct stat st { };
if (rump_sys_fstat(_fd, &st) < 0) { if (rump_sys_fstat(_fd, &st) < 0) {
st.st_size = 0; st.st_size = 0;
st.st_mtime = 0; st.st_mtime = 0;
} }
Status s; return {
.size = (file_size_t)st.st_size,
s.inode = inode(); .type = File_system::Node_type::CONTINUOUS_FILE,
s.size = st.st_size; .rwx = { .readable = (st.st_mode & S_IRUSR),
s.mode = File_system::Status::MODE_FILE; .writeable = (st.st_mode & S_IWUSR),
s.modification_time = { (int64_t)st.st_mtime }; .executable = (st.st_mode & S_IXUSR) },
.inode = inode(),
return s; .modification_time = { (int64_t)st.st_mtime }
};
} }
void truncate(file_size_t size) override void truncate(file_size_t size) override

View File

@ -78,13 +78,15 @@ class Rump_fs::Symlink : public Node
st.st_mtime = 0; st.st_mtime = 0;
} }
Status s; return {
s.inode = inode(); .size = length(),
s.size = length(); .type = File_system::Node_type::SYMLINK,
s.mode = File_system::Status::MODE_SYMLINK; .rwx = { .readable = true,
s.modification_time = { (int64_t)st.st_mtime }; .writeable = true,
.executable = true },
return s; .inode = inode(),
.modification_time = { (int64_t)st.st_mtime }
};
} }
file_size_t length() file_size_t length()

View File

@ -56,20 +56,22 @@ struct Genode::Directory : Noncopyable, Interface
{ {
using Genode::print; using Genode::print;
using Vfs::Directory_service; using Vfs::Directory_service;
using Dirent_type = Directory_service::Dirent_type;
print(out, _dirent.name, " ("); print(out, _dirent.name.buf, " (");
switch (_dirent.type) { switch (_dirent.type) {
case Directory_service::DIRENT_TYPE_FILE: print(out, "file"); break; case Dirent_type::TRANSACTIONAL_FILE: print(out, "file"); break;
case Directory_service::DIRENT_TYPE_DIRECTORY: print(out, "dir"); break; case Dirent_type::CONTINUOUS_FILE: print(out, "file"); break;
case Directory_service::DIRENT_TYPE_SYMLINK: print(out, "symlink"); break; case Dirent_type::DIRECTORY: print(out, "dir"); break;
default: print(out, "other"); break; case Dirent_type::SYMLINK: print(out, "symlink"); break;
default: print(out, "other"); break;
} }
print(out, ")"); print(out, ")");
} }
typedef String<Vfs::Directory_service::DIRENT_MAX_NAME_LEN> Name; typedef String<Vfs::Directory_service::Dirent::Name::MAX_LEN> 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; } Vfs::Directory_service::Dirent_type type() const { return _dirent.type; }
}; };
@ -118,16 +120,10 @@ struct Genode::Directory : Noncopyable, Interface
return const_cast<Vfs::File_system &>(_fs); return const_cast<Vfs::File_system &>(_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; return _nonconst_fs().stat(join(_path, rel_path).string(), out);
/*
* 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;
} }
public: public:
@ -199,7 +195,7 @@ struct Genode::Directory : Noncopyable, Interface
throw Read_dir_failed(); 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; return;
fn(entry); fn(entry);
@ -215,12 +211,23 @@ struct Genode::Directory : Noncopyable, Interface
bool file_exists(Path const &rel_path) const 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 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::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(); 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();
} }
/** /**

View File

@ -104,7 +104,11 @@ struct Fs_query::Watched_directory
_dir(other, rel_path), _watcher(other, rel_path, handler) _dir(other, rel_path), _watcher(other, rel_path, handler)
{ {
_dir.for_each_entry([&] (Directory::Entry const &entry) { _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 { try {
new (_alloc) Registered<Watched_file>(_files, _dir, entry.name(), handler); new (_alloc) Registered<Watched_file>(_files, _dir, entry.name(), handler);
} catch (...) { } } catch (...) { }

View File

@ -189,19 +189,20 @@ class Vfs_import::File_system : public Vfs::File_system
dir.for_each_entry([&] (Directory::Entry const &e) { dir.for_each_entry([&] (Directory::Entry const &e) {
auto entry_path = Directory::join(path, e.name()); auto entry_path = Directory::join(path, e.name());
switch (e.type()) { 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); copy_file(env, src, entry_path, alloc, overwrite);
break; return;
case DIRENT_TYPE_DIRECTORY: case Dirent_type::DIRECTORY:
copy_dir(env, src, entry_path, alloc, overwrite); copy_dir(env, src, entry_path, alloc, overwrite);
break; return;
case DIRENT_TYPE_SYMLINK: case Dirent_type::SYMLINK:
copy_symlink(env, src, entry_path, alloc, overwrite); copy_symlink(env, src, entry_path, alloc, overwrite);
break; return;
default: case Dirent_type::END:
Genode::warning("skipping copy of ", e); return;
break;
} }
Genode::warning("skipping copy of ", e);
}); });
} }
} }

View File

@ -128,8 +128,8 @@ class Vfs::Value_file_system : public Vfs::Single_file_system
Value_file_system(Name const &name, Buffer const &initial_value) Value_file_system(Name const &name, Buffer const &initial_value)
: :
Single_file_system(NODE_TYPE_CHAR_DEVICE, type(), Single_file_system(Node_type::TRANSACTIONAL_FILE, type(),
Xml_node(_config(name).string())), Node_rwx::rw(), Xml_node(_config(name).string())),
_file_name(name) _file_name(name)
{ {
value(initial_value); 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 stat(char const *path, Stat &out) override
{ {
Stat_result result = Single_file_system::stat(path, out); Stat_result result = Single_file_system::stat(path, out);
out.mode |= 0666;
out.size = BUF_SIZE + 1; out.size = BUF_SIZE + 1;
return result; return result;
} }

View File

@ -155,8 +155,8 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system
Trace::Connection &trace, Trace::Connection &trace,
Trace::Policy_id policy, Trace::Policy_id policy,
Trace::Subject_id id) Trace::Subject_id id)
: Single_file_system(NODE_TYPE_CHAR_DEVICE, : Single_file_system(Node_type::TRANSACTIONAL_FILE, type_name(),
type_name(), Xml_node(_config().string())), Node_rwx::rw(), Xml_node(_config().string())),
_env(env), _trace(trace), _policy(policy), _id(id) _env(env), _trace(trace), _policy(policy), _id(id)
{ } { }

View File

@ -113,7 +113,8 @@ class Vfs::Glyphs_file_system : public Vfs::Single_file_system
Glyphs_file_system(Font const &font) Glyphs_file_system(Font const &font)
: :
Single_file_system(NODE_TYPE_CHAR_DEVICE, type(), Xml_node("<glyphs/>")), Single_file_system(Node_type::TRANSACTIONAL_FILE, type(),
Node_rwx::ro(), Xml_node("<glyphs/>")),
_font(font) _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 stat(char const *path, Stat &out) override
{ {
Stat_result result = Single_file_system::stat(path, out); Stat_result result = Single_file_system::stat(path, out);
out.mode |= 0444;
out.size = FILE_SIZE; out.size = FILE_SIZE;
return result; return result;
} }

View File

@ -98,11 +98,29 @@ static void vfs_stat_to_libc_stat_struct(Vfs::Directory_service::Stat const &src
{ {
enum { FS_BLOCK_SIZE = 4096 }; 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; auto type = [] (Vfs::Node_type type)
dst->st_gid = src.gid; {
dst->st_mode = src.mode; 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_size = src.size;
dst->st_blksize = FS_BLOCK_SIZE; dst->st_blksize = FS_BLOCK_SIZE;
dst->st_blocks = (dst->st_size + FS_BLOCK_SIZE - 1) / 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); _vfs_sync(*handle);
fd->modified = false; 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, (char*)&dirent_out,
sizeof(Dirent), sizeof(Dirent),
out_count)); out_count));
dirent_out.sanitize();
/* suspend me if read is still queued */ /* suspend me if read is still queued */
@ -851,29 +881,37 @@ ssize_t Libc::Vfs_plugin::getdirentries(File_descriptor *fd, char *buf,
return 0; 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 * Convert dirent structure from VFS to libc
*/ */
struct dirent *dirent = (struct dirent *)buf; auto dirent_type = [] (Dirent_type type)
Genode::memset(dirent, 0, sizeof(struct dirent)); {
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) { dirent &dirent = *(struct dirent *)buf;
case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: dirent->d_type = DT_DIR; break; dirent = { };
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->d_fileno = dirent_out.fileno; dirent.d_type = dirent_type(dirent_out.type);
dirent->d_reclen = sizeof(struct dirent); 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. * Keep track of VFS seek pointer and user-supplied basep.

View File

@ -181,30 +181,39 @@ class Fatfs::File_system : public Vfs::File_system
cur_index = 0; cur_index = 0;
} }
Dirent *vfs_dir = (Dirent*)buf; Dirent &vfs_dirent = *(Dirent*)buf;
FILINFO info; FILINFO info;
FRESULT res; 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) { while (cur_index <= dir_index) {
res = f_readdir (&dir, &info); res = f_readdir (&dir, &info);
if ((res != FR_OK) || (!info.fname[0])) { if ((res != FR_OK) || (!info.fname[0])) {
f_readdir(&dir, nullptr); f_readdir(&dir, nullptr);
cur_index = 0; 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); out_count = sizeof(Dirent);
return READ_OK; return READ_OK;
} }
cur_index++; cur_index++;
} }
vfs_dir->type = (info.fattrib & AM_DIR) ? vfs_dirent = {
DIRENT_TYPE_DIRECTORY : DIRENT_TYPE_FILE; .fileno = fileno,
Genode::strncpy(vfs_dir->name, (const char*)info.fname, .type = (info.fattrib & AM_DIR)
sizeof(vfs_dir->name)); ? Dirent_type::DIRECTORY
: Dirent_type::CONTINUOUS_FILE,
.rwx = Node_rwx::rwx(),
.name = { (char const *)info.fname }
};
out_count = sizeof(Dirent); out_count = sizeof(Dirent);
return READ_OK; 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_result stat(char const *path, Stat &stat) override
{ {
stat = Stat(); stat = Stat { };
FILINFO info; FILINFO info;
FRESULT const err = f_stat((const TCHAR*)path, &info); FRESULT const err = f_stat((const TCHAR*)path, &info);
switch (err) { switch (err) {
case FR_OK: case FR_OK:
stat.inode = 1; stat.inode = 1;
stat.device = (Genode::addr_t)this; stat.device = (Genode::addr_t)this;
stat.mode = (info.fattrib & AM_DIR) ? stat.type = (info.fattrib & AM_DIR)
STAT_MODE_DIRECTORY : STAT_MODE_FILE; ? Vfs::Node_type::DIRECTORY
: Vfs::Node_type::CONTINUOUS_FILE;
stat.rwx = Vfs::Node_rwx::rwx();
/* XXX: size in f_stat is always zero */ /* 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); File *file = _opened_file(path);
if (file) { if (file) {
stat.size = f_size(&file->fil); stat.size = f_size(&file->fil);

View File

@ -102,7 +102,8 @@ class Jitterentropy_file_system : public Vfs::Single_file_system
Jitterentropy_file_system(Genode::Allocator &alloc, Jitterentropy_file_system(Genode::Allocator &alloc,
Genode::Xml_node config) 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), _ec_stir(0),
_initialized(_init_jitterentropy(alloc)) _initialized(_init_jitterentropy(alloc))
{ } { }

View File

@ -603,35 +603,51 @@ class Lwip::Protocol_dir_impl final : public Protocol_dir
Path subpath(path); Path subpath(path);
if (subpath == "/") { if (subpath == "/") {
st.size = 1; st = { .size = 1,
st.mode = Directory_service::STAT_MODE_DIRECTORY; .type = Node_type::DIRECTORY,
st.inode = (Genode::addr_t)this; .rwx = Node_rwx::rwx(),
.inode = (Genode::addr_t)this,
.device = 0,
.modification_time = { 0 } };
return Directory_service::STAT_OK; return Directory_service::STAT_OK;
} }
if (subpath == "/new_socket") { if (subpath == "/new_socket") {
st.size = 1; st = { .size = 1,
st.mode = Directory_service::STAT_MODE_FILE | 0777; .type = Node_type::TRANSACTIONAL_FILE,
st.inode = ((Genode::addr_t)this)+1; .rwx = Node_rwx::rw(),
.inode = (Genode::addr_t)this + 1,
.device = 0,
.modification_time = { 0 } };
return Directory_service::STAT_OK; return Directory_service::STAT_OK;
} }
if (!subpath.has_single_element()) if (!subpath.has_single_element())
subpath.strip_last_element(); subpath.strip_last_element();
if (SOCKET_DIR *dir = lookup(subpath.string())) { if (SOCKET_DIR *dir = lookup(subpath.string())) {
Path filename(path); Path filename(path);
filename.keep_only_last_element(); filename.keep_only_last_element();
if (filename == subpath.base()) { if (filename == subpath.base()) {
st.size = Lwip_file_handle::INVALID; st = { .size = 0,
st.mode = Directory_service::STAT_MODE_DIRECTORY; .type = Node_type::DIRECTORY,
st.inode = (Genode::addr_t)dir; .rwx = Node_rwx::rwx(),
.inode = (Genode::addr_t)dir,
.device = 0,
.modification_time = { 0 } };
return Directory_service::STAT_OK; return Directory_service::STAT_OK;
} }
Lwip_file_handle::Kind k = Lwip_file_handle::kind_from_name(filename); Lwip_file_handle::Kind k = Lwip_file_handle::kind_from_name(filename);
if (k != Lwip_file_handle::INVALID) { if (k != Lwip_file_handle::INVALID) {
st.mode = Directory_service::STAT_MODE_CHARDEV; st = { .size = 0,
st.inode = ((Genode::addr_t)dir)+k; .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; 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 Stat_result stat(char const *path, Stat &st) override
{ {
if (*path == '/') ++path; if (*path == '/') ++path;
st = Stat(); st = Stat { };
st.device = (Genode::addr_t)this; st.device = (Genode::addr_t)this;
if (match_address(path) || match_netmask(path)) { if (match_address(path) || match_netmask(path)) {
st.size = ADDRESS_FILE_SIZE; st = { .size = ADDRESS_FILE_SIZE,
st.mode = STAT_MODE_FILE; .type = Node_type::TRANSACTIONAL_FILE,
.rwx = Node_rwx::rw(),
.inode = (Genode::addr_t)this,
.device = 0,
.modification_time = { 0 } };
return STAT_OK; return STAT_OK;
} }
if (match_nameserver(path)) { if (match_nameserver(path)) {
st.size = IPADDR_STRLEN_MAX; st = { .size = IPADDR_STRLEN_MAX,
st.mode = STAT_MODE_FILE; .type = Node_type::TRANSACTIONAL_FILE,
.rwx = Node_rwx::rw(),
.inode = 0,
.device = 0,
.modification_time = { 0 } };
return STAT_OK; return STAT_OK;
} }

View File

@ -56,8 +56,6 @@ class Fatfs_fs::Directory : public Node
return 0; return 0;
} }
Directory_entry *e = (Directory_entry *)(dst);
using namespace Fatfs; using namespace Fatfs;
FILINFO fatfs_file_info; FILINFO fatfs_file_info;
@ -99,12 +97,17 @@ class Fatfs_fs::Directory : public Node
return 0; return 0;
} }
strncpy(e->name, fatfs_file_info.fname, sizeof(e->name)); Directory_entry &e = *(Directory_entry *)(dst);
e = {
if ((fatfs_file_info.fattrib & AM_DIR) == AM_DIR) .inode = 0,
e->type = Directory_entry::TYPE_DIRECTORY; .type = ((fatfs_file_info.fattrib & AM_DIR) == AM_DIR)
else ? Node_type::DIRECTORY
e->type = Directory_entry::TYPE_FILE; : Node_type::CONTINUOUS_FILE,
.rwx = { .readable = true,
.writeable = true,
.executable = true },
.name = { fatfs_file_info.fname }
};
return sizeof(Directory_entry); return sizeof(Directory_entry);
} }

View File

@ -133,6 +133,10 @@ class Fatfs_fs::Session_component : public Session_rpc_object
succeeded = true; succeeded = true;
/* not supported */ /* not supported */
break; break;
case Packet_descriptor::WRITE_TIMESTAMP:
succeeded = false;
break;
} }
packet.length(res_length); packet.length(res_length);
@ -537,8 +541,9 @@ class Fatfs_fs::Session_component : public Session_rpc_object
Status status; Status status;
status.inode = 1; status.inode = 1;
status.size = 0; status.size = 0;
status.mode = 0; status.rwx = { .readable = true,
.writeable = true,
.executable = true };
Node &node = open_node.node(); Node &node = open_node.node();
using namespace Fatfs; 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) { if ((fatfs_file_info.fattrib & AM_DIR) == AM_DIR) {
status.mode = File_system::Status::MODE_DIRECTORY; } status.type = File_system::Node_type::DIRECTORY; }
else { else {
status.mode = File_system::Status::MODE_FILE; status.type = File_system::Node_type::CONTINUOUS_FILE;
status.size = fatfs_file_info.fsize; status.size = fatfs_file_info.fsize;
} }
} else { } 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 */ /* determine the number of directory entries */

View File

@ -16,6 +16,7 @@
#ifndef _INCLUDE__FILE_SYSTEM_SESSION__FILE_SYSTEM_SESSION_H_ #ifndef _INCLUDE__FILE_SYSTEM_SESSION__FILE_SYSTEM_SESSION_H_
#define _INCLUDE__FILE_SYSTEM_SESSION__FILE_SYSTEM_SESSION_H_ #define _INCLUDE__FILE_SYSTEM_SESSION__FILE_SYSTEM_SESSION_H_
#include <util/string.h>
#include <base/exception.h> #include <base/exception.h>
#include <os/packet_stream.h> #include <os/packet_stream.h>
#include <packet_stream_tx/packet_stream_tx.h> #include <packet_stream_tx/packet_stream_tx.h>
@ -66,6 +67,20 @@ namespace File_system {
typedef Symlink::Id Symlink_handle; typedef Symlink::Id Symlink_handle;
typedef Watch::Id Watch_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; using Genode::size_t;
typedef Genode::uint64_t seek_off_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 struct File_system::Status
{ {
enum {
MODE_SYMLINK = 0020000,
MODE_FILE = 0100000,
MODE_DIRECTORY = 0040000,
};
/*
* XXX add executable bit
*/
file_size_t size; file_size_t size;
unsigned mode; Node_type type;
Node_rwx rwx;
unsigned long inode; unsigned long inode;
Timestamp modification_time; Timestamp modification_time;
/** /**
* Return true if node is a directory * 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 * 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 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; unsigned long inode;
Type type; Node_type type;
char name[MAX_NAME_LEN]; 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;
}
}; };

View File

@ -343,8 +343,8 @@ class Vfs::Dir_file_system : public File_system
if (count < sizeof(Dirent)) if (count < sizeof(Dirent))
return READ_ERR_INVALID; return READ_ERR_INVALID;
Dirent *dirent = (Dirent*)dst; Dirent &dirent = *(Dirent*)dst;
*dirent = Dirent(); dirent = Dirent { };
out_count = sizeof(Dirent); out_count = sizeof(Dirent);
@ -456,13 +456,14 @@ class Vfs::Dir_file_system : public File_system
* current directory. * current directory.
*/ */
if (strlen(path) == 0 || _top_dir(path)) { if (strlen(path) == 0 || _top_dir(path)) {
out.size = 0; out = {
out.mode = STAT_MODE_DIRECTORY | 0755; .size = 0,
out.uid = 0; .type = Node_type::DIRECTORY,
out.gid = 0; .rwx = Node_rwx::rwx(),
out.inode = 1; .inode = 1,
out.device = (Genode::addr_t)this; .device = (Genode::addr_t)this,
out.modification_time = { Vfs::Timestamp::INVALID }; .modification_time = { Vfs::Timestamp::INVALID },
};
return STAT_OK; 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); return _complete_read_of_file_systems(dir_vfs_handle, dst, count, out_count);
if (_top_dir(dir_vfs_handle->path.base())) { 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) { if (index == 0) {
strncpy(dirent->name, _name.string(), sizeof(dirent->name));
dirent->type = DIRENT_TYPE_DIRECTORY; dirent = {
dirent->fileno = 1; .fileno = 1,
.type = Dirent_type::DIRECTORY,
.rwx = Node_rwx::rwx(),
.name = { _name.string() }
};
} else { } else {
dirent->type = DIRENT_TYPE_END;
dirent = {
.fileno = 0,
.type = Dirent_type::END,
.rwx = { },
.name = { }
};
} }
out_count = sizeof(Dirent); out_count = sizeof(Dirent);

View File

@ -141,26 +141,14 @@ struct Vfs::Directory_service : Interface
** Stat ** ** 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 struct Stat
{ {
file_size size = 0; file_size size;
unsigned mode = 0; Node_type type;
unsigned uid = 0; Node_rwx rwx;
unsigned gid = 0; unsigned long inode;
unsigned long inode = 0; unsigned long device;
unsigned long device = 0; Timestamp modification_time;
Timestamp modification_time { Timestamp::INVALID };
}; };
enum Stat_result { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS, enum Stat_result { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS,
@ -177,23 +165,42 @@ struct Vfs::Directory_service : Interface
** Dirent ** ** Dirent **
************/ ************/
enum { DIRENT_MAX_NAME_LEN = 128 }; enum class Dirent_type
{
enum Dirent_type { END,
DIRENT_TYPE_FILE, DIRECTORY,
DIRENT_TYPE_DIRECTORY, SYMLINK,
DIRENT_TYPE_FIFO, CONTINUOUS_FILE,
DIRENT_TYPE_CHARDEV, TRANSACTIONAL_FILE,
DIRENT_TYPE_BLOCKDEV,
DIRENT_TYPE_SYMLINK,
DIRENT_TYPE_END
}; };
struct Dirent struct Dirent
{ {
unsigned long fileno = 0; struct Name
Dirent_type type = DIRENT_TYPE_END; {
char name[DIRENT_MAX_NAME_LEN] = { 0 }; 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;
}
}; };

View File

@ -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) Readonly_value_file_system(Name const &name, T const &initial_value)
: :
Single_file_system(NODE_TYPE_CHAR_DEVICE, type(), Single_file_system(Node_type::TRANSACTIONAL_FILE, type(),
Xml_node(_config(name).string())), Node_rwx::ro(), Xml_node(_config(name).string())),
_file_name(name) _file_name(name)
{ {
value(initial_value); 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 stat(char const *path, Stat &out) override
{ {
Stat_result result = Single_file_system::stat(path, out); Stat_result result = Single_file_system::stat(path, out);
out.mode |= 0444;
out.size = _buffer.length(); out.size = _buffer.length();
return result; return result;
} }

View File

@ -22,16 +22,10 @@ namespace Vfs { class Single_file_system; }
class Vfs::Single_file_system : public 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: private:
Node_type const _node_type; Node_type const _type;
Node_rwx const _rwx;
typedef String<64> Filename; typedef String<64> Filename;
@ -61,8 +55,10 @@ class Vfs::Single_file_system : public File_system
{ {
private: private:
Node_type _node_type; Node_type const _type;
char const *_filename; Node_rwx const _rwx;
Filename const &_filename;
/* /*
* Noncopyable * Noncopyable
@ -75,12 +71,12 @@ class Vfs::Single_file_system : public File_system
Single_vfs_dir_handle(Directory_service &ds, Single_vfs_dir_handle(Directory_service &ds,
File_io_service &fs, File_io_service &fs,
Genode::Allocator &alloc, Genode::Allocator &alloc,
Node_type node_type, Node_type type,
char const *filename) Node_rwx rwx,
Filename const &filename)
: :
Single_vfs_handle(ds, fs, alloc, 0), Single_vfs_handle(ds, fs, alloc, 0),
_node_type(node_type), _type(type), _rwx(rwx), _filename(filename)
_filename(filename)
{ } { }
Read_result read(char *dst, file_size count, 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); 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) { if (index == 0) {
out->fileno = (Genode::addr_t)this; out = {
switch (_node_type) { .fileno = (Genode::addr_t)this,
case NODE_TYPE_FILE: out->type = DIRENT_TYPE_FILE; break; .type = dirent_type(),
case NODE_TYPE_SYMLINK: out->type = DIRENT_TYPE_SYMLINK; break; .rwx = _rwx,
case NODE_TYPE_CHAR_DEVICE: out->type = DIRENT_TYPE_CHARDEV; break; .name = { _filename.string() }
case NODE_TYPE_BLOCK_DEVICE: out->type = DIRENT_TYPE_BLOCKDEV; break; };
}
strncpy(out->name, _filename, sizeof(out->name));
} else { } else {
out->type = DIRENT_TYPE_END; out = {
.fileno = (Genode::addr_t)this,
.type = Dirent_type::END,
.rwx = { },
.name = { }
};
} }
out_count = sizeof(Dirent); out_count = sizeof(Dirent);
@ -134,9 +144,12 @@ class Vfs::Single_file_system : public File_system
public: 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))) _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 Stat_result stat(char const *path, Stat &out) override
{ {
out = Stat(); out = Stat { };
out.device = (Genode::addr_t)this; out.device = (Genode::addr_t)this;
if (_root(path)) { if (_root(path)) {
out.mode = STAT_MODE_DIRECTORY; out.type = Node_type::DIRECTORY;
} else if (_single_file(path)) { } else if (_single_file(path)) {
switch (_node_type) { out.type = _type;
case NODE_TYPE_FILE: out.mode = STAT_MODE_FILE; break; out.rwx = _rwx;
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.inode = 1; out.inode = 1;
} else { } else {
return STAT_ERR_NO_ENTRY; return STAT_ERR_NO_ENTRY;
@ -208,7 +217,7 @@ class Vfs::Single_file_system : public File_system
try { try {
*out_handle = new (alloc) *out_handle = new (alloc)
Single_vfs_dir_handle(*this, *this, alloc, Single_vfs_dir_handle(*this, *this, alloc,
_node_type, _filename.string()); _type, _rwx, _filename);
return OPENDIR_OK; return OPENDIR_OK;
} }
catch (Genode::Out_of_ram) { return OPENDIR_ERR_OUT_OF_RAM; } catch (Genode::Out_of_ram) { return OPENDIR_ERR_OUT_OF_RAM; }

View File

@ -55,6 +55,36 @@ namespace Vfs {
long long value; 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<MAX_PATH_LEN> Absolute_path; typedef Genode::Path<MAX_PATH_LEN> Absolute_path;
} }

View File

@ -50,8 +50,8 @@ class Cli_monitor::Subsystem_config_registry
unsigned _subsystem_suffix(Vfs::Directory_service::Dirent const &dirent) unsigned _subsystem_suffix(Vfs::Directory_service::Dirent const &dirent)
{ {
unsigned found = 0; unsigned found = 0;
for (unsigned i = 0; i < sizeof(dirent.name) && dirent.name[i]; i++) for (unsigned i = 0; i < sizeof(dirent.name.buf) && dirent.name.buf[i]; i++)
if (Genode::strcmp(_subsystem_suffix(), &dirent.name[i]) == 0) if (Genode::strcmp(_subsystem_suffix(), &dirent.name.buf[i]) == 0)
found = i; found = i;
return found; return found;
@ -155,7 +155,7 @@ class Cli_monitor::Subsystem_config_registry
/* iterate over the directory entries */ /* iterate over the directory entries */
for (unsigned i = 0;; i++) { for (unsigned i = 0;; i++) {
Vfs::Directory_service::Dirent dirent; Vfs::Directory_service::Dirent dirent { };
dir_handle->seek(i * sizeof(dirent)); dir_handle->seek(i * sizeof(dirent));
dir_handle->fs().queue_read(dir_handle, 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) Vfs::File_io_service::READ_QUEUED)
_ep.wait_and_dispatch_one_io_signal(); _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); _fs.close(dir_handle);
return; return;
} }
@ -179,8 +179,8 @@ class Cli_monitor::Subsystem_config_registry
if (subsystem_suffix) { if (subsystem_suffix) {
/* subsystem name is file name without the suffix */ /* subsystem name is file name without the suffix */
char name[sizeof(dirent.name)]; char name[sizeof(dirent.name.buf)];
Genode::strncpy(name, dirent.name, subsystem_suffix + 1); Genode::strncpy(name, dirent.name.buf, subsystem_suffix + 1);
try { try {
for_config(name, fn); for_config(name, fn);

View File

@ -326,7 +326,8 @@ class Vfs::Block_file_system : public Single_file_system
Block_file_system(Vfs::Env &env, Genode::Xml_node config) 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), _env(env),
_label(config.attribute_value("label", Label())), _label(config.attribute_value("label", Label())),
_block_buffer(0), _block_buffer(0),

View File

@ -69,6 +69,50 @@ class Vfs::Fs_file_system : public File_system
struct Fs_vfs_handle; struct Fs_vfs_handle;
typedef Genode::Fifo<Fs_vfs_handle> Fs_vfs_handle_queue; typedef Genode::Fifo<Fs_vfs_handle> 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, struct Fs_vfs_handle : Vfs_handle,
private ::File_system::Node, private ::File_system::Node,
private Handle_space::Element, private Handle_space::Element,
@ -295,41 +339,38 @@ class Vfs::Fs_file_system : public File_system
using ::File_system::Directory_entry; using ::File_system::Directory_entry;
Directory_entry entry; Directory_entry entry { };
file_size entry_out_count; file_size entry_out_count = 0;
Read_result read_result = Read_result const read_result =
_complete_read(&entry, DIRENT_SIZE, entry_out_count); _complete_read(&entry, DIRENT_SIZE, entry_out_count);
if (read_result != READ_OK) if (read_result != READ_OK)
return read_result; return read_result;
Dirent *dirent = (Dirent*)dst; entry.sanitize();
Dirent &dirent = *(Dirent*)dst;
if (entry_out_count < DIRENT_SIZE) { if (entry_out_count < DIRENT_SIZE) {
/* no entry found for the given index, or error */ /* 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); out_count = sizeof(Dirent);
return READ_OK; return READ_OK;
} }
/* dirent = Dirent {
* The default value has no meaning because the switch below .fileno = entry.inode,
* assigns a value in each possible branch. But it is needed to .type = _dirent_type(entry.type),
* keep the compiler happy. .rwx = _node_rwx(entry.rwx),
*/ .name = { entry.name.buf }
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));
out_count = sizeof(Dirent); out_count = sizeof(Dirent);
@ -646,20 +687,13 @@ class Vfs::Fs_file_system : public File_system
out = Stat(); out = Stat();
out.size = status.size; out.size = status.size;
out.mode = STAT_MODE_FILE | 0777; out.type = _node_type(status.type);
out.rwx = _node_rwx(status.rwx);
if (status.symlink()) out.inode = status.inode;
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.device = (Genode::addr_t)this; out.device = (Genode::addr_t)this;
out.modification_time.value = status.modification_time.value; out.modification_time.value = status.modification_time.value;
return STAT_OK; return STAT_OK;
} }

View File

@ -103,7 +103,9 @@ class Vfs::Inline_file_system : public Single_file_system
*/ */
Inline_file_system(Vfs::Env&, Genode::Xml_node config) 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"; } 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 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) { _node.with_raw_content([&] (char const *, Genode::size_t size) {
out.size = size; }); out.size = size; });
return result; return result;
} }
}; };

View File

@ -141,7 +141,8 @@ class Vfs::Log_file_system : public Single_file_system
Log_file_system(Vfs::Env &env, Log_file_system(Vfs::Env &env,
Genode::Xml_node config) 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())), _label(config.attribute_value("label", Label())),
_log(_log_session(env.env())) _log(_log_session(env.env()))
{ } { }

View File

@ -24,7 +24,8 @@ struct Vfs::Null_file_system : Single_file_system
{ {
Null_file_system(Vfs::Env&, Genode::Xml_node config) 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"; } static char const *name() { return "null"; }

View File

@ -169,6 +169,13 @@ class Vfs_ram::Node : private Genode::Avl_node<Node>, private Genode::Lock
Vfs::Timestamp modification_time() const { return _modification_time; } 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) virtual size_t read(char*, size_t, file_size)
{ {
Genode::error("Vfs_ram::Node::read() called"); 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); file_offset index = seek_offset / sizeof(Dirent);
Dirent *dirent = (Dirent*)dst; Dirent &dirent = *(Dirent*)dst;
*dirent = Dirent();
using Dirent_type = Vfs::Directory_service::Dirent_type;
out_count = sizeof(Dirent); out_count = sizeof(Dirent);
Node *node = _entries.first(); Node *node_ptr = _entries.first();
if (node) node = node->index(index); if (node_ptr) node_ptr = node_ptr->index(index);
if (!node) { if (!node_ptr) {
dirent->type = Directory_service::DIRENT_TYPE_END; dirent.type = Dirent_type::END;
return Vfs::File_io_service::READ_OK; return Vfs::File_io_service::READ_OK;
} }
dirent->fileno = node->inode; Node &node = *node_ptr;
strncpy(dirent->name, node->name(), sizeof(dirent->name));
File *file = dynamic_cast<File *>(node); auto dirent_type = [&] ()
if (file) { {
dirent->type = Directory_service::DIRENT_TYPE_FILE; if (dynamic_cast<File *>(node_ptr)) return Dirent_type::CONTINUOUS_FILE;
return Vfs::File_io_service::READ_OK; if (dynamic_cast<Directory *>(node_ptr)) return Dirent_type::DIRECTORY;
} if (dynamic_cast<Symlink *>(node_ptr)) return Dirent_type::SYMLINK;
Directory *dir = dynamic_cast<Directory *>(node); return Dirent_type::END;
if (dir) { };
dirent->type = Directory_service::DIRENT_TYPE_DIRECTORY;
return Vfs::File_io_service::READ_OK;
}
Symlink *symlink = dynamic_cast<Symlink *>(node); Dirent_type const type = dirent_type();
if (symlink) {
dirent->type = Directory_service::DIRENT_TYPE_SYMLINK;
return Vfs::File_io_service::READ_OK;
}
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; using namespace Vfs_ram;
Node *node = lookup(path); Node *node_ptr = lookup(path);
if (!node) return STAT_ERR_NO_ENTRY; if (!node_ptr) return STAT_ERR_NO_ENTRY;
Node::Guard guard(node);
stat.size = node->length(); Node::Guard guard(node_ptr);
stat.inode = node->inode;
stat.device = (Genode::addr_t)this;
stat.modification_time = node->modification_time();
File *file = dynamic_cast<File *>(node); Node &node = *node_ptr;
if (file) {
stat.mode = STAT_MODE_FILE | 0777;
return STAT_OK;
}
Directory *dir = dynamic_cast<Directory *>(node); auto node_type = [&] ()
if (dir) { {
stat.mode = STAT_MODE_DIRECTORY | 0777; if (dynamic_cast<Directory *>(node_ptr)) return Node_type::DIRECTORY;
return STAT_OK; if (dynamic_cast<Symlink *>(node_ptr)) return Node_type::SYMLINK;
}
Symlink *symlink = dynamic_cast<Symlink *>(node); return Node_type::CONTINUOUS_FILE;
if (symlink) { };
stat.mode = STAT_MODE_SYMLINK | 0777;
return STAT_OK;
}
/* this should never happen */ stat = {
return STAT_ERR_NO_ENTRY; .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 Rename_result rename(char const *from, char const *to) override

View File

@ -107,7 +107,8 @@ class Vfs::Rom_file_system : public Single_file_system
Rom_file_system(Vfs::Env &env, Rom_file_system(Vfs::Env &env,
Genode::Xml_node config) 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 */ /* use 'label' attribute if present, fall back to 'name' if not */
_label(config.attribute_value("label", _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 * found a file), obtain the size of the most current ROM module
* version. * version.
*/ */
if (out.mode == STAT_MODE_FILE) { if (out.type == Node_type::CONTINUOUS_FILE) {
_rom.update(); _rom.update();
out.size = _rom.valid() ? _rom.size() : 0; out.size = _rom.valid() ? _rom.size() : 0;
out.mode |= 0555; out.rwx = { .readable = true,
.writeable = false,
.executable = true };
} }
return result; return result;

View File

@ -103,7 +103,8 @@ class Vfs::Rtc_file_system : public Single_file_system
Rtc_file_system(Vfs::Env &env, Genode::Xml_node config) 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()), _rtc(env.env()),
_set_signal_handler(env.env().ep(), *this, _set_signal_handler(env.env().ep(), *this,
&Rtc_file_system::_handle_set_signal) &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 stat(char const *path, Stat &out) override
{ {
Stat_result result = Single_file_system::stat(path, out); return Single_file_system::stat(path, out);
out.mode |= 0444;
return result;
} }
Watch_result watch(char const *path, Watch_result watch(char const *path,

View File

@ -60,7 +60,8 @@ class Vfs::Symlink_file_system : public Single_file_system
Symlink_file_system(Vfs::Env&, Genode::Xml_node config) 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())) _target(config.attribute_value("target", Target()))
{ } { }

View File

@ -110,12 +110,22 @@ class Vfs::Tar_file_system : public File_system
TYPE_LONG_LINK = 75, TYPE_LONG_NAME = 76 TYPE_LONG_LINK = 75, TYPE_LONG_NAME = 76
}; };
file_size size() const { return _long_name() ? _next()->size() : _read(_size); } file_size size() const { return _long_name() ? _next()->size() : _read(_size); }
unsigned uid() const { return _long_name() ? _next()->uid() : _read(_uid); } long long mtime() const { return _long_name() ? _next()->mtime() : _read(_mtime); }
unsigned gid() const { return _long_name() ? _next()->gid() : _read(_gid); } unsigned uid() const { return _long_name() ? _next()->uid() : _read(_uid); }
unsigned mode() const { return _long_name() ? _next()->mode() : _read(_mode); } unsigned gid() const { return _long_name() ? _next()->gid() : _read(_gid); }
unsigned type() const { return _long_name() ? _next()->type() : _read(_type); } unsigned mode() const { return _long_name() ? _next()->mode() : _read(_mode); }
void *data() const { return _long_name() ? _next()->data() : (void *)_data_begin(); } 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; } char const *name() const { return _long_name() ? _data_begin() : _name; }
unsigned max_name_len() const { return _long_name() ? MAX_PATH_LEN : 100; } 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)) if (count < sizeof(Dirent))
return READ_ERR_INVALID; return READ_ERR_INVALID;
Dirent *dirent = (Dirent*)dst; Dirent &dirent = *(Dirent*)dst;
/* initialize */ file_offset const index = seek() / sizeof(Dirent);
*dirent = Dirent();
file_offset index = seek() / sizeof(Dirent); Node const *node_ptr = _node->lookup_child(index);
Node const *node = _node->lookup_child(index); if (!node_ptr) {
dirent = Dirent { };
if (!node) out_count = 0;
return READ_OK; 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<Tar_file_system&>(fs()); Tar_file_system &tar_fs = static_cast<Tar_file_system&>(fs());
Node const *target = tar_fs.dereference(record->linked_name()); Node const *target = tar_fs.dereference(record_ptr->linked_name());
record = target ? target->record : 0; record_ptr = target ? target->record : 0;
} }
if (record) { using Dirent_type = Vfs::Directory_service::Dirent_type;
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;
default: /* if no record exists, assume it is a directory */
Genode::error("unhandled record type ", record->type(), " " if (!record_ptr) {
"for ", node->name); dirent = {
} .fileno = (Genode::addr_t)node_ptr,
} else { .type = Dirent_type::DIRECTORY,
/* If no record exists, assume it is a directory */ .rwx = Node_rwx::rx(),
dirent->type = DIRENT_TYPE_DIRECTORY; .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); out_count = sizeof(Dirent);
return READ_OK; return READ_OK;
} }
}; };
@ -576,35 +603,40 @@ class Vfs::Tar_file_system : public File_system
Stat_result stat(char const *path, Stat &out) override Stat_result stat(char const *path, Stat &out) override
{ {
out = Stat(); out = Stat { };
Node const *node = dereference(path); Node const *node_ptr = dereference(path);
if (!node) if (!node_ptr)
return STAT_ERR_NO_ENTRY; return STAT_ERR_NO_ENTRY;
if (!node->record) { if (!node_ptr->record) {
out.mode = STAT_MODE_DIRECTORY; out.type = Node_type::DIRECTORY;
out.rwx = Node_rwx::rx();
return STAT_OK; return STAT_OK;
} }
Record const *record = node->record; Record const &record = *node_ptr->record;
/* convert TAR record modes to stat modes */ auto node_type = [&] ()
unsigned mode = record->mode(); {
switch (record->type()) { switch (record.type()) {
case Record::TYPE_FILE: mode |= STAT_MODE_FILE; break; case Record::TYPE_FILE: return Node_type::CONTINUOUS_FILE;
case Record::TYPE_SYMLINK: mode |= STAT_MODE_SYMLINK; break; case Record::TYPE_SYMLINK: return Node_type::SYMLINK;
case Record::TYPE_DIR: mode |= STAT_MODE_DIRECTORY; break; case Record::TYPE_DIR: return Node_type::DIRECTORY;
};
return Node_type::DIRECTORY;
};
default: break; out = {
} .size = record.size(),
.type = node_type(),
out.mode = mode; .rwx = { .readable = true,
out.size = record->size(); .writeable = false,
out.uid = record->uid(); .executable = record.rwx().executable },
out.gid = record->gid(); .inode = (Genode::addr_t)node_ptr,
out.inode = (Genode::addr_t)node; .device = (Genode::addr_t)this,
out.device = (Genode::addr_t)this; .modification_time = { record.mtime() }
};
return STAT_OK; return STAT_OK;
} }

View File

@ -101,7 +101,8 @@ class Vfs::Terminal_file_system : public Single_file_system
Terminal_file_system(Vfs::Env &env, Genode::Xml_node config) 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())), _label(config.attribute_value("label", Label())),
_env(env.env()) _env(env.env())
{ {

View File

@ -24,7 +24,8 @@ struct Vfs::Zero_file_system : Single_file_system
{ {
Zero_file_system(Vfs::Env&, Genode::Xml_node config) 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"; } static char const *name() { return "zero"; }

View File

@ -69,7 +69,7 @@ class Lx_fs::Directory : public Node
} }
} }
struct stat s; struct stat s { };
ret = lstat(path, &s); ret = lstat(path, &s);
if (ret == -1) if (ret == -1)
@ -203,19 +203,30 @@ class Lx_fs::Directory : public Node
if (!dent) if (!dent)
return 0; return 0;
Directory_entry *e = (Directory_entry *)(dst); Path dent_path(dent->d_name, _path.base());
switch (dent->d_type) { struct stat st { };
case DT_REG: e->type = Directory_entry::TYPE_FILE; break; lstat(dent_path.base(), &st);
case DT_DIR: e->type = Directory_entry::TYPE_DIRECTORY; break;
case DT_LNK: e->type = Directory_entry::TYPE_SYMLINK; break;
default:
return 0;
}
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); return sizeof(Directory_entry);
} }
@ -228,18 +239,21 @@ class Lx_fs::Directory : public Node
Status status() override Status status() override
{ {
struct stat st; struct stat st { };
int fd = dirfd(_fd); int fd = dirfd(_fd);
if (fd == -1 || fstat(fd, &st) < 0) if (fd == -1 || fstat(fd, &st) < 0)
st.st_mtime = 0; st.st_mtime = 0;
Status s; return {
s.inode = inode(); .size = _num_entries() * sizeof(File_system::Directory_entry),
s.size = _num_entries() * sizeof(File_system::Directory_entry); .type = Node_type::DIRECTORY,
s.mode = File_system::Status::MODE_DIRECTORY; .rwx = { .readable = (st.st_mode & S_IRUSR),
s.modification_time = { st.st_mtime }; .writeable = (st.st_mode & S_IWUSR),
return s; .executable = (st.st_mode & S_IXUSR) },
.inode = inode(),
.modification_time = { st.st_mtime }
};
} }
}; };

View File

@ -143,19 +143,22 @@ class Lx_fs::File : public Node
Status status() override Status status() override
{ {
struct stat st; struct stat st { };
if (fstat(_fd, &st) < 0) { if (fstat(_fd, &st) < 0) {
st.st_size = 0; st.st_size = 0;
st.st_mtime = 0; st.st_mtime = 0;
} }
Status s; return {
s.inode = inode(); .size = (file_size_t)st.st_size,
s.size = st.st_size; .type = File_system::Node_type::CONTINUOUS_FILE,
s.mode = File_system::Status::MODE_FILE; .rwx = { .readable = (st.st_mode & S_IRUSR),
s.modification_time = { st.st_mtime }; .writeable = (st.st_mode & S_IWUSR),
return s; .executable = (st.st_mode & S_IXUSR) },
.inode = inode(),
.modification_time = { st.st_mtime }
};
} }
void truncate(file_size_t size) override void truncate(file_size_t size) override

View File

@ -203,15 +203,25 @@ class Ram_fs::Directory : public Node
if (!node) if (!node)
return 0; return 0;
Directory_entry *e = (Directory_entry *)(dst); auto type = [&] ()
{
using Node_type = File_system::Node_type;
e->inode = node->inode(); if (dynamic_cast<Directory *>(node)) return Node_type::DIRECTORY;
if (dynamic_cast<Symlink *>(node)) return Node_type::SYMLINK;
return Node_type::CONTINUOUS_FILE;
};
if (dynamic_cast<File *>(node)) e->type = Directory_entry::TYPE_FILE; Directory_entry &e = *(Directory_entry *)(dst);
if (dynamic_cast<Directory *>(node)) e->type = Directory_entry::TYPE_DIRECTORY;
if (dynamic_cast<Symlink *>(node)) e->type = Directory_entry::TYPE_SYMLINK;
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); return sizeof(Directory_entry);
} }
@ -224,12 +234,15 @@ class Ram_fs::Directory : public Node
Status status() override Status status() override
{ {
Status s; return {
s.inode = inode(); .size = _num_entries * sizeof(File_system::Directory_entry),
s.size = _num_entries * sizeof(File_system::Directory_entry); .type = File_system::Node_type::DIRECTORY,
s.mode = File_system::Status::MODE_DIRECTORY; .rwx = { .readable = true,
s.modification_time = modification_time(); .writeable = true,
return s; .executable = true },
.inode = inode(),
.modification_time = modification_time()
};
} }
}; };

View File

@ -112,12 +112,15 @@ class Ram_fs::File : public Node
Status status() override Status status() override
{ {
Status s { }; return {
s.inode = inode(); .size = _length,
s.size = _length; .type = File_system::Node_type::CONTINUOUS_FILE,
s.mode = File_system::Status::MODE_FILE; .rwx = { .readable = true,
s.modification_time = modification_time(); .writeable = true,
return s; .executable = true },
.inode = inode(),
.modification_time = modification_time()
};
} }
void truncate(file_size_t size) override void truncate(file_size_t size) override

View File

@ -67,12 +67,15 @@ class Ram_fs::Symlink : public Node
Status status() override Status status() override
{ {
Status s; return {
s.inode = inode(); .size = _len,
s.size = _len; .type = File_system::Node_type::SYMLINK,
s.mode = File_system::Status::MODE_SYMLINK; .rwx = { .readable = true,
s.modification_time = modification_time(); .writeable = true,
return s; .executable = true },
.inode = inode(),
.modification_time = modification_time()
};
} }
}; };

View File

@ -485,35 +485,54 @@ class Vfs_server::Session_component : private Session_resources,
::File_system::Status fs_stat; ::File_system::Status fs_stat;
_apply_node(node_handle, [&] (Node &node) { _apply_node(node_handle, [&] (Node &node) {
Directory_service::Stat vfs_stat; Directory_service::Stat vfs_stat;
if (_vfs.stat(node.path(), vfs_stat) != Directory_service::STAT_OK) if (_vfs.stat(node.path(), vfs_stat) != Directory_service::STAT_OK)
throw Invalid_handle(); 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 & ( switch (type) {
Directory_service::STAT_MODE_DIRECTORY | case Vfs::Node_type::DIRECTORY: return To::DIRECTORY;
Directory_service::STAT_MODE_SYMLINK | case Vfs::Node_type::SYMLINK: return To::SYMLINK;
::File_system::Status::MODE_FILE)) { 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: auto fs_node_size = [&] (Vfs::Directory_service::Stat const &vfs_stat)
fs_stat.mode = ::File_system::Status::MODE_DIRECTORY; {
fs_stat.size = _vfs.num_dirent(node.path()) * sizeof(Directory_entry); switch (vfs_stat.type) {
return; case Vfs::Node_type::DIRECTORY:
return _vfs.num_dirent(node.path()) * sizeof(Directory_entry);
case Directory_service::STAT_MODE_SYMLINK: case Vfs::Node_type::SYMLINK:
fs_stat.mode = ::File_system::Status::MODE_SYMLINK; return 0ULL;
break;
default: /* Directory_service::STAT_MODE_FILE */ case Vfs::Node_type::CONTINUOUS_FILE:
fs_stat.mode = ::File_system::Status::MODE_FILE; case Vfs::Node_type::TRANSACTIONAL_FILE:
break; return vfs_stat.size;
} };
return 0ULL;
};
fs_stat.size = vfs_stat.size; fs_stat = ::File_system::Status {
fs_stat.modification_time.value = vfs_stat.modification_time.value; .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; return fs_stat;
} }

View File

@ -726,17 +726,21 @@ struct Vfs_server::Directory : Io_node
return true; return true;
} }
seek_off_t seek_offset = _packet.position(); seek_off_t const seek_offset = _packet.position();
Directory_service::Dirent vfs_dirent; size_t const blocksize = sizeof(::File_system::Directory_entry);
size_t blocksize = sizeof(::File_system::Directory_entry);
unsigned index = (seek_offset / blocksize); unsigned const index = (seek_offset / blocksize);
file_size out_count = 0; file_size out_count = 0;
bool result = _vfs_read(
(char*)&vfs_dirent, sizeof(vfs_dirent), Directory_service::Dirent vfs_dirent { };
index * sizeof(vfs_dirent), out_count);
bool const result = _vfs_read((char*)&vfs_dirent,
sizeof(vfs_dirent),
index * sizeof(vfs_dirent),
out_count);
vfs_dirent.sanitize();
if (result) { if (result) {
if (out_count != sizeof(vfs_dirent)) { if (out_count != sizeof(vfs_dirent)) {
@ -744,30 +748,47 @@ struct Vfs_server::Directory : Io_node
return true; return true;
} }
::File_system::Directory_entry *fs_dirent = auto fs_dirent_type = [&] (Vfs::Directory_service::Dirent_type type)
(Directory_entry *)_stream.packet_content(_packet); {
fs_dirent->inode = vfs_dirent.fileno; 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); _ack_packet(0);
return true;
case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: } else {
fs_dirent->type = ::File_system::Directory_entry::TYPE_DIRECTORY;
break; ::File_system::Directory_entry &fs_dirent =
case Vfs::Directory_service::DIRENT_TYPE_SYMLINK: *(Directory_entry *)_stream.packet_content(_packet);
fs_dirent->type = ::File_system::Directory_entry::TYPE_SYMLINK;
break; fs_dirent = {
case Vfs::Directory_service::DIRENT_TYPE_FILE: .inode = vfs_dirent.fileno,
default: .type = fs_dirent_type(vfs_dirent.type),
fs_dirent->type = ::File_system::Directory_entry::TYPE_FILE; .rwx = {
break; .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 true;
} }
return false; return false;

View File

@ -442,7 +442,7 @@ struct Unlink_test : public Stress_test
Vfs::Vfs_handle *dir_handle; Vfs::Vfs_handle *dir_handle;
assert_opendir(vfs.opendir(path, false, &dir_handle, alloc)); 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;) { for (Vfs::file_size i = vfs.num_dirent(path); i;) {
dir_handle->seek(--i * sizeof(dirent)); dir_handle->seek(--i * sizeof(dirent));
dir_handle->fs().queue_read(dir_handle, 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) Vfs::File_io_service::READ_QUEUED)
_ep.wait_and_dispatch_one_io_signal(); _ep.wait_and_dispatch_one_io_signal();
subpath.append(dirent.name); subpath.append(dirent.name.buf);
switch (dirent.type) { switch (dirent.type) {
case Vfs::Directory_service::DIRENT_TYPE_END: case Vfs::Directory_service::Dirent_type::END:
error("reached the end prematurely"); error("reached the end prematurely");
throw Exception(); throw Exception();
case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: case Vfs::Directory_service::Dirent_type::DIRECTORY:
empty_dir(subpath.base()); empty_dir(subpath.base());
default: default:

View File

@ -74,43 +74,7 @@ struct Noux::Sysio
OPEN_MODE_CREATE = 0x0800, /* libc O_EXCL */ OPEN_MODE_CREATE = 0x0800, /* libc O_EXCL */
}; };
/** typedef Vfs::Directory_service::Stat 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,
};
/*
* 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;
}
};
/** /**
* Argument structure used for ioctl syscall * Argument structure used for ioctl syscall
@ -132,7 +96,7 @@ struct Noux::Sysio
enum Lseek_whence { LSEEK_SET, LSEEK_CUR, LSEEK_END }; 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; typedef Vfs::Directory_service::Dirent_type Dirent_type;
@ -149,7 +113,7 @@ struct Noux::Sysio
{ {
fileno = dirent.fileno; fileno = dirent.fileno;
type = dirent.type; type = dirent.type;
memcpy(name, dirent.name, DIRENT_MAX_NAME_LEN); memcpy(name, dirent.name.buf, DIRENT_MAX_NAME_LEN);
return *this; return *this;
} }

View File

@ -1 +1 @@
b82025f7f85938ce713b6c442c693afe465dd83a 8eddf0d249a22993e57b3242112fb62f503101c9

View File

@ -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) static void _sysio_to_stat_struct(Noux::Sysio const *sysio, struct stat *buf)
{ {
Genode::memset(buf, 0, sizeof(*buf)); unsigned const readable_bits = S_IRUSR,
buf->st_uid = sysio->stat_out.st.uid; writeable_bits = S_IWUSR,
buf->st_gid = sysio->stat_out.st.gid; executable_bits = S_IXUSR;
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;
if (sysio->stat_out.st.mtime >= 0) auto type = [] (Vfs::Node_type type)
buf->st_mtime = sysio->stat_out.st.mtime; {
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); 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)) { if (!noux_syscall(Noux::Session::SYSCALL_DIRENT)) {
switch (sysio()->error.general) { switch (sysio()->error.general) {
@ -1708,23 +1726,35 @@ namespace {
} }
} }
switch (sysio()->dirent_out.entry.type) { using Dirent_type = Vfs::Directory_service::Dirent_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->d_fileno = sysio()->dirent_out.entry.fileno; if (sysio()->dirent_out.entry.type == Dirent_type::END)
dirent->d_reclen = sizeof(struct dirent); return 0;
Genode::strncpy(dirent->d_name, sysio()->dirent_out.entry.name, auto d_type = [] (Dirent_type const &type)
sizeof(dirent->d_name)); {
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); *basep += sizeof(struct dirent);
return sizeof(struct dirent); return sizeof(struct dirent);

View File

@ -14,14 +14,14 @@ From: Christian Prochaska <christian.prochaska@genode-labs.com>
gdb/gdbserver/linux-x86-low.c | 111 +++++++++++++++++++- gdb/gdbserver/linux-x86-low.c | 111 +++++++++++++++++++-
gdb/gdbserver/linux-x86-tdesc-selftest.c | 31 ++++++ gdb/gdbserver/linux-x86-tdesc-selftest.c | 31 ++++++
gdb/gdbserver/linux-x86-tdesc.c | 8 + 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.c | 36 ++++++
gdb/gdbserver/server.h | 4 + gdb/gdbserver/server.h | 4 +
gdb/nat/fork-inferior.c | 4 - gdb/nat/fork-inferior.c | 4 -
gdb/nat/gdb_ptrace.h | 2 gdb/nat/gdb_ptrace.h | 2
gdb/nat/linux-ptrace.c | 17 +++ gdb/nat/linux-ptrace.c | 17 +++
gdb/nat/linux-ptrace.h | 4 + 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 diff --git a/gdb/common/common-defs.h b/gdb/common/common-defs.h
index eb0ec21..4dc07ce 100644 index eb0ec21..4dc07ce 100644
@ -1071,7 +1071,7 @@ index c3aa20c..e5a57c0 100644
init_target_desc (*tdesc, amd64_expedite_regs); init_target_desc (*tdesc, amd64_expedite_regs);
} }
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c 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 --- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c
@@ -27,6 +27,12 @@ @@ -27,6 +27,12 @@
@ -1099,6 +1099,18 @@ index 45d5c8d..7b6b1be 100644
static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR; static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR;
/* FIXME headerize? */ /* 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 diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index bf6302b..b6a9494 100644 index bf6302b..b6a9494 100644
--- a/gdb/gdbserver/server.c --- a/gdb/gdbserver/server.c

View File

@ -271,7 +271,7 @@ class Noux::Pipe_sink_io_channel : public Io_channel
bool fstat(Sysio &sysio) override 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; return true;
} }
}; };
@ -345,7 +345,7 @@ class Noux::Pipe_source_io_channel : public Io_channel
bool fstat(Sysio &sysio) override 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; return true;
} }
}; };

View File

@ -121,9 +121,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
* we use the ones specificed in the config. * we use the ones specificed in the config.
*/ */
if (result) { if (result) {
stat_out.uid = _user_info.uid();
stat_out.gid = _user_info.gid();
stat_out.inode = path_hash; stat_out.inode = path_hash;
} }

View File

@ -151,12 +151,7 @@ struct Noux::Terminal_io_channel : Io_channel
bool fstat(Sysio &sysio) override bool fstat(Sysio &sysio) override
{ {
/* sysio.fstat_out.st.type = Vfs::Node_type::CONTINUOUS_FILE;
* 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;
return true; return true;
} }

View File

@ -269,7 +269,7 @@ struct Noux::Vfs_io_channel : Io_channel
*/ */
unsigned const index = _fh.seek() / sizeof(Sysio::Dirent); unsigned const index = _fh.seek() / sizeof(Sysio::Dirent);
if (index < 2) { 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, strncpy(sysio.dirent_out.entry.name,
index ? ".." : ".", index ? ".." : ".",
sizeof(sysio.dirent_out.entry.name)); 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. * Align index range to zero when calling the directory service.
*/ */
Vfs::Directory_service::Dirent dirent;
Vfs::file_size noux_dirent_seek = _fh.seek(); 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> Registered_no_delete<Vfs_io_waiter>
vfs_io_waiter(_vfs_io_waiter_registry); 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_io_waiter.wait_for_io();
Vfs::File_io_service::Read_result read_result; 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 (;;) { for (;;) {
read_result = _fh.fs().complete_read(&_fh, (char*)&dirent, read_result = _fh.fs().complete_read(&_fh, (char*)&dirent,
count, out_count); count, out_count);
@ -318,7 +316,7 @@ struct Noux::Vfs_io_channel : Io_channel
if ((read_result != Vfs::File_io_service::READ_OK) || if ((read_result != Vfs::File_io_service::READ_OK) ||
(out_count != sizeof(dirent))) { (out_count != sizeof(dirent))) {
dirent = Vfs::Directory_service::Dirent(); dirent = { };
} }
_fh.seek(noux_dirent_seek); _fh.seek(noux_dirent_seek);