mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 15:18:20 +00:00
committed by
Christian Helmuth
parent
0d1be4abe2
commit
6a43f3c11a
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,20 +30,26 @@
|
|||||||
#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:
|
||||||
|
|
||||||
Allocator &_md_alloc;
|
typedef File_system::Open_node<Node> Open_node;
|
||||||
Directory &_root;
|
|
||||||
Node_handle_registry _handle_registry;
|
Allocator &_md_alloc;
|
||||||
bool _writable;
|
Directory &_root;
|
||||||
|
Id_space<File_system::Node> _open_node_registry;
|
||||||
|
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) {
|
||||||
|
|
||||||
if (!_writable)
|
Node &dir = open_node.node();
|
||||||
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
|
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
File *file = dir->file(name.string(), mode, create);
|
if (!_writable)
|
||||||
return _handle_registry.alloc(file);
|
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
|
||||||
|
throw Permission_denied();
|
||||||
|
|
||||||
|
File *file = dir.file(name.string(), mode, create);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
if (create && !_writable)
|
Node &dir = open_node.node();
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
Symlink *link = dir->symlink(name.string(), create);
|
if (create && !_writable)
|
||||||
return _handle_registry.alloc(link);
|
throw Permission_denied();
|
||||||
|
|
||||||
|
Symlink *link = dir.symlink(name.string(), create);
|
||||||
|
|
||||||
|
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();
|
||||||
try {
|
destroy(_md_alloc, &open_node);
|
||||||
node = _handle_registry.lookup(handle);
|
destroy(_md_alloc, &node);
|
||||||
} catch (Invalid_handle) { return; }
|
};
|
||||||
|
|
||||||
_handle_registry.free(handle);
|
try {
|
||||||
/* destruct node */
|
_open_node_registry.apply<Open_node>(handle, close_fn);
|
||||||
if (node)
|
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||||
destroy(&_md_alloc, node);
|
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) {
|
||||||
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,41 +363,59 @@ class File_system::Session_component : public Session_rpc_object
|
|||||||
if (!_writable)
|
if (!_writable)
|
||||||
throw Permission_denied();
|
throw Permission_denied();
|
||||||
|
|
||||||
char const *from_str = from_name.string();
|
auto move_fn = [&] (Open_node &open_from_dir_node) {
|
||||||
char const *to_str = to_name.string();
|
|
||||||
|
|
||||||
if (!(valid_name(from_str) && valid_name(to_str)))
|
auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
|
||||||
throw Lookup_failed();
|
|
||||||
|
|
||||||
Directory *from_dir = _handle_registry.lookup(from_dir_handle);
|
Node &from_dir = open_from_dir_node.node();
|
||||||
Directory *to_dir = _handle_registry.lookup( to_dir_handle);
|
Node &to_dir = open_to_dir_node.node();
|
||||||
|
|
||||||
if (rump_sys_renameat(from_dir->fd(), from_str,
|
char const *from_str = from_name.string();
|
||||||
to_dir->fd(), to_str) == 0) {
|
char const *to_str = to_name.string();
|
||||||
from_dir->mark_as_updated();
|
|
||||||
from_dir->notify_listeners();
|
if (!(valid_name(from_str) && valid_name(to_str)))
|
||||||
if (!_handle_registry.refer_to_same_node(from_dir_handle,
|
throw Lookup_failed();
|
||||||
to_dir_handle)) {
|
|
||||||
to_dir->mark_as_updated();
|
if (rump_sys_renameat(from_dir.fd(), from_str,
|
||||||
to_dir->notify_listeners();
|
to_dir.fd(), to_str) == 0) {
|
||||||
|
from_dir.mark_as_updated();
|
||||||
|
from_dir.notify_listeners();
|
||||||
|
if (&from_dir != &to_dir) {
|
||||||
|
to_dir.mark_as_updated();
|
||||||
|
to_dir.notify_listeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (errno) {
|
||||||
|
case ENOTEMPTY: throw Node_already_exists();
|
||||||
|
case ENOENT: throw Lookup_failed();
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str);
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return;
|
try {
|
||||||
|
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
|
||||||
|
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||||
|
throw Invalid_handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (errno) {
|
|
||||||
case ENOTEMPTY: throw Node_already_exists();
|
|
||||||
case ENOENT: throw Lookup_failed();
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str);
|
|
||||||
throw Permission_denied();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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_ */
|
||||||
|
@ -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];
|
||||||
|
@ -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,101 +23,101 @@ 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:
|
||||||
|
|
||||||
Ffat::DIR _ffat_dir;
|
Ffat::DIR _ffat_dir;
|
||||||
int64_t _prev_index;
|
int64_t _prev_index;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Directory(const char *name)
|
Directory(const char *name)
|
||||||
: Node(name),
|
: Node(name),
|
||||||
_prev_index(-1) { }
|
_prev_index(-1) { }
|
||||||
|
|
||||||
void ffat_dir(Ffat::DIR ffat_dir) { _ffat_dir = ffat_dir; }
|
void ffat_dir(Ffat::DIR ffat_dir) { _ffat_dir = ffat_dir; }
|
||||||
Ffat::DIR *ffat_dir() { return &_ffat_dir; }
|
Ffat::DIR *ffat_dir() { return &_ffat_dir; }
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (len < sizeof(Directory_entry)) {
|
if (len < sizeof(Directory_entry)) {
|
||||||
error("read buffer too small for directory entry");
|
error("read buffer too small for directory entry");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seek_offset % sizeof(Directory_entry)) {
|
|
||||||
error("seek offset not alighed to sizeof(Directory_entry)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Directory_entry *e = (Directory_entry *)(dst);
|
|
||||||
|
|
||||||
using namespace Ffat;
|
|
||||||
|
|
||||||
FILINFO ffat_file_info;
|
|
||||||
ffat_file_info.lfname = e->name;
|
|
||||||
ffat_file_info.lfsize = sizeof(e->name);
|
|
||||||
|
|
||||||
int64_t index = seek_offset / sizeof(Directory_entry);
|
|
||||||
|
|
||||||
if (index != (_prev_index + 1)) {
|
|
||||||
/* rewind and iterate from the beginning */
|
|
||||||
f_readdir(&_ffat_dir, 0);
|
|
||||||
for (int i = 0; i < index; i++)
|
|
||||||
f_readdir(&_ffat_dir, &ffat_file_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
_prev_index = index;
|
|
||||||
|
|
||||||
FRESULT res = f_readdir(&_ffat_dir, &ffat_file_info);
|
|
||||||
switch(res) {
|
|
||||||
case FR_OK:
|
|
||||||
break;
|
|
||||||
case FR_INVALID_OBJECT:
|
|
||||||
error("f_readdir() failed with error code FR_INVALID_OBJECT");
|
|
||||||
return 0;
|
|
||||||
case FR_DISK_ERR:
|
|
||||||
error("f_readdir() failed with error code FR_DISK_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_INT_ERR:
|
|
||||||
error("f_readdir() failed with error code FR_INT_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_NOT_READY:
|
|
||||||
error("f_readdir() failed with error code FR_NOT_READY");
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
/* not supposed to occur according to the libffat documentation */
|
|
||||||
error("f_readdir() returned an unexpected error code");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ffat_file_info.fname[0] == 0) { /* no (more) entries */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->name[0] == 0) /* use short file name */
|
|
||||||
strncpy(e->name, ffat_file_info.fname, sizeof(e->name));
|
|
||||||
|
|
||||||
if ((ffat_file_info.fattrib & AM_DIR) == AM_DIR)
|
|
||||||
e->type = Directory_entry::TYPE_DIRECTORY;
|
|
||||||
else
|
|
||||||
e->type = Directory_entry::TYPE_FILE;
|
|
||||||
|
|
||||||
return sizeof(Directory_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t)
|
|
||||||
{
|
|
||||||
/* writing to directory nodes is not supported */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
if (seek_offset % sizeof(Directory_entry)) {
|
||||||
}
|
error("seek offset not alighed to sizeof(Directory_entry)");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory_entry *e = (Directory_entry *)(dst);
|
||||||
|
|
||||||
|
using namespace Ffat;
|
||||||
|
|
||||||
|
FILINFO ffat_file_info;
|
||||||
|
ffat_file_info.lfname = e->name;
|
||||||
|
ffat_file_info.lfsize = sizeof(e->name);
|
||||||
|
|
||||||
|
int64_t index = seek_offset / sizeof(Directory_entry);
|
||||||
|
|
||||||
|
if (index != (_prev_index + 1)) {
|
||||||
|
/* rewind and iterate from the beginning */
|
||||||
|
f_readdir(&_ffat_dir, 0);
|
||||||
|
for (int i = 0; i < index; i++)
|
||||||
|
f_readdir(&_ffat_dir, &ffat_file_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
_prev_index = index;
|
||||||
|
|
||||||
|
FRESULT res = f_readdir(&_ffat_dir, &ffat_file_info);
|
||||||
|
switch(res) {
|
||||||
|
case FR_OK:
|
||||||
|
break;
|
||||||
|
case FR_INVALID_OBJECT:
|
||||||
|
error("f_readdir() failed with error code FR_INVALID_OBJECT");
|
||||||
|
return 0;
|
||||||
|
case FR_DISK_ERR:
|
||||||
|
error("f_readdir() failed with error code FR_DISK_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_INT_ERR:
|
||||||
|
error("f_readdir() failed with error code FR_INT_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_NOT_READY:
|
||||||
|
error("f_readdir() failed with error code FR_NOT_READY");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* not supposed to occur according to the libffat documentation */
|
||||||
|
error("f_readdir() returned an unexpected error code");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ffat_file_info.fname[0] == 0) { /* no (more) entries */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->name[0] == 0) /* use short file name */
|
||||||
|
strncpy(e->name, ffat_file_info.fname, sizeof(e->name));
|
||||||
|
|
||||||
|
if ((ffat_file_info.fattrib & AM_DIR) == AM_DIR)
|
||||||
|
e->type = Directory_entry::TYPE_DIRECTORY;
|
||||||
|
else
|
||||||
|
e->type = Directory_entry::TYPE_FILE;
|
||||||
|
|
||||||
|
return sizeof(Directory_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(char const *src, size_t len, seek_off_t)
|
||||||
|
{
|
||||||
|
/* writing to directory nodes is not supported */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _DIRECTORY_H_ */
|
#endif /* _DIRECTORY_H_ */
|
||||||
|
@ -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,140 +23,236 @@ namespace Ffat { extern "C" {
|
|||||||
#include <node.h>
|
#include <node.h>
|
||||||
|
|
||||||
|
|
||||||
namespace File_system {
|
namespace Ffat_fs {
|
||||||
|
class File;
|
||||||
class File : public Node
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Ffat::FIL _ffat_fil;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
File(const char *name) : Node(name) { }
|
|
||||||
|
|
||||||
void ffat_fil(Ffat::FIL ffat_fil) { _ffat_fil = ffat_fil; }
|
|
||||||
Ffat::FIL *ffat_fil() { return &_ffat_fil; }
|
|
||||||
|
|
||||||
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
using namespace Ffat;
|
|
||||||
|
|
||||||
UINT result;
|
|
||||||
|
|
||||||
if (seek_offset == (seek_off_t)(~0))
|
|
||||||
seek_offset = _ffat_fil.fsize;
|
|
||||||
|
|
||||||
FRESULT res = f_lseek(&_ffat_fil, seek_offset);
|
|
||||||
|
|
||||||
switch(res) {
|
|
||||||
case FR_OK:
|
|
||||||
break;
|
|
||||||
case FR_INVALID_OBJECT:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT");
|
|
||||||
return 0;
|
|
||||||
case FR_DISK_ERR:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_DISK_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_INT_ERR:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_INT_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_NOT_READY:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_NOT_READY");
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
/* not supposed to occur according to the libffat documentation */
|
|
||||||
Genode::error("f_lseek() returned an unexpected error code");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = f_read(&_ffat_fil, dst, len, &result);
|
|
||||||
|
|
||||||
switch(res) {
|
|
||||||
case FR_OK:
|
|
||||||
return result;
|
|
||||||
case FR_DENIED:
|
|
||||||
Genode::warning("f_read() failed with error code FR_DENIED");
|
|
||||||
return 0;
|
|
||||||
case FR_INVALID_OBJECT:
|
|
||||||
Genode::error("f_read() failed with error code FR_INVALID_OBJECT");
|
|
||||||
return 0;
|
|
||||||
case FR_DISK_ERR:
|
|
||||||
Genode::error("f_read() failed with error code FR_DISK_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_INT_ERR:
|
|
||||||
Genode::error("f_read() failed with error code FR_INT_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_NOT_READY:
|
|
||||||
Genode::error("f_read() failed with error code FR_NOT_READY");
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
/* not supposed to occur according to the libffat documentation */
|
|
||||||
Genode::error("f_read() returned an unexpected error code");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
using namespace Ffat;
|
|
||||||
|
|
||||||
UINT result;
|
|
||||||
|
|
||||||
if (seek_offset == (seek_off_t)(~0))
|
|
||||||
seek_offset = _ffat_fil.fsize;
|
|
||||||
|
|
||||||
FRESULT res = f_lseek(&_ffat_fil, seek_offset);
|
|
||||||
|
|
||||||
switch(res) {
|
|
||||||
case FR_OK:
|
|
||||||
break;
|
|
||||||
case FR_INVALID_OBJECT:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT");
|
|
||||||
return 0;
|
|
||||||
case FR_DISK_ERR:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_DISK_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_INT_ERR:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_INT_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_NOT_READY:
|
|
||||||
Genode::error("f_lseek() failed with error code FR_NOT_READY");
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
/* not supposed to occur according to the libffat documentation */
|
|
||||||
Genode::error("f_lseek() returned an unexpected error code");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = f_write(&_ffat_fil, src, len, &result);
|
|
||||||
|
|
||||||
switch(res) {
|
|
||||||
case FR_OK:
|
|
||||||
return result;
|
|
||||||
case FR_DENIED:
|
|
||||||
Genode::error("f_write() failed with error code FR_DENIED");
|
|
||||||
return 0;
|
|
||||||
case FR_INVALID_OBJECT:
|
|
||||||
Genode::error("f_write() failed with error code FR_INVALID_OBJECT");
|
|
||||||
return 0;
|
|
||||||
case FR_DISK_ERR:
|
|
||||||
Genode::error("f_write() failed with error code FR_DISK_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_INT_ERR:
|
|
||||||
Genode::error("f_write() failed with error code FR_INT_ERR");
|
|
||||||
return 0;
|
|
||||||
case FR_NOT_READY:
|
|
||||||
Genode::error("f_write() failed with error code FR_NOT_READY");
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
/* not supposed to occur according to the libffat documentation */
|
|
||||||
Genode::error("f_write() returned an unexpected error code");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Ffat_fs::File : public Node
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Ffat::FIL _ffat_fil;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
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; }
|
||||||
|
Ffat::FIL *ffat_fil() { return &_ffat_fil; }
|
||||||
|
|
||||||
|
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
|
||||||
|
{
|
||||||
|
using namespace Ffat;
|
||||||
|
|
||||||
|
UINT result;
|
||||||
|
|
||||||
|
if (seek_offset == (seek_off_t)(~0))
|
||||||
|
seek_offset = _ffat_fil.fsize;
|
||||||
|
|
||||||
|
FRESULT res = f_lseek(&_ffat_fil, seek_offset);
|
||||||
|
|
||||||
|
switch(res) {
|
||||||
|
case FR_OK:
|
||||||
|
break;
|
||||||
|
case FR_INVALID_OBJECT:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT");
|
||||||
|
return 0;
|
||||||
|
case FR_DISK_ERR:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_DISK_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_INT_ERR:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_INT_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_NOT_READY:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_NOT_READY");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* not supposed to occur according to the libffat documentation */
|
||||||
|
Genode::error("f_lseek() returned an unexpected error code");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = f_read(&_ffat_fil, dst, len, &result);
|
||||||
|
|
||||||
|
switch(res) {
|
||||||
|
case FR_OK:
|
||||||
|
return result;
|
||||||
|
case FR_DENIED:
|
||||||
|
Genode::warning("f_read() failed with error code FR_DENIED");
|
||||||
|
return 0;
|
||||||
|
case FR_INVALID_OBJECT:
|
||||||
|
Genode::error("f_read() failed with error code FR_INVALID_OBJECT");
|
||||||
|
return 0;
|
||||||
|
case FR_DISK_ERR:
|
||||||
|
Genode::error("f_read() failed with error code FR_DISK_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_INT_ERR:
|
||||||
|
Genode::error("f_read() failed with error code FR_INT_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_NOT_READY:
|
||||||
|
Genode::error("f_read() failed with error code FR_NOT_READY");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* not supposed to occur according to the libffat documentation */
|
||||||
|
Genode::error("f_read() returned an unexpected error code");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(char const *src, size_t len, seek_off_t seek_offset) override
|
||||||
|
{
|
||||||
|
using namespace Ffat;
|
||||||
|
|
||||||
|
UINT result;
|
||||||
|
|
||||||
|
if (seek_offset == (seek_off_t)(~0))
|
||||||
|
seek_offset = _ffat_fil.fsize;
|
||||||
|
|
||||||
|
FRESULT res = f_lseek(&_ffat_fil, seek_offset);
|
||||||
|
|
||||||
|
switch(res) {
|
||||||
|
case FR_OK:
|
||||||
|
break;
|
||||||
|
case FR_INVALID_OBJECT:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_INVALID_OBJECT");
|
||||||
|
return 0;
|
||||||
|
case FR_DISK_ERR:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_DISK_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_INT_ERR:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_INT_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_NOT_READY:
|
||||||
|
Genode::error("f_lseek() failed with error code FR_NOT_READY");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* not supposed to occur according to the libffat documentation */
|
||||||
|
Genode::error("f_lseek() returned an unexpected error code");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = f_write(&_ffat_fil, src, len, &result);
|
||||||
|
|
||||||
|
switch(res) {
|
||||||
|
case FR_OK:
|
||||||
|
return result;
|
||||||
|
case FR_DENIED:
|
||||||
|
Genode::error("f_write() failed with error code FR_DENIED");
|
||||||
|
return 0;
|
||||||
|
case FR_INVALID_OBJECT:
|
||||||
|
Genode::error("f_write() failed with error code FR_INVALID_OBJECT");
|
||||||
|
return 0;
|
||||||
|
case FR_DISK_ERR:
|
||||||
|
Genode::error("f_write() failed with error code FR_DISK_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_INT_ERR:
|
||||||
|
Genode::error("f_write() failed with error code FR_INT_ERR");
|
||||||
|
return 0;
|
||||||
|
case FR_NOT_READY:
|
||||||
|
Genode::error("f_write() failed with error code FR_NOT_READY");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* not supposed to occur according to the libffat documentation */
|
||||||
|
Genode::error("f_write() returned an unexpected error code");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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,41 +24,52 @@ 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;
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Absolute_path _name;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Node(const char *name) : _name(name) { }
|
|
||||||
|
|
||||||
char const *name() { return _name.base(); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A generic Node object can be created to represent a file or
|
|
||||||
* directory by its name without opening it, so the functions
|
|
||||||
* of this class must not be abstract.
|
|
||||||
*/
|
|
||||||
|
|
||||||
virtual size_t read(char *dst, size_t len, seek_off_t)
|
|
||||||
{
|
|
||||||
Genode::error("read() called on generic Node object");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(char const *src, size_t len, seek_off_t)
|
|
||||||
{
|
|
||||||
Genode::error("write() called on generic Node object");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Ffat_fs::Node : public Node_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Absolute_path _name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Node(const char *name) : _name(name) { }
|
||||||
|
|
||||||
|
char const *name() { return _name.base(); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A generic Node object can be created to represent a file or
|
||||||
|
* directory by its name without opening it, so the functions
|
||||||
|
* of this class must not be abstract.
|
||||||
|
*/
|
||||||
|
|
||||||
|
virtual size_t read(char *dst, size_t len, seek_off_t)
|
||||||
|
{
|
||||||
|
Genode::error("read() called on generic Node object");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t write(char const *src, size_t len, seek_off_t)
|
||||||
|
{
|
||||||
|
Genode::error("write() called on generic Node object");
|
||||||
|
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_ */
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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,22 +29,29 @@
|
|||||||
#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:
|
||||||
|
|
||||||
Genode::Env &_env;
|
typedef File_system::Open_node<Node> Open_node;
|
||||||
Allocator &_md_alloc;
|
|
||||||
Directory &_root;
|
Genode::Env &_env;
|
||||||
Node_handle_registry _handle_registry;
|
Allocator &_md_alloc;
|
||||||
bool _writeable;
|
Directory &_root;
|
||||||
|
Id_space<File_system::Node> _open_node_registry;
|
||||||
|
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);
|
|
||||||
|
|
||||||
if (create && !_writeable)
|
Node &dir = open_node.node();
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
File *file = new (&_md_alloc) File(dir, name.string(), mode, create);
|
if (create && !_writeable)
|
||||||
Node_lock_guard file_guard(file);
|
throw Permission_denied();
|
||||||
|
|
||||||
return _handle_registry.alloc(file);
|
File *file = new (&_md_alloc) File(&dir, name.string(), mode, create);
|
||||||
|
|
||||||
|
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);
|
|
||||||
|
|
||||||
if (create && !_writeable)
|
Node &dir = open_node.node();
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
Symlink *symlink = new (&_md_alloc) Symlink(dir, name.string(), create);
|
if (create && !_writeable)
|
||||||
Node_lock_guard symlink_guard(symlink);
|
throw Permission_denied();
|
||||||
|
|
||||||
return _handle_registry.alloc(symlink);
|
Symlink *symlink = new (&_md_alloc) Symlink(&dir, name.string(), create);
|
||||||
|
|
||||||
|
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,25 +335,33 @@ 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);
|
|
||||||
|
|
||||||
Absolute_path absolute_path(_root.name());
|
Node &dir = open_node.node();
|
||||||
|
|
||||||
|
Absolute_path absolute_path(_root.name());
|
||||||
|
|
||||||
|
try {
|
||||||
|
absolute_path.append(dir.name());
|
||||||
|
absolute_path.append("/");
|
||||||
|
absolute_path.append(name.string());
|
||||||
|
} catch (Path_base::Path_too_long) {
|
||||||
|
throw Invalid_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX remove direct use of FUSE operations */
|
||||||
|
int res = Fuse::fuse()->op.unlink(absolute_path.base());
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
Genode::error("fuse()->op.unlink() returned unexpected error code: ", res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
absolute_path.append(dir->name());
|
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
|
||||||
absolute_path.append("/");
|
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||||
absolute_path.append(name.string());
|
throw Invalid_handle();
|
||||||
} catch (Path_base::Path_too_long) {
|
|
||||||
throw Invalid_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX remove direct use of FUSE operations */
|
|
||||||
int res = Fuse::fuse()->op.unlink(absolute_path.base());
|
|
||||||
|
|
||||||
if (res != 0) {
|
|
||||||
Genode::error("fuse()->op.unlink() returned unexpected error code: ", res);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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,40 +387,48 @@ 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 {
|
||||||
|
absolute_from_path.append(from_dir.name());
|
||||||
|
absolute_from_path.append("/");
|
||||||
|
absolute_from_path.append(from_name.string());
|
||||||
|
absolute_to_path.append(to_dir.name());
|
||||||
|
absolute_to_path.append("/");
|
||||||
|
absolute_to_path.append(to_name.string());
|
||||||
|
} catch (Path_base::Path_too_long) {
|
||||||
|
throw Invalid_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX remove direct use of FUSE operations */
|
||||||
|
int res = Fuse::fuse()->op.rename(absolute_to_path.base(),
|
||||||
|
absolute_from_path.base());
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
Genode::error("fuse()->op.rename() returned unexpected error code: ", res);
|
||||||
|
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 {
|
try {
|
||||||
absolute_from_path.append(from_dir->name());
|
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
|
||||||
absolute_from_path.append("/");
|
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||||
absolute_from_path.append(from_name.string());
|
throw Invalid_handle();
|
||||||
absolute_to_path.append(to_dir->name());
|
|
||||||
absolute_to_path.append("/");
|
|
||||||
absolute_to_path.append(to_name.string());
|
|
||||||
} catch (Path_base::Path_too_long) {
|
|
||||||
throw Invalid_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX remove direct use of FUSE operations */
|
|
||||||
int res = Fuse::fuse()->op.rename(absolute_to_path.base(),
|
|
||||||
absolute_from_path.base());
|
|
||||||
|
|
||||||
if (res != 0) {
|
|
||||||
Genode::error("fuse()->op.rename() returned unexpected error code: ", res);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,40 +6,57 @@
|
|||||||
* \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;
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
unsigned long _inode;
|
|
||||||
Absolute_path _name;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Node(char const *name) : _name(name) { }
|
|
||||||
|
|
||||||
char const *name() const { return _name.base(); }
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Fuse_fs::Node : public Node_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
unsigned long _inode;
|
||||||
|
Absolute_path _name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Node(char const *name) : _name(name) { }
|
||||||
|
|
||||||
|
char const *name() const { return _name.base(); }
|
||||||
|
|
||||||
|
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_size_t size)
|
||||||
|
{
|
||||||
|
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _NODE_H_ */
|
#endif /* _NODE_H_ */
|
||||||
|
@ -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;
|
||||||
|
@ -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; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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_ */
|
||||||
|
@ -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_ */
|
|
79
repos/os/include/file_system/open_node.h
Normal file
79
repos/os/include/file_system/open_node.h
Normal 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_ */
|
@ -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,11 +118,11 @@ 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 */
|
||||||
bool _success; /* indicates success of operation */
|
bool _success; /* indicates success of operation */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -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,
|
||||||
|
@ -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_ */
|
|
@ -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");
|
||||||
|
@ -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 =
|
||||||
|
@ -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) };
|
||||||
|
@ -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"; }
|
||||||
|
@ -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,25 +151,30 @@ 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);
|
||||||
Handle_guard guard(fs, dir);
|
|
||||||
|
|
||||||
/* open file */
|
try {
|
||||||
Genode::Path<PATH_MAX_LEN> file_name(path.base());
|
|
||||||
file_name.keep_only_last_element();
|
Handle_guard guard(fs, dir);
|
||||||
file_handle = fs.file(dir, file_name.base() + 1,
|
|
||||||
File_system::READ_ONLY, false);
|
/* open file */
|
||||||
|
Genode::Path<PATH_MAX_LEN> file_name(path.base());
|
||||||
|
file_name.keep_only_last_element();
|
||||||
|
return fs.file(dir, file_name.base() + 1,
|
||||||
|
File_system::READ_ONLY, false);
|
||||||
|
}
|
||||||
|
catch (Invalid_handle) { Genode::error(_file_path, ": Invalid_handle"); }
|
||||||
|
catch (Invalid_name) { Genode::error(_file_path, ": invalid_name"); }
|
||||||
|
catch (Lookup_failed) { Genode::error(_file_path, ": lookup_failed"); }
|
||||||
|
catch (...) { Genode::error(_file_path, ": unhandled error"); };
|
||||||
|
|
||||||
|
throw Open_file_failed();
|
||||||
|
|
||||||
|
} catch (Open_compound_dir_failed) {
|
||||||
|
throw Open_file_failed();
|
||||||
}
|
}
|
||||||
catch (Invalid_handle) { Genode::error(_file_path, ": Invalid_handle"); }
|
|
||||||
catch (Invalid_name) { Genode::error(_file_path, ": invalid_name"); }
|
|
||||||
catch (Lookup_failed) { Genode::error(_file_path, ": lookup_failed"); }
|
|
||||||
catch (...) { Genode::error(_file_path, ": unhandled error"); };
|
|
||||||
|
|
||||||
return file_handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _register_for_compound_dir_changes()
|
void _register_for_compound_dir_changes()
|
||||||
@ -167,18 +182,22 @@ 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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,42 +213,46 @@ 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;
|
|
||||||
|
|
||||||
if (_file_ds.size() && (new_file_size > _file_size)) {
|
if (_file_ds.size() && (new_file_size > _file_size)) {
|
||||||
/* mark as invalid */
|
/* mark as invalid */
|
||||||
_file_ds.realloc(&_env.ram(), 0);
|
_file_ds.realloc(&_env.ram(), 0);
|
||||||
_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,11 +307,13 @@ 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 {
|
||||||
_register_for_compound_dir_changes();
|
_file_handle.construct(_open_file(_fs, _file_path));
|
||||||
|
} catch (Open_file_failed) { }
|
||||||
|
|
||||||
|
_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) {
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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 */;
|
||||||
|
|
||||||
|
@ -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,22 +25,29 @@
|
|||||||
#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:
|
||||||
|
|
||||||
Genode::Env &_env;
|
typedef File_system::Open_node<Node> Open_node;
|
||||||
Allocator &_md_alloc;
|
|
||||||
Directory &_root;
|
Genode::Env &_env;
|
||||||
Node_handle_registry _handle_registry;
|
Allocator &_md_alloc;
|
||||||
bool _writable;
|
Directory &_root;
|
||||||
|
Id_space<File_system::Node> _open_node_registry;
|
||||||
|
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);
|
|
||||||
|
|
||||||
if (!_writable)
|
Node &dir = open_node.node();
|
||||||
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
|
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
File *file = dir->file(name.string(), mode, create);
|
if (!_writable)
|
||||||
|
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
|
||||||
|
throw Permission_denied();
|
||||||
|
|
||||||
Node_lock_guard file_guard(file);
|
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)
|
||||||
{
|
{
|
||||||
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); }
|
||||||
|
@ -5,43 +5,70 @@
|
|||||||
* \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 : public Node_base
|
class Node;
|
||||||
{
|
class File;
|
||||||
public:
|
|
||||||
|
|
||||||
typedef char Name[128];
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Name _name;
|
|
||||||
unsigned long const _inode;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
|
|
||||||
|
|
||||||
unsigned long inode() const { return _inode; }
|
|
||||||
char const *name() const { return _name; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign name
|
|
||||||
*/
|
|
||||||
void name(char const *name) { Genode::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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Lx_fs::Node : public File_system::Node_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef char Name[128];
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Name _name;
|
||||||
|
unsigned long const _inode;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
|
||||||
|
|
||||||
|
unsigned long inode() const { return _inode; }
|
||||||
|
char const *name() const { return _name; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign name
|
||||||
|
*/
|
||||||
|
void name(char const *name) { Genode::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_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_ */
|
||||||
|
@ -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_ */
|
||||||
|
@ -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_ */
|
@ -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);
|
@ -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,16 +40,18 @@ 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:
|
||||||
|
|
||||||
Genode::Entrypoint &_ep;
|
typedef File_system::Open_node<Node> Open_node;
|
||||||
Genode::Ram_session &_ram;
|
|
||||||
Genode::Allocator &_alloc;
|
Genode::Entrypoint &_ep;
|
||||||
Directory &_root;
|
Genode::Ram_session &_ram;
|
||||||
Node_handle_registry _handle_registry;
|
Genode::Allocator &_alloc;
|
||||||
bool _writable;
|
Directory &_root;
|
||||||
|
Id_space<File_system::Node> _open_node_registry;
|
||||||
|
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,33 +199,46 @@ 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);
|
|
||||||
|
|
||||||
if (!_writable)
|
Node &dir = open_node.node();
|
||||||
if (mode != STAT_ONLY && mode != READ_ONLY)
|
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
if (create) {
|
|
||||||
|
|
||||||
if (!_writable)
|
if (!_writable)
|
||||||
throw Permission_denied();
|
if (mode != STAT_ONLY && mode != READ_ONLY)
|
||||||
|
throw Permission_denied();
|
||||||
|
|
||||||
if (dir->has_sub_node_unsynchronized(name.string()))
|
if (create) {
|
||||||
throw Node_already_exists();
|
|
||||||
|
|
||||||
try {
|
if (!_writable)
|
||||||
File * const file = new (_alloc)
|
throw Permission_denied();
|
||||||
File(_alloc, name.string());
|
|
||||||
|
|
||||||
dir->adopt_unsynchronized(file);
|
if (dir.has_sub_node_unsynchronized(name.string()))
|
||||||
|
throw Node_already_exists();
|
||||||
|
|
||||||
|
try {
|
||||||
|
File * const file = new (_alloc)
|
||||||
|
File(_alloc, name.string());
|
||||||
|
|
||||||
|
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);
|
|
||||||
|
|
||||||
if (create) {
|
Node &dir = open_node.node();
|
||||||
|
|
||||||
if (!_writable)
|
if (create) {
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
if (dir->has_sub_node_unsynchronized(name.string()))
|
if (!_writable)
|
||||||
throw Node_already_exists();
|
throw Permission_denied();
|
||||||
|
|
||||||
try {
|
if (dir.has_sub_node_unsynchronized(name.string()))
|
||||||
Symlink * const symlink = new (_alloc)
|
throw Node_already_exists();
|
||||||
Symlink(name.string());
|
|
||||||
|
|
||||||
dir->adopt_unsynchronized(symlink);
|
try {
|
||||||
|
Symlink * const symlink = new (_alloc)
|
||||||
|
Symlink(name.string());
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
// XXX implement ref counting, do not destroy node that is
|
dir.discard(node);
|
||||||
// is still referenced by a node handle
|
|
||||||
|
|
||||||
node->unlock();
|
// XXX implement ref counting, do not destroy node that is
|
||||||
destroy(_alloc, node);
|
// is still referenced by a node handle
|
||||||
|
|
||||||
|
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,47 +431,69 @@ 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->name(to_name.string());
|
|
||||||
|
|
||||||
if (!_handle_registry.refer_to_same_node(from_dir_handle, to_dir_handle)) {
|
Node &from_dir = open_from_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);
|
Node *node = from_dir.lookup(from_name.string());
|
||||||
to_dir->adopt_unsynchronized(node);
|
node->name(to_name.string());
|
||||||
|
|
||||||
/*
|
Node &to_dir = open_to_dir_node.node();
|
||||||
* If the file was moved from one directory to another we
|
|
||||||
* need to inform the new directory 'to_dir'. The original
|
if (&to_dir != &from_dir) {
|
||||||
* directory 'from_dir' will always get notified (i.e.,
|
|
||||||
* when just the file name was changed) below.
|
from_dir.discard(node);
|
||||||
*/
|
to_dir.adopt_unsynchronized(node);
|
||||||
to_dir->mark_as_updated();
|
|
||||||
to_dir->notify_listeners();
|
/*
|
||||||
|
* If the file was moved from one directory to another we
|
||||||
|
* need to inform the new directory 'to_dir'. The original
|
||||||
|
* directory 'from_dir' will always get notified (i.e.,
|
||||||
|
* when just the file name was changed) below.
|
||||||
|
*/
|
||||||
|
to_dir.mark_as_updated();
|
||||||
|
to_dir.notify_listeners();
|
||||||
|
|
||||||
|
from_dir.mark_as_updated();
|
||||||
|
from_dir.notify_listeners();
|
||||||
|
|
||||||
|
node->mark_as_updated();
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
from_dir->mark_as_updated();
|
|
||||||
from_dir->notify_listeners();
|
|
||||||
|
|
||||||
node->mark_as_updated();
|
|
||||||
node->notify_listeners();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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); }
|
||||||
|
120
repos/os/src/server/ram_fs/node.h
Normal file
120
repos/os/src/server/ram_fs/node.h
Normal 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_ */
|
@ -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_ */
|
@ -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,200 +22,201 @@
|
|||||||
#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:
|
||||||
|
|
||||||
List<Node> _entries;
|
List<Node> _entries;
|
||||||
size_t _num_entries;
|
size_t _num_entries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Directory(char const *name) : _num_entries(0) { Node::name(name); }
|
Directory(char const *name) : _num_entries(0) { Node::name(name); }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the directory has the specified subnode
|
* Check if the directory has the specified subnode
|
||||||
*
|
*
|
||||||
* \param name name of the searched subnode
|
* \param name name of the searched subnode
|
||||||
*
|
*
|
||||||
* \return true if the subnode was found, either false
|
* \return true if the subnode was found, either false
|
||||||
|
*/
|
||||||
|
bool has_sub_node_unsynchronized(char const *name) const
|
||||||
|
{
|
||||||
|
Node const *sub_node = _entries.first();
|
||||||
|
for (; sub_node; sub_node = sub_node->next())
|
||||||
|
if (strcmp(sub_node->name(), name) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add node to the list of subnodes
|
||||||
|
*
|
||||||
|
* \param pointer to node
|
||||||
|
*/
|
||||||
|
void adopt_unsynchronized(Node *node)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* XXX inc ref counter
|
||||||
*/
|
*/
|
||||||
bool has_sub_node_unsynchronized(char const *name) const
|
_entries.insert(node);
|
||||||
{
|
_num_entries++;
|
||||||
Node const *sub_node = _entries.first();
|
|
||||||
for (; sub_node; sub_node = sub_node->next())
|
|
||||||
if (strcmp(sub_node->name(), name) == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
mark_as_updated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the node from the list of subnodes
|
||||||
|
*
|
||||||
|
* \param node pointer to node
|
||||||
|
*/
|
||||||
|
void discard_unsynchronized(Node *node)
|
||||||
|
{
|
||||||
|
_entries.remove(node);
|
||||||
|
_num_entries--;
|
||||||
|
|
||||||
|
mark_as_updated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup node which belongs to the specified path
|
||||||
|
*
|
||||||
|
* \param path path to lookup
|
||||||
|
* \param return_parent if true return parent node, otherwise
|
||||||
|
* actual path node
|
||||||
|
*
|
||||||
|
* \return node node founc
|
||||||
|
* \throws Lookup_failed
|
||||||
|
*/
|
||||||
|
Node *lookup(char const *path, bool return_parent = false) override
|
||||||
|
{
|
||||||
|
if (strcmp(path, "") == 0) {
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!path || path[0] == '/')
|
||||||
|
throw Lookup_failed();
|
||||||
|
|
||||||
/**
|
/* find first path delimiter */
|
||||||
* Add node to the list of subnodes
|
unsigned i = 0;
|
||||||
*
|
for (; path[i] && path[i] != '/'; i++);
|
||||||
* \param pointer to node
|
|
||||||
|
/*
|
||||||
|
* If no path delimiter was found, we are the parent of the
|
||||||
|
* specified path.
|
||||||
*/
|
*/
|
||||||
void adopt_unsynchronized(Node *node)
|
if (path[i] == 0 && return_parent) {
|
||||||
{
|
return this;
|
||||||
/*
|
|
||||||
* XXX inc ref counter
|
|
||||||
*/
|
|
||||||
_entries.insert(node);
|
|
||||||
_num_entries++;
|
|
||||||
|
|
||||||
mark_as_updated();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Remove the node from the list of subnodes
|
* The offset 'i' corresponds to the end of the first path
|
||||||
*
|
* element, which can be either the end of the string or the
|
||||||
* \param node pointer to node
|
* first '/' character.
|
||||||
*/
|
*/
|
||||||
void discard_unsynchronized(Node *node)
|
|
||||||
{
|
|
||||||
_entries.remove(node);
|
|
||||||
_num_entries--;
|
|
||||||
|
|
||||||
mark_as_updated();
|
/* try to find entry that matches the first path element */
|
||||||
|
Node *sub_node = _entries.first();
|
||||||
|
for (; sub_node; sub_node = sub_node->next())
|
||||||
|
if ((strlen(sub_node->name()) == i) &&
|
||||||
|
(strcmp(sub_node->name(), path, i) == 0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!sub_node)
|
||||||
|
throw Lookup_failed();
|
||||||
|
|
||||||
|
if (!contains_path_delimiter(path)) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because 'path' is a basename that corresponds to an
|
||||||
|
* existing sub_node, we have found what we were looking
|
||||||
|
* for.
|
||||||
|
*/
|
||||||
|
return sub_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Lookup node which belongs to the specified path
|
* As 'path' contains one or more path delimiters, traverse
|
||||||
*
|
* into the sub directory names after the first path element.
|
||||||
* \param path path to lookup
|
|
||||||
* \param return_parent if true return parent node, otherwise
|
|
||||||
* actual path node
|
|
||||||
*
|
|
||||||
* \return node node founc
|
|
||||||
* \throws Lookup_failed
|
|
||||||
*/
|
*/
|
||||||
Node *lookup(char const *path, bool return_parent = false)
|
|
||||||
{
|
|
||||||
if (strcmp(path, "") == 0) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!path || path[0] == '/')
|
/*
|
||||||
throw Lookup_failed();
|
* We cannot traverse into anything other than a directory.
|
||||||
|
*
|
||||||
/* find first path delimiter */
|
* XXX we might follow symlinks here
|
||||||
unsigned i = 0;
|
|
||||||
for (; path[i] && path[i] != '/'; i++);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If no path delimiter was found, we are the parent of the
|
|
||||||
* specified path.
|
|
||||||
*/
|
|
||||||
if (path[i] == 0 && return_parent) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The offset 'i' corresponds to the end of the first path
|
|
||||||
* element, which can be either the end of the string or the
|
|
||||||
* first '/' character.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* try to find entry that matches the first path element */
|
|
||||||
Node *sub_node = _entries.first();
|
|
||||||
for (; sub_node; sub_node = sub_node->next())
|
|
||||||
if ((strlen(sub_node->name()) == i) &&
|
|
||||||
(strcmp(sub_node->name(), path, i) == 0))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!sub_node)
|
|
||||||
throw Lookup_failed();
|
|
||||||
|
|
||||||
if (!contains_path_delimiter(path)) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Because 'path' is a basename that corresponds to an
|
|
||||||
* existing sub_node, we have found what we were looking
|
|
||||||
* for.
|
|
||||||
*/
|
|
||||||
return sub_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* As 'path' contains one or more path delimiters, traverse
|
|
||||||
* into the sub directory names after the first path element.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We cannot traverse into anything other than a directory.
|
|
||||||
*
|
|
||||||
* XXX we might follow symlinks here
|
|
||||||
*/
|
|
||||||
Directory *sub_dir = dynamic_cast<Directory *>(sub_node);
|
|
||||||
if (!sub_dir)
|
|
||||||
throw Lookup_failed();
|
|
||||||
|
|
||||||
return sub_dir->lookup(path + i + 1, return_parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return number of subnodes
|
|
||||||
*/
|
*/
|
||||||
size_t num_entries() const { return _num_entries; }
|
Directory *sub_dir = dynamic_cast<Directory *>(sub_node);
|
||||||
|
if (!sub_dir)
|
||||||
|
throw Lookup_failed();
|
||||||
|
|
||||||
|
return sub_dir->lookup(path + i + 1, return_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return number of subnodes
|
||||||
|
*/
|
||||||
|
size_t num_entries() const { return _num_entries; }
|
||||||
|
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
** Node interface **
|
** Node interface **
|
||||||
********************/
|
********************/
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
seek_off_t index = seek_offset / sizeof(Directory_entry);
|
|
||||||
|
|
||||||
if (seek_offset % sizeof(Directory_entry)) {
|
|
||||||
Genode::error("seek offset not alighed to sizeof(Directory_entry)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find list element */
|
|
||||||
Node *node = _entries.first();
|
|
||||||
for (unsigned i = 0; i < index && node; node = node->next(), i++);
|
|
||||||
|
|
||||||
/* index out of range */
|
|
||||||
if (!node)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Directory_entry *e = (Directory_entry *)(dst);
|
|
||||||
|
|
||||||
if (dynamic_cast<File *>(node)) e->type = Directory_entry::TYPE_FILE;
|
|
||||||
if (dynamic_cast<Directory *>(node)) e->type = Directory_entry::TYPE_DIRECTORY;
|
|
||||||
if (dynamic_cast<Symlink *>(node)) e->type = Directory_entry::TYPE_SYMLINK;
|
|
||||||
|
|
||||||
strncpy(e->name, node->name(), sizeof(e->name));
|
|
||||||
|
|
||||||
return sizeof(Directory_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
/* writing to directory nodes is not supported */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status status() const
|
seek_off_t index = seek_offset / sizeof(Directory_entry);
|
||||||
{
|
|
||||||
Status s;
|
|
||||||
s.inode = inode();
|
|
||||||
s.size = _num_entries * sizeof (Directory_entry);
|
|
||||||
s.mode = File_system::Status::MODE_DIRECTORY;
|
|
||||||
|
|
||||||
return s;
|
if (seek_offset % sizeof(Directory_entry)) {
|
||||||
|
Genode::error("seek offset not alighed to sizeof(Directory_entry)");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
/* find list element */
|
||||||
|
Node *node = _entries.first();
|
||||||
|
for (unsigned i = 0; i < index && node; node = node->next(), i++);
|
||||||
|
|
||||||
|
/* index out of range */
|
||||||
|
if (!node)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Directory_entry *e = (Directory_entry *)(dst);
|
||||||
|
|
||||||
|
if (dynamic_cast<File *>(node)) e->type = Directory_entry::TYPE_FILE;
|
||||||
|
if (dynamic_cast<Directory *>(node)) e->type = Directory_entry::TYPE_DIRECTORY;
|
||||||
|
if (dynamic_cast<Symlink *>(node)) e->type = Directory_entry::TYPE_SYMLINK;
|
||||||
|
|
||||||
|
strncpy(e->name, node->name(), sizeof(e->name));
|
||||||
|
|
||||||
|
return sizeof(Directory_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
/* writing to directory nodes is not supported */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status status() const
|
||||||
|
{
|
||||||
|
Status s;
|
||||||
|
s.inode = inode();
|
||||||
|
s.size = _num_entries * sizeof (Directory_entry);
|
||||||
|
s.mode = File_system::Status::MODE_DIRECTORY;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _DIRECTORY_H_ */
|
#endif /* _DIRECTORY_H_ */
|
||||||
|
@ -23,195 +23,198 @@
|
|||||||
#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
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This member is used to communicate the state and
|
|
||||||
* must be set true by classes using this class in case
|
|
||||||
* the content has changed.
|
|
||||||
*/
|
|
||||||
bool _changed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called when the content change is
|
|
||||||
* acknowledged. It may be overriden by any class using
|
|
||||||
* this particular class.
|
|
||||||
*/
|
|
||||||
virtual void _refresh_content() { }
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Changeable_content() : _changed(false) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the content was changed
|
|
||||||
*
|
|
||||||
* This evaluation has to be made by classes using this
|
|
||||||
* particular class.
|
|
||||||
*
|
|
||||||
* \return true if changed, otherwise false
|
|
||||||
*/
|
|
||||||
bool changed() const { return _changed; }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledge the content has changed
|
|
||||||
*/
|
|
||||||
void acknowledge_change()
|
|
||||||
{
|
|
||||||
_changed = false;
|
|
||||||
|
|
||||||
_refresh_content();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File interface
|
|
||||||
*/
|
|
||||||
|
|
||||||
class File : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
File(char const *name)
|
|
||||||
{
|
|
||||||
Node::name(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~File() { }
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** Node interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) = 0;
|
|
||||||
|
|
||||||
virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) = 0;
|
|
||||||
|
|
||||||
virtual Status status() const = 0;
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** File interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
virtual file_size_t length() const = 0;
|
|
||||||
|
|
||||||
virtual void truncate(file_size_t size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Memory buffered file
|
|
||||||
*
|
|
||||||
* This file merely exists in memory and grows automatically.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Buffered_file : public File
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
typedef Chunk<4096> Chunk_level_3;
|
|
||||||
typedef Chunk_index<128, Chunk_level_3> Chunk_level_2;
|
|
||||||
typedef Chunk_index<64, Chunk_level_2> Chunk_level_1;
|
|
||||||
typedef Chunk_index<64, Chunk_level_1> Chunk_level_0;
|
|
||||||
|
|
||||||
Chunk_level_0 _chunk;
|
|
||||||
|
|
||||||
file_size_t _length;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Buffered_file(Allocator &alloc, char const *name)
|
|
||||||
: File(name), _chunk(alloc, 0), _length(0) { }
|
|
||||||
|
|
||||||
virtual size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
file_size_t const chunk_used_size = _chunk.used_size();
|
|
||||||
|
|
||||||
if (seek_offset >= _length)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Constrain read transaction to available chunk data
|
|
||||||
*
|
|
||||||
* Note that 'chunk_used_size' may be lower than '_length'
|
|
||||||
* because 'Chunk' may have truncated tailing zeros.
|
|
||||||
*/
|
|
||||||
if (seek_offset + len >= _length)
|
|
||||||
len = _length - seek_offset;
|
|
||||||
|
|
||||||
file_size_t read_len = len;
|
|
||||||
|
|
||||||
if (seek_offset + read_len > chunk_used_size) {
|
|
||||||
if (chunk_used_size >= seek_offset)
|
|
||||||
read_len = chunk_used_size - seek_offset;
|
|
||||||
else
|
|
||||||
read_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_chunk.read(dst, read_len, seek_offset);
|
|
||||||
|
|
||||||
/* add zero padding if needed */
|
|
||||||
if (read_len < len)
|
|
||||||
memset(dst + read_len, 0, len - read_len);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
if (seek_offset == (seek_off_t)(~0))
|
|
||||||
seek_offset = _chunk.used_size();
|
|
||||||
|
|
||||||
if (seek_offset + len >= Chunk_level_0::SIZE) {
|
|
||||||
len = (Chunk_level_0::SIZE-1) - seek_offset;
|
|
||||||
Genode::error(name(), ": size limit ", (long)Chunk_level_0::SIZE, " reached");
|
|
||||||
}
|
|
||||||
|
|
||||||
_chunk.write(src, len, (size_t)seek_offset);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Keep track of file length. We cannot use 'chunk.used_size()'
|
|
||||||
* as file length because trailing zeros may by represented
|
|
||||||
* by zero chunks, which do not contribute to 'used_size()'.
|
|
||||||
*/
|
|
||||||
_length = max(_length, seek_offset + len);
|
|
||||||
|
|
||||||
mark_as_updated();
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Status status() const
|
|
||||||
{
|
|
||||||
Status s;
|
|
||||||
|
|
||||||
s.inode = inode();
|
|
||||||
s.size = _length;
|
|
||||||
s.mode = File_system::Status::MODE_FILE;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual file_size_t length() const { return _length; }
|
|
||||||
|
|
||||||
void truncate(file_size_t size)
|
|
||||||
{
|
|
||||||
if (size < _chunk.used_size())
|
|
||||||
_chunk.truncate(size);
|
|
||||||
|
|
||||||
_length = size;
|
|
||||||
|
|
||||||
mark_as_updated();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Trace_fs::Changeable_content
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This member is used to communicate the state and
|
||||||
|
* must be set true by classes using this class in case
|
||||||
|
* the content has changed.
|
||||||
|
*/
|
||||||
|
bool _changed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when the content change is
|
||||||
|
* acknowledged. It may be overriden by any class using
|
||||||
|
* this particular class.
|
||||||
|
*/
|
||||||
|
virtual void _refresh_content() { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Changeable_content() : _changed(false) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the content was changed
|
||||||
|
*
|
||||||
|
* This evaluation has to be made by classes using this
|
||||||
|
* particular class.
|
||||||
|
*
|
||||||
|
* \return true if changed, otherwise false
|
||||||
|
*/
|
||||||
|
bool changed() const { return _changed; }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge the content has changed
|
||||||
|
*/
|
||||||
|
void acknowledge_change()
|
||||||
|
{
|
||||||
|
_changed = false;
|
||||||
|
|
||||||
|
_refresh_content();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::File : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
File(char const *name)
|
||||||
|
{
|
||||||
|
Node::name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~File() { }
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** Node interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
virtual size_t read(char *dst, size_t len, seek_off_t seek_offset) = 0;
|
||||||
|
|
||||||
|
virtual size_t write(char const *src, size_t len, seek_off_t seek_offset) = 0;
|
||||||
|
|
||||||
|
virtual Status status() const = 0;
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** File interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
virtual file_size_t length() const = 0;
|
||||||
|
|
||||||
|
virtual void truncate(file_size_t size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory buffered file
|
||||||
|
*
|
||||||
|
* This file merely exists in memory and grows automatically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::Buffered_file : public File
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef Chunk<4096> Chunk_level_3;
|
||||||
|
typedef Chunk_index<128, Chunk_level_3> Chunk_level_2;
|
||||||
|
typedef Chunk_index<64, Chunk_level_2> Chunk_level_1;
|
||||||
|
typedef Chunk_index<64, Chunk_level_1> Chunk_level_0;
|
||||||
|
|
||||||
|
Chunk_level_0 _chunk;
|
||||||
|
|
||||||
|
file_size_t _length;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Buffered_file(Allocator &alloc, char const *name)
|
||||||
|
: File(name), _chunk(alloc, 0), _length(0) { }
|
||||||
|
|
||||||
|
virtual size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
file_size_t const chunk_used_size = _chunk.used_size();
|
||||||
|
|
||||||
|
if (seek_offset >= _length)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constrain read transaction to available chunk data
|
||||||
|
*
|
||||||
|
* Note that 'chunk_used_size' may be lower than '_length'
|
||||||
|
* because 'Chunk' may have truncated tailing zeros.
|
||||||
|
*/
|
||||||
|
if (seek_offset + len >= _length)
|
||||||
|
len = _length - seek_offset;
|
||||||
|
|
||||||
|
file_size_t read_len = len;
|
||||||
|
|
||||||
|
if (seek_offset + read_len > chunk_used_size) {
|
||||||
|
if (chunk_used_size >= seek_offset)
|
||||||
|
read_len = chunk_used_size - seek_offset;
|
||||||
|
else
|
||||||
|
read_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_chunk.read(dst, read_len, seek_offset);
|
||||||
|
|
||||||
|
/* add zero padding if needed */
|
||||||
|
if (read_len < len)
|
||||||
|
memset(dst + read_len, 0, len - read_len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
if (seek_offset == (seek_off_t)(~0))
|
||||||
|
seek_offset = _chunk.used_size();
|
||||||
|
|
||||||
|
if (seek_offset + len >= Chunk_level_0::SIZE) {
|
||||||
|
len = (Chunk_level_0::SIZE-1) - seek_offset;
|
||||||
|
Genode::error(name(), ": size limit ", (long)Chunk_level_0::SIZE, " reached");
|
||||||
|
}
|
||||||
|
|
||||||
|
_chunk.write(src, len, (size_t)seek_offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep track of file length. We cannot use 'chunk.used_size()'
|
||||||
|
* as file length because trailing zeros may by represented
|
||||||
|
* by zero chunks, which do not contribute to 'used_size()'.
|
||||||
|
*/
|
||||||
|
_length = max(_length, seek_offset + len);
|
||||||
|
|
||||||
|
mark_as_updated();
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Status status() const
|
||||||
|
{
|
||||||
|
Status s;
|
||||||
|
|
||||||
|
s.inode = inode();
|
||||||
|
s.size = _length;
|
||||||
|
s.mode = File_system::Status::MODE_FILE;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual file_size_t length() const { return _length; }
|
||||||
|
|
||||||
|
void truncate(file_size_t size) override
|
||||||
|
{
|
||||||
|
if (size < _chunk.used_size())
|
||||||
|
_chunk.truncate(size);
|
||||||
|
|
||||||
|
_length = size;
|
||||||
|
|
||||||
|
mark_as_updated();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _FILE_H_ */
|
#endif /* _FILE_H_ */
|
||||||
|
@ -22,261 +22,262 @@
|
|||||||
#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;
|
||||||
struct Followed_subject : public File_system::Directory
|
class Followed_subject_registry;
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class manages the access to the trace subject's trace buffer
|
|
||||||
*/
|
|
||||||
class Trace_buffer_manager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
class Already_managed { };
|
|
||||||
class Not_managed { };
|
|
||||||
|
|
||||||
struct Process_entry
|
|
||||||
{
|
|
||||||
virtual size_t operator()(Genode::Trace::Buffer::Entry&) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Trace::Buffer *buffer;
|
|
||||||
Genode::Trace::Buffer::Entry current_entry;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Trace_buffer_manager(Genode::Region_map &rm,
|
|
||||||
Genode::Dataspace_capability ds_cap)
|
|
||||||
:
|
|
||||||
buffer(rm.attach(ds_cap)),
|
|
||||||
current_entry(buffer->first())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
size_t dump_entry(Process_entry &process)
|
|
||||||
{
|
|
||||||
size_t len = process(current_entry);
|
|
||||||
|
|
||||||
current_entry = buffer->next(current_entry);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool last_entry() const
|
|
||||||
{
|
|
||||||
return current_entry.last();
|
|
||||||
}
|
|
||||||
|
|
||||||
void rewind() { current_entry = buffer->first(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Allocator &_md_alloc;
|
|
||||||
|
|
||||||
Genode::Region_map &_rm;
|
|
||||||
|
|
||||||
int _handle;
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id _id;
|
|
||||||
Genode::Trace::Policy_id _policy_id;
|
|
||||||
|
|
||||||
bool _was_traced;
|
|
||||||
|
|
||||||
Trace_buffer_manager *_buffer_manager;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
File_system::Active_file active_file;
|
|
||||||
File_system::Buffer_size_file buffer_size_file;
|
|
||||||
File_system::Cleanup_file cleanup_file;
|
|
||||||
File_system::Enable_file enable_file;
|
|
||||||
File_system::Events_file events_file;
|
|
||||||
File_system::Policy_file policy_file;
|
|
||||||
|
|
||||||
Followed_subject(Genode::Allocator &md_alloc, char const *name,
|
|
||||||
Genode::Region_map &rm,
|
|
||||||
Genode::Trace::Subject_id &id, int handle)
|
|
||||||
:
|
|
||||||
Directory(name),
|
|
||||||
_md_alloc(md_alloc),
|
|
||||||
_rm(rm),
|
|
||||||
_handle(handle),
|
|
||||||
_id(id),
|
|
||||||
_was_traced(false),
|
|
||||||
_buffer_manager(0),
|
|
||||||
active_file(_id),
|
|
||||||
buffer_size_file(),
|
|
||||||
cleanup_file(_id),
|
|
||||||
enable_file(_id),
|
|
||||||
events_file(_id, _md_alloc),
|
|
||||||
policy_file(_id, _md_alloc)
|
|
||||||
{
|
|
||||||
adopt_unsynchronized(&active_file);
|
|
||||||
adopt_unsynchronized(&cleanup_file);
|
|
||||||
adopt_unsynchronized(&enable_file);
|
|
||||||
adopt_unsynchronized(&events_file);
|
|
||||||
adopt_unsynchronized(&buffer_size_file);
|
|
||||||
adopt_unsynchronized(&policy_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Followed_subject()
|
|
||||||
{
|
|
||||||
discard_unsynchronized(&active_file);
|
|
||||||
discard_unsynchronized(&cleanup_file);
|
|
||||||
discard_unsynchronized(&enable_file);
|
|
||||||
discard_unsynchronized(&events_file);
|
|
||||||
discard_unsynchronized(&buffer_size_file);
|
|
||||||
discard_unsynchronized(&policy_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool marked_for_cleanup() const { return cleanup_file.cleanup(); }
|
|
||||||
bool was_traced() const { return _was_traced; }
|
|
||||||
|
|
||||||
Trace_buffer_manager* trace_buffer_manager() { return _buffer_manager; }
|
|
||||||
|
|
||||||
void manage_trace_buffer(Genode::Dataspace_capability ds_cap)
|
|
||||||
{
|
|
||||||
if (_buffer_manager != 0)
|
|
||||||
throw Trace_buffer_manager::Already_managed();
|
|
||||||
|
|
||||||
_buffer_manager = new (&_md_alloc) Trace_buffer_manager(_rm, ds_cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unmanage_trace_buffer()
|
|
||||||
{
|
|
||||||
if (_buffer_manager == 0)
|
|
||||||
throw Trace_buffer_manager::Not_managed();
|
|
||||||
|
|
||||||
destroy(&_md_alloc, _buffer_manager);
|
|
||||||
_buffer_manager = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Genode::Trace::Subject_id id() const { return _id; }
|
|
||||||
|
|
||||||
const Genode::Trace::Policy_id policy_id() const { return _policy_id; }
|
|
||||||
void policy_id(Genode::Trace::Policy_id &id) { _policy_id.id = id.id; }
|
|
||||||
bool policy_valid() const { return (_policy_id.id != 0); }
|
|
||||||
void invalidate_policy() { _policy_id = Genode::Trace::Policy_id(); }
|
|
||||||
|
|
||||||
int handle() const { return _handle; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This registry contains all current followed trace subjects
|
|
||||||
*/
|
|
||||||
class Followed_subject_registry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
class Invalid_subject { };
|
|
||||||
class Out_of_subject_handles { };
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/* XXX abitrary limit - needs to be revisited when highly
|
|
||||||
* dynamic scenarios are executed */
|
|
||||||
enum { MAX_SUBJECTS = 1024U };
|
|
||||||
|
|
||||||
Followed_subject *_subjects[MAX_SUBJECTS];
|
|
||||||
|
|
||||||
Genode::Allocator &_md_alloc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find free subject handle
|
|
||||||
*
|
|
||||||
* \throw Out_of_subject_handles
|
|
||||||
*/
|
|
||||||
int _find_free_handle()
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < MAX_SUBJECTS; i++)
|
|
||||||
if (!_subjects[i]) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Out_of_subject_handles();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _in_range(int handle) const
|
|
||||||
{
|
|
||||||
return ((handle >= 0) && (handle < MAX_SUBJECTS));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Followed_subject_registry(Genode::Allocator &md_alloc)
|
|
||||||
:
|
|
||||||
_md_alloc(md_alloc)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < MAX_SUBJECTS; i++)
|
|
||||||
_subjects[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return maximal number of subject that can be stored in the registry
|
|
||||||
*
|
|
||||||
* \return maximal number of subjects
|
|
||||||
*/
|
|
||||||
unsigned max_subjects() const { return MAX_SUBJECTS; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate new subject
|
|
||||||
*
|
|
||||||
* \param name name of subject
|
|
||||||
* \param id subject id of tracre subject
|
|
||||||
*/
|
|
||||||
Followed_subject *alloc(char const *name, Genode::Trace::Subject_id &id,
|
|
||||||
Genode::Region_map &rm)
|
|
||||||
{
|
|
||||||
int handle = _find_free_handle();
|
|
||||||
|
|
||||||
_subjects[handle] = new (&_md_alloc) Followed_subject(_md_alloc, name, rm, id, handle);
|
|
||||||
|
|
||||||
return _subjects[handle];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free subject
|
|
||||||
*
|
|
||||||
* \param subject pointer to subject
|
|
||||||
*/
|
|
||||||
void free(Followed_subject *subject)
|
|
||||||
{
|
|
||||||
int handle = subject->handle();
|
|
||||||
|
|
||||||
if (!_in_range(handle))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(!_subjects[handle])
|
|
||||||
return;
|
|
||||||
|
|
||||||
_subjects[handle] = 0;
|
|
||||||
destroy(&_md_alloc, subject);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup subject by using the id
|
|
||||||
*
|
|
||||||
* \throw Invalid_subject();
|
|
||||||
*/
|
|
||||||
Followed_subject *lookup(Genode::Trace::Subject_id const &sid)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < MAX_SUBJECTS; i++)
|
|
||||||
if (_subjects[i]) {
|
|
||||||
if (_subjects[i]->id().id == sid.id)
|
|
||||||
return _subjects[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Invalid_subject();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Trace_fs::Followed_subject : public Directory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manages the access to the trace subject's trace buffer
|
||||||
|
*/
|
||||||
|
class Trace_buffer_manager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class Already_managed { };
|
||||||
|
class Not_managed { };
|
||||||
|
|
||||||
|
struct Process_entry
|
||||||
|
{
|
||||||
|
virtual size_t operator()(Genode::Trace::Buffer::Entry&) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Trace::Buffer *buffer;
|
||||||
|
Genode::Trace::Buffer::Entry current_entry;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Trace_buffer_manager(Genode::Region_map &rm,
|
||||||
|
Genode::Dataspace_capability ds_cap)
|
||||||
|
:
|
||||||
|
buffer(rm.attach(ds_cap)),
|
||||||
|
current_entry(buffer->first())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
size_t dump_entry(Process_entry &process)
|
||||||
|
{
|
||||||
|
size_t len = process(current_entry);
|
||||||
|
|
||||||
|
current_entry = buffer->next(current_entry);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool last_entry() const
|
||||||
|
{
|
||||||
|
return current_entry.last();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rewind() { current_entry = buffer->first(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Allocator &_md_alloc;
|
||||||
|
|
||||||
|
Genode::Region_map &_rm;
|
||||||
|
|
||||||
|
int _handle;
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id _id;
|
||||||
|
Genode::Trace::Policy_id _policy_id;
|
||||||
|
|
||||||
|
bool _was_traced;
|
||||||
|
|
||||||
|
Trace_buffer_manager *_buffer_manager;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Active_file active_file;
|
||||||
|
Buffer_size_file buffer_size_file;
|
||||||
|
Cleanup_file cleanup_file;
|
||||||
|
Enable_file enable_file;
|
||||||
|
Events_file events_file;
|
||||||
|
Policy_file policy_file;
|
||||||
|
|
||||||
|
Followed_subject(Genode::Allocator &md_alloc, char const *name,
|
||||||
|
Genode::Region_map &rm,
|
||||||
|
Genode::Trace::Subject_id &id, int handle)
|
||||||
|
:
|
||||||
|
Directory(name),
|
||||||
|
_md_alloc(md_alloc),
|
||||||
|
_rm(rm),
|
||||||
|
_handle(handle),
|
||||||
|
_id(id),
|
||||||
|
_was_traced(false),
|
||||||
|
_buffer_manager(0),
|
||||||
|
active_file(_id),
|
||||||
|
buffer_size_file(),
|
||||||
|
cleanup_file(_id),
|
||||||
|
enable_file(_id),
|
||||||
|
events_file(_id, _md_alloc),
|
||||||
|
policy_file(_id, _md_alloc)
|
||||||
|
{
|
||||||
|
adopt_unsynchronized(&active_file);
|
||||||
|
adopt_unsynchronized(&cleanup_file);
|
||||||
|
adopt_unsynchronized(&enable_file);
|
||||||
|
adopt_unsynchronized(&events_file);
|
||||||
|
adopt_unsynchronized(&buffer_size_file);
|
||||||
|
adopt_unsynchronized(&policy_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Followed_subject()
|
||||||
|
{
|
||||||
|
discard_unsynchronized(&active_file);
|
||||||
|
discard_unsynchronized(&cleanup_file);
|
||||||
|
discard_unsynchronized(&enable_file);
|
||||||
|
discard_unsynchronized(&events_file);
|
||||||
|
discard_unsynchronized(&buffer_size_file);
|
||||||
|
discard_unsynchronized(&policy_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool marked_for_cleanup() const { return cleanup_file.cleanup(); }
|
||||||
|
bool was_traced() const { return _was_traced; }
|
||||||
|
|
||||||
|
Trace_buffer_manager* trace_buffer_manager() { return _buffer_manager; }
|
||||||
|
|
||||||
|
void manage_trace_buffer(Genode::Dataspace_capability ds_cap)
|
||||||
|
{
|
||||||
|
if (_buffer_manager != 0)
|
||||||
|
throw Trace_buffer_manager::Already_managed();
|
||||||
|
|
||||||
|
_buffer_manager = new (&_md_alloc) Trace_buffer_manager(_rm, ds_cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmanage_trace_buffer()
|
||||||
|
{
|
||||||
|
if (_buffer_manager == 0)
|
||||||
|
throw Trace_buffer_manager::Not_managed();
|
||||||
|
|
||||||
|
destroy(&_md_alloc, _buffer_manager);
|
||||||
|
_buffer_manager = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Genode::Trace::Subject_id id() const { return _id; }
|
||||||
|
|
||||||
|
const Genode::Trace::Policy_id policy_id() const { return _policy_id; }
|
||||||
|
void policy_id(Genode::Trace::Policy_id &id) { _policy_id.id = id.id; }
|
||||||
|
bool policy_valid() const { return (_policy_id.id != 0); }
|
||||||
|
void invalidate_policy() { _policy_id = Genode::Trace::Policy_id(); }
|
||||||
|
|
||||||
|
int handle() const { return _handle; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This registry contains all current followed trace subjects
|
||||||
|
*/
|
||||||
|
class Trace_fs::Followed_subject_registry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class Invalid_subject { };
|
||||||
|
class Out_of_subject_handles { };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* XXX abitrary limit - needs to be revisited when highly
|
||||||
|
* dynamic scenarios are executed */
|
||||||
|
enum { MAX_SUBJECTS = 1024U };
|
||||||
|
|
||||||
|
Followed_subject *_subjects[MAX_SUBJECTS];
|
||||||
|
|
||||||
|
Genode::Allocator &_md_alloc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find free subject handle
|
||||||
|
*
|
||||||
|
* \throw Out_of_subject_handles
|
||||||
|
*/
|
||||||
|
int _find_free_handle()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < MAX_SUBJECTS; i++)
|
||||||
|
if (!_subjects[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Out_of_subject_handles();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _in_range(int handle) const
|
||||||
|
{
|
||||||
|
return ((handle >= 0) && (handle < MAX_SUBJECTS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Followed_subject_registry(Genode::Allocator &md_alloc)
|
||||||
|
:
|
||||||
|
_md_alloc(md_alloc)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < MAX_SUBJECTS; i++)
|
||||||
|
_subjects[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return maximal number of subject that can be stored in the registry
|
||||||
|
*
|
||||||
|
* \return maximal number of subjects
|
||||||
|
*/
|
||||||
|
unsigned max_subjects() const { return MAX_SUBJECTS; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate new subject
|
||||||
|
*
|
||||||
|
* \param name name of subject
|
||||||
|
* \param id subject id of tracre subject
|
||||||
|
*/
|
||||||
|
Followed_subject *alloc(char const *name, Genode::Trace::Subject_id &id,
|
||||||
|
Genode::Region_map &rm)
|
||||||
|
{
|
||||||
|
int handle = _find_free_handle();
|
||||||
|
|
||||||
|
_subjects[handle] = new (&_md_alloc) Followed_subject(_md_alloc, name, rm, id, handle);
|
||||||
|
|
||||||
|
return _subjects[handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free subject
|
||||||
|
*
|
||||||
|
* \param subject pointer to subject
|
||||||
|
*/
|
||||||
|
void free(Followed_subject *subject)
|
||||||
|
{
|
||||||
|
int handle = subject->handle();
|
||||||
|
|
||||||
|
if (!_in_range(handle))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!_subjects[handle])
|
||||||
|
return;
|
||||||
|
|
||||||
|
_subjects[handle] = 0;
|
||||||
|
destroy(&_md_alloc, subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup subject by using the id
|
||||||
|
*
|
||||||
|
* \throw Invalid_subject();
|
||||||
|
*/
|
||||||
|
Followed_subject *lookup(Genode::Trace::Subject_id const &sid)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < MAX_SUBJECTS; i++)
|
||||||
|
if (_subjects[i]) {
|
||||||
|
if (_subjects[i]->id().id == sid.id)
|
||||||
|
return _subjects[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Invalid_subject();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _SUBJECT_REGISTRY_H_ */
|
#endif /* _SUBJECT_REGISTRY_H_ */
|
||||||
|
@ -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,23 +603,18 @@ 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:
|
||||||
|
|
||||||
Genode::Entrypoint &_ep;
|
typedef File_system::Open_node<Node> Open_node;
|
||||||
Ram_session &_ram;
|
|
||||||
Allocator &_md_alloc;
|
Genode::Entrypoint &_ep;
|
||||||
Directory &_root_dir;
|
Ram_session &_ram;
|
||||||
Node_handle_registry _handle_registry;
|
Allocator &_md_alloc;
|
||||||
bool _writeable;
|
Directory &_root_dir;
|
||||||
|
Id_space<File_system::Node> _open_node_registry;
|
||||||
|
bool _writeable;
|
||||||
|
|
||||||
unsigned _subject_limit;
|
unsigned _subject_limit;
|
||||||
unsigned _poll_interval;
|
unsigned _poll_interval;
|
||||||
@ -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
|
||||||
@ -748,20 +752,20 @@ class File_system::Session_component : public Session_rpc_object
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Session_component(size_t tx_buf_size,
|
Session_component(size_t tx_buf_size,
|
||||||
Genode::Entrypoint &ep,
|
Genode::Entrypoint &ep,
|
||||||
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,
|
||||||
size_t trace_quota,
|
size_t trace_quota,
|
||||||
size_t trace_meta_quota,
|
size_t trace_meta_quota,
|
||||||
size_t trace_parent_levels,
|
size_t trace_parent_levels,
|
||||||
size_t buffer_size,
|
size_t buffer_size,
|
||||||
size_t buffer_size_max)
|
size_t buffer_size_max)
|
||||||
:
|
:
|
||||||
Session_rpc_object(ram.alloc(tx_buf_size), rm, ep.rpc_ep()),
|
Session_rpc_object(ram.alloc(tx_buf_size), rm, ep.rpc_ep()),
|
||||||
_ep(ep),
|
_ep(ep),
|
||||||
@ -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) {
|
||||||
|
|
||||||
if (create)
|
Node &dir = open_node.node();
|
||||||
throw Permission_denied();
|
|
||||||
|
|
||||||
File *file = dynamic_cast<File*>(dir->lookup(name.string()));
|
if (create)
|
||||||
if (!file)
|
throw Permission_denied();
|
||||||
throw Invalid_name();
|
|
||||||
|
|
||||||
return _handle_registry.alloc(file);
|
File *file = dynamic_cast<File*>(dir.lookup(name.string()));
|
||||||
|
if (!file)
|
||||||
|
throw Invalid_name();
|
||||||
|
|
||||||
|
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); }
|
||||||
|
@ -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,49 +20,67 @@
|
|||||||
#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
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef char Name[128];
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
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()
|
|
||||||
: _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 Status status() const = 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;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Trace_fs::Node : public Node_base, public List<Node>::Element
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef char Name[128];
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
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()
|
||||||
|
: _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 Status status() const = 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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_ */
|
||||||
|
@ -4,30 +4,38 @@
|
|||||||
* \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
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
Symlink(char const *name) : File(name) { }
|
|
||||||
|
|
||||||
size_t read(char *dst, size_t len, seek_off_t seek_offset) {
|
|
||||||
return 0; }
|
|
||||||
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset) {
|
|
||||||
return 0; }
|
|
||||||
|
|
||||||
file_size_t length() const { return 0; }
|
|
||||||
|
|
||||||
void truncate(file_size_t) { }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Trace_fs::Symlink : public File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Symlink(char const *name) : File(name) { }
|
||||||
|
|
||||||
|
size_t read(char *dst, size_t len, seek_off_t seek_offset) {
|
||||||
|
return 0; }
|
||||||
|
|
||||||
|
size_t write(char const *src, size_t len, seek_off_t seek_offset) {
|
||||||
|
return 0; }
|
||||||
|
|
||||||
|
file_size_t length() const { return 0; }
|
||||||
|
|
||||||
|
void truncate(file_size_t) { }
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _SYMLINK_H_ */
|
#endif /* _SYMLINK_H_ */
|
||||||
|
@ -21,412 +21,418 @@
|
|||||||
#include <file.h>
|
#include <file.h>
|
||||||
|
|
||||||
|
|
||||||
namespace File_system {
|
namespace Trace_fs {
|
||||||
|
class State_file;
|
||||||
/**
|
class Active_file;
|
||||||
* The State_file is a stateful file that is used to implement
|
class Cleanup_file;
|
||||||
* files in the file system, which may trigger a action in the
|
class Enable_file;
|
||||||
* file system backend.
|
class Events_file;
|
||||||
*/
|
class Buffer_size_file;
|
||||||
|
class Policy_file;
|
||||||
class State_file : public File,
|
|
||||||
public Changeable_content
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
bool _state;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
State_file(char const *name)
|
|
||||||
: File(name), _state(false) { }
|
|
||||||
|
|
||||||
bool state() const { return _state; }
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** Node interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
virtual size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
/* limit len */
|
|
||||||
if (len > 2)
|
|
||||||
len = 2;
|
|
||||||
|
|
||||||
switch (len) {
|
|
||||||
case 2:
|
|
||||||
dst[1] = '\n';
|
|
||||||
case 1:
|
|
||||||
dst[0] = 0x30 + (char)_state;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* zero length is useless */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
char buf[32];
|
|
||||||
if (len >= sizeof buf)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
strncpy(buf, src, min(len + 1, sizeof (buf)));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For now, we only check the leading digit and do not care
|
|
||||||
* about the rest.
|
|
||||||
*/
|
|
||||||
if (!strcmp(buf, "1", 1)) {
|
|
||||||
_state = true;
|
|
||||||
}
|
|
||||||
else if (!strcmp(buf, "0", 1)) {
|
|
||||||
_state = false;
|
|
||||||
} else {
|
|
||||||
/* silently ignore bogus writes */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Changeable_content::_changed = true;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status status() const
|
|
||||||
{
|
|
||||||
Status s;
|
|
||||||
|
|
||||||
s.inode = inode();
|
|
||||||
s.size = 2;
|
|
||||||
s.mode = File_system::Status::MODE_FILE;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** File interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
file_size_t length() const { return 2; }
|
|
||||||
void truncate(file_size_t size) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Active_file node shows the state of the tracing
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Active_file : public State_file
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id &_id;
|
|
||||||
bool _active;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Active_file(Genode::Trace::Subject_id &id)
|
|
||||||
: State_file("active"), _id(id) { }
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id& id() const { return _id; }
|
|
||||||
|
|
||||||
bool active() const { return State_file::state(); }
|
|
||||||
|
|
||||||
void set_active() { _state = true; }
|
|
||||||
void set_inactive() { _state = false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Cleanup_file is used to trigger the removal of files used by
|
|
||||||
* the traced subject and to free utilized memory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Cleanup_file : public State_file
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id &_id;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Cleanup_file(Genode::Trace::Subject_id &id)
|
|
||||||
: State_file("cleanup"), _id(id) { }
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id& id() const { return _id; }
|
|
||||||
|
|
||||||
bool cleanup() const { return State_file::state(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Enable_file is used to initiate the tracing process
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Enable_file : public State_file
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id &_id;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Enable_file(Genode::Trace::Subject_id &id)
|
|
||||||
: State_file("enable"), _id(id) { }
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id& id() const { return _id; }
|
|
||||||
|
|
||||||
bool enabled() const { return State_file::state(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Events_file encapsulates the trace buffer of traced thread
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Events_file : public Buffered_file
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id &_id;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Events_file(Genode::Trace::Subject_id &id,
|
|
||||||
Allocator &md_alloc)
|
|
||||||
: Buffered_file(md_alloc, "events"), _id(id) { }
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id id() const { return _id; }
|
|
||||||
|
|
||||||
size_t append(char const *src, size_t len)
|
|
||||||
{
|
|
||||||
Buffered_file::write(src, len, length());
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** File interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
/* override to prevent the user from overriding the file */
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset) { return 0; }
|
|
||||||
void truncate(file_size_t size) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file contains the size of the trace buffer
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Buffer_size_file : public File,
|
|
||||||
public Changeable_content
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
file_size_t _length;
|
|
||||||
unsigned long _size_limit;
|
|
||||||
unsigned long _size;
|
|
||||||
|
|
||||||
char _content[32];
|
|
||||||
Genode::size_t _content_filled;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if new size honors the size limit
|
|
||||||
*
|
|
||||||
* \param size new size of the buffer
|
|
||||||
* \return size limit if new size is greater, otherwise new size
|
|
||||||
*/
|
|
||||||
size_t _check_size_limit(size_t size)
|
|
||||||
{
|
|
||||||
if (size > _size_limit)
|
|
||||||
return _size_limit;
|
|
||||||
else
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evalute the current content of the buffer
|
|
||||||
*/
|
|
||||||
void _refresh_content()
|
|
||||||
{
|
|
||||||
unsigned long tmp = 0;
|
|
||||||
|
|
||||||
_content[_content_filled - 1] = '\0';
|
|
||||||
_content_filled = 0;
|
|
||||||
|
|
||||||
_length = Genode::strlen(_content);
|
|
||||||
|
|
||||||
/* account for \n when reading from the file */
|
|
||||||
_length += 1;
|
|
||||||
|
|
||||||
ascii_to(_content, tmp);
|
|
||||||
|
|
||||||
_size = _check_size_limit(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Buffer_size_file() : File("buffer_size"), _size_limit(0), _size(0) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return current size of the trace buffer
|
|
||||||
*/
|
|
||||||
unsigned long size() const { return _size; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set current size of the trace buffer
|
|
||||||
*/
|
|
||||||
void size(unsigned long size)
|
|
||||||
{
|
|
||||||
_size = _check_size_limit(size);
|
|
||||||
|
|
||||||
/* update file content */
|
|
||||||
_length = Genode::snprintf(_content, sizeof (_content), "%lu", _size);
|
|
||||||
|
|
||||||
/* account for \n when reading from the file */
|
|
||||||
_length += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set max size of a trace buffer
|
|
||||||
*/
|
|
||||||
void size_limit(unsigned long limit) { _size_limit = limit; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return maximal size of the trace buffer
|
|
||||||
*/
|
|
||||||
unsigned long size_limit() const { return _size_limit; }
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** Node interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read current maximal size of the trace buffer
|
|
||||||
*/
|
|
||||||
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
if (len > 32) {
|
|
||||||
Genode::error("len:'", len, "' to small");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[32];
|
|
||||||
Genode::snprintf(buf, sizeof (buf), "%lu\n", _size);
|
|
||||||
memcpy(dst, buf, len);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write new current maximal size of the trace buffer
|
|
||||||
*/
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
if ((_content_filled + len) > sizeof (_content))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Genode::memcpy(_content + _content_filled, src, len);
|
|
||||||
_content_filled += len;
|
|
||||||
|
|
||||||
Changeable_content::_changed = true;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status status() const
|
|
||||||
{
|
|
||||||
Status s;
|
|
||||||
|
|
||||||
s.inode = inode();
|
|
||||||
s.size = _length;
|
|
||||||
s.mode = File_system::Status::MODE_FILE;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** File interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
file_size_t length() const { return _length; }
|
|
||||||
|
|
||||||
void truncate(file_size_t size) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Policy file
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Policy_file : public Buffered_file,
|
|
||||||
public Changeable_content
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id &_id;
|
|
||||||
file_size_t _length;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Policy_file(Genode::Trace::Subject_id &id,
|
|
||||||
Genode::Allocator &md_alloc)
|
|
||||||
: Buffered_file(md_alloc, "policy"), _id(id) { }
|
|
||||||
|
|
||||||
Genode::Trace::Subject_id& id() const { return _id; }
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** Node interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
return Buffered_file::read(dst, len, seek_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
|
||||||
{
|
|
||||||
size_t written = Buffered_file::write(src, len, seek_offset);
|
|
||||||
|
|
||||||
if (written > 0)
|
|
||||||
_changed = true;
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** File interface **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
void truncate(file_size_t size)
|
|
||||||
{
|
|
||||||
Buffered_file::truncate(size);
|
|
||||||
|
|
||||||
_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The State_file is a stateful file that is used to implement
|
||||||
|
* files in the file system, which may trigger a action in the
|
||||||
|
* file system backend.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::State_file : public File,
|
||||||
|
public Changeable_content
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool _state;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
State_file(char const *name)
|
||||||
|
: File(name), _state(false) { }
|
||||||
|
|
||||||
|
bool state() const { return _state; }
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** Node interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
virtual size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
/* limit len */
|
||||||
|
if (len > 2)
|
||||||
|
len = 2;
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 2:
|
||||||
|
dst[1] = '\n';
|
||||||
|
case 1:
|
||||||
|
dst[0] = 0x30 + (char)_state;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* zero length is useless */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
if (len >= sizeof buf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
strncpy(buf, src, min(len + 1, sizeof (buf)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For now, we only check the leading digit and do not care
|
||||||
|
* about the rest.
|
||||||
|
*/
|
||||||
|
if (!strcmp(buf, "1", 1)) {
|
||||||
|
_state = true;
|
||||||
|
}
|
||||||
|
else if (!strcmp(buf, "0", 1)) {
|
||||||
|
_state = false;
|
||||||
|
} else {
|
||||||
|
/* silently ignore bogus writes */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Changeable_content::_changed = true;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status status() const
|
||||||
|
{
|
||||||
|
Status s;
|
||||||
|
|
||||||
|
s.inode = inode();
|
||||||
|
s.size = 2;
|
||||||
|
s.mode = File_system::Status::MODE_FILE;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** File interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
file_size_t length() const { return 2; }
|
||||||
|
void truncate(file_size_t size) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Active_file node shows the state of the tracing
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::Active_file : public State_file
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id &_id;
|
||||||
|
bool _active;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Active_file(Genode::Trace::Subject_id &id)
|
||||||
|
: State_file("active"), _id(id) { }
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id& id() const { return _id; }
|
||||||
|
|
||||||
|
bool active() const { return State_file::state(); }
|
||||||
|
|
||||||
|
void set_active() { _state = true; }
|
||||||
|
void set_inactive() { _state = false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Cleanup_file is used to trigger the removal of files used by
|
||||||
|
* the traced subject and to free utilized memory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::Cleanup_file : public State_file
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id &_id;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Cleanup_file(Genode::Trace::Subject_id &id)
|
||||||
|
: State_file("cleanup"), _id(id) { }
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id& id() const { return _id; }
|
||||||
|
|
||||||
|
bool cleanup() const { return State_file::state(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Enable_file is used to initiate the tracing process
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::Enable_file : public State_file
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id &_id;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Enable_file(Genode::Trace::Subject_id &id)
|
||||||
|
: State_file("enable"), _id(id) { }
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id& id() const { return _id; }
|
||||||
|
|
||||||
|
bool enabled() const { return State_file::state(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Events_file encapsulates the trace buffer of traced thread
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::Events_file : public Buffered_file
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id &_id;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Events_file(Genode::Trace::Subject_id &id,
|
||||||
|
Allocator &md_alloc)
|
||||||
|
: Buffered_file(md_alloc, "events"), _id(id) { }
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id id() const { return _id; }
|
||||||
|
|
||||||
|
size_t append(char const *src, size_t len)
|
||||||
|
{
|
||||||
|
Buffered_file::write(src, len, length());
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** File interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
/* override to prevent the user from overriding the file */
|
||||||
|
size_t write(char const *src, size_t len, seek_off_t seek_offset) { return 0; }
|
||||||
|
void truncate(file_size_t size) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file contains the size of the trace buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::Buffer_size_file : public File,
|
||||||
|
public Changeable_content
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
file_size_t _length;
|
||||||
|
unsigned long _size_limit;
|
||||||
|
unsigned long _size;
|
||||||
|
|
||||||
|
char _content[32];
|
||||||
|
Genode::size_t _content_filled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if new size honors the size limit
|
||||||
|
*
|
||||||
|
* \param size new size of the buffer
|
||||||
|
* \return size limit if new size is greater, otherwise new size
|
||||||
|
*/
|
||||||
|
size_t _check_size_limit(size_t size)
|
||||||
|
{
|
||||||
|
if (size > _size_limit)
|
||||||
|
return _size_limit;
|
||||||
|
else
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evalute the current content of the buffer
|
||||||
|
*/
|
||||||
|
void _refresh_content()
|
||||||
|
{
|
||||||
|
unsigned long tmp = 0;
|
||||||
|
|
||||||
|
_content[_content_filled - 1] = '\0';
|
||||||
|
_content_filled = 0;
|
||||||
|
|
||||||
|
_length = Genode::strlen(_content);
|
||||||
|
|
||||||
|
/* account for \n when reading from the file */
|
||||||
|
_length += 1;
|
||||||
|
|
||||||
|
ascii_to(_content, tmp);
|
||||||
|
|
||||||
|
_size = _check_size_limit(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Buffer_size_file() : File("buffer_size"), _size_limit(0), _size(0) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return current size of the trace buffer
|
||||||
|
*/
|
||||||
|
unsigned long size() const { return _size; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set current size of the trace buffer
|
||||||
|
*/
|
||||||
|
void size(unsigned long size)
|
||||||
|
{
|
||||||
|
_size = _check_size_limit(size);
|
||||||
|
|
||||||
|
/* update file content */
|
||||||
|
_length = Genode::snprintf(_content, sizeof (_content), "%lu", _size);
|
||||||
|
|
||||||
|
/* account for \n when reading from the file */
|
||||||
|
_length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set max size of a trace buffer
|
||||||
|
*/
|
||||||
|
void size_limit(unsigned long limit) { _size_limit = limit; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return maximal size of the trace buffer
|
||||||
|
*/
|
||||||
|
unsigned long size_limit() const { return _size_limit; }
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** Node interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read current maximal size of the trace buffer
|
||||||
|
*/
|
||||||
|
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
if (len > 32) {
|
||||||
|
Genode::error("len:'", len, "' to small");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[32];
|
||||||
|
Genode::snprintf(buf, sizeof (buf), "%lu\n", _size);
|
||||||
|
memcpy(dst, buf, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write new current maximal size of the trace buffer
|
||||||
|
*/
|
||||||
|
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
if ((_content_filled + len) > sizeof (_content))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Genode::memcpy(_content + _content_filled, src, len);
|
||||||
|
_content_filled += len;
|
||||||
|
|
||||||
|
Changeable_content::_changed = true;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status status() const
|
||||||
|
{
|
||||||
|
Status s;
|
||||||
|
|
||||||
|
s.inode = inode();
|
||||||
|
s.size = _length;
|
||||||
|
s.mode = File_system::Status::MODE_FILE;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** File interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
file_size_t length() const { return _length; }
|
||||||
|
|
||||||
|
void truncate(file_size_t size) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Policy file
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Trace_fs::Policy_file : public Buffered_file,
|
||||||
|
public Changeable_content
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id &_id;
|
||||||
|
file_size_t _length;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Policy_file(Genode::Trace::Subject_id &id,
|
||||||
|
Genode::Allocator &md_alloc)
|
||||||
|
: Buffered_file(md_alloc, "policy"), _id(id) { }
|
||||||
|
|
||||||
|
Genode::Trace::Subject_id& id() const { return _id; }
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** Node interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
return Buffered_file::read(dst, len, seek_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
|
{
|
||||||
|
size_t written = Buffered_file::write(src, len, seek_offset);
|
||||||
|
|
||||||
|
if (written > 0)
|
||||||
|
_changed = true;
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** File interface **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
void truncate(file_size_t size)
|
||||||
|
{
|
||||||
|
Buffered_file::truncate(size);
|
||||||
|
|
||||||
|
_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _TRACE_FILES_H_ */
|
#endif /* _TRACE_FILES_H_ */
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user