From c3c6a82d13af1d85237fe488ea1d0e09252cdfc4 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 7 Apr 2014 16:15:40 +0200 Subject: [PATCH] Move VFS from noux to 'os/include/vfs' By separating the VFS from Noux, we become able to reuse the VFS for libc-using programs. The most substantial change is the removal of Noux::Sysio data structures from the VFS. Instead, the Noux::Sysio refers to the VFS types now. The new VFS library is located at 'os/include/vfs/'. Furthermore, the patch removes various code duplications related to pseudo file systems that provide a single file (block, zero, random, terminal, null). The new 'Single_file_system' holds the common boilerplate code for those. Issue #999 --- os/include/vfs/block_file_system.h | 328 +++++++++++++ os/include/vfs/dir_file_system.h | 540 ++++++++++++++++++++ os/include/vfs/directory_service.h | 179 +++++++ os/include/vfs/file_io_service.h | 123 +++++ os/include/vfs/file_system.h | 42 ++ os/include/vfs/file_system_factory.h | 27 + os/include/vfs/fs_file_system.h | 628 ++++++++++++++++++++++++ os/include/vfs/null_file_system.h | 57 +++ os/include/vfs/single_file_system.h | 174 +++++++ os/include/vfs/tar_file_system.h | 638 ++++++++++++++++++++++++ os/include/vfs/terminal_file_system.h | 105 ++++ os/include/vfs/types.h | 54 ++ os/include/vfs/vfs_handle.h | 64 +++ os/include/vfs/zero_file_system.h | 53 ++ ports/include/noux_session/sysio.h | 142 ++---- ports/src/lib/libc_noux/plugin.cc | 126 ++--- ports/src/noux/block_file_system.h | 465 ------------------ ports/src/noux/child.h | 42 +- ports/src/noux/dir_file_system.h | 640 ------------------------ ports/src/noux/directory_service.h | 57 --- ports/src/noux/file_io_service.h | 54 -- ports/src/noux/file_system.h | 50 -- ports/src/noux/file_system_registry.h | 55 --- ports/src/noux/fs_file_system.h | 647 ------------------------ ports/src/noux/io_channel.h | 17 +- ports/src/noux/main.cc | 158 ++++-- ports/src/noux/net/socket_io_channel.h | 14 +- ports/src/noux/null_file_system.h | 190 -------- ports/src/noux/path.h | 7 +- ports/src/noux/pipe_io_channel.h | 23 +- ports/src/noux/random_file_system.h | 173 +------ ports/src/noux/stdio_file_system.h | 197 ++------ ports/src/noux/tar_file_system.h | 651 ------------------------- ports/src/noux/terminal_connection.h | 8 +- ports/src/noux/terminal_file_system.h | 233 --------- ports/src/noux/terminal_io_channel.h | 30 +- ports/src/noux/vfs_handle.h | 111 ----- ports/src/noux/vfs_io_channel.h | 100 ++-- ports/src/noux/zero_file_system.h | 194 -------- 39 files changed, 3406 insertions(+), 3990 deletions(-) create mode 100644 os/include/vfs/block_file_system.h create mode 100644 os/include/vfs/dir_file_system.h create mode 100644 os/include/vfs/directory_service.h create mode 100644 os/include/vfs/file_io_service.h create mode 100644 os/include/vfs/file_system.h create mode 100644 os/include/vfs/file_system_factory.h create mode 100644 os/include/vfs/fs_file_system.h create mode 100644 os/include/vfs/null_file_system.h create mode 100644 os/include/vfs/single_file_system.h create mode 100644 os/include/vfs/tar_file_system.h create mode 100644 os/include/vfs/terminal_file_system.h create mode 100644 os/include/vfs/types.h create mode 100644 os/include/vfs/vfs_handle.h create mode 100644 os/include/vfs/zero_file_system.h delete mode 100644 ports/src/noux/block_file_system.h delete mode 100644 ports/src/noux/dir_file_system.h delete mode 100644 ports/src/noux/directory_service.h delete mode 100644 ports/src/noux/file_io_service.h delete mode 100644 ports/src/noux/file_system.h delete mode 100644 ports/src/noux/file_system_registry.h delete mode 100644 ports/src/noux/fs_file_system.h delete mode 100644 ports/src/noux/null_file_system.h delete mode 100644 ports/src/noux/tar_file_system.h delete mode 100644 ports/src/noux/terminal_file_system.h delete mode 100644 ports/src/noux/vfs_handle.h delete mode 100644 ports/src/noux/zero_file_system.h 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_ */