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
This commit is contained in:
Norman Feske 2014-04-07 16:15:40 +02:00 committed by Christian Helmuth
parent d7d62c53a6
commit c3c6a82d13
39 changed files with 3406 additions and 3990 deletions

View File

@ -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 <base/allocator_avl.h>
#include <block_session/connection.h>
#include <vfs/single_file_system.h>
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_ */

View File

@ -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 <vfs/file_system_factory.h>
#include <vfs/vfs_handle.h>
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 <typename RES, typename FN>
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 <dir> 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_ */

View File

@ -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 <vfs/types.h>
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_ */

View File

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

View File

@ -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 <vfs/directory_service.h>
#include <vfs/file_io_service.h>
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_ */

View File

@ -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 <vfs/file_system.h>
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_ */

View File

@ -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 <base/allocator_avl.h>
#include <file_system_session/connection.h>
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<Fs_file_system &>(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<Genode::Ram_dataspace>(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<Fs_vfs_handle *>(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<Fs_vfs_handle *>(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<Fs_vfs_handle *>(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_ */

View File

@ -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 <vfs/single_file_system.h>
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_ */

View File

@ -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 <vfs/file_system.h>
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_ */

View File

@ -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 <rom_session/connection.h>
#include <vfs/file_system.h>
#include <vfs/vfs_handle.h>
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 <typename T>
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<Scanner_policy_path_element> Path_element_token;
struct Node : List<Node>, List<Node>::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 <typename Tar_record_action>
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<Genode::Ram_dataspace>(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<Tar_vfs_handle *>(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_ */

View File

@ -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 <terminal_session/connection.h>
#include <vfs/single_file_system.h>
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_ */

54
os/include/vfs/types.h Normal file
View File

@ -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 <util/list.h>
#include <util/misc_math.h>
#include <util/xml_node.h>
#include <util/string.h>
#include <base/lock.h>
#include <base/env.h>
#include <base/signal.h>
#include <base/printf.h>
#include <dataspace/client.h>
#include <os/path.h>
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<MAX_PATH_LEN> Absolute_path;
}
#endif /* _INCLUDE__VFS__TYPES_H_ */

View File

@ -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 <vfs/file_io_service.h>
#include <vfs/directory_service.h>
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_ */

View File

@ -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 <vfs/file_system.h>
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_ */

View File

@ -21,6 +21,7 @@
/* Genode includes */
#include <os/ring_buffer.h>
#include <util/misc_math.h>
#include <vfs/file_system.h>
#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; }, { });

View File

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

View File

@ -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 <base/allocator_avl.h>
#include <base/printf.h>
#include <base/lock.h>
#include <base/stdint.h>
#include <block_session/connection.h>
#include <util/string.h>
/* Noux includes */
#include <noux_session/sysio.h>
#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_ */

View File

@ -22,7 +22,7 @@
/* Noux includes */
#include <file_descriptor_registry.h>
#include <dir_file_system.h>
#include <vfs/dir_file_system.h>
#include <noux_session/capability.h>
#include <args.h>
#include <environment.h>
@ -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(&notifier);
}
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<Child>(destruct_alloc),

View File

@ -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 <base/printf.h>
#include <base/lock.h>
/* Noux includes */
#include <noux_session/sysio.h>
#include <file_system_registry.h>
#include <vfs_handle.h>
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 <dir> 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_ */

View File

@ -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 <dataspace/capability.h>
/* Noux includes */
#include <noux_session/sysio.h>
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_ */

View File

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

View File

@ -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 <util/list.h>
#include <util/string.h>
#include <util/xml_node.h>
/* Noux includes */
#include <directory_service.h>
#include <file_io_service.h>
#include <path.h>
#include <noux_session/sysio.h>
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_ */

View File

@ -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 <file_system.h>
namespace Noux {
class File_system_registry
{
public:
struct Entry : List<Entry>::Element
{
virtual File_system *create(Xml_node node) = 0;
virtual bool matches(Xml_node node) = 0;
};
private:
List<Entry> _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_ */

View File

@ -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 <base/allocator_avl.h>
#include <base/env.h>
/* Noux includes */
#include <noux_session/sysio.h>
#include <file_system_session/connection.h>
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<Fs_file_system *>(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<Ram_dataspace>(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<Fs_vfs_handle *>(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<Fs_vfs_handle *>(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<Fs_vfs_handle *>(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_ */

View File

@ -19,6 +19,7 @@
/* Genode includes */
#include <base/lock.h>
#include <vfs/file_system.h>
/* Noux includes */
#include <noux_session/sysio.h>
@ -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

View File

@ -25,22 +25,21 @@
#include <terminal_io_channel.h>
#include <dummy_input_io_channel.h>
#include <pipe_io_channel.h>
#include <dir_file_system.h>
#include <user_info.h>
#include <io_receptor_registry.h>
#include <destruct_queue.h>
#include <kill_broadcaster.h>
#include <file_system_registry.h>
#include <vfs/dir_file_system.h>
/* supported file systems */
#include <tar_file_system.h>
#include <fs_file_system.h>
#include <terminal_file_system.h>
#include <null_file_system.h>
#include <zero_file_system.h>
#include <stdio_file_system.h>
#include <vfs/tar_file_system.h>
#include <vfs/fs_file_system.h>
#include <vfs/terminal_file_system.h>
#include <vfs/null_file_system.h>
#include <vfs/zero_file_system.h>
#include <vfs/block_file_system.h>
#include <random_file_system.h>
#include <block_file_system.h>
#include <stdio_file_system.h>
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_channel> 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<Io_channel>
@ -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 <typename FILE_SYSTEM>
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<Entry_base>::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 <typename FILE_SYSTEM>
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<Entry_base> _list;
public:
template <typename FS>
void add_fs_type()
{
_list.insert(new Entry<FS>(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<Tar_file_system>());
fs_registry.insert(*new File_system_factory<Fs_file_system>());
fs_registry.insert(*new File_system_factory<Terminal_file_system>());
fs_registry.insert(*new File_system_factory<Null_file_system>());
fs_registry.insert(*new File_system_factory<Zero_file_system>());
fs_registry.insert(*new File_system_factory<Stdio_file_system>());
fs_registry.insert(*new File_system_factory<Random_file_system>());
fs_registry.insert(*new File_system_factory<Block_file_system>());
static File_system_factory fs_factory;
fs_factory.add_fs_type<Vfs::Tar_file_system>();
fs_factory.add_fs_type<Vfs::Fs_file_system>();
fs_factory.add_fs_type<Vfs::Terminal_file_system>();
fs_factory.add_fs_type<Vfs::Null_file_system>();
fs_factory.add_fs_type<Vfs::Zero_file_system>();
fs_factory.add_fs_type<Vfs::Block_file_system>();
fs_factory.add_fs_type<Stdio_file_system>();
fs_factory.add_fs_type<Random_file_system>();
/* 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 {

View File

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

View File

@ -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 <base/printf.h>
#include <util/string.h>
/* Noux includes */
#include <noux_session/sysio.h>
#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_ */

View File

@ -15,11 +15,8 @@
#define _NOUX__PATH_H_
/* Genode includes */
#include <os/path.h>
#include <vfs/types.h>
/* Noux includes */
#include <noux_session/sysio.h>
namespace Noux { typedef Path<Sysio::MAX_PATH_LEN> Absolute_path; }
namespace Noux { using Vfs::Absolute_path; }
#endif /* _NOUX__PATH_H_ */

View File

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

View File

@ -21,7 +21,7 @@
/* Noux includes */
#include <noux_session/sysio.h>
#include "file_system.h"
#include <vfs/single_file_system.h>
/*-
* 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;
}
};
}

View File

@ -17,167 +17,30 @@
/* Genode includes */
#include <base/printf.h>
#include <util/string.h>
#include <vfs/single_file_system.h>
/* Noux includes */
#include <noux_session/sysio.h>
#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;
}
};
}

View File

@ -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 <base/printf.h>
#include <base/lock.h>
#include <rom_session/connection.h>
#include <dataspace/client.h>
/* Noux includes */
#include <noux_session/sysio.h>
#include <file_system.h>
#include <vfs_handle.h>
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 <typename T>
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<Scanner_policy_path_element> Path_element_token;
struct Node : List<Node>, List<Node>::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 <typename Tar_record_action>
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<Ram_dataspace>(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<Tar_vfs_handle *>(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_ */

View File

@ -22,13 +22,9 @@
/* Noux includes */
#include <noux_session/sysio.h>
#include "file_system.h"
#include <vfs/file_system.h>
namespace Noux {
Terminal::Connection *terminal();
}
namespace Noux { Terminal::Connection *terminal(); }
#endif /* _NOUX__TERMINAL_CONNECTION_H_ */

View File

@ -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 <base/printf.h>
#include <base/lock.h>
#include <terminal_session/connection.h>
#include <util/string.h>
/* Noux includes */
#include <noux_session/sysio.h>
#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<Terminal::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_ */

View File

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

View File

@ -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 <base/printf.h>
/* Noux includes */
#include <file_io_service.h>
#include <directory_service.h>
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_ */

View File

@ -16,14 +16,13 @@
/* Noux includes */
#include <io_channel.h>
#include <file_system.h>
#include <dir_file_system.h>
#include <vfs/dir_file_system.h>
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();
}

View File

@ -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 <base/printf.h>
#include <util/string.h>
/* Noux includes */
#include <noux_session/sysio.h>
#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_ */