mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-22 16:59:03 +00:00
committed by
Christian Helmuth
parent
0d1be4abe2
commit
6a43f3c11a
@ -5,6 +5,13 @@
|
||||
* \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_
|
||||
#define _DIRECTORY_H_
|
||||
|
||||
@ -19,13 +26,14 @@
|
||||
#include <lx_util.h>
|
||||
|
||||
|
||||
namespace File_system {
|
||||
namespace Lx_fs {
|
||||
using namespace Genode;
|
||||
using namespace File_system;
|
||||
class Directory;
|
||||
}
|
||||
|
||||
|
||||
class File_system::Directory : public Node
|
||||
class Lx_fs::Directory : public Node
|
||||
{
|
||||
private:
|
||||
|
||||
@ -72,6 +80,16 @@ class File_system::Directory : public Node
|
||||
return fd;
|
||||
}
|
||||
|
||||
size_t _num_entries() const
|
||||
{
|
||||
unsigned num = 0;
|
||||
|
||||
rewinddir(_fd);
|
||||
while (readdir(_fd)) ++num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
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 */
|
||||
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->lock();
|
||||
return file;
|
||||
}
|
||||
|
||||
@ -105,7 +122,6 @@ class File_system::Directory : public Node
|
||||
|
||||
Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create);
|
||||
|
||||
dir->lock();
|
||||
return dir;
|
||||
}
|
||||
|
||||
@ -134,11 +150,10 @@ class File_system::Directory : public Node
|
||||
else
|
||||
throw Lookup_failed();
|
||||
|
||||
node->lock();
|
||||
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)) {
|
||||
Genode::error("read buffer too small for directory entry");
|
||||
@ -177,20 +192,19 @@ class File_system::Directory : public Node
|
||||
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 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t num_entries() const
|
||||
Status status() override
|
||||
{
|
||||
unsigned num = 0;
|
||||
|
||||
rewinddir(_fd);
|
||||
while (readdir(_fd)) ++num;
|
||||
|
||||
return num;
|
||||
Status s;
|
||||
s.inode = inode();
|
||||
s.size = _num_entries() * sizeof(File_system::Directory_entry);
|
||||
s.mode = File_system::Status::MODE_DIRECTORY;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,13 @@
|
||||
* \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_
|
||||
#define _FILE_H_
|
||||
|
||||
@ -13,12 +20,13 @@
|
||||
#include <lx_util.h>
|
||||
|
||||
|
||||
namespace File_system {
|
||||
namespace Lx_fs {
|
||||
using namespace File_system;
|
||||
class File;
|
||||
}
|
||||
|
||||
|
||||
class File_system::File : public Node
|
||||
class Lx_fs::File : public Node
|
||||
{
|
||||
private:
|
||||
|
||||
@ -74,6 +82,16 @@ class File_system::File : public Node
|
||||
return fd;
|
||||
}
|
||||
|
||||
file_size_t _length() const
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
if (fstat(_fd, &s) < 0)
|
||||
return 0;
|
||||
|
||||
return s.st_size;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
File(int dir,
|
||||
@ -95,14 +113,14 @@ class File_system::File : public Node
|
||||
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);
|
||||
|
||||
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? */
|
||||
if (seek_offset == ~0ULL) {
|
||||
@ -117,17 +135,16 @@ class File_system::File : public Node
|
||||
return ret == -1 ? 0 : ret;
|
||||
}
|
||||
|
||||
file_size_t length() const
|
||||
Status status() override
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
if (fstat(_fd, &s) < 0)
|
||||
return 0;
|
||||
|
||||
return s.st_size;
|
||||
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 (ftruncate(_fd, size)) /* nothing */;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <base/heap.h>
|
||||
#include <base/attached_rom_dataspace.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 <os/session_policy.h>
|
||||
#include <util/xml_node.h>
|
||||
@ -25,22 +25,29 @@
|
||||
#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 Session_component;
|
||||
struct Root;
|
||||
}
|
||||
|
||||
|
||||
class File_system::Session_component : public Session_rpc_object
|
||||
class Lx_fs::Session_component : public Session_rpc_object
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Env &_env;
|
||||
Allocator &_md_alloc;
|
||||
Directory &_root;
|
||||
Node_handle_registry _handle_registry;
|
||||
bool _writable;
|
||||
typedef File_system::Open_node<Node> Open_node;
|
||||
|
||||
Genode::Env &_env;
|
||||
Allocator &_md_alloc;
|
||||
Directory &_root;
|
||||
Id_space<File_system::Node> _open_node_registry;
|
||||
bool _writable;
|
||||
|
||||
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
|
||||
*/
|
||||
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);
|
||||
size_t const length = packet.length();
|
||||
@ -66,18 +73,18 @@ class File_system::Session_component : public Session_rpc_object
|
||||
|
||||
case Packet_descriptor::READ:
|
||||
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;
|
||||
|
||||
case Packet_descriptor::WRITE:
|
||||
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;
|
||||
|
||||
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*/
|
||||
node.notify_listeners();
|
||||
open_node.node().notify_listeners();
|
||||
/* otherwise defer acknowledgement of this packet */
|
||||
return;
|
||||
|
||||
@ -98,13 +105,16 @@ class File_system::Session_component : public Session_rpc_object
|
||||
/* assume failure by default */
|
||||
packet.succeeded(false);
|
||||
|
||||
try {
|
||||
Node *node = _handle_registry.lookup_and_lock(packet.handle());
|
||||
Node_lock_guard guard(node);
|
||||
auto process_packet_fn = [&] (Open_node &open_node) {
|
||||
_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"); }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,23 +201,35 @@ class File_system::Session_component : public Session_rpc_object
|
||||
if (!valid_name(name.string()))
|
||||
throw Invalid_name();
|
||||
|
||||
Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
|
||||
Node_lock_guard dir_guard(dir);
|
||||
auto file_fn = [&] (Open_node &open_node) {
|
||||
|
||||
if (!_writable)
|
||||
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
|
||||
throw Permission_denied();
|
||||
Node &dir = open_node.node();
|
||||
|
||||
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);
|
||||
return _handle_registry.alloc(file);
|
||||
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)
|
||||
{
|
||||
Genode::error(__func__, " not implemented");
|
||||
return Symlink_handle();
|
||||
throw Permission_denied();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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)
|
||||
@ -238,43 +263,38 @@ class File_system::Session_component : public Session_rpc_object
|
||||
|
||||
Node *node = _root.node(path_str + 1);
|
||||
|
||||
Node_lock_guard guard(node);
|
||||
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)
|
||||
{
|
||||
/* FIXME when to destruct node? */
|
||||
_handle_registry.free(handle);
|
||||
auto close_fn = [&] (Open_node &open_node) {
|
||||
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)
|
||||
{
|
||||
Node *node = _handle_registry.lookup_and_lock(node_handle);
|
||||
Node_lock_guard guard(node);
|
||||
auto status_fn = [&] (Open_node &open_node) {
|
||||
return open_node.node().status();
|
||||
};
|
||||
|
||||
Status s;
|
||||
s.inode = node->inode();
|
||||
s.size = 0;
|
||||
s.mode = 0;
|
||||
|
||||
File *file = dynamic_cast<File *>(node);
|
||||
if (file) {
|
||||
s.size = file->length();
|
||||
s.mode = File_system::Status::MODE_FILE;
|
||||
return s;
|
||||
try {
|
||||
return _open_node_registry.apply<Open_node>(node_handle, status_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
|
||||
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)
|
||||
@ -292,9 +312,15 @@ class File_system::Session_component : public Session_rpc_object
|
||||
if (!_writable)
|
||||
throw Permission_denied();
|
||||
|
||||
File *file = _handle_registry.lookup_and_lock(file_handle);
|
||||
Node_lock_guard file_guard(file);
|
||||
file->truncate(size);
|
||||
auto truncate_fn = [&] (Open_node &open_node) {
|
||||
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, 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:
|
||||
|
||||
@ -419,7 +445,7 @@ class File_system::Root : public Root_component<Session_component>
|
||||
};
|
||||
|
||||
|
||||
struct File_system::Main
|
||||
struct Lx_fs::Main
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_
|
||||
#define _NODE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <file_system/listener.h>
|
||||
#include <file_system/node.h>
|
||||
|
||||
|
||||
namespace File_system {
|
||||
|
||||
class Node : public 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;
|
||||
};
|
||||
|
||||
namespace Lx_fs {
|
||||
using namespace File_system;
|
||||
class Node;
|
||||
class File;
|
||||
}
|
||||
|
||||
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_ */
|
||||
|
@ -7,6 +7,13 @@
|
||||
* 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_
|
||||
#define _SYMLINK_H_
|
||||
|
||||
@ -26,18 +33,20 @@ class File_system::Symlink : public Node
|
||||
|
||||
char _link_to[MAX_PATH_LEN];
|
||||
|
||||
file_size_t _length() const { return strlen(_link_to) + 1; }
|
||||
|
||||
public:
|
||||
|
||||
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);
|
||||
Genode::strncpy(dst, _link_to, 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. */
|
||||
if (seek_offset) return 0;
|
||||
@ -47,7 +56,14 @@ class File_system::Symlink : public Node
|
||||
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_ */
|
||||
|
Reference in New Issue
Block a user