file system: use Id_space instead of Node_handle_registry

Fixes #2436
This commit is contained in:
Christian Prochaska
2017-06-20 14:23:22 +02:00
committed by Christian Helmuth
parent 0d1be4abe2
commit 6a43f3c11a
44 changed files with 3623 additions and 3100 deletions

View File

@ -188,7 +188,8 @@ class Genode::Id_space : public Noncopyable
* \throw Unknown_id * \throw Unknown_id
*/ */
template <typename ARG, typename FUNC> template <typename ARG, typename FUNC>
void apply(Id id, FUNC const &fn) auto apply(Id id, FUNC const &fn)
-> typename Trait::Functor<decltype(&FUNC::operator())>::Return_type
{ {
T *obj = nullptr; T *obj = nullptr;
{ {
@ -201,7 +202,7 @@ class Genode::Id_space : public Noncopyable
obj = &e->_obj; obj = &e->_obj;
} }
if (obj) if (obj)
fn(static_cast<ARG &>(*obj)); return fn(static_cast<ARG &>(*obj));
else else
throw Unknown_id(); throw Unknown_id();
} }

View File

@ -26,11 +26,11 @@
#include "file.h" #include "file.h"
#include "symlink.h" #include "symlink.h"
namespace File_system { namespace Rump_fs {
class Directory; class Directory;
} }
class File_system::Directory : public Node class Rump_fs::Directory : public Node
{ {
private: private:
@ -106,14 +106,14 @@ class File_system::Directory : public Node
rump_sys_close(_fd); rump_sys_close(_fd);
} }
int fd() const { return _fd; } int fd() const override { return _fd; }
File * file(char const *name, Mode mode, bool create) File * file(char const *name, Mode mode, bool create) override
{ {
return new (&_alloc) File(_fd, name, mode, create); return new (&_alloc) File(_fd, name, mode, create);
} }
Symlink * symlink(char const *name, bool create) Symlink * symlink(char const *name, bool create) override
{ {
return new (&_alloc) Symlink(_path.base(), name, create); return new (&_alloc) Symlink(_path.base(), name, create);
} }
@ -148,7 +148,7 @@ class File_system::Directory : public Node
return node; return node;
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
if (len < sizeof(Directory_entry)) { if (len < sizeof(Directory_entry)) {
Genode::error("read buffer too small for directory entry"); Genode::error("read buffer too small for directory entry");
@ -222,12 +222,22 @@ class File_system::Directory : public Node
return sizeof(Directory_entry); return sizeof(Directory_entry);
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* writing to directory nodes is not supported */ /* writing to directory nodes is not supported */
return 0; return 0;
} }
Status status() override
{
Status s;
s.inode = inode();
s.size = num_entries() * sizeof (Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
size_t num_entries() const size_t num_entries() const
{ {
int bytes = 0; int bytes = 0;
@ -247,7 +257,7 @@ class File_system::Directory : public Node
return count; return count;
} }
void unlink(char const *path) void unlink(char const *path) override
{ {
Path node_path(path, _path.base()); Path node_path(path, _path.base());

View File

@ -21,11 +21,11 @@
#include "node.h" #include "node.h"
namespace File_system { namespace Rump_fs {
class File; class File;
} }
class File_system::File : public Node class Rump_fs::File : public Node
{ {
private: private:
@ -114,7 +114,7 @@ class File_system::File : public Node
virtual ~File() { rump_sys_close(_fd); } virtual ~File() { rump_sys_close(_fd); }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
ssize_t ret; ssize_t ret;
@ -127,7 +127,7 @@ class File_system::File : public Node
return ret == -1 ? 0 : ret; return ret == -1 ? 0 : ret;
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
ssize_t ret; ssize_t ret;
@ -140,6 +140,17 @@ class File_system::File : public Node
return ret == -1 ? 0 : ret; return ret == -1 ? 0 : ret;
} }
virtual Status status() override
{
Status s;
s.inode = inode();
s.size = length();
s.mode = File_system::Status::MODE_FILE;
return s;
}
file_size_t length() const file_size_t length() const
{ {
struct stat s; struct stat s;
@ -150,7 +161,7 @@ class File_system::File : public Node
return s.st_size; return s.st_size;
} }
void truncate(file_size_t size) void truncate(file_size_t size) override
{ {
rump_sys_ftruncate(_fd, size); rump_sys_ftruncate(_fd, size);

View File

@ -13,7 +13,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h> #include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
@ -30,19 +30,25 @@
#include "file_system.h" #include "file_system.h"
#include "directory.h" #include "directory.h"
namespace File_system { namespace Rump_fs {
using File_system::Packet_descriptor;
using File_system::Path;
struct Main; struct Main;
struct Root; struct Root;
struct Session_component; struct Session_component;
} }
class File_system::Session_component : public Session_rpc_object class Rump_fs::Session_component : public Session_rpc_object
{ {
private: private:
typedef File_system::Open_node<Node> Open_node;
Allocator &_md_alloc; Allocator &_md_alloc;
Directory &_root; Directory &_root;
Node_handle_registry _handle_registry; Id_space<File_system::Node> _open_node_registry;
bool _writable; bool _writable;
Signal_handler<Session_component> _process_packet_handler; Signal_handler<Session_component> _process_packet_handler;
@ -57,7 +63,7 @@ class File_system::Session_component : public Session_rpc_object
* *
* \return true on success, false on failure * \return true on success, false on failure
*/ */
void _process_packet_op(Packet_descriptor &packet, Node &node) void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{ {
void * const content = tx_sink()->packet_content(packet); void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length(); size_t const length = packet.length();
@ -69,18 +75,18 @@ class File_system::Session_component : public Session_rpc_object
case Packet_descriptor::READ: case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.read((char *)content, length, packet.position()); res_length = open_node.node().read((char *)content, length, packet.position());
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.write((char const *)content, length, packet.position()); res_length = open_node.node().write((char const *)content, length, packet.position());
break; break;
case Packet_descriptor::CONTENT_CHANGED: case Packet_descriptor::CONTENT_CHANGED:
_handle_registry.register_notify(*tx_sink(), packet.handle()); open_node.register_notify(*tx_sink());
/* notify_listeners may bounce the packet back*/ /* notify_listeners may bounce the packet back*/
node.notify_listeners(); open_node.node().notify_listeners();
/* otherwise defer acknowledgement of this packet */ /* otherwise defer acknowledgement of this packet */
return; return;
@ -101,12 +107,16 @@ class File_system::Session_component : public Session_rpc_object
/* assume failure by default */ /* assume failure by default */
packet.succeeded(false); packet.succeeded(false);
try { auto process_packet_fn = [&] (Open_node &open_node) {
Node *node = _handle_registry.lookup(packet.handle()); _process_packet_op(packet, open_node);
};
_process_packet_op(packet, *node); try {
_open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle");
tx_sink()->acknowledge_packet(packet);
} }
catch (Invalid_handle) { Genode::error("Invalid_handle"); }
} }
/** /**
@ -189,14 +199,29 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string())) if (!valid_name(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup(dir_handle); auto file_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node();
if (!_writable) if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY)) if (create || (mode != STAT_ONLY && mode != READ_ONLY))
throw Permission_denied(); throw Permission_denied();
File *file = dir->file(name.string(), mode, create); File *file = dir.file(name.string(), mode, create);
return _handle_registry.alloc(file);
Open_node *open_file =
new (_md_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
@ -207,13 +232,28 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string())) if (!valid_name(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup(dir_handle); auto symlink_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node();
if (create && !_writable) if (create && !_writable)
throw Permission_denied(); throw Permission_denied();
Symlink *link = dir->symlink(name.string(), create); Symlink *link = dir.symlink(name.string(), create);
return _handle_registry.alloc(link);
Open_node *open_symlink =
new (_md_alloc) Open_node(*link, _open_node_registry);
return open_symlink->id();
};
try {
return Symlink_handle {
_open_node_registry.apply<Open_node>(dir_handle, symlink_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Dir_handle dir(Path const &path, bool create) Dir_handle dir(Path const &path, bool create)
@ -231,7 +271,11 @@ class File_system::Session_component : public Session_rpc_object
throw Name_too_long(); throw Name_too_long();
Directory *dir = _root.subdir(path_str, create); Directory *dir = _root.subdir(path_str, create);
return _handle_registry.alloc(dir);
Open_node *open_dir =
new (_md_alloc) Open_node(*dir, _open_node_registry);
return Dir_handle { open_dir->id().value };
} }
Node_handle node(Path const &path) Node_handle node(Path const &path)
@ -240,55 +284,39 @@ class File_system::Session_component : public Session_rpc_object
_assert_valid_path(path_str); _assert_valid_path(path_str);
Node *node = _root.node(path_str + 1); Node *node = _root.node(path_str + 1);
Node_handle h = _handle_registry.alloc(node);
return h; Open_node *open_node =
new (_md_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
} }
void close(Node_handle handle) void close(Node_handle handle)
{ {
Node *node = 0; auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
destroy(_md_alloc, &open_node);
destroy(_md_alloc, &node);
};
try { try {
node = _handle_registry.lookup(handle); _open_node_registry.apply<Open_node>(handle, close_fn);
} catch (Invalid_handle) { return; } } catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
_handle_registry.free(handle); }
/* destruct node */
if (node)
destroy(&_md_alloc, node);
} }
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup(node_handle); auto status_fn = [&] (Open_node &open_node) {
Status s; return open_node.node().status();
s.inode = node->inode(); };
s.size = 0;
s.mode = 0;
try {
File *file = dynamic_cast<File *>(node); return _open_node_registry.apply<Open_node>(node_handle, status_fn);
if (file) { } catch (Id_space<File_system::Node>::Unknown_id const &) {
s.size = file->length(); throw Invalid_handle();
s.mode = File_system::Status::MODE_FILE;
return s;
} }
Directory *dir = dynamic_cast<Directory *>(node);
if (dir) {
s.size = dir->num_entries()*sizeof(Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
Symlink *link = dynamic_cast<Symlink *>(node);
if (link) {
s.size = link->length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
return Status();
} }
void control(Node_handle, Control) override { } void control(Node_handle, Control) override { }
@ -301,8 +329,16 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
Directory *dir = _handle_registry.lookup(dir_handle); auto unlink_fn = [&] (Open_node &open_node) {
dir->unlink(name.string()); Node &dir = open_node.node();
dir.unlink(name.string());
};
try {
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void truncate(File_handle file_handle, file_size_t size) void truncate(File_handle file_handle, file_size_t size)
@ -310,8 +346,15 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
File *file = _handle_registry.lookup(file_handle); auto truncate_fn = [&] (Open_node &open_node) {
file->truncate(size); open_node.node().truncate(size);
};
try {
_open_node_registry.apply<Open_node>(file_handle, truncate_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void move(Dir_handle from_dir_handle, Name const &from_name, void move(Dir_handle from_dir_handle, Name const &from_name,
@ -320,23 +363,26 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
auto move_fn = [&] (Open_node &open_from_dir_node) {
auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
Node &from_dir = open_from_dir_node.node();
Node &to_dir = open_to_dir_node.node();
char const *from_str = from_name.string(); char const *from_str = from_name.string();
char const *to_str = to_name.string(); char const *to_str = to_name.string();
if (!(valid_name(from_str) && valid_name(to_str))) if (!(valid_name(from_str) && valid_name(to_str)))
throw Lookup_failed(); throw Lookup_failed();
Directory *from_dir = _handle_registry.lookup(from_dir_handle); if (rump_sys_renameat(from_dir.fd(), from_str,
Directory *to_dir = _handle_registry.lookup( to_dir_handle); to_dir.fd(), to_str) == 0) {
from_dir.mark_as_updated();
if (rump_sys_renameat(from_dir->fd(), from_str, from_dir.notify_listeners();
to_dir->fd(), to_str) == 0) { if (&from_dir != &to_dir) {
from_dir->mark_as_updated(); to_dir.mark_as_updated();
from_dir->notify_listeners(); to_dir.notify_listeners();
if (!_handle_registry.refer_to_same_node(from_dir_handle,
to_dir_handle)) {
to_dir->mark_as_updated();
to_dir->notify_listeners();
} }
return; return;
@ -349,12 +395,27 @@ class File_system::Session_component : public Session_rpc_object
Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str); Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str);
throw Permission_denied(); throw Permission_denied();
};
try {
_open_node_registry.apply<Open_node>(to_dir_handle, inner_move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
};
try {
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void sync(Node_handle) override { rump_sys_sync(); } void sync(Node_handle) override { rump_sys_sync(); }
}; };
class File_system::Root : public Root_component<Session_component> class Rump_fs::Root : public Root_component<Session_component>
{ {
private: private:
@ -453,7 +514,7 @@ class File_system::Root : public Root_component<Session_component>
}; };
struct File_system::Main struct Rump_fs::Main
{ {
Genode::Env &env; Genode::Env &env;
@ -516,5 +577,5 @@ void Component::construct(Genode::Env &env)
/* XXX execute constructors of global statics (uses shared objects) */ /* XXX execute constructors of global statics (uses shared objects) */
env.exec_static_constructors(); env.exec_static_constructors();
static File_system::Main inst(env); static Rump_fs::Main inst(env);
} }

View File

@ -18,16 +18,20 @@
/* Genode includes */ /* Genode includes */
#include <file_system/node.h> #include <file_system/node.h>
#include <util/list.h>
#include <base/signal.h> #include <base/signal.h>
namespace File_system { namespace Rump_fs {
using namespace File_system;
using namespace Genode; using namespace Genode;
using Genode::size_t;
class Node; class Node;
class File;
class Directory;
class Symlink;
} }
class File_system::Node : public Node_base, public List<Node>::Element class Rump_fs::Node : public Node_base
{ {
public: public:
@ -52,6 +56,41 @@ class File_system::Node : public Node_base, public List<Node>::Element
virtual size_t read(char *dst, size_t len, seek_off_t) = 0; virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0; virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
virtual Status status() = 0;
/*
* Directory functionality
*/
virtual int fd() const
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return -1;
}
virtual File *file(char const *name, Mode mode, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual Symlink *symlink(char const *name, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual void unlink(char const *path)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
}
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
}; };
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -20,11 +20,11 @@
#include "node.h" #include "node.h"
namespace File_system { namespace Rump_fs {
class Symlink; class Symlink;
} }
class File_system::Symlink : public Node class Rump_fs::Symlink : public Node
{ {
private: private:
@ -47,7 +47,7 @@ class File_system::Symlink : public Node
Node::name(basename(path)); Node::name(basename(path));
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* Ideal symlink operations are atomic. */ /* Ideal symlink operations are atomic. */
if (!_create || seek_offset) if (!_create || seek_offset)
@ -60,12 +60,22 @@ class File_system::Symlink : public Node
return ret == -1 ? 0 : ret; return ret == -1 ? 0 : ret;
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
int ret = rump_sys_readlink(_path.base(), dst, len); int ret = rump_sys_readlink(_path.base(), dst, len);
return ret == -1 ? 0 : ret; return ret == -1 ? 0 : ret;
} }
Status status() override
{
Status s;
s.inode = inode();
s.size = length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
file_size_t length() file_size_t length()
{ {
char link_to[MAX_PATH_LEN]; char link_to[MAX_PATH_LEN];

View File

@ -4,6 +4,13 @@
* \date 2012-07-04 * \date 2012-07-04
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DIRECTORY_H_ #ifndef _DIRECTORY_H_
#define _DIRECTORY_H_ #define _DIRECTORY_H_
@ -16,11 +23,12 @@ namespace Ffat { extern "C" {
#include <node.h> #include <node.h>
namespace File_system { namespace Ffat_fs {
using namespace Genode; using namespace Genode;
class Directory;
}
class Directory : public Node class Ffat_fs::Directory : public Node
{ {
private: private:
@ -111,6 +119,5 @@ namespace File_system {
} }
}; };
}
#endif /* _DIRECTORY_H_ */ #endif /* _DIRECTORY_H_ */

View File

@ -4,6 +4,13 @@
* \date 2012-07-04 * \date 2012-07-04
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_H_ #ifndef _FILE_H_
#define _FILE_H_ #define _FILE_H_
@ -16,9 +23,11 @@ namespace Ffat { extern "C" {
#include <node.h> #include <node.h>
namespace File_system { namespace Ffat_fs {
class File;
}
class File : public Node class Ffat_fs::File : public Node
{ {
private: private:
@ -28,10 +37,38 @@ namespace File_system {
File(const char *name) : Node(name) { } File(const char *name) : Node(name) { }
~File()
{
using namespace Ffat;
FRESULT res = f_close(&_ffat_fil);
switch(res) {
case FR_OK:
return;
case FR_INVALID_OBJECT:
error("f_close() failed with error code FR_INVALID_OBJECT");
return;
case FR_DISK_ERR:
error("f_close() failed with error code FR_DISK_ERR");
return;
case FR_INT_ERR:
error("f_close() failed with error code FR_INT_ERR");
return;
case FR_NOT_READY:
error("f_close() failed with error code FR_NOT_READY");
return;
default:
/* not supposed to occur according to the libffat documentation */
error("f_close() returned an unexpected error code");
return;
}
}
void ffat_fil(Ffat::FIL ffat_fil) { _ffat_fil = ffat_fil; } void ffat_fil(Ffat::FIL ffat_fil) { _ffat_fil = ffat_fil; }
Ffat::FIL *ffat_fil() { return &_ffat_fil; } Ffat::FIL *ffat_fil() { return &_ffat_fil; }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
using namespace Ffat; using namespace Ffat;
@ -90,7 +127,7 @@ namespace File_system {
} }
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
using namespace Ffat; using namespace Ffat;
@ -149,7 +186,73 @@ namespace File_system {
} }
} }
}; void truncate(file_size_t size) override
{
using namespace Ffat;
/*
* This macro is defined in later versions of the FatFs lib, but not in the
* one currently used for Genode.
*/
#define f_tell(fp) ((fp)->fptr)
/* 'f_truncate()' truncates to the current seek pointer */
FRESULT res = f_lseek(&_ffat_fil, size);
switch(res) {
case FR_OK:
/* according to the FatFs documentation this can happen */
if (f_tell(&_ffat_fil) != size) {
error("f_lseek() could not seek to offset ", size);
return;
}
break;
case FR_DISK_ERR:
error("f_lseek() failed with error code FR_DISK_ERR");
return;
case FR_INT_ERR:
error("f_lseek() failed with error code FR_INT_ERR");
return;
case FR_NOT_READY:
error("f_lseek() failed with error code FR_NOT_READY");
return;
case FR_INVALID_OBJECT:
error("f_lseek() failed with error code FR_INVALID_OBJECT");
throw Invalid_handle();
default:
/* not supposed to occur according to the libffat documentation */
error("f_lseek() returned an unexpected error code");
return;
} }
res = f_truncate(&_ffat_fil);
switch(res) {
case FR_OK:
return;
case FR_INVALID_OBJECT:
error("f_truncate() failed with error code FR_INVALID_OBJECT");
throw Invalid_handle();
case FR_DISK_ERR:
error("f_truncate() failed with error code FR_DISK_ERR");
return;
case FR_INT_ERR:
error("f_truncate() failed with error code FR_INT_ERR");
return;
case FR_NOT_READY:
error("f_truncate() failed with error code FR_NOT_READY");
return;
case FR_TIMEOUT:
error("f_truncate() failed with error code FR_TIMEOUT");
return;
default:
/* not supposed to occur according to the libffat documentation */
error("f_truncate() returned an unexpected error code");
return;
}
}
};
#endif /* _FILE_H_ */ #endif /* _FILE_H_ */

View File

@ -13,7 +13,7 @@
/* Genode includes */ /* Genode includes */
#include <base/component.h> #include <base/component.h>
#include <file_system/node_handle_registry.h> #include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <root/component.h> #include <root/component.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
@ -35,35 +35,34 @@ namespace Ffat { extern "C" {
#include <ffat/ff.h> #include <ffat/ff.h>
} } } }
/*
* This macro is defined in later versions of the FatFs lib, but not in the
* one currently used for Genode.
*/
#define f_tell(fp) ((fp)->fptr)
using namespace Genode;
static Lock _ffat_lock;
typedef Lock_guard<Lock> Ffat_lock_guard;
/************************* /*************************
** File-system service ** ** File-system service **
*************************/ *************************/
namespace File_system { namespace Ffat_fs {
class Session_component : public Session_rpc_object using namespace Genode;
using File_system::Exception;
using File_system::Packet_descriptor;
using File_system::Path;
class Session_component;
class Root;
struct Main;
}
class Ffat_fs::Session_component : public Session_rpc_object
{ {
private: private:
typedef File_system::Open_node<Node> Open_node;
Genode::Env &_env; Genode::Env &_env;
Genode::Allocator &_heap; Genode::Allocator &_heap;
Directory &_root; Directory &_root;
Node_handle_registry _handle_registry; Id_space<File_system::Node> _open_node_registry;
bool _writable; bool _writable;
Signal_handler<Session_component> _process_packet_dispatcher; Signal_handler<Session_component> _process_packet_dispatcher;
@ -77,7 +76,7 @@ namespace File_system {
* *
* \return true on success, false on failure * \return true on success, false on failure
*/ */
void _process_packet_op(Packet_descriptor &packet, Node &node) void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{ {
void * const content = tx_sink()->packet_content(packet); void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length(); size_t const length = packet.length();
@ -91,18 +90,21 @@ namespace File_system {
/* resulting length */ /* resulting length */
size_t res_length = 0; size_t res_length = 0;
Ffat_lock_guard ffat_lock_guard(_ffat_lock);
switch (packet.operation()) { switch (packet.operation()) {
case Packet_descriptor::READ: case Packet_descriptor::READ:
res_length = node.read((char *)content, length, offset); res_length = open_node.node().read((char *)content, length, offset);
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
res_length = node.write((char const *)content, length, offset); res_length = open_node.node().write((char const *)content, length, offset);
break; break;
case Packet_descriptor::CONTENT_CHANGED:
open_node.register_notify(*tx_sink());
open_node.node().notify_listeners();
return;
case Packet_descriptor::READ_READY: case Packet_descriptor::READ_READY:
/* not supported */ /* not supported */
break; break;
@ -119,11 +121,15 @@ namespace File_system {
/* assume failure by default */ /* assume failure by default */
packet.succeeded(false); packet.succeeded(false);
auto process_packet_fn = [&] (Open_node &open_node) {
_process_packet_op(packet, open_node);
};
try { try {
Node *node = _handle_registry.lookup(packet.handle()); _open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
_process_packet_op(packet, *node); } catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle");
} }
catch (Invalid_handle) { error("Invalid_handle"); }
/* /*
* The 'acknowledge_packet' function cannot block because we * The 'acknowledge_packet' function cannot block because we
@ -211,11 +217,11 @@ namespace File_system {
File_handle file(Dir_handle dir_handle, Name const &name, File_handle file(Dir_handle dir_handle, Name const &name,
Mode mode, bool create) Mode mode, bool create)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock);
if (!valid_filename(name.string())) if (!valid_filename(name.string()))
throw Invalid_name(); throw Invalid_name();
auto file_fn = [&] (Open_node &open_node) {
using namespace Ffat; using namespace Ffat;
FIL ffat_fil; FIL ffat_fil;
@ -237,7 +243,7 @@ namespace File_system {
Absolute_path absolute_path(_root.name()); Absolute_path absolute_path(_root.name());
try { try {
absolute_path.append(_handle_registry.lookup(dir_handle)->name()); absolute_path.append(open_node.node().name());
absolute_path.append("/"); absolute_path.append("/");
absolute_path.append(name.string()); absolute_path.append(name.string());
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
@ -250,7 +256,11 @@ namespace File_system {
case FR_OK: { case FR_OK: {
File *file_node = new (&_heap) File(absolute_path.base()); File *file_node = new (&_heap) File(absolute_path.base());
file_node->ffat_fil(ffat_fil); file_node->ffat_fil(ffat_fil);
return _handle_registry.alloc(file_node);
Open_node *open_file =
new (_heap) Open_node(*file_node, _open_node_registry);
return open_file->id();
} }
case FR_NO_FILE: case FR_NO_FILE:
case FR_NO_PATH: case FR_NO_PATH:
@ -283,6 +293,15 @@ namespace File_system {
error("f_open() returned an unexpected error code"); error("f_open() returned an unexpected error code");
throw Lookup_failed(); throw Lookup_failed();
} }
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Symlink_handle symlink(Dir_handle, Name const &name, bool create) Symlink_handle symlink(Dir_handle, Name const &name, bool create)
@ -293,8 +312,6 @@ namespace File_system {
Dir_handle dir(Path const &path, bool create) Dir_handle dir(Path const &path, bool create)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock);
if (create && !_writable) if (create && !_writable)
throw Permission_denied(); throw Permission_denied();
@ -370,9 +387,14 @@ namespace File_system {
try { try {
switch(f_opendir_res) { switch(f_opendir_res) {
case FR_OK: case FR_OK: {
dir_node->ffat_dir(ffat_dir); dir_node->ffat_dir(ffat_dir);
return _handle_registry.alloc(dir_node);
Open_node *open_dir =
new (_heap) Open_node(*dir_node, _open_node_registry);
return Dir_handle { open_dir->id().value };
}
case FR_NO_PATH: case FR_NO_PATH:
throw Lookup_failed(); throw Lookup_failed();
case FR_INVALID_NAME: case FR_INVALID_NAME:
@ -407,8 +429,6 @@ namespace File_system {
Node_handle node(Path const &path) Node_handle node(Path const &path)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock);
if (!valid_path(path.string())) if (!valid_path(path.string()))
throw Lookup_failed(); throw Lookup_failed();
@ -471,79 +491,49 @@ namespace File_system {
} }
} }
return _handle_registry.alloc(node); Open_node *open_node =
new (_heap) Open_node(*node, _open_node_registry);
return open_node->id();
} }
void close(Node_handle handle) void close(Node_handle handle)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock); auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
Node *node; destroy(_heap, &open_node);
destroy(_heap, &node);
};
try { try {
node = _handle_registry.lookup(handle); _open_node_registry.apply<Open_node>(handle, close_fn);
} catch(Invalid_handle) { } catch (Id_space<File_system::Node>::Unknown_id const &) {
error("close() called with invalid handle"); throw Invalid_handle();
return;
}
/* free the handle */
_handle_registry.free(handle);
File *file = dynamic_cast<File *>(node);
if (file) {
using namespace Ffat;
FRESULT res = f_close(file->ffat_fil());
/* free the node */
destroy(&_heap, file);
switch(res) {
case FR_OK:
return;
case FR_INVALID_OBJECT:
error("f_close() failed with error code FR_INVALID_OBJECT");
return;
case FR_DISK_ERR:
error("f_close() failed with error code FR_DISK_ERR");
return;
case FR_INT_ERR:
error("f_close() failed with error code FR_INT_ERR");
return;
case FR_NOT_READY:
error("f_close() failed with error code FR_NOT_READY");
return;
default:
/* not supposed to occur according to the libffat documentation */
error("f_close() returned an unexpected error code");
return;
}
} }
} }
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock); auto status_fn = [&] (Open_node &open_node) {
Status status; Status status;
status.inode = 1; status.inode = 1;
status.size = 0; status.size = 0;
status.mode = 0; status.mode = 0;
Node *node = _handle_registry.lookup(node_handle); Node &node = open_node.node();
using namespace Ffat; using namespace Ffat;
/* f_stat() does not work for the '/' directory */ /* f_stat() does not work for the '/' directory */
if (!is_root(node->name())) { if (!is_root(node.name())) {
FILINFO ffat_file_info; FILINFO ffat_file_info;
/* the long file name is not used in this function */ /* the long file name is not used in this function */
ffat_file_info.lfname = 0; ffat_file_info.lfname = 0;
ffat_file_info.lfsize = 0; ffat_file_info.lfsize = 0;
FRESULT res = f_stat(node->name(), &ffat_file_info); FRESULT res = f_stat(node.name(), &ffat_file_info);
switch(res) { switch(res) {
case FR_OK: case FR_OK:
@ -597,7 +587,7 @@ namespace File_system {
/* determine the number of directory entries */ /* determine the number of directory entries */
Ffat::DIR ffat_dir; Ffat::DIR ffat_dir;
FRESULT f_opendir_res = f_opendir(&ffat_dir, node->name()); FRESULT f_opendir_res = f_opendir(&ffat_dir, node.name());
if (f_opendir_res != FR_OK) if (f_opendir_res != FR_OK)
return status; return status;
@ -619,26 +609,33 @@ namespace File_system {
} }
return status; return status;
};
try {
return _open_node_registry.apply<Open_node>(node_handle, status_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void control(Node_handle, Control) { } void control(Node_handle, Control) { }
void unlink(Dir_handle dir_handle, Name const &name) void unlink(Dir_handle dir_handle, Name const &name)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock);
if (!valid_filename(name.string())) if (!valid_filename(name.string()))
throw Invalid_name(); throw Invalid_name();
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
auto unlink_fn = [&] (Open_node &open_node) {
using namespace Ffat; using namespace Ffat;
Absolute_path absolute_path(_root.name()); Absolute_path absolute_path(_root.name());
try { try {
absolute_path.append(_handle_registry.lookup(dir_handle)->name()); absolute_path.append(open_node.node().name());
absolute_path.append("/"); absolute_path.append("/");
absolute_path.append(name.string()); absolute_path.append(name.string());
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
@ -679,81 +676,34 @@ namespace File_system {
error("f_unlink() returned an unexpected error code"); error("f_unlink() returned an unexpected error code");
return; return;
} }
};
try {
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void truncate(File_handle file_handle, file_size_t size) void truncate(File_handle file_handle, file_size_t size)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock);
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
File *file = _handle_registry.lookup(file_handle); auto truncate_fn = [&] (Open_node &open_node) {
open_node.node().truncate(size);
};
using namespace Ffat; try {
_open_node_registry.apply<Open_node>(file_handle, truncate_fn);
/* 'f_truncate()' truncates to the current seek pointer */ } catch (Id_space<File_system::Node>::Unknown_id const &) {
FRESULT res = f_lseek(file->ffat_fil(), size);
switch(res) {
case FR_OK:
/* according to the FatFs documentation this can happen */
if (f_tell(file->ffat_fil()) != size) {
error("f_lseek() could not seek to offset ", size);
return;
}
break;
case FR_DISK_ERR:
error("f_lseek() failed with error code FR_DISK_ERR");
return;
case FR_INT_ERR:
error("f_lseek() failed with error code FR_INT_ERR");
return;
case FR_NOT_READY:
error("f_lseek() failed with error code FR_NOT_READY");
return;
case FR_INVALID_OBJECT:
error("f_lseek() failed with error code FR_INVALID_OBJECT");
throw Invalid_handle(); throw Invalid_handle();
default:
/* not supposed to occur according to the libffat documentation */
error("f_lseek() returned an unexpected error code");
return;
}
res = f_truncate(file->ffat_fil());
switch(res) {
case FR_OK:
return;
case FR_INVALID_OBJECT:
error("f_truncate() failed with error code FR_INVALID_OBJECT");
throw Invalid_handle();
case FR_DISK_ERR:
error("f_truncate() failed with error code FR_DISK_ERR");
return;
case FR_INT_ERR:
error("f_truncate() failed with error code FR_INT_ERR");
return;
case FR_NOT_READY:
error("f_truncate() failed with error code FR_NOT_READY");
return;
case FR_TIMEOUT:
error("f_truncate() failed with error code FR_TIMEOUT");
return;
default:
/* not supposed to occur according to the libffat documentation */
error("f_truncate() returned an unexpected error code");
return;
} }
} }
void move(Dir_handle from_dir_handle, Name const &from_name, void move(Dir_handle from_dir_handle, Name const &from_name,
Dir_handle to_dir_handle, Name const &to_name) Dir_handle to_dir_handle, Name const &to_name)
{ {
Ffat_lock_guard ffat_lock_guard(_ffat_lock);
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
@ -763,14 +713,18 @@ namespace File_system {
if (!valid_filename(to_name.string())) if (!valid_filename(to_name.string()))
throw Invalid_name(); throw Invalid_name();
auto move_fn = [&] (Open_node &open_from_dir_node) {
auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
Absolute_path absolute_from_path(_root.name()); Absolute_path absolute_from_path(_root.name());
Absolute_path absolute_to_path(_root.name()); Absolute_path absolute_to_path(_root.name());
try { try {
absolute_from_path.append(_handle_registry.lookup(from_dir_handle)->name()); absolute_from_path.append(open_from_dir_node.node().name());
absolute_from_path.append("/"); absolute_from_path.append("/");
absolute_from_path.append(from_name.string()); absolute_from_path.append(from_name.string());
absolute_to_path.append(_handle_registry.lookup(to_dir_handle)->name()); absolute_to_path.append(open_to_dir_node.node().name());
absolute_to_path.append("/"); absolute_to_path.append("/");
absolute_to_path.append(to_name.string()); absolute_to_path.append(to_name.string());
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
@ -816,6 +770,20 @@ namespace File_system {
error("f_rename() returned an unexpected error code"); error("f_rename() returned an unexpected error code");
throw Lookup_failed(); throw Lookup_failed();
} }
};
try {
_open_node_registry.apply<Open_node>(to_dir_handle, inner_move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
};
try {
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void sigh(Node_handle, Genode::Signal_context_capability) void sigh(Node_handle, Genode::Signal_context_capability)
@ -825,7 +793,7 @@ namespace File_system {
}; };
class Root : public Root_component<Session_component> class Ffat_fs::Root : public Root_component<Session_component>
{ {
private: private:
@ -970,17 +938,16 @@ namespace File_system {
_env(env), _md_alloc(md_alloc), _heap(heap), _root_dir(root) _env(env), _md_alloc(md_alloc), _heap(heap), _root_dir(root)
{ } { }
}; };
};
struct Main struct Ffat_fs::Main
{ {
Genode::Env &_env; Genode::Env &_env;
Genode::Heap _heap { _env.ram(), _env.rm() }; Genode::Heap _heap { _env.ram(), _env.rm() };
Genode::Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; Genode::Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
File_system::Directory _root_dir { "/" }; Directory _root_dir { "/" };
File_system::Root _root { _env, _sliced_heap, _heap, _root_dir }; Root _root { _env, _sliced_heap, _heap, _root_dir };
Ffat::FATFS _fatfs; Ffat::FATFS _fatfs;
@ -1011,5 +978,5 @@ void Component::construct(Genode::Env &env)
/* XXX execute constructors of global statics */ /* XXX execute constructors of global statics */
env.exec_static_constructors(); env.exec_static_constructors();
static Main main(env); static Ffat_fs::Main main(env);
} }

View File

@ -4,6 +4,13 @@
* \date 2012-07-04 * \date 2012-07-04
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NODE_H_ #ifndef _NODE_H_
#define _NODE_H_ #define _NODE_H_
@ -17,11 +24,16 @@ namespace Ffat { extern "C" {
#include <ffat/ff.h> #include <ffat/ff.h>
} } } }
namespace File_system { namespace Ffat_fs {
using namespace File_system;
typedef Genode::Path<_MAX_LFN + 1> Absolute_path; typedef Genode::Path<_MAX_LFN + 1> Absolute_path;
class Node : public Node_base class Node;
}
class Ffat_fs::Node : public Node_base
{ {
protected: protected:
@ -50,8 +62,14 @@ namespace File_system {
Genode::error("write() called on generic Node object"); Genode::error("write() called on generic Node object");
return 0; return 0;
} }
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
}; };
}
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -6,6 +6,13 @@
* \date 2013-11-11 * \date 2013-11-11
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DIRECTORY_H_ #ifndef _DIRECTORY_H_
#define _DIRECTORY_H_ #define _DIRECTORY_H_
@ -30,12 +37,12 @@
#include <fuse_private.h> #include <fuse_private.h>
namespace File_system { namespace Fuse_fs {
class Directory; class Directory;
} }
class File_system::Directory : public Node class Fuse_fs::Directory : public Node
{ {
private: private:
@ -181,13 +188,12 @@ class File_system::Directory : public Node
else else
throw Lookup_failed(); throw Lookup_failed();
node->lock();
return node; return node;
} }
struct fuse_file_info *file_info() { return &_file_info; } struct fuse_file_info *file_info() { return &_file_info; }
Status status() Status status() override
{ {
struct stat s; struct stat s;
int res = Fuse::fuse()->op.getattr(_path.base(), &s); int res = Fuse::fuse()->op.getattr(_path.base(), &s);
@ -202,7 +208,7 @@ class File_system::Directory : public Node
return status; return status;
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
if (len < sizeof(Directory_entry)) { if (len < sizeof(Directory_entry)) {
Genode::error("read buffer too small for directory entry"); Genode::error("read buffer too small for directory entry");
@ -277,7 +283,7 @@ class File_system::Directory : public Node
return sizeof(Directory_entry); return sizeof(Directory_entry);
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* writing to directory nodes is not supported */ /* writing to directory nodes is not supported */
return 0; return 0;

View File

@ -6,6 +6,13 @@
* \date 2013-11-26 * \date 2013-11-26
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_H_ #ifndef _FILE_H_
#define _FILE_H_ #define _FILE_H_
@ -16,12 +23,12 @@
#include <fuse.h> #include <fuse.h>
#include <fuse_private.h> #include <fuse_private.h>
namespace File_system { namespace Fuse_fs {
class File; class File;
} }
class File_system::File : public Node class Fuse_fs::File : public Node
{ {
private: private:
@ -104,7 +111,7 @@ class File_system::File : public Node
struct fuse_file_info *file_info() { return &_file_info; } struct fuse_file_info *file_info() { return &_file_info; }
Status status() Status status() override
{ {
struct stat s; struct stat s;
int res = Fuse::fuse()->op.getattr(_path.base(), &s); int res = Fuse::fuse()->op.getattr(_path.base(), &s);
@ -118,7 +125,7 @@ class File_system::File : public Node
return status; return status;
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
/* append mode, use actual length as offset */ /* append mode, use actual length as offset */
if (seek_offset == ~0ULL) if (seek_offset == ~0ULL)
@ -129,7 +136,7 @@ class File_system::File : public Node
return ret < 0 ? 0 : ret; return ret < 0 ? 0 : ret;
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* append mode, use actual length as offset */ /* append mode, use actual length as offset */
if (seek_offset == ~0ULL) if (seek_offset == ~0ULL)
@ -140,7 +147,7 @@ class File_system::File : public Node
return ret < 0 ? 0 : ret; return ret < 0 ? 0 : ret;
} }
void truncate(file_size_t size) void truncate(file_size_t size) override
{ {
int res = Fuse::fuse()->op.ftruncate(_path.base(), size, int res = Fuse::fuse()->op.ftruncate(_path.base(), size,
&_file_info); &_file_info);

View File

@ -13,7 +13,7 @@
/* Genode includes */ /* Genode includes */
#include <base/heap.h> #include <base/heap.h>
#include <file_system/node_handle_registry.h> #include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <os/session_policy.h> #include <os/session_policy.h>
@ -29,21 +29,28 @@
#include <util.h> #include <util.h>
namespace File_system { namespace Fuse_fs {
using namespace Genode;
using File_system::Packet_descriptor;
using File_system::Path;
struct Main; struct Main;
struct Session_component; struct Session_component;
struct Root; struct Root;
} }
class File_system::Session_component : public Session_rpc_object class Fuse_fs::Session_component : public Session_rpc_object
{ {
private: private:
typedef File_system::Open_node<Node> Open_node;
Genode::Env &_env; Genode::Env &_env;
Allocator &_md_alloc; Allocator &_md_alloc;
Directory &_root; Directory &_root;
Node_handle_registry _handle_registry; Id_space<File_system::Node> _open_node_registry;
bool _writeable; bool _writeable;
Signal_handler<Session_component> _process_packet_handler; Signal_handler<Session_component> _process_packet_handler;
@ -58,7 +65,7 @@ class File_system::Session_component : public Session_rpc_object
* *
* \return true on success, false on failure * \return true on success, false on failure
*/ */
void _process_packet_op(Packet_descriptor &packet, Node &node) void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{ {
void * const content = tx_sink()->packet_content(packet); void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length(); size_t const length = packet.length();
@ -70,18 +77,18 @@ class File_system::Session_component : public Session_rpc_object
case Packet_descriptor::READ: case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.read((char *)content, length, packet.position()); res_length = open_node.node().read((char *)content, length, packet.position());
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.write((char const *)content, length, packet.position()); res_length = open_node.node().write((char const *)content, length, packet.position());
break; break;
case Packet_descriptor::CONTENT_CHANGED: case Packet_descriptor::CONTENT_CHANGED:
_handle_registry.register_notify(*tx_sink(), packet.handle()); open_node.register_notify(*tx_sink());
/* notify_listeners may bounce the packet back*/ /* notify_listeners may bounce the packet back*/
node.notify_listeners(); open_node.node().notify_listeners();
/* otherwise defer acknowledgement of this packet */ /* otherwise defer acknowledgement of this packet */
return; return;
@ -102,13 +109,16 @@ class File_system::Session_component : public Session_rpc_object
/* assume failure by default */ /* assume failure by default */
packet.succeeded(false); packet.succeeded(false);
try { auto process_packet_fn = [&] (Open_node &open_node) {
Node *node = _handle_registry.lookup_and_lock(packet.handle()); _process_packet_op(packet, open_node);
Node_lock_guard guard(node); };
_process_packet_op(packet, *node); try {
_open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle");
tx_sink()->acknowledge_packet(packet);
} }
catch (Invalid_handle) { Genode::error("Invalid_handle"); }
} }
/** /**
@ -193,38 +203,60 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_filename(name.string())) if (!valid_filename(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); auto file_fn = [&] (Open_node &open_node) {
Node_lock_guard dir_guard(dir);
Node &dir = open_node.node();
if (create && !_writeable) if (create && !_writeable)
throw Permission_denied(); throw Permission_denied();
File *file = new (&_md_alloc) File(dir, name.string(), mode, create); File *file = new (&_md_alloc) File(&dir, name.string(), mode, create);
Node_lock_guard file_guard(file);
return _handle_registry.alloc(file); Open_node *open_file =
new (_md_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
{ {
if (! Fuse::support_symlinks()) { if (! Fuse::support_symlinks()) {
Genode::error("FUSE file system does not support symlinks"); Genode::error("FUSE file system does not support symlinks");
return Symlink_handle(); throw Permission_denied();
} }
if (!valid_filename(name.string())) if (!valid_filename(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); auto symlink_fn = [&] (Open_node &open_node) {
Node_lock_guard dir_guard(dir);
Node &dir = open_node.node();
if (create && !_writeable) if (create && !_writeable)
throw Permission_denied(); throw Permission_denied();
Symlink *symlink = new (&_md_alloc) Symlink(dir, name.string(), create); Symlink *symlink = new (&_md_alloc) Symlink(&dir, name.string(), create);
Node_lock_guard symlink_guard(symlink);
return _handle_registry.alloc(symlink); Open_node *open_symlink =
new (_md_alloc) Open_node(*symlink, _open_node_registry);
return Symlink_handle { open_symlink->id().value };
};
try {
return _open_node_registry.apply<Open_node>(dir_handle, symlink_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Dir_handle dir(Path const &path, bool create) Dir_handle dir(Path const &path, bool create)
@ -241,8 +273,10 @@ class File_system::Session_component : public Session_rpc_object
Directory *dir_node = new (&_md_alloc) Directory(_md_alloc, path_str, create); Directory *dir_node = new (&_md_alloc) Directory(_md_alloc, path_str, create);
Node_lock_guard guard(dir_node); Open_node *open_dir =
return _handle_registry.alloc(dir_node); new (_md_alloc) Open_node(*dir_node, _open_node_registry);
return Dir_handle { open_dir->id().value };
} }
Node_handle node(Path const &path) Node_handle node(Path const &path)
@ -257,48 +291,38 @@ class File_system::Session_component : public Session_rpc_object
*/ */
Node *node = _root.node(path_str + 1); Node *node = _root.node(path_str + 1);
Node_lock_guard guard(node); Open_node *open_node =
return _handle_registry.alloc(node); new (_md_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
} }
void close(Node_handle handle) void close(Node_handle handle)
{ {
Node *node; auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
destroy(_md_alloc, &open_node);
destroy(_md_alloc, &node);
};
try { try {
node = _handle_registry.lookup_and_lock(handle); _open_node_registry.apply<Open_node>(handle, close_fn);
/** } catch (Id_space<File_system::Node>::Unknown_id const &) {
* We need to call unlock() here because the handle registry throw Invalid_handle();
* calls lock() itself on the node.
*/
node->unlock();
} catch (Invalid_handle) {
Genode::error("close() called with invalid handle");
return;
} }
_handle_registry.free(handle);
destroy(&_md_alloc, node);
} }
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup_and_lock(node_handle); auto status_fn = [&] (Open_node &open_node) {
Node_lock_guard guard(node); return open_node.node().status();
};
File *file = dynamic_cast<File *>(node); try {
if (file) return _open_node_registry.apply<Open_node>(node_handle, status_fn);
return file->status(); } catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
Directory *dir = dynamic_cast<Directory *>(node); }
if (dir)
return dir->status();
Symlink *symlink = dynamic_cast<Symlink *>(node);
if (symlink)
return symlink->status();
return Status();
} }
void control(Node_handle, Control) void control(Node_handle, Control)
@ -311,13 +335,14 @@ class File_system::Session_component : public Session_rpc_object
if (!_writeable) if (!_writeable)
throw Permission_denied(); throw Permission_denied();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); auto unlink_fn = [&] (Open_node &open_node) {
Node_lock_guard dir_guard(dir);
Node &dir = open_node.node();
Absolute_path absolute_path(_root.name()); Absolute_path absolute_path(_root.name());
try { try {
absolute_path.append(dir->name()); absolute_path.append(dir.name());
absolute_path.append("/"); absolute_path.append("/");
absolute_path.append(name.string()); absolute_path.append(name.string());
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
@ -331,6 +356,13 @@ class File_system::Session_component : public Session_rpc_object
Genode::error("fuse()->op.unlink() returned unexpected error code: ", res); Genode::error("fuse()->op.unlink() returned unexpected error code: ", res);
return; return;
} }
};
try {
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void truncate(File_handle file_handle, file_size_t size) void truncate(File_handle file_handle, file_size_t size)
@ -338,12 +370,15 @@ class File_system::Session_component : public Session_rpc_object
if (!_writeable) if (!_writeable)
throw Permission_denied(); throw Permission_denied();
File *file; auto truncate_fn = [&] (Open_node &open_node) {
try { file = _handle_registry.lookup_and_lock(file_handle); } open_node.node().truncate(size);
catch (Invalid_handle) { throw Lookup_failed(); } };
Node_lock_guard file_guard(file); try {
file->truncate(size); _open_node_registry.apply<Open_node>(file_handle, truncate_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void move(Dir_handle from_dir_handle, Name const &from_name, void move(Dir_handle from_dir_handle, Name const &from_name,
@ -352,27 +387,21 @@ class File_system::Session_component : public Session_rpc_object
if (!_writeable) if (!_writeable)
throw Permission_denied(); throw Permission_denied();
Directory *from_dir, *to_dir; auto move_fn = [&] (Open_node &open_from_dir_node) {
try { from_dir = _handle_registry.lookup_and_lock(from_dir_handle); }
catch (Invalid_handle) { throw Lookup_failed(); }
try { to_dir = _handle_registry.lookup_and_lock(to_dir_handle); } auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
catch (Invalid_handle) {
from_dir->unlock();
throw Lookup_failed();
}
Node_lock_guard from_dir_guard(from_dir); Node &from_dir = open_from_dir_node.node();
Node_lock_guard to_dir_guard(to_dir); Node &to_dir = open_to_dir_node.node();
Absolute_path absolute_from_path(_root.name()); Absolute_path absolute_from_path(_root.name());
Absolute_path absolute_to_path(_root.name()); Absolute_path absolute_to_path(_root.name());
try { try {
absolute_from_path.append(from_dir->name()); absolute_from_path.append(from_dir.name());
absolute_from_path.append("/"); absolute_from_path.append("/");
absolute_from_path.append(from_name.string()); absolute_from_path.append(from_name.string());
absolute_to_path.append(to_dir->name()); absolute_to_path.append(to_dir.name());
absolute_to_path.append("/"); absolute_to_path.append("/");
absolute_to_path.append(to_name.string()); absolute_to_path.append(to_name.string());
} catch (Path_base::Path_too_long) { } catch (Path_base::Path_too_long) {
@ -387,6 +416,20 @@ class File_system::Session_component : public Session_rpc_object
Genode::error("fuse()->op.rename() returned unexpected error code: ", res); Genode::error("fuse()->op.rename() returned unexpected error code: ", res);
return; return;
} }
};
try {
_open_node_registry.apply<Open_node>(to_dir_handle, inner_move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
};
try {
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void sync(Node_handle) override void sync(Node_handle) override
@ -396,7 +439,7 @@ class File_system::Session_component : public Session_rpc_object
}; };
class File_system::Root : public Root_component<Session_component> class Fuse_fs::Root : public Root_component<Session_component>
{ {
private: private:
@ -500,7 +543,7 @@ class File_system::Root : public Root_component<Session_component>
}; };
struct File_system::Main struct Fuse_fs::Main
{ {
Genode::Env & env; Genode::Env & env;
Sliced_heap sliced_heap { env.ram(), env.rm() }; Sliced_heap sliced_heap { env.ram(), env.rm() };
@ -531,6 +574,6 @@ struct File_system::Main
void Libc::Component::construct(Libc::Env &env) void Libc::Component::construct(Libc::Env &env)
{ {
static File_system::Main inst(env); static Fuse_fs::Main inst(env);
} }

View File

@ -6,24 +6,34 @@
* \date 2013-11-11 * \date 2013-11-11
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NODE_H_ #ifndef _NODE_H_
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <file_system/node.h> #include <file_system/node.h>
#include <util/list.h>
#include <base/lock.h> #include <base/lock.h>
#include <base/signal.h> #include <base/signal.h>
#include <os/path.h> #include <os/path.h>
namespace File_system { namespace Fuse_fs {
using namespace Genode; using namespace Genode;
using namespace File_system;
typedef Genode::Path<MAX_PATH_LEN> Absolute_path; typedef Genode::Path<MAX_PATH_LEN> Absolute_path;
class Node : public Node_base, public List<Node>::Element class Node;
}
class Fuse_fs::Node : public Node_base
{ {
protected: protected:
@ -38,8 +48,15 @@ namespace File_system {
virtual size_t read(char *dst, size_t len, seek_off_t) = 0; virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0; virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
virtual Status status() = 0;
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
}; };
}
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -6,6 +6,13 @@
* \date 2013-11-26 * \date 2013-11-26
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SYMLINK_H_ #ifndef _SYMLINK_H_
#define _SYMLINK_H_ #define _SYMLINK_H_
@ -13,12 +20,12 @@
#include <node.h> #include <node.h>
namespace File_system { namespace Fuse_fs {
class Symlink; class Symlink;
} }
class File_system::Symlink : public Node class Fuse_fs::Symlink : public Node
{ {
private: private:
@ -45,7 +52,7 @@ class File_system::Symlink : public Node
_path(name, parent->name()) _path(name, parent->name())
{ } { }
Status status() Status status() override
{ {
struct stat s; struct stat s;
int res = Fuse::fuse()->op.getattr(_path.base(), &s); int res = Fuse::fuse()->op.getattr(_path.base(), &s);
@ -59,7 +66,7 @@ class File_system::Symlink : public Node
return status; return status;
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
int res = Fuse::fuse()->op.readlink(_path.base(), dst, len); int res = Fuse::fuse()->op.readlink(_path.base(), dst, len);
if (res != 0) if (res != 0)
@ -68,7 +75,7 @@ class File_system::Symlink : public Node
return Genode::strlen(dst); return Genode::strlen(dst);
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* Ideal symlink operations are atomic. */ /* Ideal symlink operations are atomic. */
if (seek_offset) return 0; if (seek_offset) return 0;

View File

@ -4,6 +4,13 @@
* \date 2012-04-11 * \date 2012-04-11
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_SYSTEM__LISTENER_H_ #ifndef _FILE_SYSTEM__LISTENER_H_
#define _FILE_SYSTEM__LISTENER_H_ #define _FILE_SYSTEM__LISTENER_H_
@ -23,23 +30,21 @@ namespace File_system {
private: private:
Genode::Lock _lock; Genode::Lock _lock;
Sink *_sink = nullptr; Sink &_sink;
Node_handle _handle; Node_handle _handle;
bool _marked_as_updated; bool _marked_as_updated;
public: public:
Listener() : _marked_as_updated(false) { }
Listener(Sink &sink, Node_handle handle) Listener(Sink &sink, Node_handle handle)
: _sink(&sink), _handle(handle), _marked_as_updated(false) { } : _sink(sink), _handle(handle), _marked_as_updated(false) { }
void notify() void notify()
{ {
Genode::Lock::Guard guard(_lock); Genode::Lock::Guard guard(_lock);
if (_marked_as_updated && _sink && _sink->ready_to_ack()) { if (_marked_as_updated && _sink.ready_to_ack()) {
_sink->acknowledge_packet(Packet_descriptor( _sink.acknowledge_packet(Packet_descriptor(
_handle, Packet_descriptor::CONTENT_CHANGED)); _handle, Packet_descriptor::CONTENT_CHANGED));
_marked_as_updated = false; _marked_as_updated = false;
} }
@ -51,8 +56,6 @@ namespace File_system {
_marked_as_updated = true; _marked_as_updated = true;
} }
bool valid() const { return _sink != nullptr; }
}; };
} }

View File

@ -4,6 +4,13 @@
* \date 2012-04-11 * \date 2012-04-11
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_SYSTEM__NODE_H_ #ifndef _FILE_SYSTEM__NODE_H_
#define _FILE_SYSTEM__NODE_H_ #define _FILE_SYSTEM__NODE_H_
@ -19,7 +26,6 @@ namespace File_system {
{ {
private: private:
Genode::Lock _lock;
Genode::List<Listener> _listeners; Genode::List<Listener> _listeners;
public: public:
@ -34,9 +40,6 @@ namespace File_system {
_listeners.remove(_listeners.first()); _listeners.remove(_listeners.first());
} }
void lock() { _lock.lock(); }
void unlock() { _lock.unlock(); }
void add_listener(Listener *listener) void add_listener(Listener *listener)
{ {
_listeners.insert(listener); _listeners.insert(listener);
@ -59,19 +62,6 @@ namespace File_system {
curr->mark_as_updated(); curr->mark_as_updated();
} }
}; };
/**
* Guard used for properly releasing node locks
*/
struct Node_lock_guard
{
Node_base *node;
Node_lock_guard(Node_base *node) : node(node) { node = node; }
~Node_lock_guard() { node->unlock(); }
};
} }
#endif /* _FILE_SYSTEM__NODE_H_ */ #endif /* _FILE_SYSTEM__NODE_H_ */

View File

@ -1,218 +0,0 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_
#define _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_
#include <file_system/node.h>
namespace File_system {
class Node;
class Directory;
class File;
class Symlink;
/**
* Type trait for determining the node type for a given handle type
*/
template<typename T> struct Node_type;
template<> struct Node_type<Node_handle> { typedef Node Type; };
template<> struct Node_type<Dir_handle> { typedef Directory Type; };
template<> struct Node_type<File_handle> { typedef File Type; };
template<> struct Node_type<Symlink_handle> { typedef Symlink Type; };
/**
* Type trait for determining the handle type for a given node type
*/
template<typename T> struct Handle_type;
template<> struct Handle_type<Node> { typedef Node_handle Type; };
template<> struct Handle_type<Directory> { typedef Dir_handle Type; };
template<> struct Handle_type<File> { typedef File_handle Type; };
template<> struct Handle_type<Symlink> { typedef Symlink_handle Type; };
class Node_handle_registry
{
public:
class Out_of_node_handles : public Exception { };
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Genode::Lock mutable _lock;
Node_base *_nodes[MAX_NODE_HANDLES];
/**
* Each open node handle can act as a listener to be informed about
* node changes.
*/
Listener _listeners[MAX_NODE_HANDLES];
/**
* Allocate node handle
*
* \throw Out_of_node_handles
*/
int _alloc(Node_base *node)
{
Genode::Lock::Guard guard(_lock);
for (unsigned i = 0; i < MAX_NODE_HANDLES; i++)
if (!_nodes[i]) {
_nodes[i] = node;
return i;
}
throw Out_of_node_handles();
}
bool _in_range(int handle) const
{
return ((handle >= 0) && (handle < MAX_NODE_HANDLES));
}
public:
Node_handle_registry()
{
for (unsigned i = 0; i < MAX_NODE_HANDLES; i++)
_nodes[i] = 0;
}
template <typename NODE_TYPE>
typename Handle_type<NODE_TYPE>::Type alloc(NODE_TYPE *node)
{
typedef typename Handle_type<NODE_TYPE>::Type Handle;
return Handle(_alloc(node));
}
/**
* Release node handle
*/
void free(Node_handle handle)
{
Genode::Lock::Guard guard(_lock);
if (!_in_range(handle.value))
return;
/*
* Notify listeners about the changed file.
*/
Node_base *node = dynamic_cast<Node_base *>(_nodes[handle.value]);
if (!node) { return; }
node->lock();
node->notify_listeners();
/*
* De-allocate handle
*/
Listener &listener = _listeners[handle.value];
if (listener.valid())
node->remove_listener(&listener);
_nodes[handle.value] = 0;
listener = Listener();
node->unlock();
}
/**
* Lookup node using its handle as key
*
* \throw Invalid_handle
*/
template <typename HANDLE_TYPE>
typename Node_type<HANDLE_TYPE>::Type *lookup(HANDLE_TYPE handle)
{
Genode::Lock::Guard guard(_lock);
if (!_in_range(handle.value))
throw Invalid_handle();
typedef typename Node_type<HANDLE_TYPE>::Type Node;
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node)
throw Invalid_handle();
return node;
}
/**
* Lookup node using its handle as key
*
* The node returned by this function is in a locked state.
*
* \throw Invalid_handle
*/
template <typename HANDLE_TYPE>
typename Node_type<HANDLE_TYPE>::Type *lookup_and_lock(HANDLE_TYPE handle)
{
Genode::Lock::Guard guard(_lock);
if (!_in_range(handle.value))
throw Invalid_handle();
typedef typename Node_type<HANDLE_TYPE>::Type Node_base;
Node_base *node = dynamic_cast<Node_base *>(_nodes[handle.value]);
if (!node)
throw Invalid_handle();
node->lock();
return node;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
Genode::Lock::Guard guard(_lock);
if (!_in_range(h1.value) || !_in_range(h2.value))
throw Invalid_handle();
return _nodes[h1.value] == _nodes[h2.value];
}
/**
* Register signal handler to be notified of node changes
*/
void register_notify(Sink &sink, Node_handle handle)
{
Genode::Lock::Guard guard(_lock);
if (!_in_range(handle.value))
throw Invalid_handle();
Node_base *node = dynamic_cast<Node_base *>(_nodes[handle.value]);
if (!node)
throw Invalid_handle();
Listener &listener = _listeners[handle.value];
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (listener.valid())
node->remove_listener(&listener);
/*
* Register new handler
*/
listener = Listener(sink, handle);
node->add_listener(&listener);
}
};
}
#endif /* _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_ */

View File

@ -0,0 +1,79 @@
/*
* \brief Representation of an open file system node within the component
* \author Christian Prochaska
* \date 2017-06-09
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _OPEN_NODE_H_
#define _OPEN_NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system_session/file_system_session.h>
namespace File_system {
/*
* \param NODE component-specific node type
*/
template <typename NODE> class Open_node;
}
template <typename NODE>
class File_system::Open_node : public File_system::Node
{
private:
Genode::Id_space<File_system::Node>::Element _element;
NODE &_node;
Genode::Constructible<File_system::Listener> _listener;
public:
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space)
: _element(*this, id_space),
_node(node) { }
~Open_node()
{
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
}
NODE &node() { return _node; }
File_system::Listener &listener() { return *_listener; }
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
/**
* Register packet stream sink to be notified of node changes
*/
void register_notify(File_system::Sink &sink)
{
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Register new handler
*/
_listener.construct(sink, id());
_node.add_listener(&*_listener);
}
};
#endif /* _OPEN_NODE_H_ */

View File

@ -23,10 +23,39 @@
namespace File_system { namespace File_system {
struct Node_handle; struct Node
struct File_handle; {
struct Dir_handle; typedef Genode::Id_space<Node>::Id Id;
struct Symlink_handle; };
struct File : Node
{
struct Id : Node::Id
{
explicit Id(unsigned long value) : Node::Id { value } { };
};
};
struct Directory : Node
{
struct Id : Node::Id
{
explicit Id(unsigned long value) : Node::Id { value } { };
};
};
struct Symlink : Node
{
struct Id : Node::Id
{
explicit Id(unsigned long value) : Node::Id { value } { };
};
};
typedef Node::Id Node_handle;
typedef File::Id File_handle;
typedef Directory::Id Dir_handle;
typedef Symlink::Id Symlink_handle;
using Genode::size_t; using Genode::size_t;
@ -81,42 +110,6 @@ namespace File_system {
} }
struct File_system::Node_handle
{
unsigned long value;
Node_handle() : value(~0UL) { }
Node_handle(int v) : value(v) { }
bool valid() const { return value != ~0UL; }
bool operator == (Node_handle const &other) const { return other.value == value; }
bool operator != (Node_handle const &other) const { return other.value != value; }
};
struct File_system::File_handle : Node_handle
{
File_handle() { }
File_handle(unsigned long v) : Node_handle(v) { }
};
struct File_system::Dir_handle : Node_handle
{
Dir_handle() { }
Dir_handle(unsigned long v) : Node_handle(v) { }
};
struct File_system::Symlink_handle : Node_handle
{
Symlink_handle() { }
Symlink_handle(unsigned long v) : Node_handle(v) { }
};
class File_system::Packet_descriptor : public Genode::Packet_descriptor class File_system::Packet_descriptor : public Genode::Packet_descriptor
{ {
public: public:
@ -125,7 +118,7 @@ class File_system::Packet_descriptor : public Genode::Packet_descriptor
private: private:
Node_handle _handle; /* node handle */ Node_handle _handle { 0 }; /* node handle */
Opcode _op; /* requested operation */ Opcode _op; /* requested operation */
seek_off_t _position; /* file seek offset in bytes */ seek_off_t _position; /* file seek offset in bytes */
size_t _length; /* transaction length in bytes */ size_t _length; /* transaction length in bytes */
@ -139,7 +132,7 @@ class File_system::Packet_descriptor : public Genode::Packet_descriptor
Packet_descriptor(Genode::off_t buf_offset = 0, Packet_descriptor(Genode::off_t buf_offset = 0,
Genode::size_t buf_size = 0) Genode::size_t buf_size = 0)
: :
Genode::Packet_descriptor(buf_offset, buf_size), _handle(-1), Genode::Packet_descriptor(buf_offset, buf_size),
_op(READ), _position(0), _length(0), _success(false) { } _op(READ), _position(0), _length(0), _success(false) { }
/** /**
@ -330,16 +323,22 @@ struct File_system::Session : public Genode::Session
/** /**
* Close file * Close file
*
* \throw Invalid_handle node handle is invalid
*/ */
virtual void close(Node_handle) = 0; virtual void close(Node_handle) = 0;
/** /**
* Request information about an open file or directory * Request information about an open file or directory
*
* \throw Invalid_handle node handle is invalid
*/ */
virtual Status status(Node_handle) = 0; virtual Status status(Node_handle) = 0;
/** /**
* Set information about an open file or directory * Set information about an open file or directory
*
* \throw Invalid_handle node handle is invalid
*/ */
virtual void control(Node_handle, Control) = 0; virtual void control(Node_handle, Control) = 0;
@ -380,6 +379,9 @@ struct File_system::Session : public Genode::Session
* *
* This is only needed by file systems that maintain an internal * This is only needed by file systems that maintain an internal
* cache, which needs to be flushed on certain occasions. * cache, which needs to be flushed on certain occasions.
*
* \throw Invalid_handle node handle is invalid
*
*/ */
virtual void sync(Node_handle) { } virtual void sync(Node_handle) { }
@ -409,9 +411,15 @@ struct File_system::Session : public Genode::Session
GENODE_RPC_THROW(Rpc_node, Node_handle, node, GENODE_RPC_THROW(Rpc_node, Node_handle, node,
GENODE_TYPE_LIST(Lookup_failed, Out_of_ram, Out_of_caps), GENODE_TYPE_LIST(Lookup_failed, Out_of_ram, Out_of_caps),
Path const &); Path const &);
GENODE_RPC(Rpc_close, void, close, Node_handle); GENODE_RPC_THROW(Rpc_close, void, close,
GENODE_RPC(Rpc_status, Status, status, Node_handle); GENODE_TYPE_LIST(Invalid_handle),
GENODE_RPC(Rpc_control, void, control, Node_handle, Control); Node_handle);
GENODE_RPC_THROW(Rpc_status, Status, status,
GENODE_TYPE_LIST(Invalid_handle),
Node_handle);
GENODE_RPC_THROW(Rpc_control, void, control,
GENODE_TYPE_LIST(Invalid_handle),
Node_handle, Control);
GENODE_RPC_THROW(Rpc_unlink, void, unlink, GENODE_RPC_THROW(Rpc_unlink, void, unlink,
GENODE_TYPE_LIST(Invalid_handle, Invalid_name, GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Not_empty, Lookup_failed, Not_empty,
@ -425,7 +433,9 @@ struct File_system::Session : public Genode::Session
GENODE_TYPE_LIST(Invalid_handle, Invalid_name, GENODE_TYPE_LIST(Invalid_handle, Invalid_name,
Lookup_failed, Permission_denied), Lookup_failed, Permission_denied),
Dir_handle, Name const &, Dir_handle, Name const &); Dir_handle, Name const &, Dir_handle, Name const &);
GENODE_RPC(Rpc_sync, void, sync, Node_handle); GENODE_RPC_THROW(Rpc_sync, void, sync,
GENODE_TYPE_LIST(Invalid_handle),
Node_handle);
GENODE_RPC_INTERFACE(Rpc_tx_cap, Rpc_file, Rpc_symlink, Rpc_dir, Rpc_node, GENODE_RPC_INTERFACE(Rpc_tx_cap, Rpc_file, Rpc_symlink, Rpc_dir, Rpc_node,
Rpc_close, Rpc_status, Rpc_control, Rpc_unlink, Rpc_close, Rpc_status, Rpc_control, Rpc_unlink,

View File

@ -1,67 +0,0 @@
/*
* \brief File-system node
* \author Norman Feske
* \date 2012-04-11
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__RAM_FS__NODE_H_
#define _INCLUDE__RAM_FS__NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system/node.h>
#include <util/list.h>
namespace File_system {
using namespace Genode;
class Node;
}
class File_system::Node : public Node_base, public List<Node>::Element
{
public:
typedef char Name[128];
private:
int _ref_count;
Name _name;
unsigned long const _inode;
/**
* Generate unique inode number
*/
static unsigned long _unique_inode()
{
static unsigned long inode_count;
return ++inode_count;
}
public:
Node()
: _ref_count(0), _inode(_unique_inode())
{ _name[0] = 0; }
unsigned long inode() const { return _inode; }
char const *name() const { return _name; }
/**
* Assign name
*/
void name(char const *name) { strncpy(_name, name, sizeof(_name)); }
virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
};
#endif /* _INCLUDE__RAM_FS__NODE_H_ */

View File

@ -122,24 +122,24 @@ void Rom_to_file::Main::_handle_update()
try { try {
Dir_handle dir_handle = ensure_dir(_fs, dir_path); Dir_handle dir_handle = ensure_dir(_fs, dir_path);
Handle_guard dir_guard(_fs, dir_handle); Handle_guard dir_guard(_fs, dir_handle);
File_handle handle; Constructible<File_handle> handle;
try { try {
handle = _fs.file(dir_handle, file_name, File_system::WRITE_ONLY, true); handle.construct(_fs.file(dir_handle, file_name, File_system::WRITE_ONLY, true));
} catch (Node_already_exists) { } catch (Node_already_exists) {
handle = _fs.file(dir_handle, file_name, File_system::WRITE_ONLY, false); handle.construct(_fs.file(dir_handle, file_name, File_system::WRITE_ONLY, false));
} }
_fs.truncate(handle, 0); _fs.truncate(*handle, 0);
size_t len = max(strlen(_rom_ds->local_addr<char>()), _rom_ds->size()); size_t len = max(strlen(_rom_ds->local_addr<char>()), _rom_ds->size());
size_t written = write(_fs, handle, _rom_ds->local_addr<void>(), len, 0); size_t written = write(_fs, *handle, _rom_ds->local_addr<void>(), len, 0);
if (written < len) { if (written < len) {
warning(written, " of ", len, " bytes have been written"); warning(written, " of ", len, " bytes have been written");
} }
_fs.close(handle); _fs.close(*handle);
} catch (Permission_denied) { } catch (Permission_denied) {
error(Cstring(dir_path), file_name, ": permission denied"); error(Cstring(dir_path), file_name, ": permission denied");

View File

@ -58,7 +58,6 @@ class Usb_filter::Device_registry
Genode::Allocator_avl _fs_packet_alloc { &_alloc }; Genode::Allocator_avl _fs_packet_alloc { &_alloc };
File_system::Connection _fs { _env, _fs_packet_alloc, "usb_drv.config" }; File_system::Connection _fs { _env, _fs_packet_alloc, "usb_drv.config" };
File_system::File_handle _file;
struct Entry : public Genode::List<Entry>::Element struct Entry : public Genode::List<Entry>::Element
{ {
@ -154,16 +153,18 @@ class Usb_filter::Device_registry
{ {
using namespace Genode; using namespace Genode;
Constructible<File_system::File_handle> file;
try { try {
File_system::Dir_handle root_dir = _fs.dir("/", false); File_system::Dir_handle root_dir = _fs.dir("/", false);
_file = _fs.file(root_dir, config_file, File_system::READ_WRITE, false); file.construct(_fs.file(root_dir, config_file, File_system::READ_WRITE, false));
} catch (...) { } catch (...) {
error("could not open '", config_file, "'"); error("could not open '", config_file, "'");
return; return;
} }
char old_file[1024]; char old_file[1024];
size_t n = File_system::read(_fs, _file, old_file, size_t n = File_system::read(_fs, *file, old_file,
sizeof(old_file)); sizeof(old_file));
if (n == 0) { if (n == 0) {
error("could not read '", config_file, "'"); error("could not read '", config_file, "'");
@ -216,11 +217,11 @@ class Usb_filter::Device_registry
if (verbose) if (verbose)
log("new usb_drv configuration:\n", Cstring(new_file)); log("new usb_drv configuration:\n", Cstring(new_file));
n = File_system::write(_fs, _file, new_file, xml.used()); n = File_system::write(_fs, *file, new_file, xml.used());
if (n == 0) if (n == 0)
error("could not write '", config_file, "'"); error("could not write '", config_file, "'");
_fs.close(_file); _fs.close(*file);
} }
Genode::Signal_handler<Device_registry> _devices_handler = Genode::Signal_handler<Device_registry> _devices_handler =

View File

@ -51,16 +51,7 @@ class Vfs::Fs_file_system : public File_system
::File_system::Connection _fs; ::File_system::Connection _fs;
struct Fs_vfs_handle; typedef Genode::Id_space<::File_system::Node> Handle_space;
struct Handle_space : Genode::Id_space<Fs_vfs_handle>
{
struct Id : Genode::Id_space<Fs_vfs_handle>::Id
{
Id(unsigned long v) { value = v; }
Id(::File_system::Node_handle h) { value = h.value; }
};
};
Handle_space _handle_space; Handle_space _handle_space;
@ -77,19 +68,17 @@ class Vfs::Fs_file_system : public File_system
::File_system::Packet_descriptor queued_write_packet; ::File_system::Packet_descriptor queued_write_packet;
}; };
struct Fs_vfs_handle : Vfs_handle, Handle_space::Element, Handle_state struct Fs_vfs_handle : Vfs_handle, ::File_system::Node, Handle_space::Element, Handle_state
{ {
Handle_space::Id const id;
Fs_vfs_handle(File_system &fs, Allocator &alloc, int status_flags, Fs_vfs_handle(File_system &fs, Allocator &alloc, int status_flags,
Handle_space &space, Handle_space::Id id) Handle_space &space, Handle_space::Id id)
: :
Vfs_handle(fs, fs, alloc, status_flags), Vfs_handle(fs, fs, alloc, status_flags),
Handle_space::Element(*this, space, id), Handle_space::Element(*this, space, id)
id(id)
{ } { }
::File_system::File_handle file_handle() const { return id.value; } ::File_system::File_handle file_handle() const
{ return ::File_system::File_handle { id().value }; }
}; };
/** /**
@ -400,13 +389,13 @@ class Vfs::Fs_file_system : public File_system
if (strcmp(path, "") == 0) if (strcmp(path, "") == 0)
path = "/"; path = "/";
::File_system::Dir_handle dir_handle; Genode::Constructible<::File_system::Dir_handle> dir_handle;
try { dir_handle = _fs.dir(path, false); } try { dir_handle.construct(_fs.dir(path, false)); }
catch (::File_system::Lookup_failed) { return DIRENT_ERR_INVALID_PATH; } catch (::File_system::Lookup_failed) { return DIRENT_ERR_INVALID_PATH; }
catch (::File_system::Name_too_long) { return DIRENT_ERR_INVALID_PATH; } catch (::File_system::Name_too_long) { return DIRENT_ERR_INVALID_PATH; }
catch (...) { return DIRENT_ERR_NO_PERM; } catch (...) { return DIRENT_ERR_NO_PERM; }
Fs_handle_guard dir_guard(*this, _fs, dir_handle, _handle_space); Fs_handle_guard dir_guard(*this, _fs, *dir_handle, _handle_space);
Directory_entry entry; Directory_entry entry;
enum { DIRENT_SIZE = sizeof(Directory_entry) }; enum { DIRENT_SIZE = sizeof(Directory_entry) };

View File

@ -133,22 +133,22 @@ class Fs_log::Root_component :
Dir_handle dir_handle = ensure_dir(_fs, dir_path.base()); Dir_handle dir_handle = ensure_dir(_fs, dir_path.base());
Handle_guard dir_guard(_fs, dir_handle); Handle_guard dir_guard(_fs, dir_handle);
File_handle handle;
Genode::Constructible<File_handle> handle;
try { try {
handle = _fs.file(dir_handle, file_name, handle.construct(_fs.file(dir_handle, file_name,
File_system::WRITE_ONLY, false); File_system::WRITE_ONLY, false));
/* don't truncate at every new child session */ /* don't truncate at every new child session */
if (truncate && (strcmp(label_prefix, "") == 0)) if (truncate && (strcmp(label_prefix, "") == 0))
_fs.truncate(handle, 0); _fs.truncate(*handle, 0);
} }
catch (File_system::Lookup_failed) { catch (File_system::Lookup_failed) {
handle = _fs.file(dir_handle, file_name, handle.construct(_fs.file(dir_handle, file_name,
File_system::WRITE_ONLY, true); File_system::WRITE_ONLY, true));
} }
return new (md_alloc()) Session_component(_fs, handle, label_prefix); return new (md_alloc()) Session_component(_fs, *handle, label_prefix);
} }
catch (Permission_denied) { catch (Permission_denied) {
errstr = "permission denied"; } errstr = "permission denied"; }

View File

@ -65,7 +65,7 @@ class Fs_rom::Rom_session_component :
/** /**
* Handle of associated file * Handle of associated file
*/ */
File_system::File_handle _file_handle; Genode::Constructible<File_system::File_handle> _file_handle;
/** /**
* Size of current version of the file * Size of current version of the file
@ -83,7 +83,7 @@ class Fs_rom::Rom_session_component :
* The compund directory is watched only if the requested file could * The compund directory is watched only if the requested file could
* not be looked up. * not be looked up.
*/ */
File_system::Node_handle _compound_dir_handle; Genode::Constructible<File_system::Dir_handle> _compound_dir_handle;
/** /**
* Dataspace exposed as ROM module to the client * Dataspace exposed as ROM module to the client
@ -95,6 +95,11 @@ class Fs_rom::Rom_session_component :
*/ */
Genode::Signal_context_capability _sigh; Genode::Signal_context_capability _sigh;
/*
* Exception
*/
struct Open_compound_dir_failed { };
/** /**
* Open compound directory of specified file * Open compound directory of specified file
* *
@ -130,9 +135,14 @@ class Fs_rom::Rom_session_component :
*/ */
if (!walk_up) break; if (!walk_up) break;
} }
return Dir_handle(); /* invalid */ throw Open_compound_dir_failed();
} }
/*
* Exception
*/
struct Open_file_failed { };
/** /**
* Open file with specified name at the file system * Open file with specified name at the file system
*/ */
@ -141,17 +151,18 @@ class Fs_rom::Rom_session_component :
{ {
using namespace File_system; using namespace File_system;
File_system::File_handle file_handle;
try { try {
Dir_handle dir = _open_compound_dir(fs, path, false); Dir_handle dir = _open_compound_dir(fs, path, false);
try {
Handle_guard guard(fs, dir); Handle_guard guard(fs, dir);
/* open file */ /* open file */
Genode::Path<PATH_MAX_LEN> file_name(path.base()); Genode::Path<PATH_MAX_LEN> file_name(path.base());
file_name.keep_only_last_element(); file_name.keep_only_last_element();
file_handle = fs.file(dir, file_name.base() + 1, return fs.file(dir, file_name.base() + 1,
File_system::READ_ONLY, false); File_system::READ_ONLY, false);
} }
catch (Invalid_handle) { Genode::error(_file_path, ": Invalid_handle"); } catch (Invalid_handle) { Genode::error(_file_path, ": Invalid_handle"); }
@ -159,7 +170,11 @@ class Fs_rom::Rom_session_component :
catch (Lookup_failed) { Genode::error(_file_path, ": lookup_failed"); } catch (Lookup_failed) { Genode::error(_file_path, ": lookup_failed"); }
catch (...) { Genode::error(_file_path, ": unhandled error"); }; catch (...) { Genode::error(_file_path, ": unhandled error"); };
return file_handle; throw Open_file_failed();
} catch (Open_compound_dir_failed) {
throw Open_file_failed();
}
} }
void _register_for_compound_dir_changes() void _register_for_compound_dir_changes()
@ -167,19 +182,23 @@ class Fs_rom::Rom_session_component :
using namespace File_system; using namespace File_system;
/* forget about the previously watched compound directory */ /* forget about the previously watched compound directory */
if (_compound_dir_handle.valid()) if (_compound_dir_handle.constructed()) {
_fs.close(_compound_dir_handle); _fs.close(*_compound_dir_handle);
_compound_dir_handle.destruct();
}
_compound_dir_handle = _open_compound_dir(_fs, _file_path, true); try {
_compound_dir_handle.construct(_open_compound_dir(_fs, _file_path, true));
/* register for changes in compound directory */ /* register for changes in compound directory */
if (_compound_dir_handle.valid())
_fs.tx()->submit_packet(File_system::Packet_descriptor( _fs.tx()->submit_packet(File_system::Packet_descriptor(
_compound_dir_handle, *_compound_dir_handle,
File_system::Packet_descriptor::CONTENT_CHANGED)); File_system::Packet_descriptor::CONTENT_CHANGED));
else
} catch (Open_compound_dir_failed) {
Genode::warning("could not track compound dir, giving up"); Genode::warning("could not track compound dir, giving up");
} }
}
/** /**
* Initialize '_file_ds' dataspace with file content * Initialize '_file_ds' dataspace with file content
@ -194,9 +213,8 @@ class Fs_rom::Rom_session_component :
* content. The dataspace is re-allocated if the new version * content. The dataspace is re-allocated if the new version
* of the file has become bigger. * of the file has become bigger.
*/ */
{ try {
File_handle const file_handle = _open_file(_fs, _file_path); File_handle const file_handle = _open_file(_fs, _file_path);
if (file_handle.valid()) {
File_system::file_size_t const new_file_size = File_system::file_size_t const new_file_size =
_fs.status(file_handle).size; _fs.status(file_handle).size;
@ -206,30 +224,35 @@ class Fs_rom::Rom_session_component :
_file_size = 0; _file_size = 0;
_file_seek = 0; _file_seek = 0;
} }
}
_fs.close(file_handle); _fs.close(file_handle);
} } catch (Open_file_failed) { }
/* close and then re-open the file */ /* close and then re-open the file */
if (_file_handle.valid()) if (_file_handle.constructed()) {
_fs.close(_file_handle); _fs.close(*_file_handle);
_file_handle.destruct();
}
_file_handle = _open_file(_fs, _file_path); try {
_file_handle.construct(_open_file(_fs, _file_path));
} catch (Open_file_failed) { }
/* /*
* If we got the file, we can stop paying attention to the * If we got the file, we can stop paying attention to the
* compound directory. * compound directory.
*/ */
if (_file_handle.valid() && _compound_dir_handle.valid()) if (_file_handle.constructed() && _compound_dir_handle.constructed()) {
_fs.close(_compound_dir_handle); _fs.close(*_compound_dir_handle);
_compound_dir_handle.destruct();
}
/* register for file changes */ /* register for file changes */
if (_file_handle.valid()) if (_file_handle.constructed())
_fs.tx()->submit_packet(File_system::Packet_descriptor( _fs.tx()->submit_packet(File_system::Packet_descriptor(
_file_handle, File_system::Packet_descriptor::CONTENT_CHANGED)); *_file_handle, File_system::Packet_descriptor::CONTENT_CHANGED));
size_t const file_size = _file_handle.valid() size_t const file_size = _file_handle.constructed()
? _fs.status(_file_handle).size : 0; ? _fs.status(*_file_handle).size : 0;
/* allocate new RAM dataspace according to file size */ /* allocate new RAM dataspace according to file size */
if (file_size > 0) { if (file_size > 0) {
@ -255,7 +278,7 @@ class Fs_rom::Rom_session_component :
source.bulk_buffer_size() / 2); source.bulk_buffer_size() / 2);
File_system::Packet_descriptor File_system::Packet_descriptor
packet(source.alloc_packet(chunk_size), packet(source.alloc_packet(chunk_size),
_file_handle, *_file_handle,
File_system::Packet_descriptor::READ, File_system::Packet_descriptor::READ,
chunk_size, chunk_size,
_file_seek); _file_seek);
@ -284,10 +307,12 @@ class Fs_rom::Rom_session_component :
: :
_env(env), _fs(fs), _env(env), _fs(fs),
_file_path(file_path), _file_path(file_path),
_file_handle(_open_file(_fs, _file_path)),
_file_ds(env.ram(), env.rm(), 0) /* realloc later */ _file_ds(env.ram(), env.rm(), 0) /* realloc later */
{ {
if (!_file_handle.valid()) try {
_file_handle.construct(_open_file(_fs, _file_path));
} catch (Open_file_failed) { }
_register_for_compound_dir_changes(); _register_for_compound_dir_changes();
} }
@ -297,11 +322,11 @@ class Fs_rom::Rom_session_component :
~Rom_session_component() ~Rom_session_component()
{ {
/* close re-open the file */ /* close re-open the file */
if (_file_handle.valid()) if (_file_handle.constructed())
_fs.close(_file_handle); _fs.close(*_file_handle);
if (_compound_dir_handle.valid()) if (_compound_dir_handle.constructed())
_fs.close(_compound_dir_handle); _fs.close(*_compound_dir_handle);
} }
/** /**
@ -327,8 +352,8 @@ class Fs_rom::Rom_session_component :
switch (packet.operation()) { switch (packet.operation()) {
case File_system::Packet_descriptor::CONTENT_CHANGED: case File_system::Packet_descriptor::CONTENT_CHANGED:
if (_file_handle == packet.handle() || if ((_file_handle.constructed() && (*_file_handle == packet.handle())) ||
_compound_dir_handle == packet.handle()) (_compound_dir_handle.constructed() && (*_compound_dir_handle == packet.handle())))
{ {
if (_sigh.valid()) if (_sigh.valid())
Genode::Signal_transmitter(_sigh).submit(); Genode::Signal_transmitter(_sigh).submit();
@ -337,7 +362,7 @@ class Fs_rom::Rom_session_component :
return false; return false;
case File_system::Packet_descriptor::READ: { case File_system::Packet_descriptor::READ: {
if (_file_handle != packet.handle()) if (!(_file_handle.constructed() && (*_file_handle == packet.handle())))
return false; return false;
if (packet.position() > _file_seek || _file_seek >= _file_size) { if (packet.position() > _file_seek || _file_seek >= _file_size) {

View File

@ -5,6 +5,13 @@
* \date 2013-11-11 * \date 2013-11-11
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DIRECTORY_H_ #ifndef _DIRECTORY_H_
#define _DIRECTORY_H_ #define _DIRECTORY_H_
@ -19,13 +26,14 @@
#include <lx_util.h> #include <lx_util.h>
namespace File_system { namespace Lx_fs {
using namespace Genode; using namespace Genode;
using namespace File_system;
class Directory; class Directory;
} }
class File_system::Directory : public Node class Lx_fs::Directory : public Node
{ {
private: private:
@ -72,6 +80,16 @@ class File_system::Directory : public Node
return fd; return fd;
} }
size_t _num_entries() const
{
unsigned num = 0;
rewinddir(_fd);
while (readdir(_fd)) ++num;
return num;
}
public: public:
Directory(Allocator &alloc, char const *path, bool create) Directory(Allocator &alloc, char const *path, bool create)
@ -90,11 +108,10 @@ class File_system::Directory : public Node
} }
/* FIXME returned file node must be locked */ /* FIXME returned file node must be locked */
File * file(char const *name, Mode mode, bool create) File * file(char const *name, Mode mode, bool create) override
{ {
File *file = new (&_alloc) File(dirfd(_fd), name, mode, create); File *file = new (&_alloc) File(dirfd(_fd), name, mode, create);
file->lock();
return file; return file;
} }
@ -105,7 +122,6 @@ class File_system::Directory : public Node
Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create); Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create);
dir->lock();
return dir; return dir;
} }
@ -134,11 +150,10 @@ class File_system::Directory : public Node
else else
throw Lookup_failed(); throw Lookup_failed();
node->lock();
return node; return node;
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
if (len < sizeof(Directory_entry)) { if (len < sizeof(Directory_entry)) {
Genode::error("read buffer too small for directory entry"); Genode::error("read buffer too small for directory entry");
@ -177,20 +192,19 @@ class File_system::Directory : public Node
return sizeof(Directory_entry); return sizeof(Directory_entry);
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* writing to directory nodes is not supported */ /* writing to directory nodes is not supported */
return 0; return 0;
} }
size_t num_entries() const Status status() override
{ {
unsigned num = 0; Status s;
s.inode = inode();
rewinddir(_fd); s.size = _num_entries() * sizeof(File_system::Directory_entry);
while (readdir(_fd)) ++num; s.mode = File_system::Status::MODE_DIRECTORY;
return s;
return num;
} }
}; };

View File

@ -5,6 +5,13 @@
* \date 2013-11-11 * \date 2013-11-11
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_H_ #ifndef _FILE_H_
#define _FILE_H_ #define _FILE_H_
@ -13,12 +20,13 @@
#include <lx_util.h> #include <lx_util.h>
namespace File_system { namespace Lx_fs {
using namespace File_system;
class File; class File;
} }
class File_system::File : public Node class Lx_fs::File : public Node
{ {
private: private:
@ -74,6 +82,16 @@ class File_system::File : public Node
return fd; return fd;
} }
file_size_t _length() const
{
struct stat s;
if (fstat(_fd, &s) < 0)
return 0;
return s.st_size;
}
public: public:
File(int dir, File(int dir,
@ -95,14 +113,14 @@ class File_system::File : public Node
Node::name(basename(path)); Node::name(basename(path));
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
int ret = pread(_fd, dst, len, seek_offset); int ret = pread(_fd, dst, len, seek_offset);
return ret == -1 ? 0 : ret; return ret == -1 ? 0 : ret;
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* should we append? */ /* should we append? */
if (seek_offset == ~0ULL) { if (seek_offset == ~0ULL) {
@ -117,17 +135,16 @@ class File_system::File : public Node
return ret == -1 ? 0 : ret; return ret == -1 ? 0 : ret;
} }
file_size_t length() const Status status() override
{ {
struct stat s; Status s;
s.inode = inode();
if (fstat(_fd, &s) < 0) s.size = _length();
return 0; s.mode = File_system::Status::MODE_FILE;
return s;
return s.st_size;
} }
void truncate(file_size_t size) void truncate(file_size_t size) override
{ {
if (ftruncate(_fd, size)) /* nothing */; if (ftruncate(_fd, size)) /* nothing */;

View File

@ -16,7 +16,7 @@
#include <base/heap.h> #include <base/heap.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <root/component.h> #include <root/component.h>
#include <file_system/node_handle_registry.h> #include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <os/session_policy.h> #include <os/session_policy.h>
#include <util/xml_node.h> #include <util/xml_node.h>
@ -25,21 +25,28 @@
#include <directory.h> #include <directory.h>
namespace File_system { namespace Lx_fs {
using namespace File_system;
using File_system::Packet_descriptor;
using File_system::Path;
struct Main; struct Main;
struct Session_component; struct Session_component;
struct Root; struct Root;
} }
class File_system::Session_component : public Session_rpc_object class Lx_fs::Session_component : public Session_rpc_object
{ {
private: private:
typedef File_system::Open_node<Node> Open_node;
Genode::Env &_env; Genode::Env &_env;
Allocator &_md_alloc; Allocator &_md_alloc;
Directory &_root; Directory &_root;
Node_handle_registry _handle_registry; Id_space<File_system::Node> _open_node_registry;
bool _writable; bool _writable;
Signal_handler<Session_component> _process_packet_dispatcher; Signal_handler<Session_component> _process_packet_dispatcher;
@ -54,7 +61,7 @@ class File_system::Session_component : public Session_rpc_object
* *
* \return true on success, false on failure * \return true on success, false on failure
*/ */
void _process_packet_op(Packet_descriptor &packet, Node &node) void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{ {
void * const content = tx_sink()->packet_content(packet); void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length(); size_t const length = packet.length();
@ -66,18 +73,18 @@ class File_system::Session_component : public Session_rpc_object
case Packet_descriptor::READ: case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.read((char *)content, length, packet.position()); res_length = open_node.node().read((char *)content, length, packet.position());
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.write((char const *)content, length, packet.position()); res_length = open_node.node().write((char const *)content, length, packet.position());
break; break;
case Packet_descriptor::CONTENT_CHANGED: case Packet_descriptor::CONTENT_CHANGED:
_handle_registry.register_notify(*tx_sink(), packet.handle()); open_node.register_notify(*tx_sink());
/* notify_listeners may bounce the packet back*/ /* notify_listeners may bounce the packet back*/
node.notify_listeners(); open_node.node().notify_listeners();
/* otherwise defer acknowledgement of this packet */ /* otherwise defer acknowledgement of this packet */
return; return;
@ -98,13 +105,16 @@ class File_system::Session_component : public Session_rpc_object
/* assume failure by default */ /* assume failure by default */
packet.succeeded(false); packet.succeeded(false);
try { auto process_packet_fn = [&] (Open_node &open_node) {
Node *node = _handle_registry.lookup_and_lock(packet.handle()); _process_packet_op(packet, open_node);
Node_lock_guard guard(node); };
_process_packet_op(packet, *node); try {
_open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle");
tx_sink()->acknowledge_packet(packet);
} }
catch (Invalid_handle) { Genode::error("Invalid_handle"); }
} }
/** /**
@ -191,23 +201,35 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string())) if (!valid_name(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); auto file_fn = [&] (Open_node &open_node) {
Node_lock_guard dir_guard(dir);
Node &dir = open_node.node();
if (!_writable) if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY)) if (create || (mode != STAT_ONLY && mode != READ_ONLY))
throw Permission_denied(); throw Permission_denied();
File *file = dir->file(name.string(), mode, create); File *file = dir.file(name.string(), mode, create);
Node_lock_guard file_guard(file); Open_node *open_file =
return _handle_registry.alloc(file); new (_md_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
{ {
Genode::error(__func__, " not implemented"); Genode::error(__func__, " not implemented");
return Symlink_handle(); throw Permission_denied();
} }
Dir_handle dir(Path const &path, bool create) Dir_handle dir(Path const &path, bool create)
@ -226,8 +248,11 @@ class File_system::Session_component : public Session_rpc_object
throw Name_too_long(); throw Name_too_long();
Directory *dir = _root.subdir(path_str, create); Directory *dir = _root.subdir(path_str, create);
Node_lock_guard guard(dir);
return _handle_registry.alloc(dir); Open_node *open_dir =
new (_md_alloc) Open_node(*dir, _open_node_registry);
return Dir_handle { open_dir->id().value };
} }
Node_handle node(Path const &path) Node_handle node(Path const &path)
@ -238,43 +263,38 @@ class File_system::Session_component : public Session_rpc_object
Node *node = _root.node(path_str + 1); Node *node = _root.node(path_str + 1);
Node_lock_guard guard(node); Open_node *open_node =
return _handle_registry.alloc(node); new (_md_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
} }
void close(Node_handle handle) void close(Node_handle handle)
{ {
/* FIXME when to destruct node? */ auto close_fn = [&] (Open_node &open_node) {
_handle_registry.free(handle); Node &node = open_node.node();
destroy(_md_alloc, &open_node);
destroy(_md_alloc, &node);
};
try {
_open_node_registry.apply<Open_node>(handle, close_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup_and_lock(node_handle); auto status_fn = [&] (Open_node &open_node) {
Node_lock_guard guard(node); return open_node.node().status();
};
Status s; try {
s.inode = node->inode(); return _open_node_registry.apply<Open_node>(node_handle, status_fn);
s.size = 0; } catch (Id_space<File_system::Node>::Unknown_id const &) {
s.mode = 0; throw Invalid_handle();
File *file = dynamic_cast<File *>(node);
if (file) {
s.size = file->length();
s.mode = File_system::Status::MODE_FILE;
return s;
} }
Directory *dir = dynamic_cast<Directory *>(node);
if (dir) {
s.size = dir->num_entries()*sizeof(Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
Genode::error(__func__, " for symlinks not implemented");
return Status();
} }
void control(Node_handle, Control) void control(Node_handle, Control)
@ -292,9 +312,15 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
File *file = _handle_registry.lookup_and_lock(file_handle); auto truncate_fn = [&] (Open_node &open_node) {
Node_lock_guard file_guard(file); open_node.node().truncate(size);
file->truncate(size); };
try {
_open_node_registry.apply<Open_node>(file_handle, truncate_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void move(Dir_handle, Name const &, Dir_handle, Name const &) void move(Dir_handle, Name const &, Dir_handle, Name const &)
@ -311,7 +337,7 @@ class File_system::Session_component : public Session_rpc_object
}; };
class File_system::Root : public Root_component<Session_component> class Lx_fs::Root : public Root_component<Session_component>
{ {
private: private:
@ -419,7 +445,7 @@ class File_system::Root : public Root_component<Session_component>
}; };
struct File_system::Main struct Lx_fs::Main
{ {
Genode::Env &env; Genode::Env &env;
@ -434,4 +460,4 @@ struct File_system::Main
}; };
void Component::construct(Genode::Env &env) { static File_system::Main inst(env); } void Component::construct(Genode::Env &env) { static Lx_fs::Main inst(env); }

View File

@ -5,17 +5,27 @@
* \date 2013-11-11 * \date 2013-11-11
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NODE_H_ #ifndef _NODE_H_
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <file_system/listener.h>
#include <file_system/node.h> #include <file_system/node.h>
namespace File_system { namespace Lx_fs {
using namespace File_system;
class Node;
class File;
}
class Node : public Node_base class Lx_fs::Node : public File_system::Node_base
{ {
public: public:
@ -40,8 +50,25 @@ namespace File_system {
virtual size_t read(char *dst, size_t len, seek_off_t) = 0; virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0; virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
};
virtual Status status() = 0;
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
} }
/*
* Directory functionality
*/
virtual File *file(char const *name, Mode mode, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
};
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -7,6 +7,13 @@
* FIXME unfinished * FIXME unfinished
*/ */
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SYMLINK_H_ #ifndef _SYMLINK_H_
#define _SYMLINK_H_ #define _SYMLINK_H_
@ -26,18 +33,20 @@ class File_system::Symlink : public Node
char _link_to[MAX_PATH_LEN]; char _link_to[MAX_PATH_LEN];
file_size_t _length() const { return strlen(_link_to) + 1; }
public: public:
Symlink(char const *name) { Node::name(name); } Symlink(char const *name) { Node::name(name); }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
size_t count = min(len, sizeof(_link_to) + 1); size_t count = min(len, sizeof(_link_to) + 1);
Genode::strncpy(dst, _link_to, count); Genode::strncpy(dst, _link_to, count);
return count; return count;
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* Ideal symlink operations are atomic. */ /* Ideal symlink operations are atomic. */
if (seek_offset) return 0; if (seek_offset) return 0;
@ -47,7 +56,14 @@ class File_system::Symlink : public Node
return count; return count;
} }
file_size_t length() const { return strlen(_link_to) + 1; } Status status() override
{
Status s;
s.inode = inode();
s.size = _length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
}; };
#endif /* _SYMLINK_H_ */ #endif /* _SYMLINK_H_ */

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (C) 2011-2017 Genode Labs GmbH * Copyright (C) 2012-2017 Genode Labs GmbH
* *
* This file is part of the Genode OS framework, which is distributed * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
@ -18,32 +18,32 @@
#include <file_system/util.h> #include <file_system/util.h>
/* local includes */ /* local includes */
#include <ram_fs/node.h> #include "node.h"
#include <ram_fs/file.h> #include "file.h"
#include <ram_fs/symlink.h> #include "symlink.h"
namespace File_system { class Directory; } namespace Ram_fs { class Directory; }
class File_system::Directory : public Node class Ram_fs::Directory : public Node
{ {
private: private:
List<Node> _entries; List<Node> _entries;
size_t _num_entries; size_t _num_entries;
public: Node *_entry_unsynchronized(size_t index)
Directory(char const *name) : _num_entries(0) { Node::name(name); }
Node *entry_unsynchronized(size_t index)
{ {
Node *node = _entries.first(); Node *node = _entries.first();
for (unsigned i = 0; i < index && node; node = node->next(), i++); for (unsigned i = 0; i < index && node; node = node->next(), i++);
return node; return node;
} }
bool has_sub_node_unsynchronized(char const *name) const public:
Directory(char const *name) : _num_entries(0) { Node::name(name); }
bool has_sub_node_unsynchronized(char const *name) const override
{ {
Node const *sub_node = _entries.first(); Node const *sub_node = _entries.first();
for (; sub_node; sub_node = sub_node->next()) for (; sub_node; sub_node = sub_node->next())
@ -53,7 +53,7 @@ class File_system::Directory : public Node
return false; return false;
} }
void adopt_unsynchronized(Node *node) void adopt_unsynchronized(Node *node) override
{ {
/* /*
* XXX inc ref counter * XXX inc ref counter
@ -64,7 +64,7 @@ class File_system::Directory : public Node
mark_as_updated(); mark_as_updated();
} }
void discard_unsynchronized(Node *node) void discard(Node *node) override
{ {
_entries.remove(node); _entries.remove(node);
_num_entries--; _num_entries--;
@ -72,15 +72,14 @@ class File_system::Directory : public Node
mark_as_updated(); mark_as_updated();
} }
Node *lookup_and_lock(char const *path, bool return_parent = false) Node *lookup(char const *path, bool return_parent = false) override
{ {
if (strcmp(path, "") == 0) { if (strcmp(path, "") == 0) {
lock();
return this; return this;
} }
if (!path || path[0] == '/') if (!path || path[0] == '/')
throw Lookup_failed(); throw File_system::Lookup_failed();
/* find first path delimiter */ /* find first path delimiter */
unsigned i = 0; unsigned i = 0;
@ -91,7 +90,6 @@ class File_system::Directory : public Node
* specified path. * specified path.
*/ */
if (path[i] == 0 && return_parent) { if (path[i] == 0 && return_parent) {
lock();
return this; return this;
} }
@ -109,16 +107,15 @@ class File_system::Directory : public Node
break; break;
if (!sub_node) if (!sub_node)
throw Lookup_failed(); throw File_system::Lookup_failed();
if (!contains_path_delimiter(path)) { if (!File_system::contains_path_delimiter(path)) {
/* /*
* Because 'path' is a basename that corresponds to an * Because 'path' is a basename that corresponds to an
* existing sub_node, we have found what we were looking * existing sub_node, we have found what we were looking
* for. * for.
*/ */
sub_node->lock();
return sub_node; return sub_node;
} }
@ -134,59 +131,58 @@ class File_system::Directory : public Node
*/ */
Directory *sub_dir = dynamic_cast<Directory *>(sub_node); Directory *sub_dir = dynamic_cast<Directory *>(sub_node);
if (!sub_dir) if (!sub_dir)
throw Lookup_failed(); throw File_system::Lookup_failed();
return sub_dir->lookup_and_lock(path + i + 1, return_parent); return sub_dir->lookup(path + i + 1, return_parent);
} }
Directory *lookup_and_lock_dir(char const *path) Directory *lookup_dir(char const *path)
{ {
Node *node = lookup_and_lock(path); Node *node = lookup(path);
Directory *dir = dynamic_cast<Directory *>(node); Directory *dir = dynamic_cast<Directory *>(node);
if (dir) if (dir)
return dir; return dir;
node->unlock(); throw File_system::Lookup_failed();
throw Lookup_failed();
} }
File *lookup_and_lock_file(char const *path) File *lookup_file(char const *path) override
{ {
Node *node = lookup_and_lock(path); Node *node = lookup(path);
File *file = dynamic_cast<File *>(node); File *file = dynamic_cast<File *>(node);
if (file) if (file)
return file; return file;
node->unlock(); throw File_system::Lookup_failed();
throw Lookup_failed();
} }
Symlink *lookup_and_lock_symlink(char const *path) Symlink *lookup_symlink(char const *path)
{ {
Node *node = lookup_and_lock(path); Node *node = lookup(path);
Symlink *symlink = dynamic_cast<Symlink *>(node); Symlink *symlink = dynamic_cast<Symlink *>(node);
if (symlink) if (symlink)
return symlink; return symlink;
node->unlock(); throw File_system::Lookup_failed();
throw Lookup_failed();
} }
/** /**
* Lookup parent directory of the specified path * Lookup parent directory of the specified path
* *
* \throw Lookup_failed * \throw File_system::Lookup_failed
*/ */
Directory *lookup_and_lock_parent(char const *path) Directory *lookup_parent(char const *path)
{ {
return static_cast<Directory *>(lookup_and_lock(path, true)); return static_cast<Directory *>(lookup(path, true));
} }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
using File_system::Directory_entry;
if (len < sizeof(Directory_entry)) { if (len < sizeof(Directory_entry)) {
Genode::error("read buffer too small for directory entry"); Genode::error("read buffer too small for directory entry");
return 0; return 0;
@ -199,7 +195,7 @@ class File_system::Directory : public Node
return 0; return 0;
} }
Node *node = entry_unsynchronized(index); Node *node = _entry_unsynchronized(index);
/* index out of range */ /* index out of range */
if (!node) if (!node)
@ -218,13 +214,20 @@ class File_system::Directory : public Node
return sizeof(Directory_entry); return sizeof(Directory_entry);
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* writing to directory nodes is not supported */ /* writing to directory nodes is not supported */
return 0; return 0;
} }
size_t num_entries() const { return _num_entries; } Status status() override
{
Status s;
s.inode = inode();
s.size = _num_entries * sizeof(File_system::Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
}; };
#endif /* _INCLUDE__RAM_FS__DIRECTORY_H_ */ #endif /* _INCLUDE__RAM_FS__DIRECTORY_H_ */

View File

@ -19,13 +19,20 @@
#include <base/allocator.h> #include <base/allocator.h>
/* local includes */ /* local includes */
#include <ram_fs/node.h>
#include <ram_fs/chunk.h> #include <ram_fs/chunk.h>
#include "node.h"
namespace File_system { class File; } namespace Ram_fs
{
using File_system::Chunk;
using File_system::Chunk_index;
using File_system::file_size_t;
using File_system::SEEK_TAIL;
class File;
}
class File_system::File : public Node class Ram_fs::File : public Node
{ {
private: private:
@ -43,7 +50,7 @@ class File_system::File : public Node
File(Allocator &alloc, char const *name) File(Allocator &alloc, char const *name)
: _chunk(alloc, 0), _length(0) { Node::name(name); } : _chunk(alloc, 0), _length(0) { Node::name(name); }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
file_size_t const chunk_used_size = _chunk.used_size(); file_size_t const chunk_used_size = _chunk.used_size();
@ -79,7 +86,7 @@ class File_system::File : public Node
return len; return len;
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
if (seek_offset == SEEK_TAIL) if (seek_offset == SEEK_TAIL)
seek_offset = _length; seek_offset = _length;
@ -102,9 +109,16 @@ class File_system::File : public Node
return len; return len;
} }
file_size_t length() const { return _length; } Status status() override
{
Status s;
s.inode = inode();
s.size = _length;
s.mode = File_system::Status::MODE_FILE;
return s;
}
void truncate(file_size_t size) void truncate(file_size_t size) override
{ {
if (size < _chunk.used_size()) if (size < _chunk.used_size())
_chunk.truncate(size); _chunk.truncate(size);

View File

@ -12,7 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h> #include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <base/component.h> #include <base/component.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
@ -21,14 +21,18 @@
#include <os/session_policy.h> #include <os/session_policy.h>
/* local includes */ /* local includes */
#include <ram_fs/directory.h> #include "directory.h"
/************************* /*************************
** File-system service ** ** File-system service **
*************************/ *************************/
namespace File_system { namespace Ram_fs {
using namespace File_system;
using File_system::Packet_descriptor;
using File_system::Path;
class Session_component; class Session_component;
class Root; class Root;
@ -36,15 +40,17 @@ namespace File_system {
}; };
class File_system::Session_component : public Session_rpc_object class Ram_fs::Session_component : public File_system::Session_rpc_object
{ {
private: private:
typedef File_system::Open_node<Node> Open_node;
Genode::Entrypoint &_ep; Genode::Entrypoint &_ep;
Genode::Ram_session &_ram; Genode::Ram_session &_ram;
Genode::Allocator &_alloc; Genode::Allocator &_alloc;
Directory &_root; Directory &_root;
Node_handle_registry _handle_registry; Id_space<File_system::Node> _open_node_registry;
bool _writable; bool _writable;
Signal_handler<Session_component> _process_packet_handler; Signal_handler<Session_component> _process_packet_handler;
@ -59,7 +65,7 @@ class File_system::Session_component : public Session_rpc_object
* *
* \return true on success, false on failure * \return true on success, false on failure
*/ */
void _process_packet_op(Packet_descriptor &packet, Node &node) void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{ {
void * const content = tx_sink()->packet_content(packet); void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length(); size_t const length = packet.length();
@ -71,17 +77,17 @@ class File_system::Session_component : public Session_rpc_object
case Packet_descriptor::READ: case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.read((char *)content, length, packet.position()); res_length = open_node.node().read((char *)content, length, packet.position());
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.write((char const *)content, length, packet.position()); res_length = open_node.node().write((char const *)content, length, packet.position());
break; break;
case Packet_descriptor::CONTENT_CHANGED: case Packet_descriptor::CONTENT_CHANGED:
_handle_registry.register_notify(*tx_sink(), packet.handle()); open_node.register_notify(*tx_sink());
node.notify_listeners(); open_node.node().notify_listeners();
return; return;
case Packet_descriptor::READ_READY: case Packet_descriptor::READ_READY:
@ -101,13 +107,13 @@ class File_system::Session_component : public Session_rpc_object
/* assume failure by default */ /* assume failure by default */
packet.succeeded(false); packet.succeeded(false);
try { auto process_packet_fn = [&] (Open_node &open_node) {
Node *node = _handle_registry.lookup_and_lock(packet.handle()); _process_packet_op(packet, open_node);
Node_lock_guard guard(node); };
_process_packet_op(packet, *node); try {
} _open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
catch (Invalid_handle) { } catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle"); Genode::error("Invalid_handle");
tx_sink()->acknowledge_packet(packet); tx_sink()->acknowledge_packet(packet);
} }
@ -193,8 +199,9 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string())) if (!valid_name(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); auto file_fn = [&] (Open_node &open_node) {
Node_lock_guard dir_guard(dir);
Node &dir = open_node.node();
if (!_writable) if (!_writable)
if (mode != STAT_ONLY && mode != READ_ONLY) if (mode != STAT_ONLY && mode != READ_ONLY)
@ -205,21 +212,33 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
if (dir->has_sub_node_unsynchronized(name.string())) if (dir.has_sub_node_unsynchronized(name.string()))
throw Node_already_exists(); throw Node_already_exists();
try { try {
File * const file = new (_alloc) File * const file = new (_alloc)
File(_alloc, name.string()); File(_alloc, name.string());
dir->adopt_unsynchronized(file); dir.adopt_unsynchronized(file);
} }
catch (Allocator::Out_of_memory) { throw No_space(); } catch (Allocator::Out_of_memory) { throw No_space(); }
} }
File *file = dir->lookup_and_lock_file(name.string()); File *file = dir.lookup_file(name.string());
Node_lock_guard file_guard(file);
return _handle_registry.alloc(file); Open_node *open_file =
new (_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
@ -227,29 +246,42 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(name.string())) if (!valid_name(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); auto symlink_fn = [&] (Open_node &open_node) {
Node_lock_guard dir_guard(dir);
Node &dir = open_node.node();
if (create) { if (create) {
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
if (dir->has_sub_node_unsynchronized(name.string())) if (dir.has_sub_node_unsynchronized(name.string()))
throw Node_already_exists(); throw Node_already_exists();
try { try {
Symlink * const symlink = new (_alloc) Symlink * const symlink = new (_alloc)
Symlink(name.string()); Symlink(name.string());
dir->adopt_unsynchronized(symlink); dir.adopt_unsynchronized(symlink);
} }
catch (Allocator::Out_of_memory) { throw No_space(); } catch (Allocator::Out_of_memory) { throw No_space(); }
} }
Symlink *symlink = dir->lookup_and_lock_symlink(name.string()); Symlink *symlink = dir.lookup_symlink(name.string());
Node_lock_guard file_guard(symlink);
return _handle_registry.alloc(symlink); Open_node *open_symlink =
new (_alloc) Open_node(*symlink, _open_node_registry);
return open_symlink->id();
};
try {
return Symlink_handle {
_open_node_registry.apply<Open_node>(dir_handle, symlink_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Dir_handle dir(Path const &path, bool create) Dir_handle dir(Path const &path, bool create)
@ -269,9 +301,7 @@ class File_system::Session_component : public Session_rpc_object
if (!path.valid_string()) if (!path.valid_string())
throw Name_too_long(); throw Name_too_long();
Directory *parent = _root.lookup_and_lock_parent(path_str); Directory *parent = _root.lookup_parent(path_str);
Node_lock_guard guard(parent);
char const *name = basename(path_str); char const *name = basename(path_str);
@ -285,55 +315,61 @@ class File_system::Session_component : public Session_rpc_object
} }
} }
Directory *dir = _root.lookup_and_lock_dir(path_str); Directory *dir = _root.lookup_dir(path_str);
Node_lock_guard guard(dir);
return _handle_registry.alloc(dir); Open_node *open_dir =
new (_alloc) Open_node(*dir, _open_node_registry);
return Dir_handle { open_dir->id().value };
} }
Node_handle node(Path const &path) Node_handle node(Path const &path)
{ {
_assert_valid_path(path.string()); _assert_valid_path(path.string());
Node *node = _root.lookup_and_lock(path.string() + 1); Node *node = _root.lookup(path.string() + 1);
Node_lock_guard guard(node); Open_node *open_node =
return _handle_registry.alloc(node); new (_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
} }
void close(Node_handle handle) void close(Node_handle handle)
{ {
_handle_registry.free(handle); auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
/*
* Notify listeners about the changed file.
*/
node.notify_listeners();
/*
* De-allocate handle
*/
destroy(_alloc, &open_node);
};
try {
_open_node_registry.apply<Open_node>(handle, close_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup_and_lock(node_handle); auto status_fn = [&] (Open_node &open_node) {
Node_lock_guard guard(node); return open_node.node().status();
};
Status s; try {
s.inode = node->inode(); return _open_node_registry.apply<Open_node>(node_handle, status_fn);
s.size = 0; } catch (Id_space<File_system::Node>::Unknown_id const &) {
s.mode = 0; throw Invalid_handle();
File *file = dynamic_cast<File *>(node);
if (file) {
s.size = file->length();
s.mode = File_system::Status::MODE_FILE;
return s;
} }
Directory *dir = dynamic_cast<Directory *>(node);
if (dir) {
s.size = dir->num_entries()*sizeof(Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
Symlink *symlink = dynamic_cast<Symlink *>(node);
if (symlink) {
s.size = symlink->length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
return Status();
} }
void control(Node_handle, Control) { } void control(Node_handle, Control) { }
@ -346,18 +382,25 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); auto unlink_fn = [&] (Open_node &open_node) {
Node_lock_guard dir_guard(dir);
Node *node = dir->lookup_and_lock(name.string()); Node &dir = open_node.node();
dir->discard_unsynchronized(node); Node *node = dir.lookup(name.string());
dir.discard(node);
// XXX implement ref counting, do not destroy node that is // XXX implement ref counting, do not destroy node that is
// is still referenced by a node handle // is still referenced by a node handle
node->unlock();
destroy(_alloc, node); destroy(_alloc, node);
};
try {
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void truncate(File_handle file_handle, file_size_t size) void truncate(File_handle file_handle, file_size_t size)
@ -365,9 +408,15 @@ class File_system::Session_component : public Session_rpc_object
if (!_writable) if (!_writable)
throw Permission_denied(); throw Permission_denied();
File *file = _handle_registry.lookup_and_lock(file_handle); auto truncate_fn = [&] (Open_node &open_node) {
Node_lock_guard file_guard(file); open_node.node().truncate(size);
file->truncate(size); };
try {
_open_node_registry.apply<Open_node>(file_handle, truncate_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void move(Dir_handle from_dir_handle, Name const &from_name, void move(Dir_handle from_dir_handle, Name const &from_name,
@ -382,19 +431,21 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_name(to_name.string())) if (!valid_name(to_name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *from_dir = _handle_registry.lookup_and_lock(from_dir_handle); auto move_fn = [&] (Open_node &open_from_dir_node) {
Node_lock_guard from_dir_guard(from_dir);
Node *node = from_dir->lookup_and_lock(from_name.string()); auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
Node_lock_guard node_guard(node);
Node &from_dir = open_from_dir_node.node();
Node *node = from_dir.lookup(from_name.string());
node->name(to_name.string()); node->name(to_name.string());
if (!_handle_registry.refer_to_same_node(from_dir_handle, to_dir_handle)) { Node &to_dir = open_to_dir_node.node();
Directory *to_dir = _handle_registry.lookup_and_lock(to_dir_handle);
Node_lock_guard to_dir_guard(to_dir);
from_dir->discard_unsynchronized(node); if (&to_dir != &from_dir) {
to_dir->adopt_unsynchronized(node);
from_dir.discard(node);
to_dir.adopt_unsynchronized(node);
/* /*
* If the file was moved from one directory to another we * If the file was moved from one directory to another we
@ -402,27 +453,47 @@ class File_system::Session_component : public Session_rpc_object
* directory 'from_dir' will always get notified (i.e., * directory 'from_dir' will always get notified (i.e.,
* when just the file name was changed) below. * when just the file name was changed) below.
*/ */
to_dir->mark_as_updated(); to_dir.mark_as_updated();
to_dir->notify_listeners(); to_dir.notify_listeners();
}
from_dir->mark_as_updated(); from_dir.mark_as_updated();
from_dir->notify_listeners(); from_dir.notify_listeners();
node->mark_as_updated(); node->mark_as_updated();
node->notify_listeners(); node->notify_listeners();
} }
};
try {
_open_node_registry.apply<Open_node>(to_dir_handle, inner_move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
};
try {
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
void sync(Node_handle handle) override void sync(Node_handle handle) override
{ {
Node *node = _handle_registry.lookup_and_lock(handle); auto sync_fn = [&] (Open_node &open_node) {
Node_lock_guard guard(node); open_node.node().notify_listeners();
node->notify_listeners(); };
try {
_open_node_registry.apply<Open_node>(handle, sync_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
}; };
class File_system::Root : public Root_component<Session_component> class Ram_fs::Root : public Root_component<Session_component>
{ {
private: private:
@ -493,9 +564,8 @@ class File_system::Root : public Root_component<Session_component>
* delimiter. For performing the lookup, we skip the first * delimiter. For performing the lookup, we skip the first
* character. * character.
*/ */
session_root_dir = _root_dir.lookup_and_lock_dir( session_root_dir = _root_dir.lookup_dir(
session_root.base() + 1); session_root.base() + 1);
session_root_dir->unlock();
} }
catch (Lookup_failed) { throw Service_denied(); } catch (Lookup_failed) { throw Service_denied(); }
} }
@ -588,7 +658,7 @@ struct Attribute_string
static void preload_content(Genode::Env &env, static void preload_content(Genode::Env &env,
Genode::Allocator &alloc, Genode::Allocator &alloc,
Genode::Xml_node node, Genode::Xml_node node,
File_system::Directory &dir) Ram_fs::Directory &dir)
{ {
using namespace File_system; using namespace File_system;
@ -606,7 +676,7 @@ static void preload_content(Genode::Env &env,
*/ */
if (sub_node.has_type("dir")) { if (sub_node.has_type("dir")) {
Directory *sub_dir = new (&alloc) Directory(name); Ram_fs::Directory *sub_dir = new (&alloc) Ram_fs::Directory(name);
/* traverse into the new directory */ /* traverse into the new directory */
preload_content(env, alloc, sub_node, *sub_dir); preload_content(env, alloc, sub_node, *sub_dir);
@ -626,7 +696,7 @@ static void preload_content(Genode::Env &env,
try { try {
Attached_rom_dataspace rom(env, name); Attached_rom_dataspace rom(env, name);
File *file = new (&alloc) File(alloc, as); Ram_fs::File *file = new (&alloc) Ram_fs::File(alloc, as);
file->write(rom.local_addr<char>(), rom.size(), 0); file->write(rom.local_addr<char>(), rom.size(), 0);
dir.adopt_unsynchronized(file); dir.adopt_unsynchronized(file);
} }
@ -641,7 +711,7 @@ static void preload_content(Genode::Env &env,
*/ */
if (sub_node.has_type("inline")) { if (sub_node.has_type("inline")) {
File *file = new (&alloc) File(alloc, name); Ram_fs::File *file = new (&alloc) Ram_fs::File(alloc, name);
file->write(sub_node.content_addr(), sub_node.content_size(), 0); file->write(sub_node.content_addr(), sub_node.content_size(), 0);
dir.adopt_unsynchronized(file); dir.adopt_unsynchronized(file);
} }
@ -649,7 +719,7 @@ static void preload_content(Genode::Env &env,
} }
struct File_system::Main struct Ram_fs::Main
{ {
Genode::Env &_env; Genode::Env &_env;
@ -679,4 +749,4 @@ struct File_system::Main
}; };
void Component::construct(Genode::Env &env) { static File_system::Main inst(env); } void Component::construct(Genode::Env &env) { static Ram_fs::Main inst(env); }

View File

@ -0,0 +1,120 @@
/*
* \brief File-system node
* \author Norman Feske
* \date 2012-04-11
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__RAM_FS__NODE_H_
#define _INCLUDE__RAM_FS__NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system/node.h>
#include <util/list.h>
namespace Ram_fs {
using namespace Genode;
using File_system::seek_off_t;
using File_system::Status;
class Node;
class File;
class Symlink;
}
class Ram_fs::Node : public File_system::Node_base, public List<Node>::Element
{
public:
typedef char Name[128];
private:
int _ref_count;
Name _name;
unsigned long const _inode;
/**
* Generate unique inode number
*/
static unsigned long _unique_inode()
{
static unsigned long inode_count;
return ++inode_count;
}
public:
Node()
: _ref_count(0), _inode(_unique_inode())
{ _name[0] = 0; }
unsigned long inode() const { return _inode; }
char const *name() const { return _name; }
/**
* Assign name
*/
void name(char const *name) { strncpy(_name, name, sizeof(_name)); }
virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
virtual Status status() = 0;
/* File functionality */
virtual void truncate(File_system::file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
/* Directory functionality */
virtual bool has_sub_node_unsynchronized(char const *name) const
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return false;
}
virtual void adopt_unsynchronized(Node *node)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
}
virtual File *lookup_file(char const *path)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual Symlink *lookup_symlink(char const *path)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual Node *lookup(char const *path, bool return_parent = false)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual void discard(Node *node)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
}
};
#endif /* _INCLUDE__RAM_FS__NODE_H_ */

View File

@ -15,30 +15,30 @@
#define _INCLUDE__RAM_FS__SYMLINK_H_ #define _INCLUDE__RAM_FS__SYMLINK_H_
/* local includes */ /* local includes */
#include <ram_fs/node.h> #include "node.h"
namespace File_system { class Symlink; } namespace Ram_fs { class Symlink; }
class File_system::Symlink : public Node class Ram_fs::Symlink : public Node
{ {
private: private:
char _link_to[MAX_PATH_LEN]; char _link_to[File_system::MAX_PATH_LEN];
size_t _len; size_t _len;
public: public:
Symlink(char const *name): _len(0) { Node::name(name); } Symlink(char const *name): _len(0) { Node::name(name); }
size_t read(char *dst, size_t len, seek_off_t seek_offset) size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{ {
size_t count = min(len, _len-seek_offset); size_t count = min(len, _len-seek_offset);
Genode::memcpy(dst, _link_to+seek_offset, count); Genode::memcpy(dst, _link_to+seek_offset, count);
return count; return count;
} }
size_t write(char const *src, size_t len, seek_off_t seek_offset) size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{ {
/* Ideal symlink operations are atomic. */ /* Ideal symlink operations are atomic. */
if (seek_offset) return 0; if (seek_offset) return 0;
@ -48,7 +48,14 @@ class File_system::Symlink : public Node
return _len; return _len;
} }
file_size_t length() const { return _len; } Status status() override
{
Status s;
s.inode = inode();
s.size = _len;
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
}; };
#endif /* _INCLUDE__RAM_FS__SYMLINK_H_ */ #endif /* _INCLUDE__RAM_FS__SYMLINK_H_ */

View File

@ -4,6 +4,13 @@
* \date 2012-04-11 * \date 2012-04-11
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DIRECTORY_H_ #ifndef _DIRECTORY_H_
#define _DIRECTORY_H_ #define _DIRECTORY_H_
@ -15,9 +22,11 @@
#include <file.h> #include <file.h>
#include <symlink.h> #include <symlink.h>
namespace File_system { namespace Trace_fs {
class Directory;
}
class Directory : public Node class Trace_fs::Directory : public Node
{ {
private: private:
@ -86,7 +95,7 @@ namespace File_system {
* \return node node founc * \return node node founc
* \throws Lookup_failed * \throws Lookup_failed
*/ */
Node *lookup(char const *path, bool return_parent = false) Node *lookup(char const *path, bool return_parent = false) override
{ {
if (strcmp(path, "") == 0) { if (strcmp(path, "") == 0) {
return this; return this;
@ -209,6 +218,5 @@ namespace File_system {
return s; return s;
} }
}; };
}
#endif /* _DIRECTORY_H_ */ #endif /* _DIRECTORY_H_ */

View File

@ -23,13 +23,17 @@
#include <node.h> #include <node.h>
#include <chunk.h> #include <chunk.h>
namespace File_system { namespace Trace_fs {
class Changeable_content;
class File;
class Buffered_file;
}
/** /**
* *
* *
*/ */
class Changeable_content class Trace_fs::Changeable_content
{ {
protected: protected:
@ -78,7 +82,7 @@ namespace File_system {
* File interface * File interface
*/ */
class File : public Node class Trace_fs::File : public Node
{ {
public: public:
@ -114,7 +118,7 @@ namespace File_system {
* This file merely exists in memory and grows automatically. * This file merely exists in memory and grows automatically.
*/ */
class Buffered_file : public File class Trace_fs::Buffered_file : public File
{ {
private: private:
@ -202,7 +206,7 @@ namespace File_system {
virtual file_size_t length() const { return _length; } virtual file_size_t length() const { return _length; }
void truncate(file_size_t size) void truncate(file_size_t size) override
{ {
if (size < _chunk.used_size()) if (size < _chunk.used_size())
_chunk.truncate(size); _chunk.truncate(size);
@ -212,6 +216,5 @@ namespace File_system {
mark_as_updated(); mark_as_updated();
} }
}; };
}
#endif /* _FILE_H_ */ #endif /* _FILE_H_ */

View File

@ -22,10 +22,12 @@
#include <trace_files.h> #include <trace_files.h>
namespace Trace_fs { namespace Trace_fs {
typedef Genode::size_t size_t; typedef Genode::size_t size_t;
class Followed_subject;
class Followed_subject_registry;
}
struct Followed_subject : public File_system::Directory class Trace_fs::Followed_subject : public Directory
{ {
public: public:
@ -93,12 +95,12 @@ namespace Trace_fs {
public: public:
File_system::Active_file active_file; Active_file active_file;
File_system::Buffer_size_file buffer_size_file; Buffer_size_file buffer_size_file;
File_system::Cleanup_file cleanup_file; Cleanup_file cleanup_file;
File_system::Enable_file enable_file; Enable_file enable_file;
File_system::Events_file events_file; Events_file events_file;
File_system::Policy_file policy_file; Policy_file policy_file;
Followed_subject(Genode::Allocator &md_alloc, char const *name, Followed_subject(Genode::Allocator &md_alloc, char const *name,
Genode::Region_map &rm, Genode::Region_map &rm,
@ -172,7 +174,7 @@ namespace Trace_fs {
/** /**
* This registry contains all current followed trace subjects * This registry contains all current followed trace subjects
*/ */
class Followed_subject_registry class Trace_fs::Followed_subject_registry
{ {
public: public:
@ -277,6 +279,5 @@ namespace Trace_fs {
throw Invalid_subject(); throw Invalid_subject();
} }
}; };
}
#endif /* _SUBJECT_REGISTRY_H_ */ #endif /* _SUBJECT_REGISTRY_H_ */

View File

@ -13,7 +13,7 @@
/* Genode includes */ /* Genode includes */
#include <base/component.h> #include <base/component.h>
#include <file_system/node_handle_registry.h> #include <file_system/open_node.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h> #include <base/attached_rom_dataspace.h>
#include <os/session_policy.h> #include <os/session_policy.h>
@ -33,6 +33,18 @@
#include <trace_files.h> #include <trace_files.h>
namespace Trace_fs {
using File_system::Packet_descriptor;
using File_system::Path;
class Trace_file_system;
struct Main;
struct Session_component;
struct Root;
}
/** /**
* Return true if 'str' is a valid file name * Return true if 'str' is a valid file name
*/ */
@ -59,7 +71,7 @@ static inline bool valid_filename(char const *str)
* needed, refreshing their content or deleting them if they are no * needed, refreshing their content or deleting them if they are no
* longer of any use. * longer of any use.
*/ */
class Trace_file_system class Trace_fs::Trace_file_system
{ {
private: private:
@ -70,13 +82,6 @@ class Trace_file_system
typedef Genode::Trace::Subject_info Subject_info; typedef Genode::Trace::Subject_info Subject_info;
typedef Genode::Trace::Connection Trace; typedef Genode::Trace::Connection Trace;
typedef Trace_fs::Followed_subject_registry Followed_subject_registry;
typedef Trace_fs::Followed_subject Followed_subject;
typedef File_system::Directory Directory;
typedef File_system::Node Node;
/** /**
* Simple node list * Simple node list
* *
@ -95,9 +100,9 @@ class Trace_file_system
*/ */
struct Node_list_entry : public Genode::List<Node_list_entry>::Element struct Node_list_entry : public Genode::List<Node_list_entry>::Element
{ {
File_system::Node *node; Node *node;
Node_list_entry(File_system::Node *n) : node(n) { } Node_list_entry(Node *n) : node(n) { }
}; };
Genode::Allocator &_md_alloc; Genode::Allocator &_md_alloc;
@ -598,22 +603,17 @@ class Trace_file_system
}; };
namespace File_system { class Trace_fs::Session_component : public Session_rpc_object
struct Main;
struct Session_component;
struct Root;
}
class File_system::Session_component : public Session_rpc_object
{ {
private: private:
typedef File_system::Open_node<Node> Open_node;
Genode::Entrypoint &_ep; Genode::Entrypoint &_ep;
Ram_session &_ram; Ram_session &_ram;
Allocator &_md_alloc; Allocator &_md_alloc;
Directory &_root_dir; Directory &_root_dir;
Node_handle_registry _handle_registry; Id_space<File_system::Node> _open_node_registry;
bool _writeable; bool _writeable;
unsigned _subject_limit; unsigned _subject_limit;
@ -647,7 +647,7 @@ class File_system::Session_component : public Session_rpc_object
/** /**
* Perform packet operation * Perform packet operation
*/ */
void _process_packet_op(Packet_descriptor &packet, Node &node) void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{ {
void * const content = tx_sink()->packet_content(packet); void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length(); size_t const length = packet.length();
@ -659,18 +659,18 @@ class File_system::Session_component : public Session_rpc_object
case Packet_descriptor::READ: case Packet_descriptor::READ:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.read((char *)content, length, packet.position()); res_length = open_node.node().read((char *)content, length, packet.position());
break; break;
case Packet_descriptor::WRITE: case Packet_descriptor::WRITE:
if (content && (packet.length() <= packet.size())) if (content && (packet.length() <= packet.size()))
res_length = node.write((char const *)content, length, packet.position()); res_length = open_node.node().write((char const *)content, length, packet.position());
break; break;
case Packet_descriptor::CONTENT_CHANGED: case Packet_descriptor::CONTENT_CHANGED:
_handle_registry.register_notify(*tx_sink(), packet.handle()); open_node.register_notify(*tx_sink());
/* notify_listeners may bounce the packet back*/ /* notify_listeners may bounce the packet back*/
node.notify_listeners(); open_node.node().notify_listeners();
/* otherwise defer acknowledgement of this packet */ /* otherwise defer acknowledgement of this packet */
return; return;
@ -691,11 +691,15 @@ class File_system::Session_component : public Session_rpc_object
/* assume failure by default */ /* assume failure by default */
packet.succeeded(false); packet.succeeded(false);
auto process_packet_fn = [&] (Open_node &open_node) {
_process_packet_op(packet, open_node);
};
try { try {
Node *node = _handle_registry.lookup(packet.handle()); _open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
_process_packet_op(packet, *node); } catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle");
} }
catch (Invalid_handle) { Genode::error("Invalid_handle"); }
/* /*
* The 'acknowledge_packet' function cannot block because we * The 'acknowledge_packet' function cannot block because we
@ -753,7 +757,7 @@ class File_system::Session_component : public Session_rpc_object
Genode::Ram_session &ram, Genode::Ram_session &ram,
Genode::Region_map &rm, Genode::Region_map &rm,
Genode::Env &env, Genode::Env &env,
File_system::Directory &root_dir, Directory &root_dir,
Allocator &md_alloc, Allocator &md_alloc,
unsigned subject_limit, unsigned subject_limit,
unsigned poll_interval, unsigned poll_interval,
@ -814,22 +818,36 @@ class File_system::Session_component : public Session_rpc_object
if (!valid_filename(name.string())) if (!valid_filename(name.string()))
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup(dir_handle); auto file_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node();
if (create) if (create)
throw Permission_denied(); throw Permission_denied();
File *file = dynamic_cast<File*>(dir->lookup(name.string())); File *file = dynamic_cast<File*>(dir.lookup(name.string()));
if (!file) if (!file)
throw Invalid_name(); throw Invalid_name();
return _handle_registry.alloc(file); Open_node *open_file =
new (_md_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
{ {
Genode::warning("symlinks not supported"); Genode::warning("symlinks not supported");
return Symlink_handle(); throw Permission_denied();
} }
Dir_handle dir(Path const &path, bool create) Dir_handle dir(Path const &path, bool create)
@ -848,7 +866,10 @@ class File_system::Session_component : public Session_rpc_object
if (!dir) if (!dir)
throw Invalid_name(); throw Invalid_name();
return _handle_registry.alloc(dir); Open_node *open_dir =
new (_md_alloc) Open_node(*dir, _open_node_registry);
return Dir_handle { open_dir->id().value };
} }
Node_handle node(Path const &path) Node_handle node(Path const &path)
@ -859,40 +880,61 @@ class File_system::Session_component : public Session_rpc_object
Node *node = _root_dir.lookup(path_str + 1); Node *node = _root_dir.lookup(path_str + 1);
return _handle_registry.alloc(node); Open_node *open_node =
new (_md_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
} }
void close(Node_handle handle) void close(Node_handle handle)
{ {
Node *node; auto close_fn = [&] (Open_node &open_node) {
try { node = _handle_registry.lookup(handle); } Node &node = open_node.node();
catch (Invalid_handle) {
Genode::error("close() called with invalid handle");
return;
}
/** /**
* Acknowledge the change of the content of files which may be * Acknowledge the change of the content of files which may be
* modified by the user of the file system. * modified by the user of the file system.
*/ */
Changeable_content *changeable = dynamic_cast<Changeable_content*>(node); Changeable_content *changeable = dynamic_cast<Changeable_content*>(&node);
if (changeable) { if (changeable) {
if (changeable->changed()) { if (changeable->changed()) {
changeable->acknowledge_change(); changeable->acknowledge_change();
/* let the trace fs perform the provoked actions */ /* let the trace fs perform the provoked actions */
_trace_fs->handle_changed_node(node); _trace_fs->handle_changed_node(&node);
} }
} }
_handle_registry.free(handle); /*
* Notify listeners about the changed file.
*/
node.notify_listeners();
/*
* De-allocate handle
*/
destroy(_md_alloc, &open_node);
};
try {
_open_node_registry.apply<Open_node>(handle, close_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup(node_handle); auto status_fn = [&] (Open_node &open_node) {
return node->status(); return open_node.node().status();
};
try {
return _open_node_registry.apply<Open_node>(node_handle, status_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
} }
void control(Node_handle, Control) { } void control(Node_handle, Control) { }
@ -900,22 +942,22 @@ class File_system::Session_component : public Session_rpc_object
void truncate(File_handle handle, file_size_t size) void truncate(File_handle handle, file_size_t size)
{ {
Node *node; auto truncate_fn = [&] (Open_node &open_node) {
open_node.node().truncate(size);
};
try { try {
node = _handle_registry.lookup(handle); _open_node_registry.apply<Open_node>(handle, truncate_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
File *file = dynamic_cast<File*>(node); throw Invalid_handle();
if (file) { file->truncate(size); }
} }
catch (Invalid_handle) { }
} }
void move(Dir_handle, Name const &, Dir_handle, Name const &) { } void move(Dir_handle, Name const &, Dir_handle, Name const &) { }
}; };
class File_system::Root : public Root_component<Session_component> class Trace_fs::Root : public Root_component<Session_component>
{ {
private: private:
@ -1055,7 +1097,7 @@ class File_system::Root : public Root_component<Session_component>
}; };
struct File_system::Main struct Trace_fs::Main
{ {
Env &_env; Env &_env;
@ -1074,4 +1116,4 @@ struct File_system::Main
} }
}; };
void Component::construct(Genode::Env &env) { static File_system::Main main(env); } void Component::construct(Genode::Env &env) { static Trace_fs::Main main(env); }

View File

@ -4,6 +4,13 @@
* \date 2012-04-11 * \date 2012-04-11
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NODE_H_ #ifndef _NODE_H_
#define _NODE_H_ #define _NODE_H_
@ -13,11 +20,13 @@
#include <base/lock.h> #include <base/lock.h>
#include <base/signal.h> #include <base/signal.h>
namespace File_system { namespace Trace_fs {
using namespace File_system;
using namespace Genode; using namespace Genode;
class Node;
}
class Node : public Node_base, public List<Node>::Element class Trace_fs::Node : public Node_base, public List<Node>::Element
{ {
public: public:
@ -55,7 +64,23 @@ namespace File_system {
virtual size_t read(char *dst, size_t len, seek_off_t) = 0; virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0; virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
};
/*
* Directory functionality
*/
virtual Node *lookup(char const *path, bool return_parent = false)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
} }
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
};
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -4,15 +4,24 @@
* \date 2012-04-11 * \date 2012-04-11
*/ */
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SYMLINK_H_ #ifndef _SYMLINK_H_
#define _SYMLINK_H_ #define _SYMLINK_H_
/* local includes */ /* local includes */
#include <file.h> #include <file.h>
namespace File_system { namespace Trace_fs {
class Symlink;
}
class Symlink : public File class Trace_fs::Symlink : public File
{ {
public: public:
@ -28,6 +37,5 @@ namespace File_system {
void truncate(file_size_t) { } void truncate(file_size_t) { }
}; };
}
#endif /* _SYMLINK_H_ */ #endif /* _SYMLINK_H_ */

View File

@ -21,7 +21,15 @@
#include <file.h> #include <file.h>
namespace File_system { namespace Trace_fs {
class State_file;
class Active_file;
class Cleanup_file;
class Enable_file;
class Events_file;
class Buffer_size_file;
class Policy_file;
}
/** /**
* The State_file is a stateful file that is used to implement * The State_file is a stateful file that is used to implement
@ -29,7 +37,7 @@ namespace File_system {
* file system backend. * file system backend.
*/ */
class State_file : public File, class Trace_fs::State_file : public File,
public Changeable_content public Changeable_content
{ {
protected: protected:
@ -122,7 +130,7 @@ namespace File_system {
* The Active_file node shows the state of the tracing * The Active_file node shows the state of the tracing
*/ */
class Active_file : public State_file class Trace_fs::Active_file : public State_file
{ {
private: private:
@ -149,7 +157,7 @@ namespace File_system {
* the traced subject and to free utilized memory. * the traced subject and to free utilized memory.
*/ */
class Cleanup_file : public State_file class Trace_fs::Cleanup_file : public State_file
{ {
private: private:
@ -171,7 +179,7 @@ namespace File_system {
* The Enable_file is used to initiate the tracing process * The Enable_file is used to initiate the tracing process
*/ */
class Enable_file : public State_file class Trace_fs::Enable_file : public State_file
{ {
private: private:
@ -193,7 +201,7 @@ namespace File_system {
* The Events_file encapsulates the trace buffer of traced thread * The Events_file encapsulates the trace buffer of traced thread
*/ */
class Events_file : public Buffered_file class Trace_fs::Events_file : public Buffered_file
{ {
private: private:
@ -229,7 +237,7 @@ namespace File_system {
* This file contains the size of the trace buffer * This file contains the size of the trace buffer
*/ */
class Buffer_size_file : public File, class Trace_fs::Buffer_size_file : public File,
public Changeable_content public Changeable_content
{ {
private: private:
@ -376,7 +384,7 @@ namespace File_system {
* Policy file * Policy file
*/ */
class Policy_file : public Buffered_file, class Trace_fs::Policy_file : public Buffered_file,
public Changeable_content public Changeable_content
{ {
private: private:
@ -427,6 +435,4 @@ namespace File_system {
}; };
}
#endif /* _TRACE_FILES_H_ */ #endif /* _TRACE_FILES_H_ */

View File

@ -94,16 +94,17 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
* \throw Invalid_handle * \throw Invalid_handle
*/ */
template <typename HANDLE_TYPE, typename FUNC> template <typename HANDLE_TYPE, typename FUNC>
void _apply(HANDLE_TYPE handle, FUNC const &fn) auto _apply(HANDLE_TYPE handle, FUNC const &fn)
-> typename Genode::Trait::Functor<decltype(&FUNC::operator())>::Return_type
{ {
Node_space::Id id { handle.value }; Node_space::Id id { handle.value };
try { _node_space.apply<Node>(id, [&] (Node &node) { try { return _node_space.apply<Node>(id, [&] (Node &node) {
typedef typename Node_type<HANDLE_TYPE>::Type Typed_node; typedef typename Node_type<HANDLE_TYPE>::Type Typed_node;
Typed_node *n = dynamic_cast<Typed_node *>(&node); Typed_node *n = dynamic_cast<Typed_node *>(&node);
if (!n) if (!n)
throw Invalid_handle(); throw Invalid_handle();
fn(*n); return fn(*n);
}); } catch (Node_space::Unknown_id) { throw Invalid_handle(); } }); } catch (Node_space::Unknown_id) { throw Invalid_handle(); }
} }
@ -385,7 +386,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
if (file.notify_read_ready() && file.read_ready() if (file.notify_read_ready() && file.read_ready()
&& tx_sink()->ready_to_ack()) { && tx_sink()->ready_to_ack()) {
Packet_descriptor packet(Packet_descriptor(), Packet_descriptor packet(Packet_descriptor(),
Node_handle(file.id().value), Node_handle { file.id().value },
Packet_descriptor::READ_READY, Packet_descriptor::READ_READY,
0, 0); 0, 0);
tx_sink()->acknowledge_packet(packet); tx_sink()->acknowledge_packet(packet);
@ -431,33 +432,29 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
if ((create || (fs_mode & WRITE_ONLY)) && (!_writable)) if ((create || (fs_mode & WRITE_ONLY)) && (!_writable))
throw Permission_denied(); throw Permission_denied();
File_handle new_handle; return _apply(dir_handle, [&] (Directory &dir) {
_apply(dir_handle, [&] (Directory &dir) {
char const *name_str = name.string(); char const *name_str = name.string();
_assert_valid_name(name_str); _assert_valid_name(name_str);
new_handle = dir.file( return File_handle {
_node_space, _vfs, _alloc, *this, name_str, fs_mode, create).value; dir.file(_node_space, _vfs, _alloc, *this, name_str, fs_mode, create).value
};
}); });
return new_handle;
} }
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) override Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) override
{ {
if (create && !_writable) throw Permission_denied(); if (create && !_writable) throw Permission_denied();
Symlink_handle new_handle; return _apply(dir_handle, [&] (Directory &dir) {
_apply(dir_handle, [&] (Directory &dir) {
char const *name_str = name.string(); char const *name_str = name.string();
_assert_valid_name(name_str); _assert_valid_name(name_str);
new_handle = dir.symlink( return Symlink_handle {dir.symlink(
_node_space, _vfs, _alloc, name_str, _node_space, _vfs, _alloc, name_str,
_writable ? READ_WRITE : READ_ONLY, create).value; _writable ? READ_WRITE : READ_ONLY, create).value
};
}); });
return new_handle;
} }
Node_handle node(File_system::Path const &path) override Node_handle node(File_system::Path const &path) override
@ -465,7 +462,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
char const *path_str = path.string(); char const *path_str = path.string();
/* '/' is bound to '0' */ /* '/' is bound to '0' */
if (!strcmp(path_str, "/")) if (!strcmp(path_str, "/"))
return Node_handle(0); return Node_handle { 0 };
_assert_valid_path(path_str); _assert_valid_path(path_str);
@ -480,7 +477,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
try { node = new (_alloc) Node(_node_space, path_str, STAT_ONLY); } try { node = new (_alloc) Node(_node_space, path_str, STAT_ONLY); }
catch (Out_of_memory) { throw Out_of_ram(); } catch (Out_of_memory) { throw Out_of_ram(); }
return Node_handle(node->id().value); return Node_handle { node->id().value };
} }
void close(Node_handle handle) override void close(Node_handle handle) override