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);
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<Vfs::Directory*>(node))
out->type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY;
return -1;
}
if (dynamic_cast<Vfs::File*>(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<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);
}
@ -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<Vfs::Directory*>(node);
if (dir) {
out.mode = STAT_MODE_DIRECTORY | 0777;
out = { };
if (dynamic_cast<Vfs::Directory*>(node)) {
out.type = Node_type::DIRECTORY;
out.rwx = Node_rwx::rwx();
return STAT_OK;
}
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;
return STAT_OK;
}
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 */
return STAT_OK;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<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; }
};
@ -118,16 +120,10 @@ struct Genode::Directory : Noncopyable, Interface
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;
/*
* 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();
}
/**

View File

@ -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<Watched_file>(_files, _dir, entry.name(), handler);
} catch (...) { }

View File

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

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)
:
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;
}

View File

@ -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)
{ }

View File

@ -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("<glyphs/>")),
Single_file_system(Node_type::TRANSACTIONAL_FILE, type(),
Node_rwx::ro(), Xml_node("<glyphs/>")),
_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;
}

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

View File

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

View File

@ -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))
{ }

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@
#ifndef _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 <os/packet_stream.h>
#include <packet_stream_tx/packet_stream_tx.h>
@ -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;
}
};

View File

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

View File

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

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)
:
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;
}

View File

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

View File

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

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)
:
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),

View File

@ -69,6 +69,50 @@ class Vfs::Fs_file_system : public File_system
struct Fs_vfs_handle;
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,
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;
}

View File

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

View File

@ -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()))
{ }

View File

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

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::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<File *>(node);
if (file) {
dirent->type = Directory_service::DIRENT_TYPE_FILE;
return Vfs::File_io_service::READ_OK;
}
auto dirent_type = [&] ()
{
if (dynamic_cast<File *>(node_ptr)) return Dirent_type::CONTINUOUS_FILE;
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);
if (dir) {
dirent->type = Directory_service::DIRENT_TYPE_DIRECTORY;
return Vfs::File_io_service::READ_OK;
}
return Dirent_type::END;
};
Symlink *symlink = dynamic_cast<Symlink *>(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<File *>(node);
if (file) {
stat.mode = STAT_MODE_FILE | 0777;
return STAT_OK;
}
Node &node = *node_ptr;
Directory *dir = dynamic_cast<Directory *>(node);
if (dir) {
stat.mode = STAT_MODE_DIRECTORY | 0777;
return STAT_OK;
}
auto node_type = [&] ()
{
if (dynamic_cast<Directory *>(node_ptr)) return Node_type::DIRECTORY;
if (dynamic_cast<Symlink *>(node_ptr)) return Node_type::SYMLINK;
Symlink *symlink = dynamic_cast<Symlink *>(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

View File

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

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)
:
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,

View File

@ -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()))
{ }

View File

@ -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<Tar_file_system&>(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;
}

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)
:
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())
{

View File

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

View File

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

View File

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

View File

@ -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<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;
if (dynamic_cast<Directory *>(node)) e->type = Directory_entry::TYPE_DIRECTORY;
if (dynamic_cast<Symlink *>(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()
};
}
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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)
{
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);

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

View File

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

View File

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

View File

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

View File

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