diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h
index f51439d5db..caa46564ff 100644
--- a/ports/include/noux_session/noux_session.h
+++ b/ports/include/noux_session/noux_session.h
@@ -44,6 +44,7 @@ namespace Noux {
SYSCALL_OPEN,
SYSCALL_CLOSE,
SYSCALL_IOCTL,
+ SYSCALL_LSEEK,
SYSCALL_DIRENT,
SYSCALL_FCHDIR,
SYSCALL_EXECVE,
@@ -53,6 +54,9 @@ namespace Noux {
SYSCALL_WAIT4,
SYSCALL_PIPE,
SYSCALL_DUP2,
+ SYSCALL_UNLINK,
+ SYSCALL_RENAME,
+ SYSCALL_MKDIR,
SYSCALL_INVALID = -1
};
@@ -69,6 +73,7 @@ namespace Noux {
NOUX_DECL_SYSCALL_NAME(OPEN)
NOUX_DECL_SYSCALL_NAME(CLOSE)
NOUX_DECL_SYSCALL_NAME(IOCTL)
+ NOUX_DECL_SYSCALL_NAME(LSEEK)
NOUX_DECL_SYSCALL_NAME(DIRENT)
NOUX_DECL_SYSCALL_NAME(FCHDIR)
NOUX_DECL_SYSCALL_NAME(EXECVE)
@@ -78,6 +83,9 @@ namespace Noux {
NOUX_DECL_SYSCALL_NAME(WAIT4)
NOUX_DECL_SYSCALL_NAME(PIPE)
NOUX_DECL_SYSCALL_NAME(DUP2)
+ NOUX_DECL_SYSCALL_NAME(UNLINK)
+ NOUX_DECL_SYSCALL_NAME(RENAME)
+ NOUX_DECL_SYSCALL_NAME(MKDIR)
case SYSCALL_INVALID: return 0;
}
return 0;
diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h
index da4be46513..543a6794c2 100644
--- a/ports/include/noux_session/sysio.h
+++ b/ports/include/noux_session/sysio.h
@@ -58,6 +58,17 @@ namespace Noux {
typedef __SIZE_TYPE__ size_t;
+ /**
+ * Flags of 'mode' argument of open syscall
+ */
+ enum {
+ OPEN_MODE_RDONLY = 0,
+ OPEN_MODE_WRONLY = 1,
+ OPEN_MODE_RDWR = 2,
+ OPEN_MODE_ACCMODE = 3,
+ OPEN_MODE_CREATE = 0x0200,
+ };
+
enum {
STAT_MODE_SYMLINK = 0120000,
STAT_MODE_FILE = 0100000,
@@ -100,6 +111,8 @@ namespace Noux {
};
};
+ enum Lseek_whence { LSEEK_SET, LSEEK_CUR, LSEEK_END };
+
enum { DIRENT_MAX_NAME_LEN = 128 };
enum Dirent_type {
@@ -208,8 +221,14 @@ namespace Noux {
enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS };
enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS };
- enum Open_error { OPEN_ERR_UNACCESSIBLE = NUM_GENERAL_ERRORS };
+ enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM };
enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS };
+ enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM };
+ enum Rename_error { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS,
+ RENAME_ERR_NO_PERM };
+ enum Mkdir_error { MKDIR_ERR_EXISTS, MKDIR_ERR_NO_ENTRY,
+ MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM,
+ MKDIR_ERR_NAME_TOO_LONG};
union {
General_error general;
@@ -217,13 +236,17 @@ namespace Noux {
Fcntl_error fcntl;
Open_error open;
Execve_error execve;
+ Unlink_error unlink;
+ Rename_error rename;
+ Mkdir_error mkdir;
} error;
union {
SYSIO_DECL(getcwd, { }, { Path path; });
- SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; }, { });
+ SYSIO_DECL(write, { int fd; size_t count; Chunk chunk; },
+ { size_t count; });
SYSIO_DECL(stat, { Path path; }, { Stat st; });
@@ -238,7 +261,10 @@ namespace Noux {
SYSIO_DECL(ioctl, : Ioctl_in { int fd; }, : Ioctl_out { });
- SYSIO_DECL(dirent, { int fd; int index; }, { Dirent entry; });
+ SYSIO_DECL(lseek, { int fd; off_t offset; Lseek_whence whence; },
+ { off_t offset; });
+
+ SYSIO_DECL(dirent, { int fd; }, { Dirent entry; });
SYSIO_DECL(fchdir, { int fd; }, { });
@@ -261,6 +287,12 @@ namespace Noux {
SYSIO_DECL(pipe, { }, { int fd[2]; });
SYSIO_DECL(dup2, { int fd; int to_fd; }, { });
+
+ SYSIO_DECL(unlink, { Path path; }, { });
+
+ SYSIO_DECL(rename, { Path from_path; Path to_path; }, { });
+
+ SYSIO_DECL(mkdir, { Path path; int mode; }, { });
};
};
};
diff --git a/ports/run/noux.run b/ports/run/noux.run
index e99fcf3acb..8a9e411ba5 100644
--- a/ports/run/noux.run
+++ b/ports/run/noux.run
@@ -47,7 +47,7 @@ install_config {
-
+
diff --git a/ports/run/noux_bash.run b/ports/run/noux_bash.run
index d026e82cba..96dda1e06a 100644
--- a/ports/run/noux_bash.run
+++ b/ports/run/noux_bash.run
@@ -12,7 +12,7 @@ if {![have_spec x86]} {
set build_components {
core init drivers/timer noux lib/libc_noux
drivers/framebuffer drivers/pci drivers/input
- server/terminal
+ server/terminal server/ram_fs
test/libports/ncurses
}
@@ -38,9 +38,9 @@ close $vimrc_fd
# strip all binaries prior archiving
exec sh -c "find bin/bash/ bin/vim/ bin/coreutils/ -type f | (xargs strip || true) 2>/dev/null"
-exec tar cfv bin/bash.tar -h -C bin/bash .
-exec tar rfv bin/bash.tar -h -C bin/coreutils .
-exec tar rfv bin/bash.tar -h -C bin/vim .
+exec tar cfv bin/bash.tar -h -C bin/bash .
+exec tar cfv bin/coreutils.tar -h -C bin/coreutils .
+exec tar cfv bin/vim.tar -h -C bin/vim .
create_boot_directory
@@ -101,23 +101,62 @@ append_if [have_spec ps2] config {
}
append config {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
install_config $config
@@ -129,9 +168,9 @@ install_config $config
# generic modules
set boot_modules {
- core init timer ld.lib.so noux terminal
+ core init timer ld.lib.so noux terminal ram_fs
libc.lib.so libm.lib.so libc_noux.lib.so ncurses.lib.so
- bash.tar
+ bash.tar coreutils.tar vim.tar
}
# platform-specific modules
diff --git a/ports/run/noux_fork.run b/ports/run/noux_fork.run
index 58f1e126cf..d783866944 100644
--- a/ports/run/noux_fork.run
+++ b/ports/run/noux_fork.run
@@ -46,7 +46,7 @@ install_config {
-
+
diff --git a/ports/run/noux_vim.run b/ports/run/noux_vim.run
index 351d72ceba..9c9eefbf44 100644
--- a/ports/run/noux_vim.run
+++ b/ports/run/noux_vim.run
@@ -90,7 +90,7 @@ append config {
-
+
diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc
index 910ea7479f..5b6cbdab39 100644
--- a/ports/src/lib/libc_noux/plugin.cc
+++ b/ports/src/lib/libc_noux/plugin.cc
@@ -122,7 +122,7 @@ static void _sysio_to_stat_struct(Noux::Sysio const *sysio, struct stat *buf)
}
-static int _stat(const char *path, struct stat *buf, bool lstat = false)
+static int _stat(char const *path, struct stat *buf, bool lstat = false)
{
if ((path == NULL) or (buf == NULL)) {
errno = EFAULT;
@@ -144,7 +144,7 @@ static int _stat(const char *path, struct stat *buf, bool lstat = false)
}
-extern "C" int lstat(const char *path, struct stat *buf) { return _stat(path, buf, true); }
+extern "C" int lstat(char const *path, struct stat *buf) { return _stat(path, buf, true); }
static bool serialize_string_array(char const * const * array, char *dst, Genode::size_t dst_len)
@@ -166,7 +166,7 @@ static bool serialize_string_array(char const * const * array, char *dst, Genode
}
-extern "C" int execve(const char *filename, char *const argv[],
+extern "C" int execve(char const *filename, char *const argv[],
char *const envp[])
{
if (verbose) {
@@ -383,6 +383,20 @@ extern "C" pid_t getpid(void)
}
+extern "C" int access(char const *pathname, int mode)
+{
+ PDBG("access '%s' (mode=%x) called, not implemented", pathname, mode);
+ return 0;
+}
+
+
+extern "C" int chmod(char const *path, mode_t mode)
+{
+ PDBG("chmod '%s' to 0x%x not implemented", path, mode);
+ return 0;
+}
+
+
extern "C" pid_t _wait4(pid_t pid, int *status, int options,
struct rusage *rusage)
{
@@ -496,35 +510,42 @@ namespace {
_stderr(Libc::file_descriptor_allocator()->alloc(this, noux_context(2), 2))
{ }
- bool supports_chdir(const char *) { return true; }
- bool supports_open(const char *, int) { return true; }
- bool supports_stat(const char *) { return true; }
- bool supports_pipe() { return true; }
+ bool supports_chdir(char const *) { return true; }
+ bool supports_open(char const *, int) { return true; }
+ bool supports_stat(char const *) { return true; }
+ bool supports_pipe() { return true; }
+ bool supports_unlink(char const *) { return true; }
+ bool supports_rename(const char *, const char *) { return true; }
+ bool supports_mkdir(const char *, mode_t) { return true; }
- Libc::File_descriptor *open(const char *, int);
+ Libc::File_descriptor *open(char const *, int);
ssize_t write(Libc::File_descriptor *, const void *, ::size_t);
int close(Libc::File_descriptor *);
int dup2(Libc::File_descriptor *, Libc::File_descriptor *);
int fstat(Libc::File_descriptor *, struct stat *);
+ int fsync(Libc::File_descriptor *);
int fstatfs(Libc::File_descriptor *, struct statfs *);
int fcntl(Libc::File_descriptor *, int, long);
ssize_t getdirentries(Libc::File_descriptor *, char *, ::size_t, ::off_t *);
::off_t lseek(Libc::File_descriptor *, ::off_t offset, int whence);
int fchdir(Libc::File_descriptor *);
ssize_t read(Libc::File_descriptor *, void *, ::size_t);
- int stat(const char *, struct stat *);
+ int stat(char const *, struct stat *);
int ioctl(Libc::File_descriptor *, int request, char *argp);
int pipe(Libc::File_descriptor *pipefd[2]);
+ int unlink(char const *path);
+ int rename(const char *oldpath, const char *newpath);
+ int mkdir(const char *path, mode_t mode);
};
- int Plugin::stat(const char *path, struct stat *buf)
+ int Plugin::stat(char const *path, struct stat *buf)
{
return _stat(path, buf, false);
}
- Libc::File_descriptor *Plugin::open(const char *pathname, int flags)
+ Libc::File_descriptor *Plugin::open(char const *pathname, int flags)
{
if (Genode::strlen(pathname) + 1 > sizeof(sysio()->open_in.path)) {
errno = ENAMETOOLONG;
@@ -549,6 +570,7 @@ namespace {
int Plugin::fstatfs(Libc::File_descriptor *, struct statfs *buf)
{
+ buf->f_flags = MNT_UNION;
return 0;
}
@@ -556,11 +578,6 @@ namespace {
ssize_t Plugin::write(Libc::File_descriptor *fd, const void *buf,
::size_t count)
{
- if (fd != _stdout && fd != _stderr) {
- errno = EBADF;
- return -1;
- }
-
/* remember original len for the return value */
int const orig_count = count;
@@ -574,7 +591,7 @@ namespace {
Genode::memcpy(sysio()->write_in.chunk, src, curr_count);
if (!noux()->syscall(Noux::Session::SYSCALL_WRITE)) {
- PERR("write error %d", sysio()->error.general);
+ PERR("write error %d (fd %d)", sysio()->error.general, noux_fd(fd->context));
}
count -= curr_count;
@@ -750,12 +767,52 @@ namespace {
}
+ int Plugin::fsync(Libc::File_descriptor *fd)
+ {
+ PDBG("not implemented");
+ return 0;
+ }
+
+
int Plugin::fcntl(Libc::File_descriptor *fd, int cmd, long arg)
{
/* copy arguments to sysio */
sysio()->fcntl_in.fd = noux_fd(fd->context);
switch (cmd) {
+ case F_DUPFD:
+ {
+ /*
+ * Allocate free file descriptor locally. Noux FDs are expected
+ * to correspond one-to-one to libc FDs.
+ */
+ Libc::File_descriptor *new_fd =
+ Libc::file_descriptor_allocator()->alloc(this, 0);
+
+ new_fd->context = noux_context(new_fd->libc_fd);
+
+ /*
+ * Use new allocated number as name of file descriptor
+ * duplicate.
+ */
+ if (dup2(fd, new_fd)) {
+ PERR("Plugin::fcntl: dup2 unexpectedly failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ return new_fd->libc_fd;
+ }
+
+ case F_GETFD:
+ /*
+ * Normally, we would return the file-descriptor flags.
+ *
+ * XXX: FD_CLOEXEC not yet supported
+ */
+ PWRN("fcntl(F_GETFD) not implemented, returning 0");
+ return 0;
+
case F_SETFD:
sysio()->fcntl_in.cmd = Noux::Sysio::FCNTL_CMD_SET_FD_FLAGS;
sysio()->fcntl_in.long_arg = arg;
@@ -793,10 +850,7 @@ namespace {
return -1;
}
- unsigned const curr_offset = *basep;
-
sysio()->dirent_in.fd = noux_fd(fd->context);
- sysio()->dirent_in.index = curr_offset / sizeof(struct dirent);
struct dirent *dirent = (struct dirent *)buf;
Genode::memset(dirent, 0, sizeof(struct dirent));
@@ -837,13 +891,29 @@ namespace {
::off_t Plugin::lseek(Libc::File_descriptor *fd,
::off_t offset, int whence)
{
- PWRN("lseek - not implemented: fd=%d, offset=%ld, whence=%d",
- noux_fd(fd->context), (long)offset, whence);
+ sysio()->lseek_in.fd = noux_fd(fd->context);
+ sysio()->lseek_in.offset = offset;
- if (whence == SEEK_SET)
- return offset;
+ switch (whence) {
+ default:
+ case SEEK_SET: sysio()->lseek_in.whence = Noux::Sysio::LSEEK_SET; break;
+ case SEEK_CUR: sysio()->lseek_in.whence = Noux::Sysio::LSEEK_CUR; break;
+ case SEEK_END: sysio()->lseek_in.whence = Noux::Sysio::LSEEK_END; break;
+ }
- return 0;
+ if (!noux()->syscall(Noux::Session::SYSCALL_LSEEK)) {
+ switch (sysio()->error.general) {
+
+ case Noux::Sysio::ERR_FD_INVALID:
+ errno = EBADF;
+ PERR("dirent: ERR_FD_INVALID");
+ return -1;
+
+ case Noux::Sysio::NUM_GENERAL_ERRORS: return -1;
+ }
+ }
+
+ return sysio()->lseek_out.offset;
}
@@ -859,6 +929,62 @@ namespace {
return 0;
}
+
+ int Plugin::unlink(char const *path)
+ {
+ Genode::strncpy(sysio()->unlink_in.path, path, sizeof(sysio()->unlink_in.path));
+
+ if (!noux()->syscall(Noux::Session::SYSCALL_UNLINK)) {
+ PWRN("unlink syscall failed for path \"%s\"", path);
+ switch (sysio()->error.unlink) {
+ case Noux::Sysio::UNLINK_ERR_NO_ENTRY: errno = ENOENT; break;
+ default: errno = EPERM; break;
+ }
+ return -1;
+ }
+
+ return 0;
+ }
+
+
+ int Plugin::rename(char const *from_path, char const *to_path)
+ {
+ Genode::strncpy(sysio()->rename_in.from_path, from_path, sizeof(sysio()->rename_in.from_path));
+ Genode::strncpy(sysio()->rename_in.to_path, to_path, sizeof(sysio()->rename_in.to_path));
+
+ if (!noux()->syscall(Noux::Session::SYSCALL_RENAME)) {
+ PWRN("rename syscall failed for \"%s\" -> \"%s\"", from_path, to_path);
+ switch (sysio()->error.rename) {
+ case Noux::Sysio::RENAME_ERR_NO_ENTRY: errno = ENOENT; break;
+ case Noux::Sysio::RENAME_ERR_CROSS_FS: errno = EXDEV; break;
+ case Noux::Sysio::RENAME_ERR_NO_PERM: errno = EPERM; break;
+ default: errno = EPERM; break;
+ }
+ return -1;
+ }
+
+ return 0;
+ }
+
+ int Plugin::mkdir(const char *path, mode_t mode)
+ {
+ Genode::strncpy(sysio()->mkdir_in.path, path, sizeof(sysio()->mkdir_in.path));
+
+ if (!noux()->syscall(Noux::Session::SYSCALL_MKDIR)) {
+ PWRN("mkdir syscall failed for \"%s\" mode=0x%x", path, (int)mode);
+ switch (sysio()->error.mkdir) {
+ case Noux::Sysio::MKDIR_ERR_EXISTS: errno = EEXIST; break;
+ case Noux::Sysio::MKDIR_ERR_NO_ENTRY: errno = ENOENT; break;
+ case Noux::Sysio::MKDIR_ERR_NO_SPACE: errno = ENOSPC; break;
+ case Noux::Sysio::MKDIR_ERR_NAME_TOO_LONG: errno = ENAMETOOLONG; break;
+ case Noux::Sysio::MKDIR_ERR_NO_PERM: errno = EPERM; break;
+ default: errno = EPERM; break;
+ }
+ return -1;
+ }
+ return 0;
+ }
+
} /* unnamed namespace */
diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h
index bf53a822e0..f3946d2ea5 100644
--- a/ports/src/noux/child.h
+++ b/ports/src/noux/child.h
@@ -22,7 +22,7 @@
/* Noux includes */
#include
-#include
+#include
#include
#include
#include
@@ -195,7 +195,7 @@ namespace Noux {
*/
Environment _env;
- Vfs * const _vfs;
+ Dir_file_system * const _root_dir;
/**
* ELF binary
@@ -266,7 +266,7 @@ namespace Noux {
Family_member *parent,
int pid,
Signal_receiver *sig_rec,
- Vfs *vfs,
+ Dir_file_system *root_dir,
Args const &args,
char const *env,
char const *pwd,
@@ -286,9 +286,9 @@ namespace Noux {
_resources(name, resources_ep, false),
_args(ARGS_DS_SIZE, args),
_env(env),
- _vfs(vfs),
+ _root_dir(root_dir),
_binary_ds(forked ? Dataspace_capability()
- : vfs->dataspace_from_file(name)),
+ : root_dir->dataspace(name)),
_sysio_ds(Genode::env()->ram_session(), SYSIO_DS_SIZE),
_sysio(_sysio_ds.local_addr()),
_noux_session_cap(Session_capability(_entrypoint.manage(this))),
@@ -313,7 +313,7 @@ namespace Noux {
_entrypoint.dissolve(this);
- _vfs->release_dataspace_for_file(_child_policy.name(), _binary_ds);
+ _root_dir->release(_child_policy.name(), _binary_ds);
}
void start() { _entrypoint.activate(); }
diff --git a/ports/src/noux/dir_file_system.h b/ports/src/noux/dir_file_system.h
new file mode 100644
index 0000000000..59eee3ca93
--- /dev/null
+++ b/ports/src/noux/dir_file_system.h
@@ -0,0 +1,518 @@
+/*
+ * \brief Directory file system
+ * \author Norman Feske
+ * \date 2012-04-23
+ */
+
+/*
+ * Copyright (C) 2011-2012 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _NOUX__DIR_FILE_SYSTEM_H_
+#define _NOUX__DIR_FILE_SYSTEM_H_
+
+/* Genode includes */
+#include
+#include
+
+/* Noux includes */
+#include
+#include
+#include
+
+namespace Noux {
+
+ class Dir_file_system : public File_system
+ {
+ public:
+
+ enum { MAX_NAME_LEN = 128 };
+
+ private:
+
+ Lock _lock;
+
+ /* pointer to first child file system */
+ File_system *_first_file_system;
+
+ /* add new file system to the list of children */
+ void _append_file_system(File_system *fs)
+ {
+ if (!_first_file_system) {
+ _first_file_system = fs;
+ return;
+ }
+
+ File_system *curr = _first_file_system;
+ while (curr->next)
+ curr = curr->next;
+
+ curr->next = fs;
+ }
+
+ /**
+ * Directory name
+ */
+ char _name[MAX_NAME_LEN];
+
+ bool _is_root() const { return _name[0] == 0; }
+
+ public:
+
+ Dir_file_system(Xml_node node) : _first_file_system(0)
+ {
+ /* remember directory name */
+ if (node.has_type("fstab"))
+ _name[0] = 0;
+ else
+ node.attribute("name").value(_name, sizeof(_name));
+
+ for (unsigned i = 0; i < node.num_sub_nodes(); i++) {
+
+ Xml_node sub_node = node.sub_node(i);
+
+ if (sub_node.has_type("tar")) {
+ _append_file_system(new Tar_file_system(sub_node));
+ continue;
+ }
+
+ if (sub_node.has_type("fs")) {
+ _append_file_system(new Fs_file_system(sub_node));
+ continue;
+ }
+
+ /* traverse into nodes */
+ if (sub_node.has_type("dir")) {
+ _append_file_system(new Dir_file_system(sub_node));
+ continue;
+ }
+
+ {
+ char type_name[64];
+ sub_node.type_name(type_name, sizeof(type_name));
+ PWRN("unknown fstab node type <%s>", type_name);
+ }
+ }
+ }
+
+ /**
+ * Return portion of the path after the element corresponding to
+ * the current directory.
+ */
+ char const *_sub_path(char const *path) const
+ {
+ /* do not strip anything from the path when we are root */
+ if (_is_root())
+ return path;
+
+ /* skip heading slash in path if present */
+ if (path[0] == '/')
+ path++;
+
+ size_t const name_len = strlen(_name);
+ if (strcmp(path, _name, name_len) != 0)
+ return 0;
+ path += name_len;
+
+ /*
+ * The first characters of the first path element are equal to
+ * the current directory name. Let's check if the length of the
+ * first path element matches the name length.
+ */
+ if (*path != 0 && *path != '/')
+ return 0;
+
+ return path;
+ }
+
+
+ /*********************************
+ ** Directory-service interface **
+ *********************************/
+
+ Dataspace_capability dataspace(char const *path)
+ {
+ path = _sub_path(path);
+ if (!path)
+ return Dataspace_capability();
+
+ /*
+ * Query sub file systems for dataspace using the path local to
+ * the respective file system
+ */
+ File_system *fs = _first_file_system;
+ for (; fs; fs = fs->next) {
+ Dataspace_capability ds = fs->dataspace(path);
+ if (ds.valid())
+ return ds;
+ }
+
+ return Dataspace_capability();
+ }
+
+ void release(char const *path, Dataspace_capability ds_cap)
+ {
+ path = _sub_path(path);
+ if (!path)
+ return;
+
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ fs->release(path, ds_cap);
+ }
+
+ bool stat(Sysio *sysio, char const *path)
+ {
+ path = _sub_path(path);
+
+ /* path does not match directory name */
+ if (!path) {
+ sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
+ return false;
+ }
+
+ /*
+ * If path equals directory name, return information about the
+ * current directory.
+ */
+ if (strlen(path) == 0) {
+ sysio->stat_out.st.size = 0;
+ sysio->stat_out.st.mode = Sysio::STAT_MODE_DIRECTORY | 0755;
+ sysio->stat_out.st.uid = 0;
+ sysio->stat_out.st.gid = 0;
+ return true;
+ }
+
+ /*
+ * The given path refers to one of our sub directories.
+ * Propagate the request into our file systems.
+ */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ if (fs->stat(sysio, path))
+ return true;
+
+ /* none of our file systems felt responsible for the path */
+ sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
+ return false;
+ }
+
+ /**
+ * The 'path' is relative to the child file systems.
+ */
+ bool _dirent_of_file_systems(Sysio *sysio, char const *path, off_t index)
+ {
+ int base = 0;
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+
+ /*
+ * Determine number of matching directory entries within
+ * the current file system.
+ */
+ int const fs_num_dirent = fs->num_dirent(path);
+
+ /*
+ * Query directory entry if index lies with the file
+ * system.
+ */
+ if (index - base < fs_num_dirent) {
+ index = index - base;
+ bool const res = fs->dirent(sysio, path, index);
+ sysio->dirent_out.entry.fileno += base;
+ return res;
+ }
+
+ /* adjust base index for next file system */
+ base += fs_num_dirent;
+ }
+
+ sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
+ return true;
+ }
+
+ bool _dirent_of_this_dir_node(Sysio *sysio, off_t index)
+ {
+ if (index == 0) {
+ strncpy(sysio->dirent_out.entry.name, _name,
+ sizeof(sysio->dirent_out.entry.name));
+
+ sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_DIRECTORY;
+ sysio->dirent_out.entry.fileno = (unsigned)this;
+ } else
+ sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
+ return true;
+ }
+
+ bool dirent(Sysio *sysio, char const *path, off_t index)
+ {
+ Lock::Guard guard(_lock);
+
+ if (_is_root()) {
+ return _dirent_of_file_systems(sysio, path, index);
+ } else {
+
+ if (strcmp(path, "/") == 0)
+ return _dirent_of_this_dir_node(sysio, index);
+
+ /* path contains at least one element */
+
+ /* remove current element from path */
+ path = _sub_path(path);
+ if (path) {
+ return _dirent_of_file_systems(sysio, path, index);
+
+ } else {
+ /* path does not lie within our tree */
+ return false;
+ }
+ }
+ }
+
+ /*
+ * Accumulate number of directory entries that match in any of
+ * our sub file systems.
+ */
+ size_t _sum_dirents_of_file_systems(char const *path)
+ {
+ size_t cnt = 0;
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+ cnt += fs->num_dirent(path);
+ }
+ return cnt;
+ }
+
+ size_t num_dirent(char const *path)
+ {
+ Lock::Guard guard(_lock);
+
+ if (_is_root()) {
+ return _sum_dirents_of_file_systems(path);
+
+ } else {
+
+ if (strcmp(path, "/") == 0)
+ return 1;
+
+ /*
+ * The path contains at least one element. Remove current
+ * element from path.
+ */
+ path = _sub_path(path);
+
+ /*
+ * If the resulting 'path' is non-NULL, the path lies
+ * within our tree. In this case, determine the sum of
+ * matching dirents of all our file systems. Otherwise,
+ * the specified path lies outside our directory node.
+ */
+ return path ? _sum_dirents_of_file_systems(path) : 0;
+ }
+ }
+
+ bool is_directory(char const *path)
+ {
+ Lock::Guard guard(_lock);
+
+ path = _sub_path(path);
+ if (!path)
+ return false;
+
+ if (strlen(path) == 0)
+ return true;
+
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ if (fs->is_directory(path))
+ return true;
+
+ return false;
+ }
+
+ char const *leaf_path(char const *path)
+ {
+ Lock::Guard guard(_lock);
+
+ path = _sub_path(path);
+ if (!path)
+ return 0;
+
+ if (strlen(path) == 0)
+ return path;
+
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+ char const *leaf_path = fs->leaf_path(path);
+ if (leaf_path)
+ return leaf_path;
+ }
+
+ return 0;
+ }
+
+ Vfs_handle *open(Sysio *sysio, char const *path)
+ {
+ /*
+ * If 'path' is a directory, we create a 'Vfs_handle'
+ * for the root directory so that subsequent 'dirent' calls
+ * are subjected to the stacked file-system layout.
+ */
+ if (is_directory(path))
+ return new (env()->heap()) Vfs_handle(this, this, 0);
+
+ /*
+ * If 'path' refers to a non-directory node, create a
+ * 'Vfs_handle' local to the file system that provides the
+ * file.
+ */
+ Lock::Guard guard(_lock);
+
+ path = _sub_path(path);
+
+ /* check if path does not match directory name */
+ if (!path)
+ return 0;
+
+ /* path equals directory name */
+ if (strlen(path) == 0)
+ return new (env()->heap()) Vfs_handle(this, this, 0);
+
+ /* path refers to any of our sub file systems */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+ Vfs_handle *vfs_handle = fs->open(sysio, path);
+ if (vfs_handle)
+ return vfs_handle;
+ }
+
+ /* path does not match any existing file or directory */
+ return 0;
+ }
+
+ bool unlink(Sysio *sysio, char const *path)
+ {
+ path = _sub_path(path);
+
+ /* path does not match directory name */
+ if (!path) {
+ sysio->error.unlink = Sysio::UNLINK_ERR_NO_ENTRY;
+ return false;
+ }
+
+ /*
+ * Prevent unlinking if path equals directory name defined
+ * via the static fstab configuration.
+ */
+ if (strlen(path) == 0) {
+ sysio->error.unlink = Sysio::UNLINK_ERR_NO_PERM;
+ return false;
+ }
+
+ /*
+ * The given path refers to at least one of our sub
+ * directories. Propagate the request into all of our file
+ * systems. If at least one unlink operation succeeded, we
+ * return success.
+ */
+ bool unlink_ret = false;
+ Sysio::Unlink_error error = Sysio::UNLINK_ERR_NO_ENTRY;
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ if (fs->unlink(sysio, path)) {
+ unlink_ret = true;
+ } else {
+ /*
+ * Keep the most meaningful error code. When using
+ * stacked file systems, most child file systems will
+ * eventually return 'UNLINK_ERR_NO_ENTRY'. If any of
+ * those file systems has anything more interesting to
+ * tell (in particular 'UNLINK_ERR_NO_PERM'), return
+ * this information.
+ */
+ if (sysio->error.unlink != Sysio::UNLINK_ERR_NO_ENTRY)
+ error = sysio->error.unlink;
+ }
+
+ sysio->error.unlink = error;
+ return unlink_ret;
+ }
+
+ bool rename(Sysio *sysio, char const *from_path, char const *to_path)
+ {
+ from_path = _sub_path(from_path);
+
+ /* path does not match directory name */
+ if (!from_path) {
+ sysio->error.rename = Sysio::RENAME_ERR_NO_ENTRY;
+ return false;
+ }
+
+ /*
+ * Prevent renaming if path equals directory name defined
+ * via the static fstab configuration.
+ */
+ if (strlen(from_path) == 0) {
+ sysio->error.rename = Sysio::RENAME_ERR_NO_PERM;
+ return false;
+ }
+
+ /*
+ * Check if destination path resides within the same file
+ * system instance as the source path.
+ */
+ to_path = _sub_path(to_path);
+ if (!to_path) {
+ sysio->error.rename = Sysio::RENAME_ERR_CROSS_FS;
+ return false;
+ }
+
+ /* path refers to any of our sub file systems */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ if (fs->rename(sysio, from_path, to_path))
+ return true;
+
+ /* none of our file systems could successfully rename the path */
+ return false;
+ }
+
+ bool mkdir(Sysio *sysio, char const *path)
+ {
+ path = _sub_path(path);
+
+ /* path does not match directory name */
+ if (!path) {
+ sysio->error.mkdir = Sysio::MKDIR_ERR_NO_ENTRY;
+ return false;
+ }
+
+ /*
+ * Prevent mkdir of path that equals directory name defined
+ * via the static fstab configuration.
+ */
+ if (strlen(path) == 0) {
+ sysio->error.mkdir = Sysio::MKDIR_ERR_EXISTS;
+ return false;
+ }
+
+ /* path refers to any of our sub file systems */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ if (fs->mkdir(sysio, path))
+ return true;
+
+ /* none of our file systems could create the directory */
+ return false;
+ }
+
+ /***************************
+ ** File_system interface **
+ ***************************/
+
+ char const *name() const { return "dir"; }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ bool write(Sysio *sysio, Vfs_handle *handle) { return false; }
+ bool read(Sysio *sysio, Vfs_handle *vfs_handle) { return false; }
+ };
+}
+
+#endif /* _NOUX__DIR_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/directory_service.h b/ports/src/noux/directory_service.h
index 64b808f810..62771340e4 100644
--- a/ports/src/noux/directory_service.h
+++ b/ports/src/noux/directory_service.h
@@ -30,14 +30,25 @@ namespace Noux {
struct Directory_service
{
virtual Dataspace_capability dataspace(char const *path) = 0;
- virtual void release(Dataspace_capability) = 0;
+ virtual void release(char const *path, Dataspace_capability) = 0;
virtual Vfs_handle *open(Sysio *sysio, char const *path) = 0;
virtual bool stat(Sysio *sysio, char const *path) = 0;
- virtual bool dirent(Sysio *sysio, char const *path) = 0;
+ virtual bool dirent(Sysio *sysio, char const *path, off_t index) = 0;
+ virtual bool unlink(Sysio *sysio, char const *path) = 0;
+ virtual bool rename(Sysio *sysio, char const *from_path,
+ char const *to_path) = 0;
+ virtual bool mkdir(Sysio *sysio, char const *path) = 0;
- virtual void close(Vfs_handle *handle) = 0;
+ /**
+ * Return number of directory entries located at given path
+ */
+ virtual size_t num_dirent(char const *path) = 0;
+
+ virtual bool is_directory(char const *path) = 0;
+
+ virtual char const *leaf_path(char const *path) = 0;
};
}
diff --git a/ports/src/noux/file_system.h b/ports/src/noux/file_system.h
index 7ae9adb8f5..376a26bbfd 100644
--- a/ports/src/noux/file_system.h
+++ b/ports/src/noux/file_system.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2011-2012 gENODe Labs GmbH
+ * Copyright (C) 2011-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@@ -22,71 +22,26 @@
/* Noux includes */
#include
#include
+#include
#include
namespace Noux {
- class File_system : public Directory_service, public File_io_service,
- public List::Element
+ struct File_system : Directory_service, File_io_service
{
- private:
+ /**
+ * Our next sibling within the same 'Dir_file_system'
+ */
+ struct File_system *next;
- char _mount_point[Sysio::MAX_PATH_LEN];
+ File_system() : next(0) { }
- /**
- * Strip any number of trailing slashes
- */
- void _strip_trailing_slashes_from_mount_point()
- {
- size_t len;
- while ((len = strlen(_mount_point)) && (_mount_point[len - 1] == '/'))
- _mount_point[len - 1] = 0;
- }
-
- public:
-
- File_system(Xml_node config)
- {
- enum { TYPE_MAX_LEN = 64 };
- char type[TYPE_MAX_LEN];
- config.type_name(type, sizeof(type));
-
- config.attribute("at").value(_mount_point, sizeof(_mount_point));
- _strip_trailing_slashes_from_mount_point();
-
- PINF("created %s file system at \"%s\"", type, _mount_point);
- }
-
- File_system(char const *mount_point)
- {
- strncpy(_mount_point, mount_point, sizeof(_mount_point));
- _strip_trailing_slashes_from_mount_point();
- }
-
- /**
- * Return file-system-local path for the given global path
- *
- * This function checks if the global path lies within the mount
- * point of the file system. If yes, it returns the sub string of
- * the global path that corresponds to the path relative to the
- * file system.
- *
- * \return pointer to file-system relative path name within
- * the 'global_path' string, or
- * 0 if global path lies outside the file system
- */
- char const *local_path(char const *global_path)
- {
- size_t const mount_point_len = strlen(_mount_point);
-
- if (strlen(global_path) < mount_point_len)
- return 0;
-
- if (strcmp(global_path, _mount_point, mount_point_len))
- return 0;
-
- return global_path + mount_point_len;
- }
+ /**
+ * Return name of file system
+ *
+ * This function is used for debugging only.
+ */
+ virtual char const *name() const = 0;
};
}
diff --git a/ports/src/noux/fs_file_system.h b/ports/src/noux/fs_file_system.h
new file mode 100644
index 0000000000..350ae769c6
--- /dev/null
+++ b/ports/src/noux/fs_file_system.h
@@ -0,0 +1,451 @@
+/*
+ * \brief Adapter from Genode 'File_system' session to Noux file system
+ * \author Norman Feske
+ * \date 2011-02-17
+ */
+
+/*
+ * Copyright (C) 2012 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _NOUX__FS_FILE_SYSTEM_H_
+#define _NOUX__FS_FILE_SYSTEM_H_
+
+/* Genode includes */
+#include
+#include
+
+/* Noux includes */
+#include
+#include
+
+namespace Noux {
+
+ class Fs_file_system : public File_system
+ {
+ private:
+
+ Lock _lock;
+
+ Allocator_avl _fs_packet_alloc;
+
+ struct Label
+ {
+ enum { LABEL_MAX_LEN = 64 };
+ char string[LABEL_MAX_LEN];
+
+ Label(Xml_node config)
+ {
+ string[0] = 0;
+ try { config.attribute("label").value(string, sizeof(string)); }
+ catch (...) { }
+ }
+ } _label;
+
+ ::File_system::Connection _fs;
+
+ class Fs_vfs_handle : public Vfs_handle
+ {
+ private:
+
+ ::File_system::File_handle const _handle;
+
+ public:
+
+ Fs_vfs_handle(File_system *fs, int status_flags,
+ ::File_system::File_handle handle)
+ : Vfs_handle(fs, fs, status_flags), _handle(handle)
+ { }
+
+ ~Fs_vfs_handle()
+ {
+ Fs_file_system *fs = static_cast(ds());
+ fs->_fs.close(_handle);
+ }
+
+ ::File_system::File_handle file_handle() const { return _handle; }
+ };
+
+ /**
+ * Helper for managing the lifetime of temporary open node handles
+ */
+ struct Fs_handle_guard
+ {
+ ::File_system::Session &_fs;
+ ::File_system::Node_handle _handle;
+
+ Fs_handle_guard(::File_system::Session &fs,
+ ::File_system::Node_handle handle)
+ : _fs(fs), _handle(handle) { }
+
+ ~Fs_handle_guard() { _fs.close(_handle); }
+ };
+
+ public:
+
+ /*
+ * XXX read label from config
+ */
+ Fs_file_system(Xml_node config)
+ :
+ _fs_packet_alloc(env()->heap()),
+ _label(config),
+ _fs(_fs_packet_alloc, 128*1024, _label.string)
+ { }
+
+
+ /*********************************
+ ** Directory-service interface **
+ *********************************/
+
+ Dataspace_capability dataspace(char const *path)
+ {
+ return Dataspace_capability();
+ }
+
+ void release(char const *path, Dataspace_capability ds_cap)
+ {
+ }
+
+ bool stat(Sysio *sysio, char const *path)
+ {
+ ::File_system::Status status;
+
+ try {
+ ::File_system::Node_handle node = _fs.node(path);
+ Fs_handle_guard node_guard(_fs, node);
+ status = _fs.status(node);
+ } catch (...) {
+ PWRN("stat failed for path '%s'", path);
+ return false;
+ }
+
+ sysio->stat_out.st.size = status.size;
+
+ sysio->stat_out.st.mode = Sysio::STAT_MODE_FILE | 0777;
+
+ if (status.is_symlink())
+ sysio->stat_out.st.mode = Sysio::STAT_MODE_SYMLINK | 0777;
+
+ if (status.is_directory())
+ sysio->stat_out.st.mode = Sysio::STAT_MODE_DIRECTORY | 0777;
+
+ sysio->stat_out.st.uid = 0;
+ sysio->stat_out.st.gid = 0;
+ return true;
+ }
+
+ bool dirent(Sysio *sysio, char const *path, off_t index)
+ {
+ Lock::Guard guard(_lock);
+
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+
+ if (strcmp(path, "") == 0)
+ path = "/";
+
+ ::File_system::Dir_handle dir_handle = _fs.dir(path, false);
+ Fs_handle_guard dir_guard(_fs, dir_handle);
+
+ enum { DIRENT_SIZE = sizeof(::File_system::Directory_entry) };
+
+ ::File_system::Packet_descriptor
+ packet(source.alloc_packet(DIRENT_SIZE),
+ 0,
+ dir_handle,
+ ::File_system::Packet_descriptor::READ,
+ DIRENT_SIZE,
+ index*DIRENT_SIZE);
+
+ /* pass packet to server side */
+ source.submit_packet(packet);
+ source.get_acked_packet();
+
+ /*
+ * XXX check if acked packet belongs to request,
+ * needed for thread safety
+ */
+
+ typedef ::File_system::Directory_entry Directory_entry;
+
+ /* copy-out payload into destination buffer */
+ Directory_entry const *entry =
+ (Directory_entry *)source.packet_content(packet);
+
+ Sysio::Dirent_type type;
+ switch (entry->type) {
+ case Directory_entry::TYPE_DIRECTORY: type = Sysio::DIRENT_TYPE_DIRECTORY; break;
+ case Directory_entry::TYPE_FILE: type = Sysio::DIRENT_TYPE_FILE; break;
+ case Directory_entry::TYPE_SYMLINK: type = Sysio::DIRENT_TYPE_SYMLINK; break;
+ }
+
+ sysio->dirent_out.entry.type = type;
+ sysio->dirent_out.entry.fileno = index + 1;
+
+ strncpy(sysio->dirent_out.entry.name, entry->name,
+ sizeof(sysio->dirent_out.entry.name));
+
+ source.release_packet(packet);
+
+ return true;
+ }
+
+ bool unlink(Sysio *sysio, char const *path)
+ {
+ Lock::Guard guard(_lock);
+
+ Absolute_path dir_path(path);
+ dir_path.strip_last_element();
+
+ Absolute_path file_name(path);
+ file_name.keep_only_last_element();
+
+ try {
+ ::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
+ Fs_handle_guard dir_guard(_fs, dir);
+
+ _fs.unlink(dir, file_name.base() + 1);
+
+ } catch (...) {
+ sysio->error.unlink = Sysio::UNLINK_ERR_NO_ENTRY;
+ return false;
+ }
+ return true;
+ }
+
+ bool rename(Sysio *sysio, char const *from_path, char const *to_path)
+ {
+ Absolute_path from_dir_path(from_path);
+ from_dir_path.strip_last_element();
+
+ Absolute_path from_file_name(from_path);
+ from_file_name.keep_only_last_element();
+
+ Absolute_path to_dir_path(to_path);
+ to_dir_path.strip_last_element();
+
+ Absolute_path to_file_name(to_path);
+ to_file_name.keep_only_last_element();
+
+ try {
+ ::File_system::Dir_handle from_dir = _fs.dir(from_dir_path.base(), false);
+ Fs_handle_guard from_dir_guard(_fs, from_dir);
+
+ ::File_system::Dir_handle to_dir = _fs.dir(to_dir_path.base(), false);
+ Fs_handle_guard to_dir_guard(_fs, to_dir);
+
+ _fs.move(from_dir, from_file_name.base() + 1,
+ to_dir, to_file_name.base() + 1);
+
+ } catch (...) {
+ sysio->error.unlink = Sysio::UNLINK_ERR_NO_ENTRY;
+ return false;
+ }
+ return true;
+ }
+
+ bool mkdir(Sysio *sysio, char const *path)
+ {
+ /*
+ * Canonicalize path (i.e., path must start with '/')
+ */
+ Absolute_path abs_path(path);
+
+ Sysio::Mkdir_error error = Sysio::MKDIR_ERR_NO_PERM;
+ try {
+ _fs.dir(abs_path.base(), true);
+ return true;
+ }
+ catch (::File_system::Permission_denied) { error = Sysio::MKDIR_ERR_NO_PERM; }
+ catch (::File_system::Node_already_exists) { error = Sysio::MKDIR_ERR_EXISTS; }
+ catch (::File_system::Lookup_failed) { error = Sysio::MKDIR_ERR_NO_ENTRY; }
+ catch (::File_system::Name_too_long) { error = Sysio::MKDIR_ERR_NAME_TOO_LONG; }
+ catch (::File_system::No_space) { error = Sysio::MKDIR_ERR_NO_SPACE; }
+
+ sysio->error.mkdir = error;
+ return false;
+ }
+
+ size_t num_dirent(char const *path)
+ {
+ if (strcmp(path, "") == 0)
+ path = "/";
+
+ /*
+ * XXX handle exceptions
+ */
+ ::File_system::Node_handle node = _fs.node(path);
+ Fs_handle_guard node_guard(_fs, node);
+
+ ::File_system::Status status = _fs.status(node);
+
+ return status.size / sizeof(::File_system::Directory_entry);
+ }
+
+ bool is_directory(char const *path)
+ {
+ try {
+ ::File_system::Node_handle node = _fs.node(path);
+ Fs_handle_guard node_guard(_fs, node);
+
+ ::File_system::Status status = _fs.status(node);
+
+ return status.is_directory();
+ }
+ catch (...) { return false; }
+ }
+
+ char const *leaf_path(char const *path)
+ {
+ /* check if node at path exists within file system */
+ try {
+ ::File_system::Node_handle node = _fs.node(path);
+ _fs.close(node);
+ }
+ catch (...) {
+ return 0; }
+
+ return path;
+ }
+
+ Vfs_handle *open(Sysio *sysio, char const *path)
+ {
+ Lock::Guard guard(_lock);
+
+ Absolute_path dir_path(path);
+ dir_path.strip_last_element();
+
+ Absolute_path file_name(path);
+ file_name.keep_only_last_element();
+
+ ::File_system::Mode mode;
+
+ switch (sysio->open_in.mode & Sysio::OPEN_MODE_ACCMODE) {
+ default: mode = ::File_system::STAT_ONLY; break;
+ case Sysio::OPEN_MODE_RDONLY: mode = ::File_system::READ_ONLY; break;
+ case Sysio::OPEN_MODE_WRONLY: mode = ::File_system::WRITE_ONLY; break;
+ case Sysio::OPEN_MODE_RDWR: mode = ::File_system::READ_WRITE; break;
+ }
+
+ bool const create = sysio->open_in.mode & Sysio::OPEN_MODE_CREATE;
+
+ if (create)
+ PDBG("creation of file %s requested", file_name.base());
+
+ ::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
+ Fs_handle_guard dir_guard(_fs, dir);
+
+ Sysio::Open_error error = Sysio::OPEN_ERR_UNACCESSIBLE;
+ try {
+ ::File_system::File_handle file = _fs.file(dir, file_name.base() + 1,
+ mode, create);
+ return new (env()->heap()) Fs_vfs_handle(this, 0, file);
+ }
+ catch (::File_system::Permission_denied) {
+ error = Sysio::OPEN_ERR_NO_PERM; }
+ catch (::File_system::Invalid_handle) {
+ error = Sysio::OPEN_ERR_NO_PERM; }
+
+ sysio->error.open = error;
+
+ return 0;
+ }
+
+
+ /***************************
+ ** File_system interface **
+ ***************************/
+
+ char const *name() const { return "fs"; }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ bool write(Sysio *sysio, Vfs_handle *vfs_handle)
+ {
+ Fs_vfs_handle const *handle = static_cast(vfs_handle);
+
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+
+ size_t const max_packet_size = source.bulk_buffer_size() / 2;
+ size_t const count = min(max_packet_size,
+ min(sizeof(sysio->write_in.chunk),
+ sysio->write_in.count));
+
+ ::File_system::Packet_descriptor
+ packet(source.alloc_packet(count),
+ 0,
+ handle->file_handle(),
+ ::File_system::Packet_descriptor::WRITE,
+ count,
+ handle->seek());
+
+ memcpy(source.packet_content(packet), sysio->write_in.chunk, count);
+
+ /* pass packet to server side */
+ source.submit_packet(packet);
+ source.get_acked_packet();
+
+ sysio->write_out.count = count;
+
+ /*
+ * XXX check if acked packet belongs to request,
+ * needed for thread safety
+ */
+
+ source.release_packet(packet);
+
+ return true;
+ }
+
+ bool read(Sysio *sysio, Vfs_handle *vfs_handle)
+ {
+ Fs_vfs_handle const *handle = static_cast(vfs_handle);
+
+ ::File_system::Status status = _fs.status(handle->file_handle());
+ size_t const file_size = status.size;
+
+ size_t const file_bytes_left = file_size >= handle->seek()
+ ? file_size - handle->seek() : 0;
+
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+
+ size_t const max_packet_size = source.bulk_buffer_size() / 2;
+ size_t const count = min(max_packet_size,
+ min(file_bytes_left,
+ min(sizeof(sysio->read_out.chunk),
+ sysio->read_in.count)));
+
+ ::File_system::Packet_descriptor
+ packet(source.alloc_packet(count),
+ 0,
+ handle->file_handle(),
+ ::File_system::Packet_descriptor::READ,
+ count,
+ handle->seek());
+
+ /* pass packet to server side */
+ source.submit_packet(packet);
+ source.get_acked_packet();
+
+ memcpy(sysio->read_out.chunk, source.packet_content(packet), count);
+
+ sysio->read_out.count = count;
+
+ /*
+ * XXX check if acked packet belongs to request,
+ * needed for thread safety
+ */
+
+ source.release_packet(packet);
+ return true;
+ }
+ };
+}
+
+#endif /* _NOUX__FS_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/io_channel.h b/ports/src/noux/io_channel.h
index 2ecec4cbe9..9f5b3e7bf2 100644
--- a/ports/src/noux/io_channel.h
+++ b/ports/src/noux/io_channel.h
@@ -44,6 +44,10 @@ namespace Noux {
public:
+ bool close_on_execve;
+
+ Io_channel() : close_on_execve(false) { }
+
virtual ~Io_channel() { }
virtual bool write(Sysio *sysio, size_t &count) { return false; }
@@ -53,6 +57,7 @@ namespace Noux {
virtual bool fchdir(Sysio *sysio, Pwd *pwd) { return false; }
virtual bool dirent(Sysio *sysio) { return false; }
virtual bool ioctl(Sysio *sysio) { return false; }
+ virtual bool lseek(Sysio *sysio) { return false; }
/**
* Return true if an unblocking condition of the channel is satisfied
diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc
index 9a387201f8..10b0888567 100644
--- a/ports/src/noux/main.cc
+++ b/ports/src/noux/main.cc
@@ -34,8 +34,8 @@
* ;- import env into child (execve and fork)
* ;- shell
* - debug 'find'
- * - stacked file system infrastructure
- * - TMP file system
+ * ;- stacked file system infrastructure
+ * ;- TMP file system
* ;- RAM service using a common quota pool
*/
@@ -49,8 +49,7 @@
#include
#include
#include
-#include
-#include
+#include
enum { verbose_syscall = false };
@@ -121,8 +120,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_STAT:
case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */
- return _vfs->stat(_sysio, Absolute_path(_sysio->stat_in.path,
- _env.pwd()).base());
+ return _root_dir->stat(_sysio, Absolute_path(_sysio->stat_in.path,
+ _env.pwd()).base());
case SYSCALL_FSTAT:
@@ -130,28 +129,41 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_FCNTL:
+ if (_sysio->fcntl_in.cmd == Sysio::FCNTL_CMD_SET_FD_FLAGS) {
+
+ /* we assume that there is only the close-on-execve flag */
+ _lookup_channel(_sysio->fcntl_in.fd)->close_on_execve =
+ !!_sysio->fcntl_in.long_arg;
+ return true;
+ }
+
return _lookup_channel(_sysio->fcntl_in.fd)->fcntl(_sysio);
case SYSCALL_OPEN:
{
Absolute_path absolute_path(_sysio->open_in.path, _env.pwd());
- PINF("open pwd=%s path=%s", _env.pwd(), _sysio->open_in.path);
-
- /* remember mode only for debug output */
- int const mode = _sysio->open_in.mode;
-
- Vfs_handle *vfs_handle = _vfs->open(_sysio, absolute_path.base());
+ Vfs_handle *vfs_handle = _root_dir->open(_sysio, absolute_path.base());
if (!vfs_handle)
return false;
- Shared_pointer channel(new Vfs_io_channel(absolute_path.base(), _vfs, vfs_handle),
- Genode::env()->heap());
+ char const *leaf_path = _root_dir->leaf_path(absolute_path.base());
+
+ /*
+ * File descriptors of opened directories are handled by
+ * '_root_dir'. In this case, we use the absolute path as leaf
+ * path because path operations always refer to the global
+ * root.
+ */
+ if (vfs_handle->ds() == _root_dir)
+ leaf_path = absolute_path.base();
+
+ Shared_pointer
+ channel(new Vfs_io_channel(absolute_path.base(),
+ leaf_path, _root_dir, vfs_handle),
+ Genode::env()->heap());
_sysio->open_out.fd = add_io_channel(channel);
-
- PINF("open fd %d for \"%s\" with mode %o",
- _sysio->open_out.fd, absolute_path.base(), mode);
return true;
}
@@ -165,6 +177,10 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
return _lookup_channel(_sysio->ioctl_in.fd)->ioctl(_sysio);
+ case SYSCALL_LSEEK:
+
+ return _lookup_channel(_sysio->lseek_in.fd)->lseek(_sysio);
+
case SYSCALL_DIRENT:
return _lookup_channel(_sysio->dirent_in.fd)->dirent(_sysio);
@@ -175,7 +191,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_EXECVE:
{
- char const *filename = _sysio->execve_in.filename;
+ Absolute_path absolute_path(_sysio->execve_in.filename, _env.pwd());
/*
* Deserialize environment variable buffer into a
@@ -208,11 +224,11 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
j += strlen(src);
}
- Child *child = new Child(filename,
+ Child *child = new Child(absolute_path.base(),
parent(),
pid(),
_sig_rec,
- _vfs,
+ _root_dir,
Args(_sysio->execve_in.args,
sizeof(_sysio->execve_in.args)),
env,
@@ -350,7 +366,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
this,
new_pid,
_sig_rec,
- _vfs,
+ _root_dir,
_args,
_env.env(),
_env.pwd(),
@@ -425,6 +441,23 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
return true;
}
+ case SYSCALL_UNLINK:
+
+ return _root_dir->unlink(_sysio, Absolute_path(_sysio->unlink_in.path,
+ _env.pwd()).base());
+
+ case SYSCALL_RENAME:
+
+ return _root_dir->rename(_sysio, Absolute_path(_sysio->rename_in.from_path,
+ _env.pwd()).base(),
+ Absolute_path(_sysio->rename_in.to_path,
+ _env.pwd()).base());
+
+ case SYSCALL_MKDIR:
+
+ return _root_dir->mkdir(_sysio, Absolute_path(_sysio->mkdir_in.path,
+ _env.pwd()).base());
+
case SYSCALL_INVALID: break;
}
}
@@ -568,15 +601,8 @@ int main(int argc, char **argv)
static Genode::Cap_connection cap;
/* initialize virtual file system */
- static Vfs vfs;
-
- try {
- Genode::Xml_node fs = Genode::config()->xml_node().sub_node("fstab").sub_node();
- for (; ; fs = fs.next()) {
- if (fs.has_type("tar"))
- vfs.add_file_system(new Tar_file_system(fs));
- }
- } catch (Genode::Xml_node::Nonexistent_sub_node) { }
+ static Dir_file_system
+ root_dir(config()->xml_node().sub_node("fstab"));
/*
* Entrypoint used to virtualize child resources such as RAM, RM
@@ -591,7 +617,7 @@ int main(int argc, char **argv)
0,
pid_allocator()->alloc(),
&sig_rec,
- &vfs,
+ &root_dir,
args_of_init_process(),
env_string_of_init_process(),
"/",
diff --git a/ports/src/noux/path.h b/ports/src/noux/path.h
index af483ebcf0..dcd99d8b71 100644
--- a/ports/src/noux/path.h
+++ b/ports/src/noux/path.h
@@ -59,9 +59,10 @@ namespace Noux {
path[i] = 0;
}
- static char const *last_element(char const *path)
+ template
+ static T *last_element(T *path)
{
- char const *result = path;
+ T *result = path;
for (; *path; path++)
if (path[0] == '/' && path[1] != 0)
result = path;
@@ -199,10 +200,8 @@ namespace Noux {
_append_slash_if_needed();
_append(relative_path);
}
-// PDBG("path: '%s'", _path);
}
_canonicalize();
-// PDBG("canonical path: '%s'", _path);
}
public:
@@ -231,6 +230,11 @@ namespace Noux {
*dst = 0;
}
+ void strip_last_element()
+ {
+ last_element(_path)[1] = 0;
+ }
+
bool equals(Path_base const &ref) const { return strcmp(ref._path, _path) == 0; }
bool equals(char const *str) const { return strcmp(str, _path) == 0; }
@@ -269,7 +273,7 @@ namespace Noux {
return (num_slashes == 1) && !equals("/");
}
- void append(char const *str) { _append(str); }
+ void append(char const *str) { _append(str); _canonicalize(); }
};
diff --git a/ports/src/noux/root_file_system.h b/ports/src/noux/root_file_system.h
deleted file mode 100644
index 063f654fd9..0000000000
--- a/ports/src/noux/root_file_system.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * \brief Root file system
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2012 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU General Public License version 2.
- */
-
-#ifndef _NOUX__ROOT_FILE_SYSTEM_H_
-#define _NOUX__ROOT_FILE_SYSTEM_H_
-
-/* Genode includes */
-#include
-#include
-
-/* Noux includes */
-#include
-
-namespace Noux {
-
- class Root_file_system : public File_system
- {
- private:
-
- Lock _lock;
-
- public:
-
- Root_file_system() : File_system("/") { }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- bool stat(Sysio *sysio, char const *path)
- {
- sysio->stat_out.st.size = 1234;
- sysio->stat_out.st.mode = Sysio::STAT_MODE_DIRECTORY | 0755;
- sysio->stat_out.st.uid = 13;
- sysio->stat_out.st.gid = 14;
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path)
- {
- Lock::Guard guard(_lock);
-
- int const index = sysio->dirent_in.index;
- if (index) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- return true;
- }
- sysio->dirent_out.entry.fileno = 13;
-
- strncpy(sysio->dirent_out.entry.name, "test",
- sizeof(sysio->dirent_out.entry.name));
-
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_DIRECTORY;
- return true;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- Lock::Guard guard(_lock);
-
- if (strcmp(path, "/") == 0)
- return new (env()->heap()) Vfs_handle(this, this, 0);
-
- return 0;
- }
-
- void close(Vfs_handle *handle)
- {
- Lock::Guard guard(_lock);
- destroy(env()->heap(), handle);
- }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *handle) { return false; }
- };
-}
-
-#endif /* _NOUX__ROOT_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/tar_file_system.h b/ports/src/noux/tar_file_system.h
index 813dbac248..e50cc7e337 100644
--- a/ports/src/noux/tar_file_system.h
+++ b/ports/src/noux/tar_file_system.h
@@ -22,6 +22,8 @@
/* Noux includes */
#include
+#include
+#include
namespace Noux {
@@ -227,13 +229,43 @@ namespace Noux {
}
+ struct Num_dirent_cache
+ {
+ Lock lock;
+ Tar_file_system &tar_fs;
+ bool valid; /* true after first lookup */
+ char key[256]; /* key used for lookup */
+ size_t cached_num_dirent; /* cached value */
+
+ Num_dirent_cache(Tar_file_system &tar_fs)
+ : tar_fs(tar_fs), valid(false), cached_num_dirent(0) { }
+
+ size_t num_dirent(char const *path)
+ {
+ Lock::Guard guard(lock);
+
+ /* check for cache miss */
+ if (!valid || strcmp(path, key) != 0) {
+
+ Lookup_member_of_path lookup_criterion(path, ~0);
+ tar_fs._lookup(&lookup_criterion);
+ strncpy(key, path, sizeof(key));
+ cached_num_dirent = lookup_criterion.cnt;
+ valid = true;
+ }
+ return cached_num_dirent;
+ }
+ } _cached_num_dirent;
+
+
public:
Tar_file_system(Xml_node config)
:
- File_system(config), _rom_name(config), _rom(_rom_name.name),
+ _rom_name(config), _rom(_rom_name.name),
_tar_base(env()->rm_session()->attach(_rom.dataspace())),
- _tar_size(Dataspace_client(_rom.dataspace()).size())
+ _tar_size(Dataspace_client(_rom.dataspace()).size()),
+ _cached_num_dirent(*this)
{
PINF("tar archive '%s' local at %p, size is %zd",
_rom_name.name, _tar_base, _tar_size);
@@ -284,7 +316,7 @@ namespace Noux {
return Dataspace_capability();
}
- void release(Dataspace_capability ds_cap)
+ void release(char const *, Dataspace_capability ds_cap)
{
env()->ram_session()->free(static_cap_cast(ds_cap));
}
@@ -315,12 +347,10 @@ namespace Noux {
return true;
}
- bool dirent(Sysio *sysio, char const *path)
+ bool dirent(Sysio *sysio, char const *path, off_t index)
{
Lock::Guard guard(_lock);
- int const index = sysio->dirent_in.index;
-
Lookup_member_of_path lookup_criterion(path, index);
Record *record = _lookup(&lookup_criterion);
if (!record) {
@@ -345,16 +375,43 @@ namespace Noux {
absolute_path.base() + 1,
sizeof(sysio->dirent_out.entry.name));
- PWRN("direntry in %s: %s", path, absolute_path.base() + 1);
return true;
}
+ bool unlink(Sysio *, char const *) { return false; }
+
+ bool rename(Sysio *, char const *, char const *) { return false; }
+
+ bool mkdir(Sysio *, char const *) { return false; }
+
+ size_t num_dirent(char const *path)
+ {
+ return _cached_num_dirent.num_dirent(path);
+ }
+
+ bool is_directory(char const *path)
+ {
+ Lookup_exact lookup_criterion(path);
+ Record const * record = _lookup(&lookup_criterion);
+ return record && (record->type() == Record::TYPE_DIR);
+ }
+
+ char const *leaf_path(char const *path)
+ {
+ /*
+ * Check if path exists within the file system. If this is the
+ * case, return the whole path, which is relative to the root
+ * of this file system.
+ */
+ Lookup_exact lookup_criterion(path);
+ Record const * record = _lookup(&lookup_criterion);
+ return record ? path : 0;
+ }
+
Vfs_handle *open(Sysio *sysio, char const *path)
{
Lock::Guard guard(_lock);
- PDBG("open %s", path);
-
Lookup_exact lookup_criterion(path);
Record *record = 0;
if ((record = _lookup(&lookup_criterion)))
@@ -365,11 +422,12 @@ namespace Noux {
return 0;
}
- void close(Vfs_handle *handle)
- {
- Lock::Guard guard(_lock);
- destroy(env()->heap(), handle);
- }
+
+ /***************************
+ ** File_system interface **
+ ***************************/
+
+ char const *name() const { return "tar"; }
/********************************
diff --git a/ports/src/noux/vfs.h b/ports/src/noux/vfs.h
deleted file mode 100644
index 0993805a7f..0000000000
--- a/ports/src/noux/vfs.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * \brief Management of file systems within virtual directory tree
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2012 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU General Public License version 2.
- */
-
-#ifndef _NOUX__VFS_H_
-#define _NOUX__VFS_H_
-
-/* Genode includes */
-#include
-#include
-
-/* Noux includes */
-#include
-#include
-#include
-#include
-#include
-
-namespace Noux {
-
- class Vfs
- {
- private:
-
- List _file_systems;
-
- public:
-
- Dataspace_capability dataspace_from_file(char const *filename)
- {
- for (File_system *fs = _file_systems.first(); fs; fs = fs->next()) {
- char const *fs_local_path = fs->local_path(filename);
- Dataspace_capability ds_cap;
- if (fs_local_path && (ds_cap = fs->dataspace(fs_local_path)).valid())
- return ds_cap;
- }
- return Dataspace_capability();
- }
-
- void release_dataspace_for_file(char const *filename,
- Dataspace_capability ds_cap)
- {
- for (File_system *fs = _file_systems.first(); fs; fs = fs->next()) {
- char const *fs_local_path = fs->local_path(filename);
- if (fs_local_path)
- fs->release(ds_cap);
- }
- }
-
- void add_file_system(File_system *file_system)
- {
- _file_systems.insert(file_system);
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- for (File_system *fs = _file_systems.first(); fs; fs = fs->next()) {
- char const *fs_local_path = fs->local_path(path);
- if (fs_local_path && fs->stat(sysio, fs_local_path))
- return true;
- }
-
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- Vfs_handle *handle;
- for (File_system *fs = _file_systems.first(); fs; fs = fs->next()) {
- char const *fs_local_path = fs->local_path(path);
- if (fs_local_path && (handle = fs->open(sysio, fs_local_path)))
- return handle;
- }
-
- PWRN("no file system for \"%s\"", path);
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
- void close(Vfs_handle *handle)
- {
- handle->ds()->close(handle);
- }
- };
-}
-
-#endif /* _NOUX__VIRTUAL_DIRECTORY_SERVICE_H_ */
diff --git a/ports/src/noux/vfs_handle.h b/ports/src/noux/vfs_handle.h
index 3fab73ae92..3a3ec50a02 100644
--- a/ports/src/noux/vfs_handle.h
+++ b/ports/src/noux/vfs_handle.h
@@ -51,12 +51,17 @@ namespace Noux {
return Dataspace_capability();
}
- void release(Dataspace_capability) { }
+ void release(char const *, Dataspace_capability) { }
- bool stat(Sysio *, char const *) { return _msg("stat"); }
- Vfs_handle *open(Sysio *, char const *) { _msg("open"); return 0; }
- void close(Vfs_handle *) { _msg("close"); }
- bool dirent(Sysio *, char const *) { return _msg("dirent"); }
+ bool stat(Sysio *, char const *) { return _msg("stat"); }
+ Vfs_handle *open(Sysio *, char const *) { _msg("open"); return 0; }
+ bool dirent(Sysio *, char const *, off_t) { return _msg("dirent"); }
+ bool unlink(Sysio *, char const *) { return _msg("unlink"); }
+ bool rename(Sysio *, char const *, char const *) { return _msg("rename"); }
+ bool mkdir(Sysio *, char const *) { return _msg("mkdir"); }
+ size_t num_dirent(char const *) { return 0; }
+ bool is_directory(char const *) { return false; }
+ char const *leaf_path(char const *path) { return 0; }
};
static Pseudo_directory_service ds;
return &ds;
diff --git a/ports/src/noux/vfs_io_channel.h b/ports/src/noux/vfs_io_channel.h
index 2204468336..2b8619fa49 100644
--- a/ports/src/noux/vfs_io_channel.h
+++ b/ports/src/noux/vfs_io_channel.h
@@ -17,23 +17,33 @@
/* Noux includes */
#include
#include
+#include
#include
namespace Noux {
struct Vfs_io_channel : public Io_channel
{
- Vfs *_vfs;
Vfs_handle *_fh;
Absolute_path _path;
+ Absolute_path _leaf_path;
- Vfs_io_channel(char const *path, Vfs *vfs, Vfs_handle *vfs_handle)
- : _vfs(vfs), _fh(vfs_handle), _path(path) { }
+ Vfs_io_channel(char const *path, char const *leaf_path,
+ Dir_file_system *root_dir, Vfs_handle *vfs_handle)
+ : _fh(vfs_handle), _path(path), _leaf_path(leaf_path) { }
- ~Vfs_io_channel() { _vfs->close(_fh); }
+ ~Vfs_io_channel() { destroy(env()->heap(), _fh); }
- bool write(Sysio *sysio) { return _fh->fs()->write(sysio, _fh); }
+ bool write(Sysio *sysio, size_t &count)
+ {
+ if (!_fh->fs()->write(sysio, _fh))
+ return false;
+
+ count = sysio->write_out.count;
+ _fh->_seek += count;
+ return true;
+ }
bool read(Sysio *sysio)
{
@@ -44,16 +54,15 @@ namespace Noux {
return true;
}
- bool fstat(Sysio *sysio) { return _fh->ds()->stat(sysio, _path.base()); }
+ bool fstat(Sysio *sysio)
+ {
+ return _fh->ds()->stat(sysio, _leaf_path.base());
+ }
bool fcntl(Sysio *sysio)
{
switch (sysio->fcntl_in.cmd) {
- case Sysio::FCNTL_CMD_SET_FD_FLAGS:
-
- return true;
-
case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS:
sysio->fcntl_out.result = _fh->status_flags();
@@ -73,12 +82,18 @@ namespace Noux {
return true;
}
+ /*
+ * The 'dirent' function for the root directory only (the
+ * 'Dir_file_system::open()' function handles all requests referring
+ * to directories). Hence, '_path' is the absolute path of the
+ * directory to inspect.
+ */
bool dirent(Sysio *sysio)
{
/*
* Return artificial dir entries for "." and ".."
*/
- unsigned const index = sysio->dirent_in.index;
+ unsigned const index = _fh->seek() / sizeof(Sysio::Dirent);
if (index < 2) {
sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_DIRECTORY;
strncpy(sysio->dirent_out.entry.name,
@@ -86,15 +101,46 @@ namespace Noux {
sizeof(sysio->dirent_out.entry.name));
sysio->dirent_out.entry.fileno = 1;
+ _fh->_seek += sizeof(Sysio::Dirent);
return true;
}
/*
- * Delegate remaining dir-entry request to the actual file
- * system.
+ * Delegate remaining dir-entry request to the actual file system.
+ * Align index range to zero when calling the directory service.
*/
- sysio->dirent_in.index -= 2;
- return _fh->ds()->dirent(sysio, _path.base());
+
+ if (!_fh->ds()->dirent(sysio, _path.base(), index - 2))
+ return false;
+
+ _fh->_seek += sizeof(Sysio::Dirent);
+ return true;
+ }
+
+ /**
+ * Return size of file that the I/O channel refers to
+ *
+ * Note that this function overwrites the 'sysio' argument. Do not
+ * call it prior saving all input arguments from the original sysio
+ * structure.
+ */
+ size_t size(Sysio *sysio)
+ {
+ if (fstat(sysio))
+ return sysio->stat_out.st.size;
+
+ return 0;
+ }
+
+ bool lseek(Sysio *sysio)
+ {
+ switch (sysio->lseek_in.whence) {
+ case Sysio::LSEEK_SET: _fh->_seek = sysio->lseek_in.offset; break;
+ case Sysio::LSEEK_CUR: break;
+ case Sysio::LSEEK_END: _fh->_seek = size(sysio); break;
+ }
+ sysio->lseek_out.offset = _fh->_seek;
+ return true;
}
bool check_unblock(bool rd, bool wr, bool ex) const