diff --git a/os/include/vfs/block_file_system.h b/os/include/vfs/block_file_system.h
new file mode 100644
index 000000000..b7e292d2e
--- /dev/null
+++ b/os/include/vfs/block_file_system.h
@@ -0,0 +1,328 @@
+/*
+ * \brief Block device file system
+ * \author Josef Soentgen
+ * \author Norman Feske
+ * \date 2013-12-20
+ */
+
+/*
+ * Copyright (C) 2013-2014 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 _INCLUDE__VFS__BLOCK_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__BLOCK_FILE_SYSTEM_H_
+
+#include
+#include
+#include
+
+namespace Vfs { class Block_file_system; }
+
+
+class Vfs::Block_file_system : public Single_file_system
+{
+ private:
+
+ 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;
+
+ /*
+ * Serialize access to packet stream of the block session
+ */
+ Lock _lock;
+
+ char *_block_buffer;
+ unsigned _block_buffer_count;
+
+ Genode::Allocator_avl _tx_block_alloc;
+ Block::Connection _block;
+ size_t _block_size;
+ Block::sector_t _block_count;
+ Block::Session::Operations _block_ops;
+ Block::Session::Tx::Source *_tx_source;
+
+ bool _readable;
+ bool _writeable;
+
+ size_t _block_io(size_t nr, void *buf, size_t sz, bool write, bool bulk = false)
+ {
+ Lock::Guard guard(_lock);
+
+ Block::Packet_descriptor::Opcode op;
+ op = write ? Block::Packet_descriptor::WRITE : Block::Packet_descriptor::READ;
+
+ size_t packet_size = bulk ? sz : _block_size;
+ size_t packet_count = bulk ? (sz / _block_size) : 1;
+
+ /* sanity check */
+ if (packet_count > _block_buffer_count) {
+ packet_size = _block_buffer_count * _block_size;
+ packet_count = _block_buffer_count;
+ }
+
+ Block::Packet_descriptor p(_tx_source->alloc_packet(packet_size), op,
+ nr, packet_count);
+
+ if (write)
+ Genode::memcpy(_tx_source->packet_content(p), buf, packet_size);
+
+ _tx_source->submit_packet(p);
+ p = _tx_source->get_acked_packet();
+
+ if (!p.succeeded()) {
+ PERR("Could not read block(s)");
+ _tx_source->release_packet(p);
+ return 0;
+ }
+
+ if (!write)
+ Genode::memcpy(buf, _tx_source->packet_content(p), packet_size);
+
+ _tx_source->release_packet(p);
+ return packet_size;
+ }
+
+ public:
+
+ Block_file_system(Xml_node config)
+ :
+ Single_file_system(NODE_TYPE_BLOCK_DEVICE, name(), config),
+ _label(config),
+ _block_buffer(0),
+ _block_buffer_count(1),
+ _tx_block_alloc(env()->heap()),
+ _block(&_tx_block_alloc, 128*1024, _label.string),
+ _tx_source(_block.tx()),
+ _readable(false),
+ _writeable(false)
+ {
+ try { config.attribute("block_buffer_count").value(&_block_buffer_count); }
+ catch (...) { }
+
+ _block.info(&_block_count, &_block_size, &_block_ops);
+
+ _readable = _block_ops.supported(Block::Packet_descriptor::READ);
+ _writeable = _block_ops.supported(Block::Packet_descriptor::WRITE);
+
+ _block_buffer = new (env()->heap()) char[_block_buffer_count * _block_size];
+ }
+
+ ~Block_file_system()
+ {
+ destroy(env()->heap(), _block_buffer);
+ }
+
+ static char const *name() { return "block"; }
+
+
+ /*********************************
+ ** Directory service interface **
+ *********************************/
+
+ Stat_result stat(char const *path, Stat &out) override
+ {
+ Stat_result const result = Single_file_system::stat(path, out);
+ out.size = _block_size*_block_count;
+ return result;
+ }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *vfs_handle, char const *buf, size_t count,
+ size_t &out_count) override
+ {
+ if (!_writeable) {
+ PERR("block device is not writeable");
+ return WRITE_ERR_INVALID;
+ }
+
+ size_t seek_offset = vfs_handle->seek();
+
+ size_t written = 0;
+ while (count > 0) {
+ size_t displ = 0;
+ size_t length = 0;
+ size_t nbytes = 0;
+ size_t blk_nr = seek_offset / _block_size;
+
+ displ = seek_offset % _block_size;
+
+ if ((displ + count) > _block_size)
+ length = (_block_size - displ);
+ else
+ length = count;
+
+ /*
+ * We take a shortcut and write as much as possible without
+ * using the block buffer if the offset is aligned on a block
+ * boundary and the count is a multiple of the block size,
+ * e.g. 4K writes will be written at once.
+ *
+ * XXX this is quite hackish because we have to omit partial
+ * blocks at the end.
+ */
+ if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
+ size_t bytes_left = count - (count % _block_size);
+
+ nbytes = _block_io(blk_nr, (void*)(buf + written),
+ bytes_left, true, true);
+ if (nbytes == 0) {
+ PERR("error while write block:%zu from block device",
+ blk_nr);
+ return WRITE_ERR_INVALID;
+ }
+
+ written += nbytes;
+ count -= nbytes;
+
+ continue;
+ }
+
+ /*
+ * The offset is not aligned on a block boundary. Therefore
+ * we need to read the block to the block buffer first and
+ * put the buffer content at the right offset before we can
+ * write the whole block back. In addition if length is less
+ * than block size, we also have to read the block first.
+ */
+ if (displ > 0 || length < _block_size) {
+ PWRN("offset:%zd block_size:%zd displacement:%zd length:%zu",
+ seek_offset, _block_size, displ, length);
+
+ _block_io(blk_nr, _block_buffer, _block_size, false);
+ /* rewind seek offset to account for the block read */
+ seek_offset -= _block_size;
+ }
+
+ Genode::memcpy(_block_buffer + displ, buf + written, length);
+
+ nbytes = _block_io(blk_nr, _block_buffer, _block_size, true);
+ if ((unsigned)nbytes != _block_size) {
+ PERR("error while writing block:%zu from Block_device",
+ blk_nr);
+ return WRITE_ERR_INVALID;
+ }
+
+ written += length;
+ count -= length;
+ }
+
+ out_count = written;
+
+ return WRITE_OK;
+ }
+
+ Read_result read(Vfs_handle *vfs_handle, char *dst, size_t count,
+ size_t &out_count) override
+ {
+ if (!_readable) {
+ PERR("block device is not readable");
+ return READ_ERR_INVALID;
+ }
+
+ size_t seek_offset = vfs_handle->seek();
+
+ size_t read = 0;
+ while (count > 0) {
+ size_t displ = 0;
+ size_t length = 0;
+ size_t nbytes = 0;
+ size_t blk_nr = seek_offset / _block_size;
+
+ displ = seek_offset % _block_size;
+
+ if ((displ + count) > _block_size)
+ length = (_block_size - displ);
+ else
+ length = count;
+
+ /*
+ * We take a shortcut and read the blocks all at once if t he
+ * offset is aligned on a block boundary and we the count is a
+ * multiple of the block size, e.g. 4K reads will be read at
+ * once.
+ *
+ * XXX this is quite hackish because we have to omit partial
+ * blocks at the end.
+ */
+ if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
+ size_t bytes_left = count - (count % _block_size);
+
+ nbytes = _block_io(blk_nr, dst + read, bytes_left, false, true);
+ if (nbytes == 0) {
+ PERR("error while reading block:%zu from block device",
+ blk_nr);
+ return READ_ERR_INVALID;
+ }
+
+ read += nbytes;
+ count -= nbytes;
+
+ continue;
+ }
+
+ if (displ > 0)
+ PWRN("offset:%zd is not aligned to block_size:%zu"
+ " displacement:%zu", seek_offset, _block_size,
+ displ);
+
+ nbytes = _block_io(blk_nr, _block_buffer, _block_size, false);
+ if ((unsigned)nbytes != _block_size) {
+ PERR("error while reading block:%zu from block device",
+ blk_nr);
+ return READ_ERR_INVALID;
+ }
+
+ Genode::memcpy(dst + read, _block_buffer + displ, length);
+
+ read += length;
+ count -= length;
+ }
+
+ out_count = read;
+
+ return READ_OK;
+ }
+
+ Ftruncate_result ftruncate(Vfs_handle *vfs_handle, size_t) override
+ {
+ return FTRUNCATE_OK;
+ }
+
+ Ioctl_result ioctl(Vfs_handle *vfs_handle, Ioctl_opcode opcode, Ioctl_arg,
+ Ioctl_out &out) override
+ {
+ switch (opcode) {
+ case IOCTL_OP_DIOCGMEDIASIZE:
+
+ out.diocgmediasize.size = _block_count * _block_size;
+ return IOCTL_OK;
+
+ default:
+
+ PDBG("invalid ioctl request %d", opcode);
+ break;
+ }
+
+ /* never reached */
+ return IOCTL_ERR_INVALID;
+ }
+};
+
+#endif /* _INCLUDE__VFS__BLOCK_FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/dir_file_system.h b/os/include/vfs/dir_file_system.h
new file mode 100644
index 000000000..28f4731ae
--- /dev/null
+++ b/os/include/vfs/dir_file_system.h
@@ -0,0 +1,540 @@
+/*
+ * \brief Directory file system
+ * \author Norman Feske
+ * \date 2012-04-23
+ */
+
+/*
+ * Copyright (C) 2011-2014 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 _INCLUDE__VFS__DIR_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__DIR_FILE_SYSTEM_H_
+
+#include
+#include
+
+
+namespace Vfs { class Dir_file_system; }
+
+
+class Vfs::Dir_file_system : public File_system
+{
+ public:
+
+ enum { MAX_NAME_LEN = 128 };
+
+ private:
+
+ /* 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; }
+
+ /**
+ * Perform operation on a file system
+ *
+ * \param fn functor that takes a file-system reference and
+ * the path as arguments
+ */
+ template
+ RES _dir_op(RES const no_entry, RES const no_perm, RES const ok,
+ char const *path, FN const &fn)
+ {
+ path = _sub_path(path);
+
+ /* path does not match directory name */
+ if (!path)
+ return no_entry;
+
+ /*
+ * Prevent operation if path equals directory name defined
+ * via the static VFS configuration.
+ */
+ if (strlen(path) == 0)
+ return no_perm;
+
+ /*
+ * If any of the sub file systems returns a permission error and
+ * there exists no sub file system that takes the request, we
+ * return the permission error.
+ */
+ bool permission_denied = 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 operation succeeds, we return success.
+ */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+
+ RES const err = fn(*fs, path);
+
+ if (err == ok)
+ return err;
+
+ /*
+ * Keep the most meaningful error code. When using stacked file
+ * systems, most child file systems will eventually return no
+ * entry (or leave the error code unchanged). If any of those
+ * file systems has anything more interesting to tell (in
+ * particular no perm), return this information.
+ */
+ if (err != no_entry && err != no_perm)
+ return err;
+
+ if (err == no_perm)
+ permission_denied = true;
+ }
+
+ /* none of our file systems could successfully operate on the path */
+ return permission_denied ? no_perm : no_entry;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * The 'path' is relative to the child file systems.
+ */
+ Dirent_result _dirent_of_file_systems(char const *path, off_t index, Dirent &out)
+ {
+ 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;
+ Dirent_result const err = fs->dirent(path, index, out);
+ out.fileno += base;
+ return err;
+ }
+
+ /* adjust base index for next file system */
+ base += fs_num_dirent;
+ }
+
+ out.type = DIRENT_TYPE_END;
+ return DIRENT_OK;
+ }
+
+ void _dirent_of_this_dir_node(off_t index, Dirent &out)
+ {
+ if (index == 0) {
+ strncpy(out.name, _name, sizeof(out.name));
+
+ out.type = DIRENT_TYPE_DIRECTORY;
+ out.fileno = 1;
+ } else {
+ out.type = DIRENT_TYPE_END;
+ }
+ }
+
+ /*
+ * 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;
+ }
+
+ public:
+
+ Dir_file_system(Xml_node node, File_system_factory &fs_factory)
+ :
+ _first_file_system(0)
+ {
+ /* remember directory name */
+ if (node.has_type("fstab") || node.has_type("vfs"))
+ _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);
+
+ /* traverse into nodes */
+ if (sub_node.has_type("dir")) {
+ _append_file_system(new (env()->heap())
+ Dir_file_system(sub_node, fs_factory));
+ continue;
+ }
+
+ File_system *fs = fs_factory.create(sub_node);
+ if (fs) {
+ _append_file_system(fs);
+ continue;
+ }
+
+ char type_name[64];
+ sub_node.type_name(type_name, sizeof(type_name));
+ PWRN("unknown fstab node type <%s>", type_name);
+ }
+ }
+
+
+ /*********************************
+ ** Directory-service interface **
+ *********************************/
+
+ Dataspace_capability dataspace(char const *path) override
+ {
+ 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) override
+ {
+ path = _sub_path(path);
+ if (!path)
+ return;
+
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ fs->release(path, ds_cap);
+ }
+
+ Stat_result stat(char const *path, Stat &out) override
+ {
+ path = _sub_path(path);
+
+ /* path does not match directory name */
+ if (!path)
+ return STAT_ERR_NO_ENTRY;
+
+ /*
+ * If path equals directory name, return information about the
+ * current directory.
+ */
+ if (strlen(path) == 0 || (strcmp(path, "/") == 0)) {
+ out.size = 0;
+ out.mode = STAT_MODE_DIRECTORY | 0755;
+ out.uid = 0;
+ out.gid = 0;
+ return STAT_OK;
+ }
+
+ /*
+ * 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) {
+
+ Stat_result const err = fs->stat(path, out);
+
+ if (err == STAT_OK)
+ return err;
+
+ if (err != STAT_ERR_NO_ENTRY)
+ return err;
+ }
+
+ /* none of our file systems felt responsible for the path */
+ return STAT_ERR_NO_ENTRY;
+ }
+
+ Dirent_result dirent(char const *path, off_t index, Dirent &out) override
+ {
+ if (_is_root())
+ return _dirent_of_file_systems(path, index, out);
+
+ if (strcmp(path, "/") == 0) {
+ _dirent_of_this_dir_node(index, out);
+ return DIRENT_OK;
+ }
+
+ /* path contains at least one element */
+
+ /* remove current element from path */
+ path = _sub_path(path);
+
+ /* path does not lie within our tree */
+ if (!path)
+ return DIRENT_ERR_INVALID_PATH;
+
+ return _dirent_of_file_systems(path, index, out);
+ }
+
+ size_t num_dirent(char const *path) override
+ {
+ 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) override
+ {
+ 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) override
+ {
+ 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;
+ }
+
+ Open_result open(char const *path, unsigned mode, Vfs_handle **out_handle) override
+ {
+ /*
+ * 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)) {
+ *out_handle = new (env()->heap()) Vfs_handle(*this, *this, 0);
+ return OPEN_OK;
+ }
+
+ /*
+ * If 'path' refers to a non-directory node, create a
+ * 'Vfs_handle' local to the file system that provides the
+ * file.
+ */
+
+ path = _sub_path(path);
+
+ /* check if path does not match directory name */
+ if (!path)
+ return OPEN_ERR_UNACCESSIBLE;
+
+ /* path equals directory name */
+ if (strlen(path) == 0) {
+ *out_handle = new (env()->heap()) Vfs_handle(*this, *this, 0);
+ return OPEN_OK;
+ }
+
+ /* path refers to any of our sub file systems */
+ for (File_system *fs = _first_file_system; fs; fs = fs->next) {
+
+ Open_result const err = fs->open(path, mode, out_handle);
+
+ if (err == OPEN_OK)
+ return err;
+ }
+
+ /* path does not match any existing file or directory */
+ return OPEN_ERR_UNACCESSIBLE;
+ }
+
+ Unlink_result unlink(char const *path) override
+ {
+ auto unlink_fn = [] (File_system &fs, char const *path)
+ {
+ return fs.unlink(path);
+ };
+
+ return _dir_op(UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM, UNLINK_OK,
+ path, unlink_fn);
+ }
+
+ Readlink_result readlink(char const *path, char *buf, size_t buf_size,
+ size_t &out_len) override
+ {
+ auto readlink_fn = [&] (File_system &fs, char const *path)
+ {
+ return fs.readlink(path, buf, buf_size, out_len);
+ };
+
+ return _dir_op(READLINK_ERR_NO_ENTRY, READLINK_ERR_NO_ENTRY, READLINK_OK,
+ path, readlink_fn);
+ }
+
+ Rename_result rename(char const *from_path, char const *to_path) override
+ {
+ /*
+ * Check if destination path resides within the same file
+ * system instance as the source path.
+ */
+ to_path = _sub_path(to_path);
+ if (!to_path)
+ return RENAME_ERR_CROSS_FS;
+
+ auto rename_fn = [&] (File_system &fs, char const *from_path)
+ {
+ return fs.rename(from_path, to_path);
+ };
+
+ return _dir_op(RENAME_ERR_NO_ENTRY, RENAME_ERR_NO_PERM, RENAME_OK,
+ from_path, rename_fn);
+ }
+
+ Symlink_result symlink(char const *from, char const *to) override
+ {
+ auto symlink_fn = [&] (File_system &fs, char const *to)
+ {
+ return fs.symlink(from, to);
+ };
+
+ return _dir_op(SYMLINK_ERR_NO_ENTRY, SYMLINK_ERR_NO_PERM, SYMLINK_OK,
+ to, symlink_fn);
+ }
+
+ Mkdir_result mkdir(char const *path, unsigned mode) override
+ {
+ auto mkdir_fn = [&] (File_system &fs, char const *path)
+ {
+ return fs.mkdir(path, mode);
+ };
+
+ return _dir_op(MKDIR_ERR_NO_ENTRY, MKDIR_ERR_NO_PERM, MKDIR_OK,
+ path, mkdir_fn);
+ }
+
+
+ /***************************
+ ** File_system interface **
+ ***************************/
+
+ char const *name() const { return "dir"; }
+
+ /**
+ * Synchronize all file systems
+ */
+ void sync() override
+ {
+ for (File_system *fs = _first_file_system; fs; fs = fs->next)
+ fs->sync();
+ }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *handle, char const *, size_t, size_t &) override
+ {
+ return WRITE_ERR_INVALID;
+ }
+
+ Read_result read(Vfs_handle *, char *, size_t, size_t &) override
+ {
+ return READ_ERR_INVALID;
+ }
+
+ Ftruncate_result ftruncate(Vfs_handle *, size_t) override
+ {
+ return FTRUNCATE_ERR_NO_PERM;
+ }
+};
+
+#endif /* _INCLUDE__VFS__DIR_FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/directory_service.h b/os/include/vfs/directory_service.h
new file mode 100644
index 000000000..4e42f33cf
--- /dev/null
+++ b/os/include/vfs/directory_service.h
@@ -0,0 +1,179 @@
+/*
+ * \brief Directory-service interface
+ * \author Norman Feske
+ * \date 2011-02-17
+ */
+
+/*
+ * Copyright (C) 2011-2014 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 _INCLUDE__VFS__DIRECTORY_SERVICE_H_
+#define _INCLUDE__VFS__DIRECTORY_SERVICE_H_
+
+#include
+
+namespace Vfs {
+ class Vfs_handle;
+ struct Directory_service;
+}
+
+
+struct Vfs::Directory_service
+{
+ virtual Dataspace_capability dataspace(char const *path) = 0;
+ virtual void release(char const *path, Dataspace_capability) = 0;
+
+
+ enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
+
+
+ /**********
+ ** Open **
+ **********/
+
+ /**
+ * 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 = 0x0800, /* libc O_EXCL */
+ };
+
+ enum Open_result
+ {
+ OPEN_ERR_UNACCESSIBLE,
+ OPEN_ERR_NO_PERM,
+ OPEN_ERR_EXISTS,
+ OPEN_OK
+ };
+
+ virtual Open_result open(char const *path, unsigned mode, Vfs_handle **) = 0;
+
+
+ /**********
+ ** 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
+ {
+ size_t size;
+ unsigned mode;
+ unsigned uid;
+ unsigned gid;
+ unsigned long inode;
+ unsigned device;
+ };
+
+ enum Stat_result { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS, STAT_OK };
+
+ virtual Stat_result stat(char const *path, Stat &) = 0;
+
+
+ /************
+ ** Dirent **
+ ************/
+
+ enum Dirent_result { DIRENT_ERR_INVALID_PATH, DIRENT_OK };
+
+ 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
+ };
+
+ struct Dirent
+ {
+ int fileno;
+ Dirent_type type;
+ char name[DIRENT_MAX_NAME_LEN];
+ };
+
+ virtual Dirent_result dirent(char const *path, off_t index, Dirent &) = 0;
+
+
+ /************
+ ** Unlink **
+ ************/
+
+ enum Unlink_result { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM, UNLINK_OK };
+
+ virtual Unlink_result unlink(char const *path) = 0;
+
+
+ /**************
+ ** Readlink **
+ **************/
+
+ enum Readlink_result { READLINK_ERR_NO_ENTRY, READLINK_OK };
+
+ virtual Readlink_result readlink(char const *path, char *buf, size_t buf_size,
+ size_t &out_len) = 0;
+
+
+ /************
+ ** Rename **
+ ************/
+
+ enum Rename_result { RENAME_ERR_NO_ENTRY, RENAME_ERR_CROSS_FS,
+ RENAME_ERR_NO_PERM, RENAME_OK };
+
+ virtual Rename_result rename(char const *from, char const *to) = 0;
+
+
+ /***********
+ ** Mkdir **
+ ***********/
+
+ enum Mkdir_result { MKDIR_ERR_EXISTS, MKDIR_ERR_NO_ENTRY,
+ MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM,
+ MKDIR_ERR_NAME_TOO_LONG, MKDIR_OK};
+
+ virtual Mkdir_result mkdir(char const *path, unsigned mode) = 0;
+
+
+ /*************
+ ** Symlink **
+ *************/
+
+ enum Symlink_result { SYMLINK_ERR_EXISTS, SYMLINK_ERR_NO_ENTRY,
+ SYMLINK_ERR_NAME_TOO_LONG, SYMLINK_ERR_NO_PERM,
+ SYMLINK_OK };
+
+ virtual Symlink_result symlink(char const *from, char const *to) = 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;
+};
+
+#endif /* _INCLUDE__VFS__DIRECTORY_SERVICE_H_ */
diff --git a/os/include/vfs/file_io_service.h b/os/include/vfs/file_io_service.h
new file mode 100644
index 000000000..b4d8d77dc
--- /dev/null
+++ b/os/include/vfs/file_io_service.h
@@ -0,0 +1,123 @@
+/*
+ * \brief Interface for operations provided by file I/O service
+ * \author Norman Feske
+ * \date 2011-02-17
+ */
+
+/*
+ * Copyright (C) 2011-2014 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 _INCLUDE__VFS__FILE_IO_SERVICE_H_
+#define _INCLUDE__VFS__FILE_IO_SERVICE_H_
+
+namespace Vfs {
+ class Vfs_handle;
+ struct File_io_service;
+}
+
+
+struct Vfs::File_io_service
+{
+ enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
+
+
+ /***********
+ ** Write **
+ ***********/
+
+ enum Write_result { WRITE_ERR_AGAIN, WRITE_ERR_WOULD_BLOCK,
+ WRITE_ERR_INVALID, WRITE_ERR_IO,
+ WRITE_ERR_INTERRUPT, WRITE_OK };
+
+ virtual Write_result write(Vfs_handle *vfs_handle,
+ char const *buf, size_t buf_size,
+ size_t &out_count) = 0;
+
+
+ /**********
+ ** Read **
+ **********/
+
+ enum Read_result { READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK,
+ READ_ERR_INVALID, READ_ERR_IO,
+ READ_ERR_INTERRUPT, READ_OK };
+
+ virtual Read_result read(Vfs_handle *vfs_handle, char *dst, size_t count,
+ size_t &out_count) = 0;
+
+
+ /***************
+ ** Ftruncate **
+ ***************/
+
+ enum Ftruncate_result { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS,
+ FTRUNCATE_ERR_INTERRUPT, FTRUNCATE_OK };
+
+ virtual Ftruncate_result ftruncate(Vfs_handle *vfs_handle, size_t len) = 0;
+
+
+ /***********
+ ** Ioctl **
+ ***********/
+
+ enum Ioctl_result { IOCTL_ERR_INVALID, IOCTL_ERR_NOTTY, IOCTL_OK };
+
+ enum Ioctl_opcode { IOCTL_OP_UNDEFINED, IOCTL_OP_TIOCGWINSZ,
+ IOCTL_OP_TIOCSETAF, IOCTL_OP_TIOCSETAW,
+ IOCTL_OP_FIONBIO, IOCTL_OP_DIOCGMEDIASIZE };
+
+ enum Ioctl_value { IOCTL_VAL_NULL, IOCTL_VAL_ECHO, IOCTL_VAL_ECHONL };
+
+ typedef unsigned long Ioctl_arg;
+
+ struct Ioctl_out
+ {
+ union
+ {
+ /* if request was 'IOCTL_OP_TIOCGSIZE' */
+ struct {
+ int rows;
+ int columns;
+ } tiocgwinsz;
+
+ /* if request was 'IOCTL_OP_DIOCGMEDIASIZE' */
+ struct {
+ /* disk size rounded up to sector size in bytes*/
+ int size;
+
+ } diocgmediasize;
+ };
+ };
+
+ virtual Ioctl_result ioctl(Vfs_handle *vfs_handle, Ioctl_opcode, Ioctl_arg,
+ Ioctl_out &out)
+ {
+ /*
+ * This method is only needed in file systems which actually implement a
+ * device and is therefore false by default.
+ */
+ return IOCTL_ERR_INVALID;
+ }
+
+
+ /**
+ * Return true if an unblocking condition of the file is satisfied
+ *
+ * \param rd if true, check for data available for reading
+ * \param wr if true, check for readiness for writing
+ * \param ex if true, check for exceptions
+ */
+ virtual bool check_unblock(Vfs_handle *vfs_handle,
+ bool rd, bool wr, bool ex)
+ { return true; }
+
+ virtual void register_read_ready_sigh(Vfs_handle *vfs_handle,
+ Signal_context_capability sigh)
+ { }
+};
+
+#endif /* _INCLUDE__VFS__FILE_IO_SERVICE_H_ */
diff --git a/os/include/vfs/file_system.h b/os/include/vfs/file_system.h
new file mode 100644
index 000000000..bd4254a37
--- /dev/null
+++ b/os/include/vfs/file_system.h
@@ -0,0 +1,42 @@
+/*
+ * \brief VFS file-system back-end interface
+ * \author Norman Feske
+ * \date 2011-02-17
+ */
+
+/*
+ * Copyright (C) 2011-2014 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 _INCLUDE__VFS__FILE_SYSTEM_H_
+#define _INCLUDE__VFS__FILE_SYSTEM_H_
+
+#include
+#include
+
+namespace Vfs { struct File_system; }
+
+
+struct Vfs::File_system : Directory_service, File_io_service
+{
+ /**
+ * Our next sibling within the same 'Dir_file_system'
+ */
+ struct File_system *next;
+
+ File_system() : next(0) { }
+
+ /**
+ * Synchronize file system
+ *
+ * This function is only used by a Fs_file_system because such a file
+ * system may employ a backend, which maintains a internal cache, that
+ * needs to be flushed.
+ */
+ virtual void sync() { }
+};
+
+#endif /* _INCLUDE__VFS__FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/file_system_factory.h b/os/include/vfs/file_system_factory.h
new file mode 100644
index 000000000..798af9318
--- /dev/null
+++ b/os/include/vfs/file_system_factory.h
@@ -0,0 +1,27 @@
+/*
+ * \brief Interface for creating file-system instances
+ * \author Norman Feske
+ * \date 2014-04-07
+ */
+
+/*
+ * Copyright (C) 2014 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 _INCLUDE__VFS__FILE_SYSTEM_FACTORY_H_
+#define _INCLUDE__VFS__FILE_SYSTEM_FACTORY_H_
+
+#include
+
+namespace Vfs { class File_system_factory; }
+
+
+struct Vfs::File_system_factory
+{
+ virtual File_system *create(Xml_node node) = 0;
+};
+
+#endif /* _INCLUDE__VFS__FILE_SYSTEM_FACTORY_H_ */
diff --git a/os/include/vfs/fs_file_system.h b/os/include/vfs/fs_file_system.h
new file mode 100644
index 000000000..34a59def6
--- /dev/null
+++ b/os/include/vfs/fs_file_system.h
@@ -0,0 +1,628 @@
+/*
+ * \brief Adapter from Genode 'File_system' session to VFS
+ * \author Norman Feske
+ * \date 2011-02-17
+ */
+
+/*
+ * Copyright (C) 2012-2014 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 _INCLUDE__VFS__FS_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__FS_FILE_SYSTEM_H_
+
+/* Genode includes */
+#include
+#include
+
+namespace Vfs { class Fs_file_system; }
+
+
+class Vfs::Fs_file_system : public File_system
+{
+ enum { verbose = false };
+
+ private:
+
+ /*
+ * Lock used to serialize the interaction with the packet stream of the
+ * file-system session.
+ *
+ * XXX Once, we change the VFS file-system interface to use
+ * asynchronous read/write operations, we can possibly remove it.
+ */
+ Lock _lock;
+
+ Genode::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); }
+ };
+
+ size_t _read(::File_system::Node_handle node_handle, void *buf,
+ size_t const count, size_t const seek_offset)
+ {
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+
+ size_t const max_packet_size = source.bulk_buffer_size() / 2;
+ size_t const clipped_count = min(max_packet_size, count);
+
+ ::File_system::Packet_descriptor const
+ packet_in(source.alloc_packet(clipped_count),
+ 0,
+ node_handle,
+ ::File_system::Packet_descriptor::READ,
+ clipped_count,
+ seek_offset);
+
+ /* pass packet to server side */
+ source.submit_packet(packet_in);
+
+ /* obtain result packet descriptor with updated status info */
+ ::File_system::Packet_descriptor const
+ packet_out = source.get_acked_packet();
+
+ size_t const read_num_bytes = min(packet_out.length(), count);
+
+ memcpy(buf, source.packet_content(packet_out), read_num_bytes);
+
+ /*
+ * XXX check if acked packet belongs to request,
+ * needed for thread safety
+ */
+
+ source.release_packet(packet_out);
+
+ return read_num_bytes;
+ }
+
+ size_t _write(::File_system::Node_handle node_handle,
+ const char *buf, size_t count, size_t seek_offset)
+ {
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+
+ size_t const max_packet_size = source.bulk_buffer_size() / 2;
+ count = min(max_packet_size, count);
+
+ ::File_system::Packet_descriptor
+ packet(source.alloc_packet(count),
+ 0,
+ node_handle,
+ ::File_system::Packet_descriptor::WRITE,
+ count,
+ seek_offset);
+
+ memcpy(source.packet_content(packet), buf, count);
+
+ /* 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
+ */
+
+ source.release_packet(packet);
+
+ return count;
+ }
+
+ 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) override
+ {
+ 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();
+
+ Ram_dataspace_capability ds_cap;
+ char *local_addr = 0;
+
+ try {
+ ::File_system::Dir_handle dir = _fs.dir(dir_path.base(),
+ false);
+ Fs_handle_guard dir_guard(_fs, dir);
+
+ ::File_system::File_handle file =
+ _fs.file(dir, file_name.base() + 1,
+ ::File_system::READ_ONLY, false);
+ Fs_handle_guard file_guard(_fs, file);
+
+ ::File_system::Status status = _fs.status(file);
+
+ Ram_dataspace_capability ds_cap =
+ env()->ram_session()->alloc(status.size);
+
+ local_addr = env()->rm_session()->attach(ds_cap);
+
+ ::File_system::Session::Tx::Source &source = *_fs.tx();
+ size_t const max_packet_size = source.bulk_buffer_size() / 2;
+
+ for (size_t seek_offset = 0; seek_offset < status.size;
+ seek_offset += max_packet_size) {
+
+ size_t const count = min(max_packet_size, status.size - seek_offset);
+
+ ::File_system::Packet_descriptor
+ packet(source.alloc_packet(count),
+ 0,
+ file,
+ ::File_system::Packet_descriptor::READ,
+ count,
+ seek_offset);
+
+ /* pass packet to server side */
+ source.submit_packet(packet);
+ source.get_acked_packet();
+
+ memcpy(local_addr + seek_offset, source.packet_content(packet), count);
+
+ /*
+ * XXX check if acked packet belongs to request,
+ * needed for thread safety
+ */
+
+ source.release_packet(packet);
+ }
+
+ env()->rm_session()->detach(local_addr);
+
+ return ds_cap;
+ } catch(...) {
+ env()->rm_session()->detach(local_addr);
+ env()->ram_session()->free(ds_cap);
+ return Dataspace_capability();
+ }
+ }
+
+ void release(char const *path, Dataspace_capability ds_cap) override
+ {
+ env()->ram_session()->free(static_cap_cast(ds_cap));
+ }
+
+ Stat_result stat(char const *path, Stat &out) override
+ {
+ ::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 (...) {
+ if (verbose)
+ PDBG("stat failed for path '%s'", path);
+ return STAT_ERR_NO_ENTRY;
+ }
+
+ memset(&out, 0, sizeof(out));
+
+ out.size = status.size;
+ out.mode = STAT_MODE_FILE | 0777;
+
+ if (status.is_symlink())
+ out.mode = STAT_MODE_SYMLINK | 0777;
+
+ if (status.is_directory())
+ out.mode = STAT_MODE_DIRECTORY | 0777;
+
+ out.uid = 0;
+ out.gid = 0;
+ return STAT_OK;
+ }
+
+ Dirent_result dirent(char const *path, off_t index, Dirent &out) override
+ {
+ 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);
+
+ /*
+ * 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;
+
+ 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;
+ }
+
+ out.type = type;
+ out.fileno = index + 1;
+
+ strncpy(out.name, entry->name, sizeof(out.name));
+
+ source.release_packet(packet);
+
+ return DIRENT_OK;
+ }
+
+ Unlink_result unlink(char const *path) override
+ {
+ 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 (...) {
+ return UNLINK_ERR_NO_ENTRY;
+ }
+
+ return UNLINK_OK;
+ }
+
+ Readlink_result readlink(char const *path, char *buf, size_t buf_size,
+ size_t &out_len) override
+ {
+ /*
+ * Canonicalize path (i.e., path must start with '/')
+ */
+ Absolute_path abs_path(path);
+ abs_path.strip_last_element();
+
+ Absolute_path symlink_name(path);
+ symlink_name.keep_only_last_element();
+
+ try {
+ ::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
+ Fs_handle_guard from_dir_guard(_fs, dir_handle);
+
+ ::File_system::Symlink_handle symlink_handle =
+ _fs.symlink(dir_handle, symlink_name.base() + 1, false);
+ Fs_handle_guard symlink_guard(_fs, symlink_handle);
+
+ out_len = _read(symlink_handle, buf, buf_size, 0);
+
+ return READLINK_OK;
+ } catch (...) { }
+
+ return READLINK_ERR_NO_ENTRY;
+ }
+
+ Rename_result rename(char const *from_path, char const *to_path) override
+ {
+ 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 (...) {
+ return RENAME_ERR_NO_ENTRY; }
+
+ return RENAME_OK;
+ }
+
+ Mkdir_result mkdir(char const *path, unsigned mode) override
+ {
+ /*
+ * Canonicalize path (i.e., path must start with '/')
+ */
+ Absolute_path abs_path(path);
+
+ try {
+ _fs.dir(abs_path.base(), true);
+ return MKDIR_OK;
+ }
+ catch (::File_system::Permission_denied) { return MKDIR_ERR_NO_PERM; }
+ catch (::File_system::Node_already_exists) { return MKDIR_ERR_EXISTS; }
+ catch (::File_system::Lookup_failed) { return MKDIR_ERR_NO_ENTRY; }
+ catch (::File_system::Name_too_long) { return MKDIR_ERR_NAME_TOO_LONG; }
+ catch (::File_system::No_space) { return MKDIR_ERR_NO_SPACE; }
+
+ return MKDIR_ERR_NO_PERM;
+ }
+
+ Symlink_result symlink(char const *from, char const *to) override
+ {
+ /*
+ * We write to the symlink via the packet stream. Hence we need
+ * to serialize with other packet-stream operations.
+ */
+ Lock::Guard guard(_lock);
+
+ /*
+ * Canonicalize path (i.e., path must start with '/')
+ */
+ Absolute_path abs_path(to);
+ abs_path.strip_last_element();
+
+ Absolute_path symlink_name(to);
+ symlink_name.keep_only_last_element();
+
+ try {
+ ::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
+ Fs_handle_guard from_dir_guard(_fs, dir_handle);
+
+ ::File_system::Symlink_handle symlink_handle =
+ _fs.symlink(dir_handle, symlink_name.base() + 1, true);
+ Fs_handle_guard symlink_guard(_fs, symlink_handle);
+
+ _write(symlink_handle, from, strlen(from) + 1, 0);
+ return SYMLINK_OK;
+ }
+ catch (::File_system::Invalid_handle) { return SYMLINK_ERR_NO_ENTRY; }
+ catch (::File_system::Node_already_exists) { return SYMLINK_ERR_EXISTS; }
+ catch (::File_system::Invalid_name) { return SYMLINK_ERR_NAME_TOO_LONG; }
+ catch (::File_system::Lookup_failed) { return SYMLINK_ERR_NO_ENTRY; }
+ catch (::File_system::Permission_denied) { return SYMLINK_ERR_NO_PERM; }
+
+ return SYMLINK_ERR_NO_ENTRY;
+ }
+
+ size_t num_dirent(char const *path) override
+ {
+ 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) override
+ {
+ 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) override
+ {
+ /* 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;
+ }
+
+ Open_result open(char const *path, unsigned vfs_mode, Vfs_handle **out_handle) override
+ {
+ 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 (vfs_mode & OPEN_MODE_ACCMODE) {
+ default: mode = ::File_system::STAT_ONLY; break;
+ case OPEN_MODE_RDONLY: mode = ::File_system::READ_ONLY; break;
+ case OPEN_MODE_WRONLY: mode = ::File_system::WRITE_ONLY; break;
+ case OPEN_MODE_RDWR: mode = ::File_system::READ_WRITE; break;
+ }
+
+ bool const create = vfs_mode & OPEN_MODE_CREATE;
+
+ if (create)
+ if (verbose)
+ PDBG("creation of file %s requested", file_name.base() + 1);
+
+ try {
+ ::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
+ Fs_handle_guard dir_guard(_fs, dir);
+
+ ::File_system::File_handle file = _fs.file(dir, file_name.base() + 1,
+ mode, create);
+
+ *out_handle = new (env()->heap()) Fs_vfs_handle(*this, vfs_mode, file);
+ return OPEN_OK;
+ }
+ catch (::File_system::Permission_denied) { return OPEN_ERR_NO_PERM; }
+ catch (::File_system::Invalid_handle) { return OPEN_ERR_NO_PERM; }
+ catch (::File_system::Lookup_failed) { return OPEN_ERR_UNACCESSIBLE; }
+ catch (::File_system::Node_already_exists) { return OPEN_ERR_EXISTS; }
+
+ return OPEN_ERR_UNACCESSIBLE;
+ }
+
+
+ /***************************
+ ** File_system interface **
+ ***************************/
+
+ static char const *name() { return "fs"; }
+
+ void sync() override
+ {
+ _fs.sync();
+ }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *vfs_handle, char const *buf, size_t buf_size,
+ size_t &out_count) override
+ {
+ Lock::Guard guard(_lock);
+
+ Fs_vfs_handle const *handle = static_cast(vfs_handle);
+
+ out_count = _write(handle->file_handle(), buf, buf_size, handle->seek());
+
+ return WRITE_OK;
+ }
+
+ Read_result read(Vfs_handle *vfs_handle, char *dst, size_t count,
+ size_t &out_count) override
+ {
+ Lock::Guard guard(_lock);
+
+ 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;
+
+ count = min(count, file_bytes_left);
+
+ out_count = _read(handle->file_handle(), dst, count, handle->seek());
+
+ return READ_OK;
+ }
+
+ Ftruncate_result ftruncate(Vfs_handle *vfs_handle, size_t len) override
+ {
+ Fs_vfs_handle const *handle = static_cast(vfs_handle);
+
+ try {
+ _fs.truncate(handle->file_handle(), len);
+ }
+ catch (::File_system::Invalid_handle) { return FTRUNCATE_ERR_NO_PERM; }
+ catch (::File_system::Permission_denied) { return FTRUNCATE_ERR_NO_PERM; }
+
+ return FTRUNCATE_OK;
+ }
+};
+
+#endif /* _INCLUDE__VFS__FS_FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/null_file_system.h b/os/include/vfs/null_file_system.h
new file mode 100644
index 000000000..6a2770157
--- /dev/null
+++ b/os/include/vfs/null_file_system.h
@@ -0,0 +1,57 @@
+/*
+ * \brief null filesystem
+ * \author Josef Soentgen
+ * \author Norman Feske
+ * \date 2012-07-31
+ */
+
+/*
+ * Copyright (C) 2012-2014 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 _INCLUDE__VFS__NULL_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__NULL_FILE_SYSTEM_H_
+
+#include
+
+namespace Vfs { class Null_file_system; }
+
+
+struct Vfs::Null_file_system : Single_file_system
+{
+ Null_file_system(Xml_node config)
+ :
+ Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config)
+ { }
+
+ static char const *name() { return "null"; }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *handle, char const *, size_t count, size_t &out_count) override
+ {
+ out_count = count;
+
+ return WRITE_OK;
+ }
+
+ Read_result read(Vfs_handle *vfs_handle, char *, size_t, size_t &out_count) override
+ {
+ out_count = 0;
+
+ return READ_OK;
+ }
+
+ Ftruncate_result ftruncate(Vfs_handle *vfs_handle, size_t) override
+ {
+ return FTRUNCATE_OK;
+ }
+};
+
+#endif /* _INCLUDE__VFS__NULL_FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/single_file_system.h b/os/include/vfs/single_file_system.h
new file mode 100644
index 000000000..c8b2b4eeb
--- /dev/null
+++ b/os/include/vfs/single_file_system.h
@@ -0,0 +1,174 @@
+/*
+ * \brief File system that hosts a single node
+ * \author Norman Feske
+ * \date 2014-04-07
+ */
+
+/*
+ * Copyright (C) 2014 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 _INCLUDE__VFS__SINGLE_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__SINGLE_FILE_SYSTEM_H_
+
+#include
+
+namespace Vfs { class Single_file_system; }
+
+
+class Vfs::Single_file_system : public File_system
+{
+ public:
+
+ enum Node_type { NODE_TYPE_FILE, NODE_TYPE_CHAR_DEVICE, NODE_TYPE_BLOCK_DEVICE };
+
+ private:
+
+ Node_type const _node_type;
+
+ enum { FILENAME_MAX_LEN = 64 };
+ char _filename[FILENAME_MAX_LEN];
+
+ bool _is_root(const char *path)
+ {
+ return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
+ }
+
+ bool _is_single_file(const char *path)
+ {
+ return (strlen(path) == (strlen(_filename) + 1)) &&
+ (strcmp(&path[1], _filename) == 0);
+ }
+
+ public:
+
+ Single_file_system(Node_type node_type, char const *type_name, Xml_node config)
+ :
+ _node_type(node_type)
+ {
+ strncpy(_filename, type_name, sizeof(_filename));
+
+ try { config.attribute("name").value(_filename, sizeof(_filename)); }
+ catch (...) { }
+ }
+
+
+ /*********************************
+ ** Directory-service interface **
+ *********************************/
+
+ Dataspace_capability dataspace(char const *path) override
+ {
+ return Dataspace_capability();
+ }
+
+ void release(char const *path, Dataspace_capability ds_cap) override { }
+
+ Stat_result stat(char const *path, Stat &out) override
+ {
+ out = { 0, 0, 0, 0, 0, 0 };
+
+ if (_is_root(path)) {
+ out.mode = STAT_MODE_DIRECTORY;
+
+ } else if (_is_single_file(path)) {
+ switch (_node_type) {
+ case NODE_TYPE_FILE: out.mode = STAT_MODE_FILE; break;
+ case NODE_TYPE_CHAR_DEVICE: out.mode = STAT_MODE_CHARDEV; break;
+ case NODE_TYPE_BLOCK_DEVICE: out.mode = STAT_MODE_BLOCKDEV; break;
+ }
+ } else {
+ return STAT_ERR_NO_ENTRY;
+ }
+ return STAT_OK;
+ }
+
+ Dirent_result dirent(char const *path, off_t index, Dirent &out) override
+ {
+ if (!_is_root(path))
+ return DIRENT_ERR_INVALID_PATH;
+
+ if (index == 0) {
+ switch (_node_type) {
+ case NODE_TYPE_FILE: out.type = DIRENT_TYPE_FILE; 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));
+ } else {
+ out.type = DIRENT_TYPE_END;
+ }
+
+ return DIRENT_OK;
+ }
+
+ size_t num_dirent(char const *path) override
+ {
+ if (_is_root(path))
+ return 1;
+ else
+ return 0;
+ }
+
+ bool is_directory(char const *path) override
+ {
+ if (_is_root(path))
+ return true;
+
+ return false;
+ }
+
+ char const *leaf_path(char const *path) override
+ {
+ return path;
+ }
+
+ Open_result open(char const *path, unsigned, Vfs_handle **out_handle) override
+ {
+ if (!_is_single_file(path))
+ return OPEN_ERR_UNACCESSIBLE;
+
+ *out_handle = new (env()->heap()) Vfs_handle(*this, *this, 0);
+ return OPEN_OK;
+ }
+
+ Unlink_result unlink(char const *) override
+ {
+ return UNLINK_ERR_NO_PERM;
+ }
+
+ Readlink_result readlink(char const *, char *, size_t, size_t &) override
+ {
+ return READLINK_ERR_NO_ENTRY;
+ }
+
+ Rename_result rename(char const *, char const *) override
+ {
+ return RENAME_ERR_NO_PERM;
+ }
+
+ Mkdir_result mkdir(char const *, unsigned) override
+ {
+ return MKDIR_ERR_NO_PERM;
+ }
+
+ Symlink_result symlink(char const *, char const *) override
+ {
+ return SYMLINK_ERR_NO_ENTRY;
+ }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Ftruncate_result ftruncate(Vfs_handle *vfs_handle, size_t) override
+ {
+ return FTRUNCATE_ERR_NO_PERM;
+ }
+};
+
+#endif /* _INCLUDE__VFS__SINGLE_FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/tar_file_system.h b/os/include/vfs/tar_file_system.h
new file mode 100644
index 000000000..768aeb442
--- /dev/null
+++ b/os/include/vfs/tar_file_system.h
@@ -0,0 +1,638 @@
+/*
+ * \brief TAR file system
+ * \author Norman Feske
+ * \date 2011-02-17
+ */
+
+/*
+ * Copyright (C) 2011-2014 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 _INCLUDE__VFS__TAR_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__TAR_FILE_SYSTEM_H_
+
+#include
+#include
+#include
+
+namespace Vfs { class Tar_file_system; }
+
+
+class Vfs::Tar_file_system : public File_system
+{
+ enum { verbose = false };
+
+ struct Rom_name
+ {
+ enum { ROM_NAME_MAX_LEN = 64 };
+ char name[ROM_NAME_MAX_LEN];
+
+ Rom_name(Xml_node config) {
+ config.attribute("name").value(name, sizeof(name));
+ }
+ } _rom_name;
+
+ Genode::Rom_connection _rom;
+
+ char *_tar_base;
+ size_t _tar_size;
+
+ class Record
+ {
+ private:
+
+ char _name[100];
+ char _mode[8];
+ char _uid[8];
+ char _gid[8];
+ char _size[12];
+ char _mtime[12];
+ char _checksum[8];
+ char _type[1];
+ char _linked_name[100];
+
+ /**
+ * Convert ASCII-encoded octal number to unsigned value
+ */
+ template
+ unsigned long _read(T const &field) const
+ {
+ /*
+ * Copy-out ASCII string to temporary buffer that is
+ * large enough to host an additional zero.
+ */
+ char buf[sizeof(field) + 1];
+ strncpy(buf, field, sizeof(buf));
+
+ unsigned long value = 0;
+ ascii_to(buf, &value, 8);
+ return value;
+ }
+
+ public:
+
+ /* length of on data block in tar */
+ enum { BLOCK_LEN = 512 };
+
+ /* record type values */
+ enum { TYPE_FILE = 0, TYPE_HARDLINK = 1,
+ TYPE_SYMLINK = 2, TYPE_DIR = 5 };
+
+ size_t size() const { return _read(_size); }
+ unsigned uid() const { return _read(_uid); }
+ unsigned gid() const { return _read(_gid); }
+ unsigned mode() const { return _read(_mode); }
+ unsigned type() const { return _read(_type); }
+ char const *name() const { return _name; }
+ char const *linked_name() const { return _linked_name; }
+
+ void *data() const { return (char *)this + BLOCK_LEN; }
+ };
+
+
+ class Tar_vfs_handle : public Vfs_handle
+ {
+ private:
+
+ Record const *_record;
+
+ public:
+
+ Tar_vfs_handle(File_system &fs, int status_flags, Record const *record)
+ : Vfs_handle(fs, fs, status_flags), _record(record)
+ { }
+
+ Record const *record() const { return _record; }
+ };
+
+
+ struct Scanner_policy_path_element
+ {
+ static bool identifier_char(char c, unsigned /* i */)
+ {
+ return (c != '/') && (c != 0);
+ }
+ };
+
+
+ typedef Genode::Token Path_element_token;
+
+
+ struct Node : List, List::Element
+ {
+ char const *name;
+ Record const *record;
+
+ Node(char const *name, Record const *record) : name(name), record(record) { }
+
+ Node *lookup(char const *name)
+ {
+ Absolute_path lookup_path(name);
+
+ if (verbose)
+ PDBG("lookup_path = %s", lookup_path.base());
+
+ Node *parent_node = this;
+ Node *child_node;
+
+ Path_element_token t(lookup_path.base());
+
+ while (t) {
+
+ if (t.type() != Path_element_token::IDENT) {
+ t = t.next();
+ continue;
+ }
+
+ char path_element[MAX_PATH_LEN];
+
+ t.string(path_element, sizeof(path_element));
+
+ if (verbose)
+ PDBG("path_element = %s", path_element);
+
+ for (child_node = parent_node->first(); child_node; child_node = child_node->next()) {
+ if (verbose)
+ PDBG("comparing with node %s", child_node->name);
+ if (strcmp(child_node->name, path_element) == 0) {
+ if (verbose)
+ PDBG("found matching child node");
+ parent_node = child_node;
+ break;
+ }
+ }
+
+ if (!child_node)
+ return 0;
+
+ t = t.next();
+ }
+
+ return parent_node;
+ }
+
+
+ Node *lookup_child(int index)
+ {
+ for (Node *child_node = first(); child_node; child_node = child_node->next(), index--) {
+ if (index == 0)
+ return child_node;
+ }
+
+ return 0;
+ }
+
+
+ size_t num_dirent()
+ {
+ size_t count = 0;
+ for (Node *child_node = first(); child_node; child_node = child_node->next(), count++) ;
+ return count;
+ }
+
+ } _root_node;
+
+
+ /*
+ * Create a Node for a tar record and insert it into the node list
+ */
+ class Add_node_action
+ {
+ private:
+
+ Node &_root_node;
+
+ public:
+
+ Add_node_action(Node &root_node) : _root_node(root_node) { }
+
+ void operator()(Record const *record)
+ {
+ Absolute_path current_path(record->name());
+
+ if (verbose)
+ PDBG("current_path = %s", current_path.base());
+
+ char path_element[MAX_PATH_LEN];
+
+ Path_element_token t(current_path.base());
+
+ Node *parent_node = &_root_node;
+ Node *child_node;
+
+ while(t) {
+
+ if (t.type() != Path_element_token::IDENT) {
+ t = t.next();
+ continue;
+ }
+
+ Absolute_path remaining_path(t.start());
+
+ t.string(path_element, sizeof(path_element));
+
+ for (child_node = parent_node->first(); child_node; child_node = child_node->next()) {
+ if (strcmp(child_node->name, path_element) == 0)
+ break;
+ }
+
+ if (child_node) {
+
+ if (verbose)
+ PDBG("found node for %s", path_element);
+
+ if (remaining_path.has_single_element()) {
+ /* Found a node for the record to be inserted.
+ * This is usually a directory node without
+ * record. */
+ child_node->record = record;
+ }
+ } else {
+ if (remaining_path.has_single_element()) {
+
+ if (verbose)
+ PDBG("creating node for %s", path_element);
+
+ /*
+ * TODO: find 'path_element' in 'record->name'
+ * and use the location in the record as name
+ * pointer to save some memory
+ */
+ size_t name_size = strlen(path_element) + 1;
+ char *name = (char*)env()->heap()->alloc(name_size);
+ strncpy(name, path_element, name_size);
+ child_node = new (env()->heap()) Node(name, record);
+ } else {
+
+ if (verbose)
+ PDBG("creating node without record for %s", path_element);
+
+ /* create a directory node without record */
+ size_t name_size = strlen(path_element) + 1;
+ char *name = (char*)env()->heap()->alloc(name_size);
+ strncpy(name, path_element, name_size);
+ child_node = new (env()->heap()) Node(name, 0);
+ }
+ parent_node->insert(child_node);
+ }
+
+ parent_node = child_node;
+ t = t.next();
+ }
+ }
+ };
+
+
+ template
+ void _for_each_tar_record_do(Tar_record_action tar_record_action)
+ {
+ /* measure size of archive in blocks */
+ unsigned block_id = 0, block_cnt = _tar_size/Record::BLOCK_LEN;
+
+ /* scan metablocks of archive */
+ while (block_id < block_cnt) {
+
+ Record *record = (Record *)(_tar_base + block_id*Record::BLOCK_LEN);
+
+ tar_record_action(record);
+
+ size_t file_size = record->size();
+
+ /* some datablocks */ /* one metablock */
+ block_id = block_id + (file_size / Record::BLOCK_LEN) + 1;
+
+ /* round up */
+ if (file_size % Record::BLOCK_LEN != 0) block_id++;
+
+ /* check for end of tar archive */
+ if (block_id*Record::BLOCK_LEN >= _tar_size)
+ break;
+
+ /* lookout for empty eof-blocks */
+ if (*(_tar_base + (block_id*Record::BLOCK_LEN)) == 0x00)
+ if (*(_tar_base + (block_id*Record::BLOCK_LEN + 1)) == 0x00)
+ break;
+ }
+ }
+
+
+ struct Num_dirent_cache
+ {
+ Lock lock;
+ Node &root_node;
+ bool valid; /* true after first lookup */
+ char key[256]; /* key used for lookup */
+ size_t cached_num_dirent; /* cached value */
+
+ Num_dirent_cache(Node &root_node)
+ : root_node(root_node), 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) {
+ Node *node = root_node.lookup(path);
+ if (!node)
+ return 0;
+ strncpy(key, path, sizeof(key));
+ cached_num_dirent = node->num_dirent();
+ valid = true;
+ }
+ return cached_num_dirent;
+ }
+ } _cached_num_dirent;
+
+
+ public:
+
+ Tar_file_system(Xml_node config)
+ :
+ _rom_name(config), _rom(_rom_name.name),
+ _tar_base(env()->rm_session()->attach(_rom.dataspace())),
+ _tar_size(Dataspace_client(_rom.dataspace()).size()),
+ _root_node("", 0),
+ _cached_num_dirent(_root_node)
+ {
+ PINF("tar archive '%s' local at %p, size is %zd",
+ _rom_name.name, _tar_base, _tar_size);
+
+ _for_each_tar_record_do(Add_node_action(_root_node));
+ }
+
+
+ /*********************************
+ ** Directory-service interface **
+ *********************************/
+
+ Dataspace_capability dataspace(char const *path) override
+ {
+ /*
+ * Walk hardlinks until we reach a file
+ */
+ Record const *record = 0;
+ for (;;) {
+ Node *node = _root_node.lookup(path);
+
+ if (!node)
+ return Dataspace_capability();
+
+ record = node->record;
+
+ if (record) {
+ if (record->type() == Record::TYPE_HARDLINK) {
+ path = record->linked_name();
+ continue;
+ }
+
+ if (record->type() == Record::TYPE_FILE)
+ break;
+
+ PERR("TAR record \"%s\" has unsupported type %d",
+ record->name(), record->type());
+ }
+
+ PERR("TAR record \"%s\" has unsupported type %d",
+ path, Record::TYPE_DIR);
+
+ return Dataspace_capability();
+ }
+
+ try {
+ Ram_dataspace_capability ds_cap =
+ env()->ram_session()->alloc(record->size());
+
+ void *local_addr = env()->rm_session()->attach(ds_cap);
+ memcpy(local_addr, record->data(), record->size());
+ env()->rm_session()->detach(local_addr);
+
+ return ds_cap;
+ }
+ catch (...) { PDBG("Could not create new dataspace"); }
+
+ return Dataspace_capability();
+ }
+
+ void release(char const *, Dataspace_capability ds_cap) override
+ {
+ env()->ram_session()->free(static_cap_cast(ds_cap));
+ }
+
+ Stat_result stat(char const *path, Stat &out) override
+ {
+ if (verbose)
+ PDBG("path = %s", path);
+
+ Node const *node = 0;
+ Record const *record = 0;
+
+ /*
+ * Walk hardlinks until we reach a file
+ */
+ for (;;) {
+ node = _root_node.lookup(path);
+
+ if (!node)
+ return STAT_ERR_NO_ENTRY;
+
+ record = node->record;
+
+ if (record) {
+ if (record->type() == Record::TYPE_HARDLINK) {
+ path = record->linked_name();
+ continue;
+ } else
+ break;
+ } else {
+ if (verbose)
+ PDBG("found a virtual directoty node");
+
+ memset(&out, 0, sizeof(out));
+ out.mode = STAT_MODE_DIRECTORY;
+ return STAT_OK;
+ }
+ }
+
+ /* 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;
+
+ default:
+ if (verbose)
+ PDBG("unhandled record type %d", record->type());
+ }
+
+ memset(&out, 0, sizeof(out));
+ out.mode = mode;
+ out.size = record->size();
+ out.uid = record->uid();
+ out.gid = record->gid();
+ out.inode = (unsigned long)node;
+
+ return STAT_OK;
+ }
+
+ Dirent_result dirent(char const *path, off_t index, Dirent &out) override
+ {
+ Node *node = _root_node.lookup(path);
+
+ if (!node)
+ return DIRENT_ERR_INVALID_PATH;
+
+ node = node->lookup_child(index);
+
+ if (!node) {
+ out.type = DIRENT_TYPE_END;
+ return DIRENT_OK;
+ }
+
+ out.fileno = (unsigned long)node;
+
+ Record const *record = node->record;
+
+ if (record) {
+ switch (record->type()) {
+ case 0: out.type = DIRENT_TYPE_FILE; break;
+ case 2: out.type = DIRENT_TYPE_SYMLINK; break;
+ case 5: out.type = DIRENT_TYPE_DIRECTORY; break;
+
+ default:
+ if (verbose)
+ PDBG("unhandled record type %d", record->type());
+ }
+ }
+
+ strncpy(out.name, node->name, sizeof(out.name));
+
+ return DIRENT_OK;
+ }
+
+ Unlink_result unlink(char const *) override { return UNLINK_ERR_NO_PERM; }
+
+ Readlink_result readlink(char const *path, char *buf, size_t buf_size,
+ size_t &out_len) override
+ {
+ Node *node = _root_node.lookup(path);
+ Record const *record = node ? node->record : 0;
+
+ if (!record || (record->type() != Record::TYPE_SYMLINK))
+ return READLINK_ERR_NO_ENTRY;
+
+ size_t const count = min(buf_size, (size_t)100);
+
+ memcpy(buf, record->linked_name(), count);
+
+ out_len = count;
+
+ return READLINK_OK;
+ }
+
+ Rename_result rename(char const *, char const *) override
+ {
+ return RENAME_ERR_NO_PERM;
+ }
+
+ Mkdir_result mkdir(char const *, unsigned) override
+ {
+ return MKDIR_ERR_NO_PERM;
+ }
+
+ Symlink_result symlink(char const *, char const *) override
+ {
+ return SYMLINK_ERR_NO_ENTRY;
+ }
+
+ size_t num_dirent(char const *path) override
+ {
+ return _cached_num_dirent.num_dirent(path);
+ }
+
+ bool is_directory(char const *path) override
+ {
+ Node *node = _root_node.lookup(path);
+
+ if (!node)
+ return false;
+
+ Record const *record = node->record;
+
+ return record ? (record->type() == Record::TYPE_DIR) : true;
+ }
+
+ char const *leaf_path(char const *path) override
+ {
+ /*
+ * 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.
+ */
+ Node *node = _root_node.lookup(path);
+ return node ? path : 0;
+ }
+
+ Open_result open(char const *path, unsigned, Vfs_handle **out_handle) override
+ {
+ Node *node = _root_node.lookup(path);
+
+ if (!node)
+ return OPEN_ERR_UNACCESSIBLE;
+
+ *out_handle = new (env()->heap())
+ Tar_vfs_handle(*this, 0, node->record);
+
+ return OPEN_OK;
+ }
+
+
+ /***************************
+ ** File_system interface **
+ ***************************/
+
+ static char const *name() { return "tar"; }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *, char const *, size_t, size_t &) override
+ {
+ PDBG("called\n");
+ return WRITE_ERR_INVALID;
+ }
+
+ Read_result read(Vfs_handle *vfs_handle, char *dst, size_t count,
+ size_t &out_count) override
+ {
+ Tar_vfs_handle const *handle = static_cast(vfs_handle);
+
+ size_t const record_size = handle->record()->size();
+
+ size_t const record_bytes_left = record_size >= handle->seek()
+ ? record_size - handle->seek() : 0;
+
+ count = min(record_bytes_left, count);
+
+ char const *data = (char *)handle->record()->data() + handle->seek();
+
+ memcpy(dst, data, count);
+
+ out_count = count;
+ return READ_OK;
+ }
+
+ Ftruncate_result ftruncate(Vfs_handle *handle, size_t) override
+ {
+ PDBG("called\n");
+ return FTRUNCATE_ERR_NO_PERM;
+ }
+};
+
+#endif /* _INCLUDE__VFS__TAR_FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/terminal_file_system.h b/os/include/vfs/terminal_file_system.h
new file mode 100644
index 000000000..a9c2a88cb
--- /dev/null
+++ b/os/include/vfs/terminal_file_system.h
@@ -0,0 +1,105 @@
+/*
+ * \brief Terminal file system
+ * \author Christian Prochaska
+ * \author Norman Feske
+ * \date 2012-05-23
+ */
+
+/*
+ * Copyright (C) 2012-2014 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 _INCLUDE__VFS__TERMINAL_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__TERMINAL_FILE_SYSTEM_H_
+
+#include
+#include
+
+namespace Vfs { class Terminal_file_system; }
+
+
+class Vfs::Terminal_file_system : public Single_file_system
+{
+ private:
+
+ 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;
+
+ Terminal::Connection _terminal;
+
+ public:
+
+ Terminal_file_system(Xml_node config)
+ :
+ Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config),
+ _label(config),
+ _terminal(_label.string)
+ {
+ /*
+ * Wait for connection-established signal
+ */
+
+ /* create signal receiver, just for the single signal */
+ Genode::Signal_context sig_ctx;
+ Genode::Signal_receiver sig_rec;
+ Signal_context_capability sig_cap = sig_rec.manage(&sig_ctx);
+
+ /* register signal handler */
+ _terminal.connected_sigh(sig_cap);
+
+ /* wati for signal */
+ sig_rec.wait_for_signal();
+ sig_rec.dissolve(&sig_ctx);
+ }
+
+ static const char *name() { return "terminal"; }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *, char const *buf, size_t buf_size, size_t &out_count) override
+ {
+ out_count = _terminal.write(buf, buf_size);
+ return WRITE_OK;
+ }
+
+ Read_result read(Vfs_handle *, char *dst, size_t count, size_t &out_count) override
+ {
+ out_count = _terminal.read(dst, count);
+ return READ_OK;
+ }
+
+ bool check_unblock(Vfs_handle *vfs_handle, bool rd, bool wr, bool ex) override
+ {
+ if (rd && (_terminal.avail() > 0))
+ return true;
+
+ if (wr)
+ return true;
+
+ return false;
+ }
+
+ void register_read_ready_sigh(Vfs_handle *vfs_handle,
+ Signal_context_capability sigh) override
+ {
+ _terminal.read_avail_sigh(sigh);
+ }
+};
+
+#endif /* _INCLUDE__VFS__TERMINAL_FILE_SYSTEM_H_ */
diff --git a/os/include/vfs/types.h b/os/include/vfs/types.h
new file mode 100644
index 000000000..eb9d594a7
--- /dev/null
+++ b/os/include/vfs/types.h
@@ -0,0 +1,54 @@
+/*
+ * \brief Types used by VFS
+ * \author Norman Feske
+ * \date 2014-04-07
+ */
+
+/*
+ * Copyright (C) 2014 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 _INCLUDE__VFS__TYPES_H_
+#define _INCLUDE__VFS__TYPES_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Vfs {
+
+ enum { MAX_PATH_LEN = 512 };
+
+ using Genode::Ram_dataspace_capability;
+ using Genode::Dataspace_capability;
+ using Genode::Dataspace_client;
+ using Genode::env;
+ using Genode::min;
+ using Genode::ascii_to;
+ using Genode::strncpy;
+ using Genode::strcmp;
+ using Genode::strlen;
+ using Genode::off_t;
+ using Genode::memcpy;
+ using Genode::memset;
+ using Genode::size_t;
+ using Genode::Lock;
+ using Genode::List;
+ using Genode::Xml_node;
+ using Genode::Signal_context_capability;
+ using Genode::static_cap_cast;
+
+ typedef Genode::Path Absolute_path;
+}
+
+#endif /* _INCLUDE__VFS__TYPES_H_ */
diff --git a/os/include/vfs/vfs_handle.h b/os/include/vfs/vfs_handle.h
new file mode 100644
index 000000000..03ac31f15
--- /dev/null
+++ b/os/include/vfs/vfs_handle.h
@@ -0,0 +1,64 @@
+/*
+ * \brief Representation of an open file
+ * \author Norman Feske
+ * \date 2011-02-17
+ */
+
+/*
+ * Copyright (C) 2011-2014 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 _INCLUDE__VFS__VFS_HANDLE_H_
+#define _INCLUDE__VFS__VFS_HANDLE_H_
+
+#include
+#include
+
+namespace Vfs { class Vfs_handle; }
+
+
+class Vfs::Vfs_handle
+{
+ private:
+
+ Directory_service &_ds;
+ File_io_service &_fs;
+ int _status_flags;
+ size_t _seek;
+
+ public:
+
+ enum { STATUS_RDONLY = 0, STATUS_WRONLY = 1, STATUS_RDWR = 2 };
+
+ Vfs_handle(Directory_service &ds, File_io_service &fs, int status_flags)
+ :
+ _ds(ds), _fs(fs), _status_flags(status_flags), _seek(0)
+ { }
+
+ virtual ~Vfs_handle() { }
+
+ Directory_service &ds() { return _ds; }
+ File_io_service &fs() { return _fs; }
+
+ int status_flags() const { return _status_flags; }
+
+ /**
+ * Return seek offset in bytes
+ */
+ size_t seek() const { return _seek; }
+
+ /**
+ * Set seek offset in bytes
+ */
+ void seek(off_t seek) { _seek = seek; }
+
+ /**
+ * Advance seek offset by 'incr' bytes
+ */
+ void advance_seek(size_t incr) { _seek += incr; }
+};
+
+#endif /* _INCLUDE__VFS__VFS_HANDLE_H_ */
diff --git a/os/include/vfs/zero_file_system.h b/os/include/vfs/zero_file_system.h
new file mode 100644
index 000000000..2c2f968d5
--- /dev/null
+++ b/os/include/vfs/zero_file_system.h
@@ -0,0 +1,53 @@
+/*
+ * \brief zero filesystem
+ * \author Josef Soentgen
+ * \author Norman Feske
+ * \date 2012-07-31
+ */
+
+/*
+ * Copyright (C) 2012-2014 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 _INCLUDE__VFS__ZERO_FILE_SYSTEM_H_
+#define _INCLUDE__VFS__ZERO_FILE_SYSTEM_H_
+
+#include
+
+namespace Vfs { class Zero_file_system; }
+
+
+struct Vfs::Zero_file_system : Single_file_system
+{
+ Zero_file_system(Xml_node config)
+ :
+ Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config)
+ { }
+
+ static char const *name() { return "zero"; }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *, char const *, size_t count, size_t &count_out) override
+ {
+ count_out = count;
+
+ return WRITE_OK;
+ }
+
+ Read_result read(Vfs_handle *vfs_handle, char *dst, size_t count, size_t &out_count) override
+ {
+ memset(dst, 0, count);
+ out_count = count;
+
+ return READ_OK;
+ }
+};
+
+#endif /* _INCLUDE__VFS__ZERO_FILE_SYSTEM_H_ */
diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h
index 359eaf795..61076f2ef 100644
--- a/ports/include/noux_session/sysio.h
+++ b/ports/include/noux_session/sysio.h
@@ -21,6 +21,7 @@
/* Genode includes */
#include
#include
+#include
#define SYSIO_DECL(syscall_name, args, results) \
@@ -81,25 +82,16 @@ namespace Noux {
STAT_MODE_BLOCKDEV = 0060000,
};
- struct Stat
- {
- size_t size;
- unsigned mode;
- unsigned uid;
- unsigned gid;
- unsigned long inode;
- unsigned device;
- };
+ typedef Vfs::Directory_service::Stat Stat;
/**
* Argument structure used for ioctl syscall
*/
struct Ioctl_in
{
- enum Opcode { OP_UNDEFINED, OP_TIOCGWINSZ, OP_TIOCSETAF,
- OP_TIOCSETAW, OP_FIONBIO, OP_DIOCGMEDIASIZE };
+ typedef Vfs::File_io_service::Ioctl_opcode Opcode;
- enum Val { VAL_NULL, VAL_ECHO, VAL_ECHONL };
+ typedef Vfs::File_io_service::Ioctl_value Value;
Opcode request;
int argp;
@@ -108,45 +100,14 @@ namespace Noux {
/**
* Structure carrying the result values of 'ioctl' syscalls
*/
- struct Ioctl_out
- {
- union
- {
- /* if request was 'OP_TIOCGSIZE' */
- struct {
- int rows;
- int columns;
- } tiocgwinsz;
-
- /* if request was 'OP_DIOCGMEDIASIZE' */
- struct {
- /* disk size rounded up to sector size in bytes*/
- int size;
-
- } diocgmediasize;
- };
- };
+ typedef Vfs::File_io_service::Ioctl_out Ioctl_out;
enum Lseek_whence { LSEEK_SET, LSEEK_CUR, LSEEK_END };
- enum { DIRENT_MAX_NAME_LEN = 128 };
+ enum { DIRENT_MAX_NAME_LEN = Vfs::Directory_service::DIRENT_MAX_NAME_LEN };
- enum Dirent_type {
- DIRENT_TYPE_FILE,
- DIRENT_TYPE_DIRECTORY,
- DIRENT_TYPE_FIFO,
- DIRENT_TYPE_CHARDEV,
- DIRENT_TYPE_BLOCKDEV,
- DIRENT_TYPE_SYMLINK,
- DIRENT_TYPE_END
- };
-
- struct Dirent
- {
- int fileno;
- Dirent_type type;
- char name[DIRENT_MAX_NAME_LEN];
- };
+ typedef Vfs::Directory_service::Dirent_type Dirent_type;
+ typedef Vfs::Directory_service::Dirent Dirent;
enum Fcntl_cmd {
FCNTL_CMD_GET_FILE_STATUS_FLAGS,
@@ -304,34 +265,9 @@ namespace Noux {
*/
enum Clock_Id { CLOCK_ID_SECOND };
- 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 Ftruncate_error { FTRUNCATE_ERR_NO_PERM = NUM_GENERAL_ERRORS,
- FTRUNCATE_ERR_INTERRUPT };
- enum Open_error { OPEN_ERR_UNACCESSIBLE, OPEN_ERR_NO_PERM,
- OPEN_ERR_EXISTS };
- enum Execve_error { EXECVE_NONEXISTENT = NUM_GENERAL_ERRORS };
+ enum Fcntl_error { FCNTL_ERR_CMD_INVALID = Vfs::Directory_service::NUM_GENERAL_ERRORS };
+ enum Execve_error { EXECVE_NONEXISTENT = Vfs::Directory_service::NUM_GENERAL_ERRORS };
enum Select_error { SELECT_ERR_INTERRUPT };
- enum Unlink_error { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM };
- enum Readlink_error { READLINK_ERR_NO_ENTRY };
- 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};
- enum Symlink_error { SYMLINK_ERR_EXISTS, SYMLINK_ERR_NO_ENTRY,
- SYMLINK_ERR_NAME_TOO_LONG};
-
- enum Read_error { READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK,
- READ_ERR_INVALID, READ_ERR_IO,
- READ_ERR_INTERRUPT };
-
- enum Write_error { WRITE_ERR_AGAIN, WRITE_ERR_WOULD_BLOCK,
- WRITE_ERR_INVALID, WRITE_ERR_IO,
- WRITE_ERR_INTERRUPT };
-
- enum Ioctl_error { IOCTL_ERR_INVALID, IOCTL_ERR_NOTTY };
/**
* Socket related errors
@@ -375,33 +311,35 @@ namespace Noux {
enum Kill_error { KILL_ERR_SRCH };
union {
- General_error general;
- Stat_error stat;
- Fcntl_error fcntl;
- Ftruncate_error ftruncate;
- Open_error open;
- Execve_error execve;
- Select_error select;
- Unlink_error unlink;
- Readlink_error readlink;
- Rename_error rename;
- Mkdir_error mkdir;
- Symlink_error symlink;
- Read_error read;
- Write_error write;
- Ioctl_error ioctl;
- Accept_error accept;
- Bind_error bind;
- Connect_error connect;
- Listen_error listen;
- Recv_error recv;
- Send_error send;
- Shutdown_error shutdown;
- Socket_error socket;
- Clock_error clock;
- Utimes_error utimes;
- Wait4_error wait4;
- Kill_error kill;
+ Vfs::Directory_service::General_error general;
+ Vfs::Directory_service::Stat_result stat;
+ Vfs::File_io_service::Ftruncate_result ftruncate;
+ Vfs::Directory_service::Open_result open;
+ Vfs::Directory_service::Unlink_result unlink;
+ Vfs::Directory_service::Readlink_result readlink;
+ Vfs::Directory_service::Rename_result rename;
+ Vfs::Directory_service::Mkdir_result mkdir;
+ Vfs::Directory_service::Symlink_result symlink;
+ Vfs::File_io_service::Read_result read;
+ Vfs::File_io_service::Write_result write;
+ Vfs::File_io_service::Ioctl_result ioctl;
+
+ Fcntl_error fcntl;
+ Execve_error execve;
+ Select_error select;
+ Accept_error accept;
+ Bind_error bind;
+ Connect_error connect;
+ Listen_error listen;
+ Recv_error recv;
+ Send_error send;
+ Shutdown_error shutdown;
+ Socket_error socket;
+ Clock_error clock;
+ Utimes_error utimes;
+ Wait4_error wait4;
+ Kill_error kill;
+
} error;
union {
@@ -435,7 +373,7 @@ namespace Noux {
{ Chunk chunk; size_t count; });
SYSIO_DECL(readlink, { Path path; size_t bufsiz; },
- { Chunk chunk; ssize_t count; });
+ { Chunk chunk; size_t count; });
SYSIO_DECL(execve, { Path filename; Args args; Env env; }, { });
diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc
index 8aa69da74..7f59cb5b0 100644
--- a/ports/src/lib/libc_noux/plugin.cc
+++ b/ports/src/lib/libc_noux/plugin.cc
@@ -962,7 +962,8 @@ namespace {
if (verbose)
PWRN("stat syscall failed for path \"%s\"", path);
switch (sysio()->error.stat) {
- case Noux::Sysio::STAT_ERR_NO_ENTRY: errno = ENOENT; break;
+ case Vfs::Directory_service::STAT_OK: /* never reached */
+ case Vfs::Directory_service::STAT_ERR_NO_ENTRY: errno = ENOENT; break;
}
return -1;
}
@@ -988,7 +989,7 @@ namespace {
opened = true;
else
switch (sysio()->error.open) {
- case Noux::Sysio::OPEN_ERR_UNACCESSIBLE:
+ case Vfs::Directory_service::OPEN_ERR_UNACCESSIBLE:
if (!(flags & O_CREAT)) {
errno = ENOENT;
return 0;
@@ -1000,16 +1001,18 @@ namespace {
opened = true;
else
switch (sysio()->error.open) {
- case Noux::Sysio::OPEN_ERR_EXISTS:
- /* file has been created by someone else in the meantime */
- break;
- case Noux::Sysio::OPEN_ERR_NO_PERM: errno = EPERM; return 0;
- default: errno = ENOENT; return 0;
+ case Vfs::Directory_service::OPEN_ERR_EXISTS:
+ /* file has been created by someone else in the meantime */
+ break;
+ case Vfs::Directory_service::OPEN_ERR_NO_PERM:
+ errno = EPERM; return 0;
+ default:
+ errno = ENOENT; return 0;
}
break;
- case Noux::Sysio::OPEN_ERR_NO_PERM: errno = EPERM; return 0;
- case Noux::Sysio::OPEN_ERR_EXISTS: errno = EEXIST; return 0;
- default: errno = ENOENT; return 0;
+ case Vfs::Directory_service::OPEN_ERR_NO_PERM: errno = EPERM; return 0;
+ case Vfs::Directory_service::OPEN_ERR_EXISTS: errno = EEXIST; return 0;
+ default: errno = ENOENT; return 0;
}
}
@@ -1070,13 +1073,13 @@ namespace {
if (!noux_syscall(Noux::Session::SYSCALL_WRITE)) {
switch (sysio()->error.write) {
- case Noux::Sysio::WRITE_ERR_AGAIN: errno = EAGAIN; break;
- case Noux::Sysio::WRITE_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
- case Noux::Sysio::WRITE_ERR_INVALID: errno = EINVAL; break;
- case Noux::Sysio::WRITE_ERR_IO: errno = EIO; break;
- case Noux::Sysio::WRITE_ERR_INTERRUPT: errno = EINTR; break;
+ case Vfs::File_io_service::WRITE_ERR_AGAIN: errno = EAGAIN; break;
+ case Vfs::File_io_service::WRITE_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
+ case Vfs::File_io_service::WRITE_ERR_INVALID: errno = EINVAL; break;
+ case Vfs::File_io_service::WRITE_ERR_IO: errno = EIO; break;
+ case Vfs::File_io_service::WRITE_ERR_INTERRUPT: errno = EINTR; break;
default:
- if (sysio()->error.general == Noux::Sysio::ERR_FD_INVALID)
+ if (sysio()->error.general == Vfs::Directory_service::ERR_FD_INVALID)
errno = EBADF;
else
errno = 0;
@@ -1106,13 +1109,13 @@ namespace {
if (!noux_syscall(Noux::Session::SYSCALL_READ)) {
switch (sysio()->error.read) {
- case Noux::Sysio::READ_ERR_AGAIN: errno = EAGAIN; break;
- case Noux::Sysio::READ_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
- case Noux::Sysio::READ_ERR_INVALID: errno = EINVAL; break;
- case Noux::Sysio::READ_ERR_IO: errno = EIO; break;
- case Noux::Sysio::READ_ERR_INTERRUPT: errno = EINTR; break;
+ case Vfs::File_io_service::READ_ERR_AGAIN: errno = EAGAIN; break;
+ case Vfs::File_io_service::READ_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break;
+ case Vfs::File_io_service::READ_ERR_INVALID: errno = EINVAL; break;
+ case Vfs::File_io_service::READ_ERR_IO: errno = EIO; break;
+ case Vfs::File_io_service::READ_ERR_INTERRUPT: errno = EINTR; break;
default:
- if (sysio()->error.general == Noux::Sysio::ERR_FD_INVALID)
+ if (sysio()->error.general == Vfs::Directory_service::ERR_FD_INVALID)
errno = EBADF;
else
errno = 0;
@@ -1159,12 +1162,12 @@ namespace {
* Marshal ioctl arguments
*/
sysio()->ioctl_in.fd = noux_fd(fd->context);
- sysio()->ioctl_in.request = Noux::Sysio::Ioctl_in::OP_UNDEFINED;
+ sysio()->ioctl_in.request = Vfs::File_io_service::IOCTL_OP_UNDEFINED;
switch (request) {
case TIOCGWINSZ:
- sysio()->ioctl_in.request = Noux::Sysio::Ioctl_in::OP_TIOCGWINSZ;
+ sysio()->ioctl_in.request = Vfs::File_io_service::IOCTL_OP_TIOCGWINSZ;
break;
case TIOCGETA:
@@ -1192,7 +1195,7 @@ namespace {
case TIOCSETAF:
{
- sysio()->ioctl_in.request = Noux::Sysio::Ioctl_in::OP_TIOCSETAF;
+ sysio()->ioctl_in.request = Vfs::File_io_service::IOCTL_OP_TIOCSETAF;
::termios *termios = (::termios *)argp;
@@ -1200,11 +1203,11 @@ namespace {
* For now only enabling/disabling of ECHO is supported
*/
if (termios->c_lflag & (ECHO | ECHONL)) {
- sysio()->ioctl_in.argp = (Noux::Sysio::Ioctl_in::VAL_ECHO |
- Noux::Sysio::Ioctl_in::VAL_ECHONL);
+ sysio()->ioctl_in.argp = (Vfs::File_io_service::IOCTL_VAL_ECHO |
+ Vfs::File_io_service::IOCTL_VAL_ECHONL);
}
else {
- sysio()->ioctl_in.argp = Noux::Sysio::Ioctl_in::VAL_NULL;
+ sysio()->ioctl_in.argp = Vfs::File_io_service::IOCTL_VAL_NULL;
}
break;
@@ -1212,7 +1215,7 @@ namespace {
case TIOCSETAW:
{
- sysio()->ioctl_in.request = Noux::Sysio::Ioctl_in::OP_TIOCSETAW;
+ sysio()->ioctl_in.request = Vfs::File_io_service::IOCTL_OP_TIOCSETAW;
sysio()->ioctl_in.argp = argp ? *(int*)argp : 0;
break;
@@ -1223,7 +1226,7 @@ namespace {
if (verbose)
PDBG("FIONBIO - *argp=%d", *argp);
- sysio()->ioctl_in.request = Noux::Sysio::Ioctl_in::OP_FIONBIO;
+ sysio()->ioctl_in.request = Vfs::File_io_service::IOCTL_OP_FIONBIO;
sysio()->ioctl_in.argp = argp ? *(int*)argp : 0;
break;
@@ -1231,7 +1234,7 @@ namespace {
case DIOCGMEDIASIZE:
{
- sysio()->ioctl_in.request = Noux::Sysio::Ioctl_in::OP_DIOCGMEDIASIZE;
+ sysio()->ioctl_in.request = Vfs::File_io_service::IOCTL_OP_DIOCGMEDIASIZE;
sysio()->ioctl_in.argp = 0;
break;
@@ -1243,7 +1246,7 @@ namespace {
break;
}
- if (sysio()->ioctl_in.request == Noux::Sysio::Ioctl_in::OP_UNDEFINED) {
+ if (sysio()->ioctl_in.request == Vfs::File_io_service::IOCTL_OP_UNDEFINED) {
errno = ENOTTY;
return -1;
}
@@ -1251,8 +1254,8 @@ namespace {
/* perform syscall */
if (!noux_syscall(Noux::Session::SYSCALL_IOCTL)) {
switch (sysio()->error.ioctl) {
- case Noux::Sysio::IOCTL_ERR_INVALID: errno = EINVAL; break;
- case Noux::Sysio::IOCTL_ERR_NOTTY: errno = ENOTTY; break;
+ case Vfs::File_io_service::IOCTL_ERR_INVALID: errno = EINVAL; break;
+ case Vfs::File_io_service::IOCTL_ERR_NOTTY: errno = ENOTTY; break;
default: errno = 0; break;
}
@@ -1373,8 +1376,9 @@ namespace {
sysio()->ftruncate_in.length = length;
if (!noux_syscall(Noux::Session::SYSCALL_FTRUNCATE)) {
switch (sysio()->error.ftruncate) {
- case Noux::Sysio::FTRUNCATE_ERR_NO_PERM: errno = EPERM; break;
- case Noux::Sysio::FTRUNCATE_ERR_INTERRUPT: errno = EINTR; break;
+ case Vfs::File_io_service::FTRUNCATE_OK: /* never reached */
+ case Vfs::File_io_service::FTRUNCATE_ERR_NO_PERM: errno = EPERM; break;
+ case Vfs::File_io_service::FTRUNCATE_ERR_INTERRUPT: errno = EINTR; break;
}
return -1;
}
@@ -1453,8 +1457,8 @@ namespace {
case Noux::Sysio::FCNTL_ERR_CMD_INVALID: errno = EINVAL; break;
default:
switch (sysio()->error.general) {
- case Noux::Sysio::ERR_FD_INVALID: errno = EINVAL; break;
- case Noux::Sysio::NUM_GENERAL_ERRORS: break;
+ case Vfs::Directory_service::ERR_FD_INVALID: errno = EINVAL; break;
+ case Vfs::Directory_service::NUM_GENERAL_ERRORS: break;
}
}
return -1;
@@ -1481,23 +1485,23 @@ namespace {
if (!noux_syscall(Noux::Session::SYSCALL_DIRENT)) {
switch (sysio()->error.general) {
- case Noux::Sysio::ERR_FD_INVALID:
+ case Vfs::Directory_service::ERR_FD_INVALID:
errno = EBADF;
PERR("dirent: ERR_FD_INVALID");
return -1;
- case Noux::Sysio::NUM_GENERAL_ERRORS: return -1;
+ case Vfs::Directory_service::NUM_GENERAL_ERRORS: return -1;
}
}
switch (sysio()->dirent_out.entry.type) {
- case Noux::Sysio::DIRENT_TYPE_DIRECTORY: dirent->d_type = DT_DIR; break;
- case Noux::Sysio::DIRENT_TYPE_FILE: dirent->d_type = DT_REG; break;
- case Noux::Sysio::DIRENT_TYPE_SYMLINK: dirent->d_type = DT_LNK; break;
- case Noux::Sysio::DIRENT_TYPE_FIFO: dirent->d_type = DT_FIFO; break;
- case Noux::Sysio::DIRENT_TYPE_CHARDEV: dirent->d_type = DT_CHR; break;
- case Noux::Sysio::DIRENT_TYPE_BLOCKDEV: dirent->d_type = DT_BLK; break;
- case Noux::Sysio::DIRENT_TYPE_END: return 0;
+ case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY: dirent->d_type = DT_DIR; break;
+ case Vfs::Directory_service::DIRENT_TYPE_FILE: dirent->d_type = DT_REG; break;
+ case Vfs::Directory_service::DIRENT_TYPE_SYMLINK: dirent->d_type = DT_LNK; break;
+ case Vfs::Directory_service::DIRENT_TYPE_FIFO: dirent->d_type = DT_FIFO; break;
+ case Vfs::Directory_service::DIRENT_TYPE_CHARDEV: dirent->d_type = DT_CHR; break;
+ case Vfs::Directory_service::DIRENT_TYPE_BLOCKDEV: dirent->d_type = DT_BLK; break;
+ case Vfs::Directory_service::DIRENT_TYPE_END: return 0;
}
dirent->d_fileno = sysio()->dirent_out.entry.fileno;
@@ -1529,12 +1533,12 @@ namespace {
if (!noux_syscall(Noux::Session::SYSCALL_LSEEK)) {
switch (sysio()->error.general) {
- case Noux::Sysio::ERR_FD_INVALID:
+ case Vfs::Directory_service::ERR_FD_INVALID:
errno = EBADF;
PERR("lseek: ERR_FD_INVALID");
return -1;
- case Noux::Sysio::NUM_GENERAL_ERRORS: return -1;
+ case Vfs::Directory_service::NUM_GENERAL_ERRORS: return -1;
}
}
@@ -1549,8 +1553,8 @@ namespace {
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;
+ case Vfs::Directory_service::UNLINK_ERR_NO_ENTRY: errno = ENOENT; break;
+ default: errno = EPERM; break;
}
return -1;
}
@@ -1592,10 +1596,10 @@ namespace {
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;
+ case Vfs::Directory_service::RENAME_ERR_NO_ENTRY: errno = ENOENT; break;
+ case Vfs::Directory_service::RENAME_ERR_CROSS_FS: errno = EXDEV; break;
+ case Vfs::Directory_service::RENAME_ERR_NO_PERM: errno = EPERM; break;
+ default: errno = EPERM; break;
}
return -1;
}
@@ -1611,12 +1615,12 @@ namespace {
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;
+ case Vfs::Directory_service::MKDIR_ERR_EXISTS: errno = EEXIST; break;
+ case Vfs::Directory_service::MKDIR_ERR_NO_ENTRY: errno = ENOENT; break;
+ case Vfs::Directory_service::MKDIR_ERR_NO_SPACE: errno = ENOSPC; break;
+ case Vfs::Directory_service::MKDIR_ERR_NAME_TOO_LONG: errno = ENAMETOOLONG; break;
+ case Vfs::Directory_service::MKDIR_ERR_NO_PERM: errno = EPERM; break;
+ default: errno = EPERM; break;
}
return -1;
}
diff --git a/ports/src/noux/block_file_system.h b/ports/src/noux/block_file_system.h
deleted file mode 100644
index 8a7915689..000000000
--- a/ports/src/noux/block_file_system.h
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * \brief Block device file system
- * \author Josef Soentgen
- * \date 2013-12-20
- */
-
-/*
- * Copyright (C) 2013 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__BLOCK_FILE_SYSTEM_H_
-#define _NOUX__BLOCK_FILE_SYSTEM_H_
-
-/* Genode includes */
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* Noux includes */
-#include
-#include "file_system.h"
-
-
-namespace Noux {
-
- class Block_file_system : public File_system
- {
- private:
-
- 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;
-
- char *_block_buffer;
- unsigned _block_buffer_count;
-
- Genode::Allocator_avl _tx_block_alloc;
- Block::Connection _block;
- size_t _block_size;
- Block::sector_t _block_count;
- Block::Session::Operations _block_ops;
- Block::Session::Tx::Source *_tx_source;
-
- off_t _seek_offset;
-
- bool _readable;
- bool _writeable;
-
-
- enum { FILENAME_MAX_LEN = 64 };
- char _filename[FILENAME_MAX_LEN];
-
- bool _is_root(const char *path)
- {
- return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
- }
-
- bool _is_block_file(const char *path)
- {
- return (strlen(path) == (strlen(_filename) + 1)) &&
- (strcmp(&path[1], _filename) == 0);
- }
-
- size_t _block_io(size_t nr, void *buf, size_t sz, bool write, bool bulk = false)
- {
- Block::Packet_descriptor::Opcode op;
- op = write ? Block::Packet_descriptor::WRITE : Block::Packet_descriptor::READ;
-
- size_t packet_size = bulk ? sz : _block_size;
- size_t packet_count = bulk ? (sz / _block_size) : 1;
-
- /* sanity check */
- if (packet_count > _block_buffer_count) {
- packet_size = _block_buffer_count * _block_size;
- packet_count = _block_buffer_count;
- }
-
- //if (verbose)
- PDBG("%5s: block:%zu size:%zu packets:%zu",
- write ? "write" : "read", nr, sz, packet_count);
-
- Block::Packet_descriptor p(_tx_source->alloc_packet(packet_size), op,
- nr, packet_count);
-
- if (write)
- Genode::memcpy(_tx_source->packet_content(p), buf, packet_size);
-
- _tx_source->submit_packet(p);
- p = _tx_source->get_acked_packet();
-
- if (!p.succeeded()) {
- PERR("Could not read block(s)");
- _tx_source->release_packet(p);
- return 0;
- }
-
- if (!write)
- Genode::memcpy(buf, _tx_source->packet_content(p), packet_size);
-
- _tx_source->release_packet(p);
- return packet_size;
- }
-
- public:
-
- Block_file_system(Xml_node config)
- :
- _label(config),
- _block_buffer(0),
- _block_buffer_count(1),
- _tx_block_alloc(env()->heap()),
- _block(&_tx_block_alloc, 128*1024, _label.string),
- _tx_source(_block.tx()),
- _seek_offset(0),
- _readable(false),
- _writeable(false)
- {
- _filename[0] = 0;
- try { config.attribute("name").value(_filename, sizeof(_filename)); }
- catch (...) { }
-
- try { config.attribute("block_buffer_count").value(&_block_buffer_count); }
- catch (...) { }
-
- _block.info(&_block_count, &_block_size, &_block_ops);
-
- _readable = _block_ops.supported(Block::Packet_descriptor::READ);
- _writeable = _block_ops.supported(Block::Packet_descriptor::WRITE);
-
- _block_buffer = new (env()->heap()) char[_block_buffer_count * _block_size];
-
- //if (verbose)
- PDBG("number of blocks: %llu with block size: %zu (bytes)"
- " , readable: %d writeable: %d",
- _block_count, _block_size, _readable, _writeable);
- }
-
- ~Block_file_system()
- {
- destroy(env()->heap(), _block_buffer);
- }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- Dataspace_capability dataspace(char const *path)
- {
- /* not supported */
- return Dataspace_capability();
- }
-
- void release(char const *path, Dataspace_capability ds_cap)
- {
- /* not supported */
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
-
- if (_is_root(path))
- st.mode = Sysio::STAT_MODE_DIRECTORY;
- else if (_is_block_file(path)) {
- st.mode = Sysio::STAT_MODE_BLOCKDEV;
- } else {
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- sysio->stat_out.st = st;
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path, off_t index)
- {
- if (_is_root(path)) {
- if (index == 0) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_BLOCKDEV;
- strncpy(sysio->dirent_out.entry.name,
- _filename,
- sizeof(sysio->dirent_out.entry.name));
- } else {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- }
-
- return true;
- }
-
- return false;
- }
-
- size_t num_dirent(char const *path)
- {
- if (_is_root(path))
- return 1;
- else
- return 0;
- }
-
- bool is_directory(char const *path)
- {
- if (_is_root(path))
- return true;
-
- return false;
- }
-
- char const *leaf_path(char const *path)
- {
- return path;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- if (!_is_block_file(path)) {
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
- return new (env()->heap()) Vfs_handle(this, this, 0);
- }
-
- bool unlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool rename(Sysio *sysio, char const *from_path, char const *to_path)
- {
- /* not supported */
- return false;
- }
-
- bool mkdir(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- /***************************
- ** File_system interface **
- ***************************/
-
- static char const *name() { return "block"; }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- if (!_writeable) {
- PERR("block device is not writeable");
- return false;
- }
-
- size_t _seek_offset = vfs_handle->seek();
- size_t count = sysio->write_in.count;
- const char *_buf = (const char*) sysio->write_in.chunk;
-
- size_t written = 0;
- while (count > 0) {
- size_t displ = 0;
- size_t length = 0;
- size_t nbytes = 0;
- size_t blk_nr = _seek_offset / _block_size;
-
- displ = _seek_offset % _block_size;
-
- if ((displ + count) > _block_size)
- length = (_block_size - displ);
- else
- length = count;
-
- /**
- * We take a shortcut and write as much as possible without
- * using the block buffer if the offset is aligned on a block
- * boundary and the count is a multiple of the block size,
- * e.g. 4K writes will be written at once.
- *
- * XXX this is quite hackish because we have to omit partial
- * blocks at the end.
- */
- if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
- size_t bytes_left = count - (count % _block_size);
-
- nbytes = _block_io(blk_nr, (void*)(_buf + written),
- bytes_left, true, true);
- if (nbytes == 0) {
- PERR("error while reading block:%zu from block device",
- blk_nr);
- return false;
- }
-
- written += nbytes;
- count -= nbytes;
-
- continue;
- }
-
- /**
- * The offset is not aligned on a block boundary. Therefore
- * we need to read the block to the block buffer first and
- * put the buffer content at the right offset before we can
- * write the whole block back. In addition if length is less
- * than block size, we also have to read the block first.
- */
- if (displ > 0 || length < _block_size) {
- PWRN("offset:%zd block_size:%zd displacement:%zd length:%zu",
- _seek_offset, _block_size, displ, length);
-
- _block_io(blk_nr, _block_buffer, _block_size, false);
- /* rewind seek offset to account for the block read */
- _seek_offset -= _block_size;
- }
-
- Genode::memcpy(_block_buffer + displ, _buf + written, length);
-
- nbytes = _block_io(blk_nr, _block_buffer, _block_size, true);
- if ((unsigned)nbytes != _block_size) {
- PERR("error while reading block:%zu from Block_device",
- blk_nr);
- return false;
- }
-
- written += length;
- count -= length;
- }
-
- sysio->write_out.count = written;
-
- return true;
- }
-
- bool read(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- if (!_readable) {
- PERR("block device is not readable");
- return false;
- }
-
- size_t _seek_offset = vfs_handle->seek();
- size_t count = sysio->read_in.count;
- char *_buf = (char*) sysio->read_out.chunk;
-
- size_t read = 0;
- while (count > 0) {
- size_t displ = 0;
- size_t length = 0;
- size_t nbytes = 0;
- size_t blk_nr = _seek_offset / _block_size;
-
- displ = _seek_offset % _block_size;
-
- if ((displ + count) > _block_size)
- length = (_block_size - displ);
- else
- length = count;
-
- /**
- * We take a shortcut and read the blocks all at once if t he
- * offset is aligned on a block boundary and we the count is a
- * multiple of the block size, e.g. 4K reads will be read at
- * once.
- *
- * XXX this is quite hackish because we have to omit partial
- * blocks at the end.
- */
- if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
- size_t bytes_left = count - (count % _block_size);
-
- nbytes = _block_io(blk_nr, _buf + read, bytes_left, false, true);
- if (nbytes == 0) {
- PERR("error while reading block:%zu from block device",
- blk_nr);
- return false;
- }
-
- read += nbytes;
- count -= nbytes;
-
- continue;
- }
-
- if (displ > 0)
- PWRN("offset:%zd is not aligned to block_size:%zu"
- " displacement:%zu", _seek_offset, _block_size,
- displ);
-
- nbytes = _block_io(blk_nr, _block_buffer, _block_size, false);
- if ((unsigned)nbytes != _block_size) {
- PERR("error while reading block:%zu from block device",
- blk_nr);
- return false;
- }
-
- Genode::memcpy(_buf + read, _block_buffer + displ, length);
-
- read += length;
- count -= length;
- }
-
- sysio->read_out.count = read;
-
- return true;
- }
-
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
-
- bool check_unblock(Vfs_handle *vfs_handle, bool rd, bool wr, bool ex)
- {
- return true;
- }
-
- bool ioctl(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- switch (sysio->ioctl_in.request) {
- case Sysio::Ioctl_in::OP_DIOCGMEDIASIZE:
- {
- sysio->ioctl_out.diocgmediasize.size = _block_count * _block_size;
- return true;
- }
- default:
- PDBG("invalid ioctl request %d", sysio->ioctl_in.request);
- return false;
- }
-
- /* never reached */
- return false;
- }
- };
-}
-
-#endif /* _NOUX__BLOCK_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h
index d271fb011..e71bc6035 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
@@ -183,10 +183,10 @@ namespace Noux {
enum { NAME_MAX_LEN = 128 };
char _name[NAME_MAX_LEN];
- Dir_file_system * const _root_dir;
- Dataspace_capability const _binary_ds;
+ Vfs::Dir_file_system * const _root_dir;
+ Dataspace_capability const _binary_ds;
- Elf(char const * const binary_name, Dir_file_system * root_dir,
+ Elf(char const * const binary_name, Vfs::Dir_file_system * root_dir,
Dataspace_capability binary_ds)
:
_root_dir(root_dir), _binary_ds(binary_ds)
@@ -285,7 +285,7 @@ namespace Noux {
io->unregister_wake_up_notifier(¬ifier);
}
- Dir_file_system * const root_dir() { return _elf._root_dir; }
+ Vfs::Dir_file_system * const root_dir() { return _elf._root_dir; }
/**
* Method for handling noux network related system calls
@@ -310,22 +310,22 @@ namespace Noux {
* looked up at the virtual file
* system
*/
- Child(char const *binary_name,
- Parent_exit *parent_exit,
- Kill_broadcaster &kill_broadcaster,
- Parent_execve &parent_execve,
- int pid,
- Signal_receiver *sig_rec,
- Dir_file_system *root_dir,
- Args const &args,
- Sysio::Env const &env,
- Cap_session *cap_session,
- Service_registry &parent_services,
- Rpc_entrypoint &resources_ep,
- bool forked,
- Allocator *destruct_alloc,
- Destruct_queue &destruct_queue,
- bool verbose)
+ Child(char const *binary_name,
+ Parent_exit *parent_exit,
+ Kill_broadcaster &kill_broadcaster,
+ Parent_execve &parent_execve,
+ int pid,
+ Signal_receiver *sig_rec,
+ Vfs::Dir_file_system *root_dir,
+ Args const &args,
+ Sysio::Env const &env,
+ Cap_session *cap_session,
+ Service_registry &parent_services,
+ Rpc_entrypoint &resources_ep,
+ bool forked,
+ Allocator *destruct_alloc,
+ Destruct_queue &destruct_queue,
+ bool verbose)
:
Family_member(pid),
Destruct_queue::Element(destruct_alloc),
diff --git a/ports/src/noux/dir_file_system.h b/ports/src/noux/dir_file_system.h
deleted file mode 100644
index ebea72030..000000000
--- a/ports/src/noux/dir_file_system.h
+++ /dev/null
@@ -1,640 +0,0 @@
-/*
- * \brief Directory file system
- * \author Norman Feske
- * \date 2012-04-23
- */
-
-/*
- * Copyright (C) 2011-2013 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, File_system_registry &fs_registry)
- :
- _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);
-
- /* traverse into nodes */
- if (sub_node.has_type("dir")) {
- _append_file_system(new Dir_file_system(sub_node,
- fs_registry));
- continue;
- }
-
- File_system_registry::Entry *fs = fs_registry.lookup(sub_node);
- if (fs) {
- _append_file_system(fs->create(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);
-
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
-
- /* path does not match directory name */
- if (!path)
- 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;
- } else {
- /*
- * Keep the most meaningful error code. When using
- * stacked file systems, most child file systems will
- * eventually return 'STAT_ERR_NO_ENTRY' (or leave
- * the error code unchanged). If any of those file
- * systems has anything more interesting to tell,
- * return this information.
- */
- if (sysio->error.stat != Sysio::STAT_ERR_NO_ENTRY)
- return false;
- }
- }
-
- /* none of our file systems felt responsible for the path */
- 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 = 1;
- } 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);
-
- sysio->error.unlink = Sysio::UNLINK_ERR_NO_ENTRY;
-
- /* path does not match directory name */
- if (!path)
- 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.
- */
- for (File_system *fs = _first_file_system; fs; fs = fs->next)
- if (fs->unlink(sysio, path)) {
- return true;
- } else {
- /*
- * Keep the most meaningful error code. When using
- * stacked file systems, most child file systems will
- * eventually return 'UNLINK_ERR_NO_ENTRY' (or leave
- * the error code unchanged). 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)
- return false;
- }
-
- /* none of our file systems could successfully unlink the path */
- return false;
- }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- path = _sub_path(path);
-
- sysio->error.readlink = Sysio::READLINK_ERR_NO_ENTRY;
-
- /* path does not match directory name */
- if (!path)
- return false;
-
- /* path refers to any of our sub file systems */
- for (File_system *fs = _first_file_system; fs; fs = fs->next) {
- if (fs->readlink(sysio, path)) {
- return true;
- } else {
- /*
- * Keep the most meaningful error code. When using
- * stacked file systems, most child file systems will
- * eventually return 'READLINK_ERR_NO_ENTRY' (or leave
- * the error code unchanged). If any of those file
- * systems has anything more interesting to tell,
- * return this information.
- */
- if (sysio->error.readlink != Sysio::READLINK_ERR_NO_ENTRY)
- return false;
- }
- }
-
- /* none of our file systems could read the link */
- return false;
- }
-
- bool rename(Sysio *sysio, char const *from_path, char const *to_path)
- {
- from_path = _sub_path(from_path);
-
- sysio->error.rename = Sysio::RENAME_ERR_NO_ENTRY;
-
- /* path does not match directory name */
- if (!from_path)
- 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;
-
- } else {
- /*
- * Keep the most meaningful error code. When using
- * stacked file systems, most child file systems will
- * eventually return 'RENAME_ERR_NO_ENTRY' (or leave
- * the error code unchanged). If any of those file
- * systems has anything more interesting to tell,
- * return this information.
- */
- if (sysio->error.rename != Sysio::RENAME_ERR_NO_ENTRY)
- return false;
- }
- }
-
- /* none of our file systems could successfully rename the path */
- return false;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- path = _sub_path(path);
-
- sysio->error.symlink = Sysio::SYMLINK_ERR_NO_ENTRY;
-
- /* path does not match directory name */
- if (!path)
- return false;
-
- /*
- * Prevent symlink of path that equals directory name defined
- * via the static fstab configuration.
- */
- if (strlen(path) == 0) {
- sysio->error.symlink = Sysio::SYMLINK_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->symlink(sysio, path)) {
- return true;
-
- } else {
- /*
- * Keep the most meaningful error code. When using
- * stacked file systems, most child file systems will
- * eventually return 'SYMLINK_ERR_NO_ENTRY' (or leave
- * the error code unchanged). If any of those file
- * systems has anything more interesting to tell,
- * return this information.
- */
- if (sysio->error.symlink != Sysio::SYMLINK_ERR_NO_ENTRY)
- return false;
- }
- }
-
- /* none of our file systems could create the symlink */
- return false;
- }
-
- bool mkdir(Sysio *sysio, char const *path)
- {
- path = _sub_path(path);
-
- sysio->error.mkdir = Sysio::MKDIR_ERR_NO_ENTRY;
-
- /* path does not match directory name */
- if (!path)
- 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;
- } else {
- /*
- * Keep the most meaningful error code. When using
- * stacked file systems, most child file systems will
- * eventually return 'MKDIR_ERR_NO_ENTRY' (or leave
- * the error code unchanged). If any of those file
- * systems has anything more interesting to tell,
- * return this information.
- */
- if (sysio->error.mkdir != Sysio::MKDIR_ERR_NO_ENTRY)
- return false;
- }
- }
-
- /* none of our file systems could create the directory */
- return false;
- }
-
- /***************************
- ** File_system interface **
- ***************************/
-
- char const *name() const { return "dir"; }
-
- /**
- * Synchronize all file systems
- */
- void sync()
- {
- for (File_system *fs = _first_file_system; fs; fs = fs->next)
- fs->sync();
- }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *handle) { return false; }
- bool read(Sysio *sysio, Vfs_handle *vfs_handle) { return false; }
- bool ftruncate(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
deleted file mode 100644
index 89b44d67d..000000000
--- a/ports/src/noux/directory_service.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * \brief Directory-service interface
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2013 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__DIRECTORY_SERVICE_H_
-#define _NOUX__DIRECTORY_SERVICE_H_
-
-/* Genode includes */
-#include
-
-/* Noux includes */
-#include
-
-namespace Noux {
-
- class Vfs_handle;
-
- /**
- * Abstract interface to stateless directory service
- */
- struct Directory_service
- {
- virtual Dataspace_capability dataspace(char const *path) = 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, off_t index) = 0;
- virtual bool unlink(Sysio *sysio, char const *path) = 0;
- virtual bool readlink(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 bool symlink(Sysio *sysio, char const *path) = 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;
- };
-}
-
-#endif /* _NOUX__DIRECTORY_SERVICE_H_ */
diff --git a/ports/src/noux/file_io_service.h b/ports/src/noux/file_io_service.h
deleted file mode 100644
index adc7cfd2e..000000000
--- a/ports/src/noux/file_io_service.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * \brief Interface for operations provided by file I/O service
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2013 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__FILE_IO_SERVICE_H_
-#define _NOUX__FILE_IO_SERVICE_H_
-
-namespace Noux {
-
- class Vfs_handle;
- class Sysio;
-
- /**
- * Abstract file-system interface
- */
- struct File_io_service
- {
- virtual bool write(Sysio *sysio, Vfs_handle *vfs_handle) = 0;
- virtual bool read(Sysio *sysio, Vfs_handle *vfs_handle) = 0;
- virtual bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) = 0;
-
- /**
- * This method is only needed in file-systems which actually implement
- * a device and is therefore false by default.
- */
- virtual bool ioctl(Sysio *sysio, Vfs_handle *vfs_handle) { return false; }
-
- /**
- * Return true if an unblocking condition of the file is satisfied
- *
- * \param rd if true, check for data available for reading
- * \param wr if true, check for readiness for writing
- * \param ex if true, check for exceptions
- */
- virtual bool check_unblock(Vfs_handle *vfs_handle,
- bool rd, bool wr, bool ex)
- { return true; }
-
- virtual void register_read_ready_sigh(Vfs_handle *vfs_handle,
- Signal_context_capability sigh)
- { }
- };
-}
-
-#endif /* _NOUX__FILE_IO_SERVICE_H_ */
diff --git a/ports/src/noux/file_system.h b/ports/src/noux/file_system.h
deleted file mode 100644
index 46a1a5461..000000000
--- a/ports/src/noux/file_system.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * \brief File-system related interfaces for Noux
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2013 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__FILE_SYSTEM_H_
-#define _NOUX__FILE_SYSTEM_H_
-
-/* Genode includes */
-#include
-#include
-#include
-
-/* Noux includes */
-#include
-#include
-#include
-#include
-
-namespace Noux {
-
- struct File_system : Directory_service, File_io_service
- {
- /**
- * Our next sibling within the same 'Dir_file_system'
- */
- struct File_system *next;
-
- File_system() : next(0) { }
-
- /**
- * Synchronize file system
- *
- * This function is only used by a Fs_file_system because such a
- * file system may employ a backend, which maintains a internal
- * cache, that needs to be flushed.
- */
- virtual void sync() { }
- };
-}
-
-#endif /* _NOUX__FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/file_system_registry.h b/ports/src/noux/file_system_registry.h
deleted file mode 100644
index 75ad4cd82..000000000
--- a/ports/src/noux/file_system_registry.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * \brief Registry of file systems
- * \author Norman Feske
- * \date 2014-04-07
- */
-
-/*
- * Copyright (C) 2014 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__FILE_SYSTEM_REGISTRY_H_
-#define _NOUX__FILE_SYSTEM_REGISTRY_H_
-
-/* Noux includes */
-#include
-
-namespace Noux {
-
- class File_system_registry
- {
- public:
-
- struct Entry : List::Element
- {
- virtual File_system *create(Xml_node node) = 0;
-
- virtual bool matches(Xml_node node) = 0;
- };
-
- private:
-
- List _list;
-
- public:
-
- void insert(Entry &entry)
- {
- _list.insert(&entry);
- }
-
- Entry *lookup(Xml_node node)
- {
- for (Entry *e = _list.first(); e; e = e->next())
- if (e->matches(node))
- return e;
-
- return 0;
- }
- };
-}
-
-#endif /* _NOUX__FILE_SYSTEM_REGISTRY_H_ */
diff --git a/ports/src/noux/fs_file_system.h b/ports/src/noux/fs_file_system.h
deleted file mode 100644
index 135dee193..000000000
--- a/ports/src/noux/fs_file_system.h
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * \brief Adapter from Genode 'File_system' session to Noux file system
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2012-2013 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
- {
- enum { verbose = false };
-
- 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); }
- };
-
- size_t _read(::File_system::Node_handle node_handle, void *buf,
- size_t count, size_t seek_offset)
- {
- ::File_system::Session::Tx::Source &source = *_fs.tx();
-
- size_t const max_packet_size = source.bulk_buffer_size() / 2;
- count = min(max_packet_size, count);
-
- ::File_system::Packet_descriptor
- packet(source.alloc_packet(count),
- 0,
- node_handle,
- ::File_system::Packet_descriptor::READ,
- count,
- seek_offset);
-
- /* pass packet to server side */
- source.submit_packet(packet);
- source.get_acked_packet();
-
- memcpy(buf, source.packet_content(packet), count);
-
- /*
- * XXX check if acked packet belongs to request,
- * needed for thread safety
- */
-
- source.release_packet(packet);
-
- return count;
- }
-
- size_t _write(::File_system::Node_handle node_handle,
- const char *buf, size_t count, size_t seek_offset)
- {
- ::File_system::Session::Tx::Source &source = *_fs.tx();
-
- size_t const max_packet_size = source.bulk_buffer_size() / 2;
- count = min(max_packet_size, count);
-
- ::File_system::Packet_descriptor
- packet(source.alloc_packet(count),
- 0,
- node_handle,
- ::File_system::Packet_descriptor::WRITE,
- count,
- seek_offset);
-
- memcpy(source.packet_content(packet), buf, count);
-
- /* 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
- */
-
- source.release_packet(packet);
-
- return count;
- }
-
- 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)
- {
- 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();
-
- Ram_dataspace_capability ds_cap;
- char *local_addr = 0;
-
- try {
- ::File_system::Dir_handle dir = _fs.dir(dir_path.base(),
- false);
- Fs_handle_guard dir_guard(_fs, dir);
-
- ::File_system::File_handle file =
- _fs.file(dir, file_name.base() + 1,
- ::File_system::READ_ONLY, false);
- Fs_handle_guard file_guard(_fs, file);
-
- ::File_system::Status status = _fs.status(file);
-
- Ram_dataspace_capability ds_cap =
- env()->ram_session()->alloc(status.size);
-
- local_addr = env()->rm_session()->attach(ds_cap);
-
- ::File_system::Session::Tx::Source &source = *_fs.tx();
- size_t const max_packet_size = source.bulk_buffer_size() / 2;
-
- for (size_t seek_offset = 0; seek_offset < status.size;
- seek_offset += max_packet_size) {
-
- size_t const count = min(max_packet_size, status.size - seek_offset);
-
- ::File_system::Packet_descriptor
- packet(source.alloc_packet(count),
- 0,
- file,
- ::File_system::Packet_descriptor::READ,
- count,
- seek_offset);
-
- /* pass packet to server side */
- source.submit_packet(packet);
- source.get_acked_packet();
-
- memcpy(local_addr + seek_offset, source.packet_content(packet), count);
-
- /*
- * XXX check if acked packet belongs to request,
- * needed for thread safety
- */
-
- source.release_packet(packet);
- }
-
- env()->rm_session()->detach(local_addr);
-
- return ds_cap;
- } catch(...) {
- env()->rm_session()->detach(local_addr);
- env()->ram_session()->free(ds_cap);
- return Dataspace_capability();
- }
- }
-
- void release(char const *path, Dataspace_capability ds_cap)
- {
- env()->ram_session()->free(static_cap_cast(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 (...) {
- if (verbose)
- PDBG("stat failed for path '%s'", path);
- return false;
- }
-
- memset(&sysio->stat_out.st, 0, sizeof(sysio->stat_out.st));
-
- 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);
-
- /*
- * 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.
- */
- Sysio::Dirent_type type = Sysio::DIRENT_TYPE_END;
-
- 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 readlink(Sysio *sysio, char const *path)
- {
- /*
- * Canonicalize path (i.e., path must start with '/')
- */
- Absolute_path abs_path(path);
- abs_path.strip_last_element();
-
- Absolute_path symlink_name(path);
- symlink_name.keep_only_last_element();
-
- Sysio::Readlink_error error = Sysio::READLINK_ERR_NO_ENTRY;
- try {
- ::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
- Fs_handle_guard from_dir_guard(_fs, dir_handle);
-
- ::File_system::Symlink_handle symlink_handle =
- _fs.symlink(dir_handle, symlink_name.base() + 1, false);
- Fs_handle_guard symlink_guard(_fs, symlink_handle);
-
- sysio->readlink_out.count = _read(symlink_handle,
- sysio->readlink_out.chunk,
- min(sysio->readlink_in.bufsiz,
- sizeof(sysio->readlink_out.chunk)),
- 0);
-
- return true;
- } catch (...) { }
-
- sysio->error.readlink = error;
-
- return false;
- }
-
- 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;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- /*
- * Canonicalize path (i.e., path must start with '/')
- */
- Absolute_path abs_path(path);
- abs_path.strip_last_element();
-
- Absolute_path symlink_name(path);
- symlink_name.keep_only_last_element();
-
- Sysio::Symlink_error error = Sysio::SYMLINK_ERR_NO_ENTRY;
- try {
- ::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
- Fs_handle_guard from_dir_guard(_fs, dir_handle);
-
- ::File_system::Symlink_handle symlink_handle =
- _fs.symlink(dir_handle, symlink_name.base() + 1, true);
- Fs_handle_guard symlink_guard(_fs, symlink_handle);
-
- _write(symlink_handle, sysio->symlink_in.oldpath,
- strlen(sysio->symlink_in.oldpath) + 1, 0);
- return true;
- }
- catch (::File_system::Invalid_handle) { error = Sysio::SYMLINK_ERR_NO_ENTRY; }
- catch (::File_system::Node_already_exists) { error = Sysio::SYMLINK_ERR_EXISTS; }
- catch (::File_system::Invalid_name) { error = Sysio::SYMLINK_ERR_NAME_TOO_LONG; }
- catch (::File_system::Lookup_failed) { error = Sysio::SYMLINK_ERR_NO_ENTRY; }
-
- sysio->error.symlink = 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)
- if (verbose)
- PDBG("creation of file %s requested", file_name.base() + 1);
-
- Sysio::Open_error error = Sysio::OPEN_ERR_UNACCESSIBLE;
-
- try {
- ::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
- Fs_handle_guard dir_guard(_fs, dir);
-
- ::File_system::File_handle file = _fs.file(dir, file_name.base() + 1,
- mode, create);
-
- return new (env()->heap()) Fs_vfs_handle(this, sysio->open_in.mode, file);
- }
- catch (::File_system::Permission_denied) {
- error = Sysio::OPEN_ERR_NO_PERM; }
- catch (::File_system::Invalid_handle) {
- error = Sysio::OPEN_ERR_NO_PERM; }
- catch (::File_system::Lookup_failed) {
- error = Sysio::OPEN_ERR_UNACCESSIBLE; }
- catch (::File_system::Node_already_exists) {
- error = Sysio::OPEN_ERR_EXISTS; }
-
- sysio->error.open = error;
- return 0;
- }
-
-
- /***************************
- ** File_system interface **
- ***************************/
-
- static char const *name() { return "fs"; }
-
- void sync()
- {
- _fs.sync();
- }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- Fs_vfs_handle const *handle = static_cast(vfs_handle);
-
- size_t const count = min(sizeof(sysio->write_in.chunk),
- sysio->write_in.count);
-
- sysio->write_out.count = _write(handle->file_handle(),
- sysio->write_in.chunk, count,
- handle->seek());
-
- 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;
-
- size_t const count = min(file_bytes_left,
- min(sizeof(sysio->read_out.chunk),
- sysio->read_in.count));
-
- sysio->read_out.count = _read(handle->file_handle(),
- sysio->read_out.chunk,
- count, handle->seek());
-
- return true;
- }
-
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- Fs_vfs_handle const *handle = static_cast(vfs_handle);
-
- Sysio::Ftruncate_error error;
-
- try {
- _fs.truncate(handle->file_handle(), sysio->ftruncate_in.length);
- return true;
- } catch (::File_system::Invalid_handle) {
- /* should not happen */
- error = Sysio::FTRUNCATE_ERR_NO_PERM;
- } catch (::File_system::Permission_denied) {
- error = Sysio::FTRUNCATE_ERR_NO_PERM;
- }
-
- sysio->error.ftruncate = error;
- return false;
- }
-
- };
-}
-
-#endif /* _NOUX__FS_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/io_channel.h b/ports/src/noux/io_channel.h
index 52cd12c01..83de5ddd3 100644
--- a/ports/src/noux/io_channel.h
+++ b/ports/src/noux/io_channel.h
@@ -19,6 +19,7 @@
/* Genode includes */
#include
+#include
/* Noux includes */
#include
@@ -72,14 +73,14 @@ namespace Noux {
virtual Io_channel_backend* backend() { return 0; }
- virtual bool write(Sysio *sysio, size_t &count) { return false; }
- virtual bool read(Sysio *sysio) { return false; }
- virtual bool fstat(Sysio *sysio) { return false; }
- virtual bool ftruncate(Sysio *sysio) { return false; }
- virtual bool fcntl(Sysio *sysio) { return false; }
- virtual bool dirent(Sysio *sysio) { return false; }
- virtual bool ioctl(Sysio *sysio) { return false; }
- virtual bool lseek(Sysio *sysio) { return false; }
+ virtual bool write(Sysio *sysio, size_t &offset) { return false; }
+ virtual bool read(Sysio *sysio) { return false; }
+ virtual bool fstat(Sysio *sysio) { return false; }
+ virtual bool ftruncate(Sysio *sysio) { return false; }
+ virtual bool fcntl(Sysio *sysio) { 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 662c51835..6cfdf73e0 100644
--- a/ports/src/noux/main.cc
+++ b/ports/src/noux/main.cc
@@ -25,22 +25,21 @@
#include
#include
#include
-#include
#include
#include
#include
#include
-#include
+#include
/* supported file systems */
-#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
-#include
+#include
static const bool verbose_quota = false;
@@ -164,7 +163,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
{
size_t const count_in = _sysio->write_in.count;
- for (size_t count = 0; count != count_in; ) {
+ for (size_t offset = 0; offset != count_in; ) {
Shared_pointer io = _lookup_channel(_sysio->write_in.fd);
@@ -174,20 +173,19 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
if (io->check_unblock(false, true, false)) {
/*
* 'io->write' is expected to update
- * '_sysio->write_out.count' and 'count'
+ * '_sysio->write_out.count' and 'offset'
*/
- result = io->write(_sysio, count);
+ result = io->write(_sysio, offset);
if (result == false)
break;
} else {
if (result == false) {
/* nothing was written yet */
- _sysio->error.write = Sysio::WRITE_ERR_INTERRUPT;
+ _sysio->error.write = Vfs::File_io_service::WRITE_ERR_INTERRUPT;
}
break;
}
}
-
break;
}
@@ -201,7 +199,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
if (io->check_unblock(true, false, false))
result = io->read(_sysio);
else
- _sysio->error.read = Sysio::READ_ERR_INTERRUPT;
+ _sysio->error.read = Vfs::File_io_service::READ_ERR_INTERRUPT;
break;
}
@@ -215,7 +213,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
if (io->check_unblock(false, true, false))
result = io->ftruncate(_sysio);
else
- _sysio->error.ftruncate = Sysio::FTRUNCATE_ERR_INTERRUPT;
+ _sysio->error.ftruncate = Vfs::File_io_service::FTRUNCATE_ERR_INTERRUPT;
break;
}
@@ -230,9 +228,12 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
size_t path_len = strlen(_sysio->stat_in.path);
uint32_t path_hash = hash_path(_sysio->stat_in.path, path_len);
- result = root_dir()->stat(_sysio, _sysio->stat_in.path);
+ _sysio->error.stat = root_dir()->stat(_sysio->stat_in.path,
+ _sysio->stat_out.st);
- /**
+ result = (_sysio->error.stat == Vfs::Directory_service::STAT_OK);
+
+ /*
* Instead of using the uid/gid given by the actual file system
* we use the ones specificed in the config.
*/
@@ -285,7 +286,10 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_OPEN:
{
- Vfs_handle *vfs_handle = root_dir()->open(_sysio, _sysio->open_in.path);
+ Vfs::Vfs_handle *vfs_handle = 0;
+ _sysio->error.open = root_dir()->open(_sysio->open_in.path,
+ _sysio->open_in.mode,
+ &vfs_handle);
if (!vfs_handle)
break;
@@ -297,7 +301,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
* path because path operations always refer to the global
* root.
*/
- if (vfs_handle->ds() == root_dir())
+ if (&vfs_handle->ds() == root_dir())
leaf_path = _sysio->open_in.path;
Shared_pointer
@@ -678,29 +682,43 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_UNLINK:
- result = root_dir()->unlink(_sysio, _sysio->unlink_in.path);
+ _sysio->error.unlink = root_dir()->unlink(_sysio->unlink_in.path);
+
+ result = (_sysio->error.unlink == Vfs::Directory_service::UNLINK_OK);
break;
case SYSCALL_READLINK:
- result = root_dir()->readlink(_sysio, _sysio->readlink_in.path);
- break;
+ _sysio->error.readlink = root_dir()->readlink(_sysio->readlink_in.path,
+ _sysio->readlink_out.chunk,
+ min(_sysio->readlink_in.bufsiz,
+ sizeof(_sysio->readlink_out.chunk)),
+ _sysio->readlink_out.count);
+ result = (_sysio->error.readlink == Vfs::Directory_service::READLINK_OK);
+ break;
case SYSCALL_RENAME:
- result = root_dir()->rename(_sysio, _sysio->rename_in.from_path,
- _sysio->rename_in.to_path);
+ _sysio->error.rename = root_dir()->rename(_sysio->rename_in.from_path,
+ _sysio->rename_in.to_path);
+
+ result = (_sysio->error.rename == Vfs::Directory_service::RENAME_OK);
break;
case SYSCALL_MKDIR:
- result = root_dir()->mkdir(_sysio, _sysio->mkdir_in.path);
+ _sysio->error.mkdir = root_dir()->mkdir(_sysio->mkdir_in.path, 0);
+
+ result = (_sysio->error.mkdir == Vfs::Directory_service::MKDIR_OK);
break;
case SYSCALL_SYMLINK:
- result = root_dir()->symlink(_sysio, _sysio->symlink_in.newpath);
+ _sysio->error.symlink = root_dir()->symlink(_sysio->symlink_in.oldpath,
+ _sysio->symlink_in.newpath);
+
+ result = (_sysio->error.symlink == Vfs::Directory_service::SYMLINK_OK);
break;
case SYSCALL_USERINFO:
@@ -845,7 +863,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
}
catch (Invalid_fd) {
- _sysio->error.general = Sysio::ERR_FD_INVALID;
+ _sysio->error.general = Vfs::Directory_service::ERR_FD_INVALID;
PERR("Invalid file descriptor"); }
catch (...) { PERR("Unexpected exception"); }
@@ -1004,20 +1022,56 @@ void *operator new (Genode::size_t size) {
return Genode::env()->heap()->alloc(size); }
-template
-struct File_system_factory : Noux::File_system_registry::Entry
-{
- Noux::File_system *create(Genode::Xml_node node) override
- {
- return new FILE_SYSTEM(node);
- }
- bool matches(Genode::Xml_node node) override
- {
- char buf[100];
- node.type_name(buf, sizeof(buf));
- return node.has_type(FILE_SYSTEM::name());
- }
+class File_system_factory : public Vfs::File_system_factory
+{
+ public:
+
+ struct Entry_base : Genode::List::Element
+ {
+ char const * const name;
+
+ Entry_base(char const *name) : name(name) { }
+
+ virtual Vfs::File_system *create(Genode::Xml_node node) = 0;
+
+ bool matches(Genode::Xml_node node) const
+ {
+ return node.has_type(name);
+ }
+ };
+
+ template
+ struct Entry : Entry_base
+ {
+ Entry(char const *name) : Entry_base(name) { }
+
+ Vfs::File_system *create(Genode::Xml_node node) override
+ {
+ return new FILE_SYSTEM(node);
+ }
+ };
+
+ private:
+
+ Genode::List _list;
+
+ public:
+
+ template
+ void add_fs_type()
+ {
+ _list.insert(new Entry(FS::name()));
+ }
+
+ Vfs::File_system *create(Genode::Xml_node node) override
+ {
+ for (Entry_base *e = _list.first(); e; e = e->next())
+ if (e->matches(node))
+ return e->create(node);
+
+ return 0;
+ }
};
@@ -1046,19 +1100,19 @@ int main(int argc, char **argv)
} catch (Xml_node::Nonexistent_attribute) { }
/* register file systems */
- static File_system_registry fs_registry;
- fs_registry.insert(*new File_system_factory());
- fs_registry.insert(*new File_system_factory());
- fs_registry.insert(*new File_system_factory());
- fs_registry.insert(*new File_system_factory());
- fs_registry.insert(*new File_system_factory());
- fs_registry.insert(*new File_system_factory());
- fs_registry.insert(*new File_system_factory());
- fs_registry.insert(*new File_system_factory());
+ static File_system_factory fs_factory;
+ fs_factory.add_fs_type();
+ fs_factory.add_fs_type();
+ fs_factory.add_fs_type();
+ fs_factory.add_fs_type();
+ fs_factory.add_fs_type();
+ fs_factory.add_fs_type();
+ fs_factory.add_fs_type();
+ fs_factory.add_fs_type();
/* initialize virtual file system */
- static Dir_file_system
- root_dir(config()->xml_node().sub_node("fstab"), fs_registry);
+ static Vfs::Dir_file_system
+ root_dir(config()->xml_node().sub_node("fstab"), fs_factory);
/* set user information */
try {
diff --git a/ports/src/noux/net/socket_io_channel.h b/ports/src/noux/net/socket_io_channel.h
index 8245614c7..0f38d0f3b 100644
--- a/ports/src/noux/net/socket_io_channel.h
+++ b/ports/src/noux/net/socket_io_channel.h
@@ -83,9 +83,9 @@ namespace Noux {
switch (errno) {
/* case EAGAIN: sysio->error.read = Sysio::READ_ERR_AGAIN; break; */
- case EWOULDBLOCK: sysio->error.read = Sysio::READ_ERR_WOULD_BLOCK; break;
- case EINVAL: sysio->error.read = Sysio::READ_ERR_INVALID; break;
- case EIO: sysio->error.read = Sysio::READ_ERR_IO; break;
+ case EWOULDBLOCK: sysio->error.read = Vfs::File_io_service::READ_ERR_WOULD_BLOCK; break;
+ case EINVAL: sysio->error.read = Vfs::File_io_service::READ_ERR_INVALID; break;
+ case EIO: sysio->error.read = Vfs::File_io_service::READ_ERR_IO; break;
default:
PDBG("unhandled errno: %d", errno);
break;
@@ -107,9 +107,9 @@ namespace Noux {
switch (errno) {
/* case EAGAIN: sysio->error.read = Sysio::READ_ERR_AGAIN; break; */
- case EWOULDBLOCK: sysio->error.read = Sysio::READ_ERR_WOULD_BLOCK; break;
- case EINVAL: sysio->error.read = Sysio::READ_ERR_INVALID; break;
- case EIO: sysio->error.read = Sysio::READ_ERR_IO; break;
+ case EWOULDBLOCK: sysio->error.read = Vfs::File_io_service::READ_ERR_WOULD_BLOCK; break;
+ case EINVAL: sysio->error.read = Vfs::File_io_service::READ_ERR_INVALID; break;
+ case EIO: sysio->error.read = Vfs::File_io_service::READ_ERR_IO; break;
default:
PDBG("unhandled errno: %d", errno);
break;
@@ -145,7 +145,7 @@ namespace Noux {
switch (sysio->ioctl_in.request) {
- case Sysio::Ioctl_in::OP_FIONBIO: request = FIONBIO; break;
+ case Vfs::File_io_service::IOCTL_OP_FIONBIO: request = FIONBIO; break;
default:
PDBG("invalid ioctl request: %d", sysio->ioctl_in.request);
return false;
diff --git a/ports/src/noux/null_file_system.h b/ports/src/noux/null_file_system.h
deleted file mode 100644
index ad6ca8518..000000000
--- a/ports/src/noux/null_file_system.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * \brief null filesystem
- * \author Josef Soentgen
- * \date 2012-07-31
- */
-
-/*
- * Copyright (C) 2012-2013 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__NULL_FILE_SYSTEM_H_
-#define _NOUX__NULL_FILE_SYSTEM_H_
-
-/* Genode includes */
-#include
-#include
-
-/* Noux includes */
-#include
-#include "file_system.h"
-
-
-namespace Noux {
-
- class Null_file_system : public File_system
- {
- private:
-
- const char *_filename() { return "null"; }
-
- bool _is_root(const char *path)
- {
- return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
- }
-
- bool _is_null_file(const char *path)
- {
- return (strlen(path) == (strlen(_filename()) + 1)) &&
- (strcmp(&path[1], _filename()) == 0);
- }
-
- public:
-
- Null_file_system(Xml_node) { }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- Dataspace_capability dataspace(char const *path)
- {
- /* not supported */
- return Dataspace_capability();
- }
-
- void release(char const *path, Dataspace_capability ds_cap)
- {
- /* not supported */
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
-
- if (_is_root(path))
- st.mode = Sysio::STAT_MODE_DIRECTORY;
- else if (_is_null_file(path)) {
- st.mode = Sysio::STAT_MODE_CHARDEV;
- } else {
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- sysio->stat_out.st = st;
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path, off_t index)
- {
- if (_is_root(path)) {
- if (index == 0) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV;
- strncpy(sysio->dirent_out.entry.name,
- _filename(),
- sizeof(sysio->dirent_out.entry.name));
- } else {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- }
-
- return true;
- }
-
- return false;
- }
-
- size_t num_dirent(char const *path)
- {
- if (_is_root(path))
- return 1;
- else
- return 0;
- }
-
- bool is_directory(char const *path)
- {
- if (_is_root(path))
- return true;
-
- return false;
- }
-
- char const *leaf_path(char const *path)
- {
- return path;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- if (!_is_null_file(path)) {
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
- return new (env()->heap()) Vfs_handle(this, this, 0);
- }
-
- bool unlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool rename(Sysio *sysio, char const *from_path, char const *to_path)
- {
- /* not supported */
- return false;
- }
-
- bool mkdir(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- /***************************
- ** File_system interface **
- ***************************/
-
- static char const *name() { return "null"; }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *handle)
- {
- sysio->write_out.count = sysio->write_in.count;
-
- return true;
- }
-
- bool read(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- sysio->read_out.count = 0;
-
- return true;
- }
-
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
- };
-}
-
-#endif /* _NOUX__NULL_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/path.h b/ports/src/noux/path.h
index 96a04363e..fd3d1d4fb 100644
--- a/ports/src/noux/path.h
+++ b/ports/src/noux/path.h
@@ -15,11 +15,8 @@
#define _NOUX__PATH_H_
/* Genode includes */
-#include
+#include
-/* Noux includes */
-#include
-
-namespace Noux { typedef Path Absolute_path; }
+namespace Noux { using Vfs::Absolute_path; }
#endif /* _NOUX__PATH_H_ */
diff --git a/ports/src/noux/pipe_io_channel.h b/ports/src/noux/pipe_io_channel.h
index 8cb5e0206..95bbfeb45 100644
--- a/ports/src/noux/pipe_io_channel.h
+++ b/ports/src/noux/pipe_io_channel.h
@@ -229,12 +229,12 @@ namespace Noux {
_pipe->writer_close();
}
- bool check_unblock(bool rd, bool wr, bool ex) const
+ bool check_unblock(bool rd, bool wr, bool ex) const override
{
return wr && _pipe->any_space_avail_for_writing();
}
- bool write(Sysio *sysio, size_t &count)
+ bool write(Sysio *sysio, size_t &offset) override
{
/*
* If the write operation is larger than the space available in
@@ -246,18 +246,19 @@ namespace Noux {
*/
/* dimension the pipe write operation to the not yet written data */
- size_t curr_count = _pipe->write(sysio->write_in.chunk + count,
- sysio->write_in.count - count);
- count += curr_count;
+ size_t curr_count = _pipe->write(sysio->write_in.chunk + offset,
+ sysio->write_in.count - offset);
+ offset += curr_count;
return true;
}
- bool fstat(Sysio *sysio)
+ bool fstat(Sysio *sysio) override
{
sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV;
return true;
}
+
/**************************************
** Signal_dispatcher_base interface **
**************************************/
@@ -265,7 +266,7 @@ namespace Noux {
/**
* Called by Noux main loop on the occurrence of new STDIN input
*/
- void dispatch(unsigned)
+ void dispatch(unsigned) override
{
Io_channel::invoke_all_notifiers();
}
@@ -293,7 +294,7 @@ namespace Noux {
_pipe->reader_close();
}
- bool check_unblock(bool rd, bool wr, bool ex) const
+ bool check_unblock(bool rd, bool wr, bool ex) const override
{
/* unblock if the writer has already closed its pipe end */
if (_pipe->writer_is_gone())
@@ -302,7 +303,7 @@ namespace Noux {
return (rd && _pipe->data_avail_for_reading());
}
- bool read(Sysio *sysio)
+ bool read(Sysio *sysio) override
{
size_t const max_count =
min(sysio->read_in.count,
@@ -314,7 +315,7 @@ namespace Noux {
return true;
}
- bool fstat(Sysio *sysio)
+ bool fstat(Sysio *sysio) override
{
sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV;
return true;
@@ -327,7 +328,7 @@ namespace Noux {
/**
* Called by Noux main loop on the occurrence of new STDIN input
*/
- void dispatch(unsigned)
+ void dispatch(unsigned) override
{
Io_channel::invoke_all_notifiers();
}
diff --git a/ports/src/noux/random_file_system.h b/ports/src/noux/random_file_system.h
index c1a6067a8..e1956ee8d 100644
--- a/ports/src/noux/random_file_system.h
+++ b/ports/src/noux/random_file_system.h
@@ -21,7 +21,7 @@
/* Noux includes */
#include
-#include "file_system.h"
+#include
/*-
* Copyright (c) 2010, 2012
@@ -229,154 +229,19 @@ namespace Noux {
};
- class Random_file_system : public File_system
+ class Random_file_system : public Vfs::Single_file_system
{
private:
- Arc4random *_arc4random;
-
- const char *_filename() { return "urandom"; }
-
- bool _is_root(const char *path)
- {
- return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
- }
-
- bool _is_device_random_file(const char *path)
- {
- return (strlen(path) == (strlen(_filename()) + 1)) &&
- (strcmp(&path[1], _filename()) == 0);
- }
+ Arc4random _arc4random;
public:
- Random_file_system(Xml_node node)
- {
- void *bytes = 0;
- size_t nbytes = 0;
- _arc4random = new (env()->heap()) Arc4random(bytes, nbytes);
- }
-
- ~Random_file_system()
- {
- destroy(env()->heap(), _arc4random);
- }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- Dataspace_capability dataspace(char const *path)
- {
- /* not supported */
- return Dataspace_capability();
- }
-
- void release(char const *path, Dataspace_capability ds_cap)
- {
- /* not supported */
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
-
- if (_is_root(path))
- st.mode = Sysio::STAT_MODE_DIRECTORY;
- else if (_is_device_random_file(path)) {
- st.mode = Sysio::STAT_MODE_CHARDEV;
- } else {
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- sysio->stat_out.st = st;
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path, off_t index)
- {
- if (_is_root(path)) {
- if (index == 0) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV;
- strncpy(sysio->dirent_out.entry.name,
- _filename(),
- sizeof(sysio->dirent_out.entry.name));
- } else {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- }
-
- return true;
- }
-
- return false;
- }
-
- size_t num_dirent(char const *path)
- {
- if (_is_root(path))
- return 1;
- else
- return 0;
- }
-
- bool is_directory(char const *path)
- {
- if (_is_root(path))
- return true;
-
- return false;
- }
-
- char const *leaf_path(char const *path)
- {
- return path;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- if (!_is_device_random_file(path)) {
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
- return new (env()->heap()) Vfs_handle(this, this, 0);
- }
-
- bool unlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool rename(Sysio *sysio, char const *from_path, char const *to_path)
- {
- /* not supported */
- return false;
- }
-
- bool mkdir(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- /***************************
- ** File_system interface **
- ***************************/
+ Random_file_system(Xml_node config)
+ :
+ Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config),
+ _arc4random(0, 0)
+ { }
static char const *name() { return "random"; }
@@ -385,24 +250,26 @@ namespace Noux {
** File I/O service interface **
********************************/
- bool write(Sysio *sysio, Vfs_handle *handle)
+ Write_result write(Vfs::Vfs_handle *, char const *, size_t buf_size, size_t &out_count) override
{
- sysio->write_out.count = sysio->write_in.count;
+ out_count = buf_size;
- return true;
+ return WRITE_OK;
}
- bool read(Sysio *sysio, Vfs_handle *vfs_handle)
+ Read_result read(Vfs::Vfs_handle *vfs_handle, char *dst, size_t count,
+ size_t &out_count) override
{
- size_t nbytes = sysio->read_in.count;
+ _arc4random.get(dst, count);
+ out_count = count;
- _arc4random->get(sysio->read_out.chunk, nbytes);
- sysio->read_out.count = nbytes;
-
- return true;
+ return READ_OK;
}
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
+ Ftruncate_result ftruncate(Vfs::Vfs_handle *, size_t) override
+ {
+ return FTRUNCATE_OK;
+ }
};
}
diff --git a/ports/src/noux/stdio_file_system.h b/ports/src/noux/stdio_file_system.h
index 9f3c1302c..8bfe9dd9a 100644
--- a/ports/src/noux/stdio_file_system.h
+++ b/ports/src/noux/stdio_file_system.h
@@ -17,167 +17,30 @@
/* Genode includes */
#include
#include
+#include
/* Noux includes */
#include
-#include "file_system.h"
#include "terminal_connection.h"
namespace Noux {
- class Stdio_file_system : public File_system
+ class Stdio_file_system : public Vfs::Single_file_system
{
private:
- enum { FILENAME_MAX_LEN = 64 };
- char _filename[FILENAME_MAX_LEN];
-
Terminal::Session_client *_terminal;
bool _echo;
-
- bool _is_root(const char *path)
- {
- return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
- }
-
- bool _is_stdio_file(const char *path)
- {
- return (strlen(path) == (strlen(_filename) + 1)) &&
- (strcmp(&path[1], _filename) == 0);
- }
-
public:
- Stdio_file_system(Xml_node config,
- Terminal::Session_client *terminal = terminal())
+ Stdio_file_system(Xml_node config)
:
- _terminal(terminal),
+ Single_file_system(NODE_TYPE_CHAR_DEVICE, name(), config),
+ _terminal(terminal()),
_echo(true)
- {
- _filename[0] = '\0';
-
- try { config.attribute("name").value(_filename, sizeof(_filename)); }
- catch (...) { }
-
- }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- Dataspace_capability dataspace(char const *path)
- {
- /* not supported */
- return Dataspace_capability();
- }
-
- void release(char const *path, Dataspace_capability ds_cap)
- {
- /* not supported */
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
-
- if (_is_root(path))
- st.mode = Sysio::STAT_MODE_DIRECTORY;
- else if (_is_stdio_file(path)) {
- st.mode = Sysio::STAT_MODE_CHARDEV;
- } else {
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- sysio->stat_out.st = st;
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path, off_t index)
- {
- if (_is_root(path)) {
- if (index == 0) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV;
- strncpy(sysio->dirent_out.entry.name,
- _filename,
- sizeof(sysio->dirent_out.entry.name));
- } else {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- }
-
- return true;
- }
-
- return false;
- }
-
- size_t num_dirent(char const *path)
- {
- if (_is_root(path))
- return 1;
- else
- return 0;
- }
-
- bool is_directory(char const *path)
- {
- if (_is_root(path))
- return true;
-
- return false;
- }
-
- char const *leaf_path(char const *path)
- {
- return path;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- if (!_is_stdio_file(path)) {
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
- return new (env()->heap()) Vfs_handle(this, this, 0);
- }
-
- bool unlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool rename(Sysio *sysio, char const *from_path, char const *to_path)
- {
- /* not supported */
- return false;
- }
-
- bool mkdir(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- /***************************
- ** File_system interface **
- ***************************/
+ { }
static char const *name() { return "stdio"; }
@@ -186,55 +49,53 @@ namespace Noux {
** File I/O service interface **
********************************/
- bool write(Sysio *sysio, Vfs_handle *handle)
+ Write_result write(Vfs::Vfs_handle *, char const *buf, size_t buf_size,
+ size_t &out_count) override
{
- sysio->write_out.count = _terminal->write(sysio->write_in.chunk, sysio->write_in.count);
+ out_count = _terminal->write(buf, buf_size);
- return true;
+ return WRITE_OK;
}
- bool read(Sysio *sysio, Vfs_handle *vfs_handle)
+ Read_result read(Vfs::Vfs_handle *, char *dst, size_t count, size_t &out_count) override
{
- sysio->read_out.count = _terminal->read(sysio->read_out.chunk, sysio->read_in.count);
+ out_count = _terminal->read(dst, count);
if (_echo)
- _terminal->write(sysio->read_out.chunk, sysio->read_in.count);
+ _terminal->write(dst, count);
- return true;
+ return READ_OK;
}
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
-
- bool ioctl(Sysio *sysio, Vfs_handle *vfs_handle)
+ Ftruncate_result ftruncate(Vfs::Vfs_handle *, size_t) override
{
- switch (sysio->ioctl_in.request) {
+ return FTRUNCATE_OK;
+ }
- case Sysio::Ioctl_in::OP_TIOCSETAF:
+ Ioctl_result ioctl(Vfs::Vfs_handle *vfs_handle, Ioctl_opcode opcode,
+ Ioctl_arg arg, Ioctl_out &out) override
+ {
+ switch (opcode) {
+
+ case Vfs::File_io_service::IOCTL_OP_TIOCSETAF:
{
- if (sysio->ioctl_in.argp & (Sysio::Ioctl_in::VAL_ECHO)) {
- _echo = true;
- }
- else {
- _echo = false;
- }
-
- return true;
+ _echo = (arg & (Vfs::File_io_service::IOCTL_VAL_ECHO));
+ return IOCTL_OK;
}
- case Sysio::Ioctl_in::OP_TIOCSETAW:
+ case Vfs::File_io_service::IOCTL_OP_TIOCSETAW:
{
PDBG("OP_TIOCSETAW not implemented");
- return false;
+ return IOCTL_ERR_INVALID;
}
default:
- PDBG("invalid ioctl(request=0x%x), %d", sysio->ioctl_in.request,
- Sysio::Ioctl_in::OP_TIOCSETAW);
+ PDBG("invalid ioctl(request=0x%x)", opcode);
break;
}
- return false;
+ return IOCTL_ERR_INVALID;
}
};
}
diff --git a/ports/src/noux/tar_file_system.h b/ports/src/noux/tar_file_system.h
deleted file mode 100644
index 36f29e322..000000000
--- a/ports/src/noux/tar_file_system.h
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * \brief TAR file system
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2013 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__TAR_FILE_SYSTEM_H_
-#define _NOUX__TAR_FILE_SYSTEM_H_
-
-/* Genode includes */
-#include
-#include
-#include
-#include
-
-/* Noux includes */
-#include
-#include
-#include
-
-namespace Noux {
-
- class Tar_file_system : public File_system
- {
- enum { verbose = false };
-
- Lock _lock;
-
- struct Rom_name
- {
- enum { ROM_NAME_MAX_LEN = 64 };
- char name[ROM_NAME_MAX_LEN];
-
- Rom_name(Xml_node config) {
- config.attribute("name").value(name, sizeof(name));
- }
- } _rom_name;
-
- Rom_connection _rom;
-
- char *_tar_base;
- size_t _tar_size;
-
- class Record
- {
- private:
-
- char _name[100];
- char _mode[8];
- char _uid[8];
- char _gid[8];
- char _size[12];
- char _mtime[12];
- char _checksum[8];
- char _type[1];
- char _linked_name[100];
-
- /**
- * Convert ASCII-encoded octal number to unsigned value
- */
- template
- unsigned long _read(T const &field) const
- {
- /*
- * Copy-out ASCII string to temporary buffer that is
- * large enough to host an additional zero.
- */
- char buf[sizeof(field) + 1];
- strncpy(buf, field, sizeof(buf));
-
- unsigned long value = 0;
- ascii_to(buf, &value, 8);
- return value;
- }
-
- public:
-
- /* length of on data block in tar */
- enum { BLOCK_LEN = 512 };
-
- /* record type values */
- enum { TYPE_FILE = 0, TYPE_HARDLINK = 1,
- TYPE_SYMLINK = 2, TYPE_DIR = 5 };
-
- size_t size() const { return _read(_size); }
- unsigned uid() const { return _read(_uid); }
- unsigned gid() const { return _read(_gid); }
- unsigned mode() const { return _read(_mode); }
- unsigned type() const { return _read(_type); }
- char const *name() const { return _name; }
- char const *linked_name() const { return _linked_name; }
-
- void *data() const { return (char *)this + BLOCK_LEN; }
- };
-
-
- class Tar_vfs_handle : public Vfs_handle
- {
- private:
-
- Record const *_record;
-
- public:
-
- Tar_vfs_handle(File_system *fs, int status_flags, Record const *record)
- : Vfs_handle(fs, fs, status_flags), _record(record)
- { }
-
- Record const *record() const { return _record; }
- };
-
-
- /**
- * path element token
- */
-
- struct Scanner_policy_path_element
- {
- static bool identifier_char(char c, unsigned /* i */)
- {
- return (c != '/') && (c != 0);
- }
- };
-
-
- typedef Genode::Token Path_element_token;
-
-
- struct Node : List, List::Element
- {
- char const *name;
- Record const *record;
-
- Node(char const *name, Record const *record) : name(name), record(record) { }
-
- Node *lookup(char const *name)
- {
- Absolute_path lookup_path(name);
-
- if (verbose)
- PDBG("lookup_path = %s", lookup_path.base());
-
- Node *parent_node = this;
- Node *child_node;
-
- Path_element_token t(lookup_path.base());
-
- while (t) {
-
- if (t.type() != Path_element_token::IDENT) {
- t = t.next();
- continue;
- }
-
- char path_element[Sysio::MAX_PATH_LEN];
-
- t.string(path_element, sizeof(path_element));
-
- if (verbose)
- PDBG("path_element = %s", path_element);
-
- for (child_node = parent_node->first(); child_node; child_node = child_node->next()) {
- if (verbose)
- PDBG("comparing with node %s", child_node->name);
- if (strcmp(child_node->name, path_element) == 0) {
- if (verbose)
- PDBG("found matching child node");
- parent_node = child_node;
- break;
- }
- }
-
- if (!child_node)
- return 0;
-
- t = t.next();
- }
-
- return parent_node;
- }
-
-
- Node *lookup_child(int index)
- {
- for (Node *child_node = first(); child_node; child_node = child_node->next(), index--) {
- if (index == 0)
- return child_node;
- }
-
- return 0;
- }
-
-
- size_t num_dirent()
- {
- size_t count = 0;
- for (Node *child_node = first(); child_node; child_node = child_node->next(), count++) ;
- return count;
- }
-
- } _root_node;
-
-
- /*
- * Create a Node for a tar record and insert it into the node list
- */
- class Add_node_action
- {
- private:
-
- Node &_root_node;
-
- public:
-
- Add_node_action(Node &root_node) : _root_node(root_node) { }
-
- void operator()(Record const *record)
- {
- Absolute_path current_path(record->name());
-
- if (verbose)
- PDBG("current_path = %s", current_path.base());
-
- char path_element[Sysio::MAX_PATH_LEN];
-
- Path_element_token t(current_path.base());
-
- Node *parent_node = &_root_node;
- Node *child_node;
-
- while(t) {
-
- if (t.type() != Path_element_token::IDENT) {
- t = t.next();
- continue;
- }
-
- Absolute_path remaining_path(t.start());
-
- t.string(path_element, sizeof(path_element));
-
- for (child_node = parent_node->first(); child_node; child_node = child_node->next()) {
- if (strcmp(child_node->name, path_element) == 0)
- break;
- }
-
- if (child_node) {
-
- if (verbose)
- PDBG("found node for %s", path_element);
-
- if (remaining_path.has_single_element()) {
- /* Found a node for the record to be inserted.
- * This is usually a directory node without
- * record. */
- child_node->record = record;
- }
- } else {
- if (remaining_path.has_single_element()) {
-
- if (verbose)
- PDBG("creating node for %s", path_element);
-
- /*
- * TODO: find 'path_element' in 'record->name'
- * and use the location in the record as name
- * pointer to save some memory
- */
- size_t name_size = strlen(path_element) + 1;
- char *name = (char*)env()->heap()->alloc(name_size);
- strncpy(name, path_element, name_size);
- child_node = new (env()->heap()) Node(name, record);
- } else {
-
- if (verbose)
- PDBG("creating node without record for %s", path_element);
-
- /* create a directory node without record */
- size_t name_size = strlen(path_element) + 1;
- char *name = (char*)env()->heap()->alloc(name_size);
- strncpy(name, path_element, name_size);
- child_node = new (env()->heap()) Node(name, 0);
- }
- parent_node->insert(child_node);
- }
-
- parent_node = child_node;
- t = t.next();
- }
- }
- };
-
-
- template
- void _for_each_tar_record_do(Tar_record_action tar_record_action)
- {
- /* measure size of archive in blocks */
- unsigned block_id = 0, block_cnt = _tar_size/Record::BLOCK_LEN;
-
- /* scan metablocks of archive */
- while (block_id < block_cnt) {
-
- Record *record = (Record *)(_tar_base + block_id*Record::BLOCK_LEN);
-
- tar_record_action(record);
-
- size_t file_size = record->size();
-
- /* some datablocks */ /* one metablock */
- block_id = block_id + (file_size / Record::BLOCK_LEN) + 1;
-
- /* round up */
- if (file_size % Record::BLOCK_LEN != 0) block_id++;
-
- /* check for end of tar archive */
- if (block_id*Record::BLOCK_LEN >= _tar_size)
- break;
-
- /* lookout for empty eof-blocks */
- if (*(_tar_base + (block_id*Record::BLOCK_LEN)) == 0x00)
- if (*(_tar_base + (block_id*Record::BLOCK_LEN + 1)) == 0x00)
- break;
- }
- }
-
-
- struct Num_dirent_cache
- {
- Lock lock;
- Node &root_node;
- bool valid; /* true after first lookup */
- char key[256]; /* key used for lookup */
- size_t cached_num_dirent; /* cached value */
-
- Num_dirent_cache(Node &root_node)
- : root_node(root_node), 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) {
- Node *node = root_node.lookup(path);
- if (!node)
- return 0;
- strncpy(key, path, sizeof(key));
- cached_num_dirent = node->num_dirent();
- valid = true;
- }
- return cached_num_dirent;
- }
- } _cached_num_dirent;
-
-
- public:
-
- Tar_file_system(Xml_node config)
- :
- _rom_name(config), _rom(_rom_name.name),
- _tar_base(env()->rm_session()->attach(_rom.dataspace())),
- _tar_size(Dataspace_client(_rom.dataspace()).size()),
- _root_node("", 0),
- _cached_num_dirent(_root_node)
- {
- PINF("tar archive '%s' local at %p, size is %zd",
- _rom_name.name, _tar_base, _tar_size);
-
- _for_each_tar_record_do(Add_node_action(_root_node));
- }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- Dataspace_capability dataspace(char const *path)
- {
- /*
- * Walk hardlinks until we reach a file
- */
- Record const *record = 0;
- for (;;) {
- Node *node = _root_node.lookup(path);
-
- if (!node)
- return Dataspace_capability();
-
- record = node->record;
-
- if (record) {
- if (record->type() == Record::TYPE_HARDLINK) {
- path = record->linked_name();
- continue;
- }
-
- if (record->type() == Record::TYPE_FILE)
- break;
-
- PERR("TAR record \"%s\" has unsupported type %d",
- record->name(), record->type());
- }
-
- PERR("TAR record \"%s\" has unsupported type %d",
- path, Record::TYPE_DIR);
-
- return Dataspace_capability();
- }
-
- try {
- Ram_dataspace_capability ds_cap =
- env()->ram_session()->alloc(record->size());
-
- void *local_addr = env()->rm_session()->attach(ds_cap);
- memcpy(local_addr, record->data(), record->size());
- env()->rm_session()->detach(local_addr);
-
- return ds_cap;
- }
- catch (...) { PDBG("Could not create new dataspace"); }
-
- return Dataspace_capability();
- }
-
- void release(char const *, Dataspace_capability ds_cap)
- {
- env()->ram_session()->free(static_cap_cast(ds_cap));
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- if (verbose)
- PDBG("path = %s", path);
-
- Node const *node = 0;
- Record const *record = 0;
-
- /*
- * Walk hardlinks until we reach a file
- */
- for (;;) {
- node = _root_node.lookup(path);
-
- if (!node) {
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- record = node->record;
-
- if (record) {
- if (record->type() == Record::TYPE_HARDLINK) {
- path = record->linked_name();
- continue;
- } else
- break;
- } else {
- if (verbose)
- PDBG("found a virtual directoty node");
- memset(&sysio->stat_out.st, 0, sizeof(sysio->stat_out.st));
- sysio->stat_out.st.mode = Sysio::STAT_MODE_DIRECTORY;
- return true;
- }
- }
-
- /* convert TAR record modes to stat modes */
- unsigned mode = record->mode();
- switch (record->type()) {
- case Record::TYPE_FILE: mode |= Sysio::STAT_MODE_FILE; break;
- case Record::TYPE_SYMLINK: mode |= Sysio::STAT_MODE_SYMLINK; break;
- case Record::TYPE_DIR: mode |= Sysio::STAT_MODE_DIRECTORY; break;
-
- default:
- if (verbose)
- PDBG("unhandled record type %d", record->type());
- }
-
- memset(&sysio->stat_out.st, 0, sizeof(sysio->stat_out.st));
- sysio->stat_out.st.mode = mode;
- sysio->stat_out.st.size = record->size();
- sysio->stat_out.st.uid = record->uid();
- sysio->stat_out.st.gid = record->gid();
- sysio->stat_out.st.inode = (unsigned long)node;
-
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path, off_t index)
- {
- Lock::Guard guard(_lock);
-
- Node *node = _root_node.lookup(path);
-
- if (!node)
- return false;
-
- node = node->lookup_child(index);
-
- if (!node) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- return true;
- }
-
- sysio->dirent_out.entry.fileno = (unsigned long)node;
-
- Record const *record = node->record;
-
- if (record) {
- switch (record->type()) {
- case 0: sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_FILE; break;
- case 2: sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_SYMLINK; break;
- case 5: sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_DIRECTORY; break;
-
- default:
- if (verbose)
- PDBG("unhandled record type %d", record->type());
- }
- }
-
- strncpy(sysio->dirent_out.entry.name,
- node->name,
- sizeof(sysio->dirent_out.entry.name));
-
- return true;
- }
-
- bool unlink(Sysio *, char const *) { return false; }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- Node *node = _root_node.lookup(path);
- Record const *record = node ? node->record : 0;
-
- if (!record || (record->type() != Record::TYPE_SYMLINK)) {
- sysio->error.readlink = Sysio::READLINK_ERR_NO_ENTRY;
- return false;
- }
-
- size_t const count = min(sysio->readlink_in.bufsiz,
- min(sizeof(sysio->readlink_out.chunk),
- (size_t)100));
-
- memcpy(sysio->readlink_out.chunk, record->linked_name(), count);
-
- sysio->readlink_out.count = count;
-
- return true;
- }
-
- bool rename(Sysio *, char const *, char const *) { return false; }
-
- bool mkdir(Sysio *, char const *) { return false; }
-
- bool symlink(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)
- {
- Node *node = _root_node.lookup(path);
-
- if (!node)
- return false;
-
- Record const *record = node->record;
-
- return record ? (record->type() == Record::TYPE_DIR) : true;
- }
-
- 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.
- */
- Node *node = _root_node.lookup(path);
- return node ? path : 0;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- Lock::Guard guard(_lock);
-
- Node *node = _root_node.lookup(path);
- if (node)
- return new (env()->heap())
- Tar_vfs_handle(this, 0, node->record);
-
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
-
- /***************************
- ** File_system interface **
- ***************************/
-
- static char const *name() { return "tar"; }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *handle)
- {
- PDBG("called\n");
- return false;
- }
-
- bool read(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- Tar_vfs_handle const *handle = static_cast(vfs_handle);
-
- size_t const record_size = handle->record()->size();
-
- size_t const record_bytes_left = record_size >= handle->seek()
- ? record_size - handle->seek() : 0;
-
- size_t const count = min(record_bytes_left,
- min(sizeof(sysio->read_out.chunk),
- sysio->read_in.count));
-
- char const *data = (char *)handle->record()->data() + handle->seek();
-
- memcpy(sysio->read_out.chunk, data, count);
-
- sysio->read_out.count = count;
- return true;
- }
-
- bool ftruncate(Sysio *sysio, Vfs_handle *handle)
- {
- PDBG("called\n");
- return false;
- }
- };
-}
-
-#endif /* _NOUX__TAR_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/terminal_connection.h b/ports/src/noux/terminal_connection.h
index 2fecdfa2f..7b01104cc 100644
--- a/ports/src/noux/terminal_connection.h
+++ b/ports/src/noux/terminal_connection.h
@@ -22,13 +22,9 @@
/* Noux includes */
#include
-#include "file_system.h"
+#include
-namespace Noux {
-
- Terminal::Connection *terminal();
-
-}
+namespace Noux { Terminal::Connection *terminal(); }
#endif /* _NOUX__TERMINAL_CONNECTION_H_ */
diff --git a/ports/src/noux/terminal_file_system.h b/ports/src/noux/terminal_file_system.h
deleted file mode 100644
index d4e25baa9..000000000
--- a/ports/src/noux/terminal_file_system.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * \brief Terminal file system
- * \author Christian Prochaska
- * \date 2012-05-23
- */
-
-/*
- * Copyright (C) 2012-2013 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__TERMINAL_FILE_SYSTEM_H_
-#define _NOUX__TERMINAL_FILE_SYSTEM_H_
-
-/* Genode includes */
-#include
-#include
-#include
-#include
-
-/* Noux includes */
-#include
-#include "file_system.h"
-
-
-namespace Noux {
-
- class Terminal_file_system : public File_system
- {
- private:
-
- Terminal::Session_client _terminal;
-
- enum { FILENAME_MAX_LEN = 64 };
- char _filename[FILENAME_MAX_LEN];
-
- bool _is_root(const char *path)
- {
- return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
- }
-
- bool _is_terminal_file(const char *path)
- {
- return (strlen(path) == (strlen(_filename) + 1)) &&
- (strcmp(&path[1], _filename) == 0);
- }
-
- public:
-
- Terminal_file_system(Xml_node config)
- : _terminal(env()->parent()->session
- ("ram_quota=8192, label=\"noux(terminal_fs)\""))
- {
- _filename[0] = 0;
- try { config.attribute("name").value(_filename, sizeof(_filename)); }
- catch (...) { }
-
- /*
- * Wait for connection-established signal
- */
-
- /* create signal receiver, just for the single signal */
- Signal_context sig_ctx;
- Signal_receiver sig_rec;
- Signal_context_capability sig_cap = sig_rec.manage(&sig_ctx);
-
- /* register signal handler */
- _terminal.connected_sigh(sig_cap);
-
- /* wati for signal */
- sig_rec.wait_for_signal();
- sig_rec.dissolve(&sig_ctx);
- }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- Dataspace_capability dataspace(char const *path)
- {
- /* not supported */
- return Dataspace_capability();
- }
-
- void release(char const *path, Dataspace_capability ds_cap)
- {
- /* not supported */
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
-
- if (_is_root(path))
- st.mode = Sysio::STAT_MODE_DIRECTORY;
- else if (_is_terminal_file(path)) {
- st.mode = Sysio::STAT_MODE_CHARDEV;
- } else {
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- sysio->stat_out.st = st;
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path, off_t index)
- {
- if (_is_root(path)) {
- if (index == 0) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV;
- strncpy(sysio->dirent_out.entry.name,
- _filename,
- sizeof(sysio->dirent_out.entry.name));
- } else {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- }
-
- return true;
- }
-
- return false;
- }
-
- size_t num_dirent(char const *path)
- {
- if (_is_root(path))
- return 1;
- else
- return 0;
- }
-
- bool is_directory(char const *path)
- {
- if (_is_root(path))
- return true;
-
- return false;
- }
-
- char const *leaf_path(char const *path)
- {
- return path;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- if (!_is_terminal_file(path)) {
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
- return new (env()->heap()) Vfs_handle(this, this, 0);
- }
-
- bool unlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool rename(Sysio *sysio, char const *from_path, char const *to_path)
- {
- /* not supported */
- return false;
- }
-
- bool mkdir(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- /***************************
- ** File_system interface **
- ***************************/
-
- static char const *name() { return "terminal"; }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *handle)
- {
- sysio->write_out.count = _terminal.write(sysio->write_in.chunk, sysio->write_in.count);
- return true;
- }
-
- bool read(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- sysio->read_out.count = _terminal.read(sysio->read_out.chunk, sysio->read_in.count);
- return true;
- }
-
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
-
- bool check_unblock(Vfs_handle *vfs_handle, bool rd, bool wr, bool ex)
- {
- if (rd && (_terminal.avail() > 0))
- return true;
-
- if (wr)
- return true;
-
- return false;
- }
-
- void register_read_ready_sigh(Vfs_handle *vfs_handle,
- Signal_context_capability sigh)
- {
- _terminal.read_avail_sigh(sigh);
- }
- };
-}
-
-#endif /* _NOUX__TERMINAL_FILE_SYSTEM_H_ */
diff --git a/ports/src/noux/terminal_io_channel.h b/ports/src/noux/terminal_io_channel.h
index 8f3df1e33..7d32cdd8f 100644
--- a/ports/src/noux/terminal_io_channel.h
+++ b/ports/src/noux/terminal_io_channel.h
@@ -58,14 +58,20 @@ namespace Noux {
~Terminal_io_channel() { sig_rec.dissolve(this); }
- bool write(Sysio *sysio, size_t &count)
+ bool write(Sysio *sysio, size_t &offset) override
{
- terminal.write(sysio->write_in.chunk, sysio->write_in.count);
- count = sysio->write_in.count;
+ size_t const count = min(sysio->write_in.count,
+ sizeof(sysio->write_in.chunk));
+
+ terminal.write(sysio->write_in.chunk, count);
+
+ sysio->write_out.count = count;
+ offset = count;
+
return true;
}
- bool read(Sysio *sysio)
+ bool read(Sysio *sysio) override
{
if (type != STDIN) {
PERR("attempt to read from terminal output channel");
@@ -114,7 +120,7 @@ namespace Noux {
return true;
}
- bool fcntl(Sysio *sysio)
+ bool fcntl(Sysio *sysio) override
{
/**
* Actually it is "inappropiate" to use fcntl() directly on terminals
@@ -136,7 +142,7 @@ namespace Noux {
return false;
}
- bool fstat(Sysio *sysio)
+ bool fstat(Sysio *sysio) override
{
/*
* Supply stat values such that libc is happy. I.e., the libc
@@ -147,7 +153,7 @@ namespace Noux {
return true;
}
- bool check_unblock(bool rd, bool wr, bool ex) const
+ bool check_unblock(bool rd, bool wr, bool ex) const override
{
/* never block for writing */
if (wr) return true;
@@ -159,11 +165,11 @@ namespace Noux {
return (rd && (type == STDIN) && !read_buffer.empty());
}
- bool ioctl(Sysio *sysio)
+ bool ioctl(Sysio *sysio) override
{
switch (sysio->ioctl_in.request) {
- case Sysio::Ioctl_in::OP_TIOCGWINSZ:
+ case Vfs::File_io_service::IOCTL_OP_TIOCGWINSZ:
{
Terminal::Session::Size size = terminal.size();
sysio->ioctl_out.tiocgwinsz.rows = size.lines();
@@ -171,13 +177,13 @@ namespace Noux {
return true;
}
- case Sysio::Ioctl_in::OP_TIOCSETAF:
+ case Vfs::File_io_service::IOCTL_OP_TIOCSETAF:
{
PDBG("OP_TIOCSETAF not implemented");
return false;
}
- case Sysio::Ioctl_in::OP_TIOCSETAW:
+ case Vfs::File_io_service::IOCTL_OP_TIOCSETAW:
{
PDBG("OP_TIOCSETAW not implemented");
return false;
@@ -198,7 +204,7 @@ namespace Noux {
/**
* Called by Noux main loop on the occurrence of new STDIN input
*/
- void dispatch(unsigned)
+ void dispatch(unsigned) override
{
while ((read_buffer.avail_capacity() > 0) &&
terminal.avail()) {
diff --git a/ports/src/noux/vfs_handle.h b/ports/src/noux/vfs_handle.h
deleted file mode 100644
index c69dddf29..000000000
--- a/ports/src/noux/vfs_handle.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * \brief Representation of an open file
- * \author Norman Feske
- * \date 2011-02-17
- */
-
-/*
- * Copyright (C) 2011-2013 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_HANDLE_H_
-#define _NOUX__VFS_HANDLE_H_
-
-/* Genode includes */
-#include
-
-/* Noux includes */
-#include
-#include
-
-namespace Noux {
-
- class Sysio;
-
- class Vfs_io_channel;
-
- class Vfs_handle
- {
- private:
-
- Directory_service *_ds;
- File_io_service *_fs;
- int _status_flags;
- size_t _seek;
-
- friend class Vfs_io_channel; /* for modifying '_seek' */
-
- static Directory_service *_pseudo_directory_service()
- {
- struct Pseudo_directory_service : public Directory_service
- {
- static bool _msg(char const *sc) {
- PERR("%s not supported by directory service", sc); return false; }
-
- Dataspace_capability dataspace(char const *)
- {
- _msg("dataspace");
- return 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; }
- bool dirent(Sysio *, char const *, off_t) { return _msg("dirent"); }
- bool unlink(Sysio *, char const *) { return _msg("unlink"); }
- bool readlink(Sysio *, char const *) { return _msg("readlink"); }
- bool rename(Sysio *, char const *, char const *) { return _msg("rename"); }
- bool mkdir(Sysio *, char const *) { return _msg("mkdir"); }
- bool symlink(Sysio *, char const *) { return _msg("symlink"); }
- 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;
- }
-
- static File_io_service *_pseudo_file_io_service()
- {
- struct Pseudo_file_io_service : public File_io_service
- {
- static bool _msg(char const *sc) {
- PERR("%s not supported by file system", sc); return false; }
-
- bool write(Sysio *sysio, Vfs_handle *handle) { return _msg("write"); }
- bool read(Sysio *sysio, Vfs_handle *handle) { return _msg("read"); }
- bool ftruncate(Sysio *sysio, Vfs_handle *handle) { return _msg("ftruncate"); }
- bool ioctl(Sysio *sysio, Vfs_handle *handle) { return _msg("ioctl"); }
- };
- static Pseudo_file_io_service fs;
- return &fs;
- }
-
- public:
-
- enum { STATUS_RDONLY = 0, STATUS_WRONLY = 1, STATUS_RDWR = 2 };
-
- Vfs_handle(Directory_service *ds, File_io_service *fs, int status_flags)
- :
- _ds(ds ? ds : _pseudo_directory_service()),
- _fs(fs ? fs : _pseudo_file_io_service()),
- _status_flags(status_flags),
- _seek(0)
- { }
-
- virtual ~Vfs_handle() { }
-
- Directory_service *ds() { return _ds; }
- File_io_service *fs() { return _fs; }
-
- int status_flags() { return _status_flags; }
-
- size_t seek() const { return _seek; }
- };
-}
-
-#endif /* _NOUX__VFS_HANDLE_H_ */
diff --git a/ports/src/noux/vfs_io_channel.h b/ports/src/noux/vfs_io_channel.h
index 1e09e9730..870dd04ec 100644
--- a/ports/src/noux/vfs_io_channel.h
+++ b/ports/src/noux/vfs_io_channel.h
@@ -16,14 +16,13 @@
/* Noux includes */
#include
-#include
-#include
+#include
namespace Noux {
struct Vfs_io_channel : Io_channel, Signal_dispatcher_base
{
- Vfs_handle *_fh;
+ Vfs::Vfs_handle *_fh;
Absolute_path _path;
Absolute_path _leaf_path;
@@ -31,12 +30,12 @@ namespace Noux {
Signal_receiver &_sig_rec;
Vfs_io_channel(char const *path, char const *leaf_path,
- Dir_file_system *root_dir, Vfs_handle *vfs_handle,
+ Vfs::Dir_file_system *root_dir, Vfs::Vfs_handle *vfs_handle,
Signal_receiver &sig_rec)
: _fh(vfs_handle), _path(path), _leaf_path(leaf_path),
_sig_rec(sig_rec)
{
- _fh->fs()->register_read_ready_sigh(_fh, _sig_rec.manage(this));
+ _fh->fs().register_read_ready_sigh(_fh, _sig_rec.manage(this));
}
~Vfs_io_channel()
@@ -45,42 +44,63 @@ namespace Noux {
destroy(env()->heap(), _fh);
}
- bool write(Sysio *sysio, size_t &count)
+ bool write(Sysio *sysio, size_t &offset) override
{
- if (!_fh->fs()->write(sysio, _fh))
- return false;
+ size_t out_count = 0;
+
+ sysio->error.write = _fh->fs().write(_fh, sysio->write_in.chunk,
+ sysio->write_in.count, out_count);
+ if (sysio->error.write != Vfs::File_io_service::WRITE_OK)
+ return false;
+
+ _fh->advance_seek(out_count);
+
+ sysio->write_out.count = out_count;
+ offset = out_count;
- count = sysio->write_out.count;
- _fh->_seek += count;
return true;
}
- bool read(Sysio *sysio)
+ bool read(Sysio *sysio) override
{
- if (!_fh->fs()->read(sysio, _fh))
+ size_t count = min(sysio->read_in.count, sizeof(sysio->read_out.chunk));
+
+ size_t out_count = 0;
+
+ sysio->error.read = _fh->fs().read(_fh, sysio->read_out.chunk, count, out_count);
+
+ if (sysio->error.read != Vfs::File_io_service::READ_OK)
return false;
- _fh->_seek += sysio->read_out.count;
+ sysio->read_out.count = out_count;
+
+ _fh->advance_seek(out_count);
+
return true;
}
- bool fstat(Sysio *sysio)
+ bool fstat(Sysio *sysio) override
{
/*
- * 'sysio.stat_in' is not used in '_fh->ds()->stat()',
+ * 'sysio.stat_in' is not used in '_fh->ds().stat()',
* so no 'sysio' member translation is needed here
*/
- bool result = _fh->ds()->stat(sysio, _leaf_path.base());
- sysio->fstat_out.st = sysio->stat_out.st;
- return result;
+ sysio->error.stat = _fh->ds().stat(_leaf_path.base(),
+ sysio->fstat_out.st);
+
+ return (sysio->error.stat == Vfs::Directory_service::STAT_OK);
+
}
- bool ftruncate(Sysio *sysio)
+ bool ftruncate(Sysio *sysio) override
{
- return _fh->fs()->ftruncate(sysio, _fh);
+
+ sysio->error.ftruncate = _fh->fs().ftruncate(_fh, sysio->ftruncate_in.length);
+
+ return (sysio->error.ftruncate == Vfs::File_io_service::FTRUNCATE_OK);
}
- bool fcntl(Sysio *sysio)
+ bool fcntl(Sysio *sysio) override
{
switch (sysio->fcntl_in.cmd) {
@@ -103,20 +123,20 @@ namespace Noux {
* to directories). Hence, '_path' is the absolute path of the
* directory to inspect.
*/
- bool dirent(Sysio *sysio)
+ bool dirent(Sysio *sysio) override
{
/*
* Return artificial dir entries for "." and ".."
*/
unsigned const index = _fh->seek() / sizeof(Sysio::Dirent);
if (index < 2) {
- sysio->dirent_out.entry.type = Sysio::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));
sysio->dirent_out.entry.fileno = 1;
- _fh->_seek += sizeof(Sysio::Dirent);
+ _fh->advance_seek(sizeof(Sysio::Dirent));
return true;
}
@@ -125,10 +145,11 @@ namespace Noux {
* Align index range to zero when calling the directory service.
*/
- if (!_fh->ds()->dirent(sysio, _path.base(), index - 2))
+ if (!_fh->ds().dirent(_path.base(), index - 2,
+ sysio->dirent_out.entry))
return false;
- _fh->_seek += sizeof(Sysio::Dirent);
+ _fh->advance_seek(sizeof(Sysio::Dirent));
return true;
}
@@ -147,32 +168,36 @@ namespace Noux {
return 0;
}
- bool ioctl(Sysio *sysio)
+ bool ioctl(Sysio *sysio) override
{
- return _fh->fs()->ioctl(sysio, _fh);
+ Vfs::File_system::Ioctl_arg arg = (Vfs::File_system::Ioctl_arg)sysio->ioctl_in.argp;
+
+ sysio->error.ioctl = _fh->fs().ioctl(_fh, sysio->ioctl_in.request, arg, sysio->ioctl_out);
+
+ return (sysio->error.ioctl == Vfs::File_io_service::IOCTL_OK);
}
- bool lseek(Sysio *sysio)
+ bool lseek(Sysio *sysio) override
{
switch (sysio->lseek_in.whence) {
- case Sysio::LSEEK_SET: _fh->_seek = sysio->lseek_in.offset; break;
- case Sysio::LSEEK_CUR: _fh->_seek += sysio->lseek_in.offset; break;
+ case Sysio::LSEEK_SET: _fh->seek(sysio->lseek_in.offset); break;
+ case Sysio::LSEEK_CUR: _fh->advance_seek(sysio->lseek_in.offset); break;
case Sysio::LSEEK_END:
off_t offset = sysio->lseek_in.offset;
sysio->fstat_in.fd = sysio->lseek_in.fd;
- _fh->_seek = size(sysio) + offset;
+ _fh->seek(size(sysio) + offset);
break;
}
- sysio->lseek_out.offset = _fh->_seek;
+ sysio->lseek_out.offset = _fh->seek();
return true;
}
- bool check_unblock(bool rd, bool wr, bool ex) const
+ bool check_unblock(bool rd, bool wr, bool ex) const override
{
- return _fh->fs()->check_unblock(_fh, rd, wr, ex);
+ return _fh->fs().check_unblock(_fh, rd, wr, ex);
}
- bool path(char *path, size_t len)
+ bool path(char *path, size_t len) override
{
strncpy(path, _path.base(), len);
path[len - 1] = '\0';
@@ -180,6 +205,7 @@ namespace Noux {
return true;
}
+
/**************************************
** Signal_dispatcher_base interface **
**************************************/
@@ -187,7 +213,7 @@ namespace Noux {
/**
* Called by Noux main loop on the occurrence of new input
*/
- void dispatch(unsigned)
+ void dispatch(unsigned) override
{
Io_channel::invoke_all_notifiers();
}
diff --git a/ports/src/noux/zero_file_system.h b/ports/src/noux/zero_file_system.h
deleted file mode 100644
index c5ab0eb4c..000000000
--- a/ports/src/noux/zero_file_system.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * \brief zero filesystem
- * \author Josef Soentgen
- * \date 2012-07-31
- */
-
-/*
- * Copyright (C) 2012-2013 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__ZERO_FILE_SYSTEM_H_
-#define _NOUX__ZERO_FILE_SYSTEM_H_
-
-/* Genode includes */
-#include
-#include
-
-/* Noux includes */
-#include
-#include "file_system.h"
-
-
-namespace Noux {
-
- class Zero_file_system : public File_system
- {
- private:
-
- const char *_filename() { return "zero"; }
-
- bool _is_root(const char *path)
- {
- return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
- }
-
- bool _is_device_zero_file(const char *path)
- {
- return (strlen(path) == (strlen(_filename()) + 1)) &&
- (strcmp(&path[1], _filename()) == 0);
- }
-
- public:
-
- Zero_file_system(Xml_node) { }
-
-
- /*********************************
- ** Directory-service interface **
- *********************************/
-
- Dataspace_capability dataspace(char const *path)
- {
- /* not supported */
- return Dataspace_capability();
- }
-
- void release(char const *path, Dataspace_capability ds_cap)
- {
- /* not supported */
- }
-
- bool stat(Sysio *sysio, char const *path)
- {
- Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
-
- if (_is_root(path))
- st.mode = Sysio::STAT_MODE_DIRECTORY;
- else if (_is_device_zero_file(path)) {
- st.mode = Sysio::STAT_MODE_CHARDEV;
- } else {
- sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
- return false;
- }
-
- sysio->stat_out.st = st;
- return true;
- }
-
- bool dirent(Sysio *sysio, char const *path, off_t index)
- {
- if (_is_root(path)) {
- if (index == 0) {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV;
- strncpy(sysio->dirent_out.entry.name,
- _filename(),
- sizeof(sysio->dirent_out.entry.name));
- } else {
- sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
- }
-
- return true;
- }
-
- return false;
- }
-
- size_t num_dirent(char const *path)
- {
- if (_is_root(path))
- return 1;
- else
- return 0;
- }
-
- bool is_directory(char const *path)
- {
- if (_is_root(path))
- return true;
-
- return false;
- }
-
- char const *leaf_path(char const *path)
- {
- return path;
- }
-
- Vfs_handle *open(Sysio *sysio, char const *path)
- {
- if (!_is_device_zero_file(path)) {
- sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
- return 0;
- }
-
- return new (env()->heap()) Vfs_handle(this, this, 0);
- }
-
- bool unlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool readlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool rename(Sysio *sysio, char const *from_path, char const *to_path)
- {
- /* not supported */
- return false;
- }
-
- bool mkdir(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- bool symlink(Sysio *sysio, char const *path)
- {
- /* not supported */
- return false;
- }
-
- /***************************
- ** File_system interface **
- ***************************/
-
- static char const *name() { return "zero"; }
-
-
- /********************************
- ** File I/O service interface **
- ********************************/
-
- bool write(Sysio *sysio, Vfs_handle *handle)
- {
- sysio->write_out.count = sysio->write_in.count;
-
- return true;
- }
-
- bool read(Sysio *sysio, Vfs_handle *vfs_handle)
- {
- size_t nbytes = sysio->read_in.count;
-
- memset(sysio->read_out.chunk, 0, nbytes);
-
- sysio->read_out.count = nbytes;
-
- return true;
- }
-
- bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return false; }
- };
-}
-
-#endif /* _NOUX__ZERO_FILE_SYSTEM_H_ */