Move generic fs helpers to os/include/file_system

Fixes #1488
This commit is contained in:
Emery Hemingway 2015-04-23 15:26:54 -04:00 committed by Christian Helmuth
parent eecb5cc300
commit 55c0a947e4
35 changed files with 266 additions and 1722 deletions

View File

@ -18,10 +18,10 @@
/* Genode include */ /* Genode include */
#include <os/path.h> #include <os/path.h>
#include <file_system/util.h>
/* local includes */ /* local includes */
#include "node.h" #include "node.h"
#include "util.h"
#include "file.h" #include "file.h"
#include "symlink.h" #include "symlink.h"

View File

@ -16,8 +16,10 @@
#ifndef _FILE_H_ #ifndef _FILE_H_
#define _FILE_H_ #define _FILE_H_
/* Genode includes */
#include <file_system/util.h>
#include "node.h" #include "node.h"
#include "util.h"
namespace File_system { namespace File_system {
class File; class File;

View File

@ -12,6 +12,9 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <file_system/node_handle_registry.h>
#include "undef.h" #include "undef.h"
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
@ -21,8 +24,6 @@
#include <rump_fs/fs.h> #include <rump_fs/fs.h>
#include "file_system.h" #include "file_system.h"
#include "directory.h" #include "directory.h"
#include "node_handle_registry.h"
namespace File_system { namespace File_system {
struct Main; struct Main;

View File

@ -17,47 +17,16 @@
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <file_system/node.h>
#include <util/list.h> #include <util/list.h>
#include <base/signal.h> #include <base/signal.h>
namespace File_system { namespace File_system {
class Listener;
class Node; class Node;
} }
class File_system::Listener : public List<Listener>::Element class File_system::Node : public Node_base, public List<Node>::Element
{
private:
Signal_context_capability _sigh;
bool _marked_as_updated;
public:
Listener() : _marked_as_updated(false) { }
Listener(Signal_context_capability sigh)
: _sigh(sigh), _marked_as_updated(false) { }
void notify()
{
if (_marked_as_updated && _sigh.valid())
Signal_transmitter(_sigh).submit();
_marked_as_updated = false;
}
void mark_as_updated()
{
_marked_as_updated = true;
}
bool valid() const { return _sigh.valid(); }
};
class File_system::Node : public List<Node>::Element
{ {
public: public:
@ -68,22 +37,10 @@ class File_system::Node : public List<Node>::Element
Name _name; Name _name;
unsigned long const _inode; unsigned long const _inode;
List<Listener> _listeners;
public: public:
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; } Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
virtual ~Node()
{
/* propagate event to listeners */
mark_as_updated();
notify_listeners();
while (_listeners.first())
_listeners.remove(_listeners.first());
}
unsigned long inode() const { return _inode; } unsigned long inode() const { return _inode; }
char const *name() const { return _name; } char const *name() const { return _name; }
@ -94,28 +51,6 @@ class File_system::Node : 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;
void add_listener(Listener *listener)
{
_listeners.insert(listener);
}
void remove_listener(Listener *listener)
{
_listeners.remove(listener);
}
void notify_listeners()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->notify();
}
void mark_as_updated()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->mark_as_updated();
}
}; };
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -1,184 +0,0 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
/*
* Copyright (C) 2012-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_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
{
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Node *_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 *node)
{
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)
{
if (!_in_range(handle.value))
return;
/*
* Notify listeners about the changed file.
*/
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) { return; }
node->notify_listeners();
/*
* De-allocate handle
*/
Listener &listener = _listeners[handle.value];
if (listener.valid())
node->remove_listener(&listener);
_nodes[handle.value] = 0;
listener = Listener();
}
/**
* Lookup node using its handle as key
*
* \throw Invalid_handle
*/
template <typename HANDLE_TYPE>
typename Node_type<HANDLE_TYPE>::Type *lookup(HANDLE_TYPE handle)
{
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;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
if (!_in_range(h1.value) || !_in_range(h2.value)) {
PDBG("refer_to_same_node -> Invalid_handle");
throw Invalid_handle();
}
return _nodes[h1.value] == _nodes[h2.value];
}
/**
* Register signal handler to be notified of node changes
*/
void sigh(Node_handle handle, Signal_context_capability sigh)
{
if (!_in_range(handle.value))
throw Invalid_handle();
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) {
PDBG("Invalid_handle");
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(sigh);
node->add_listener(&listener);
}
};
}
#endif /* _NODE_HANDLE_REGISTRY_H_ */

View File

@ -14,10 +14,11 @@
#ifndef _SYMLINK_H_ #ifndef _SYMLINK_H_
#define _SYMLINK_H_ #define _SYMLINK_H_
/* Genode includes */
#include <file_system/util.h>
#include <os/path.h> #include <os/path.h>
#include "node.h" #include "node.h"
#include "util.h"
namespace File_system { namespace File_system {
class Symlink; class Symlink;

View File

@ -1,70 +0,0 @@
/*
* \brief Utilities
* \author Norman Feske
* \date 2012-04-11
*/
/*
* Copyright (C) 2012-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _UTIL_H_
#define _UTIL_H_
/**
* Return base-name portion of null-terminated path string
*/
static inline char const *basename(char const *path)
{
char const *start = path;
for (; *path; path++)
if (*path == '/')
start = path + 1;
return start;
}
/**
* Return true if specified path is a base name (contains no path delimiters)
*/
static inline bool is_basename(char const *path)
{
for (; *path; path++)
if (*path == '/')
return false;
return true;
}
/**
* Return true if character 'c' occurs in null-terminated string 'str'
*/
static inline bool string_contains(char const *str, char c)
{
for (; *str; str++)
if (*str == c)
return true;
return false;
}
/**
* Return true if 'str' is a valid node name
*/
static inline bool valid_name(char const *str)
{
if (string_contains(str, '/')) return false;
/* must have at least one character */
if (str[0] == 0) return false;
return true;
}
#endif /* _UTIL_H_ */

View File

@ -73,7 +73,7 @@ namespace File_system {
switch(res) { switch(res) {
case FR_OK: case FR_OK:
if (verbose) if (verbose)
PDBG("result = %zu", result); PDBG("result = %d", result);
return result; return result;
case FR_DENIED: case FR_DENIED:
PDBG("f_read() failed with error code FR_DENIED"); PDBG("f_read() failed with error code FR_DENIED");
@ -139,7 +139,7 @@ namespace File_system {
switch(res) { switch(res) {
case FR_OK: case FR_OK:
if (verbose) if (verbose)
PDBG("result = %zu", result); PDBG("result = %d", result);
return result; return result;
case FR_DENIED: case FR_DENIED:
PERR("f_write() failed with error code FR_DENIED"); PERR("f_write() failed with error code FR_DENIED");

View File

@ -12,6 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <root/component.h> #include <root/component.h>
#include <cap_session/connection.h> #include <cap_session/connection.h>
@ -23,7 +24,6 @@
/* local includes */ /* local includes */
#include <directory.h> #include <directory.h>
#include <file.h> #include <file.h>
#include <node_handle_registry.h>
#include <util.h> #include <util.h>
/* ffat includes */ /* ffat includes */

View File

@ -8,6 +8,7 @@
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <file_system/node.h>
#include <os/path.h> #include <os/path.h>
/* ffat includes */ /* ffat includes */
@ -19,7 +20,7 @@ namespace File_system {
typedef Genode::Path<_MAX_LFN + 1> Absolute_path; typedef Genode::Path<_MAX_LFN + 1> Absolute_path;
class Node class Node : public Node_base
{ {
protected: protected:

View File

@ -1,130 +0,0 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_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
{
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Lock mutable _lock;
Node *_nodes[MAX_NODE_HANDLES];
/**
* Allocate node handle
*
* \throw Out_of_node_handles
*/
int _alloc(Node *node)
{
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)
{
Lock::Guard guard(_lock);
if (_in_range(handle.value))
_nodes[handle.value] = 0;
}
/**
* Lookup node using its handle as key
*
* \throw Invalid_handle
*/
template <typename HANDLE_TYPE>
typename Node_type<HANDLE_TYPE>::Type *lookup(HANDLE_TYPE handle)
{
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;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
Lock::Guard guard(_lock);
if (!_in_range(h1.value) || !_in_range(h2.value))
throw Invalid_handle();
return _nodes[h1.value] == _nodes[h2.value];
}
};
}
#endif /* _NODE_HANDLE_REGISTRY_H_ */

View File

@ -12,6 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <os/attached_rom_dataspace.h> #include <os/attached_rom_dataspace.h>
#include <os/config.h> #include <os/config.h>
@ -25,10 +26,8 @@
/* local includes */ /* local includes */
#include <directory.h> #include <directory.h>
#include <node_handle_registry.h>
#include <util.h> #include <util.h>
static bool const verbose = false; static bool const verbose = false;
#define PDBGV(...) if (verbose) PDBG(__VA_ARGS__) #define PDBGV(...) if (verbose) PDBG(__VA_ARGS__)
@ -104,7 +103,7 @@ class File_system::Session_component : public Session_rpc_object
try { try {
Node *node = _handle_registry.lookup_and_lock(packet.handle()); Node *node = _handle_registry.lookup_and_lock(packet.handle());
Node_lock_guard guard(*node); Node_lock_guard guard(node);
_process_packet_op(packet, *node); _process_packet_op(packet, *node);
} }
@ -201,7 +200,7 @@ class File_system::Session_component : public Session_rpc_object
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(*dir); Node_lock_guard dir_guard(dir);
PDBGV("dir: '%s' name: '%s' %s", dir->name(), name.string(), PDBGV("dir: '%s' name: '%s' %s", dir->name(), name.string(),
create ? "create" : ""); create ? "create" : "");
@ -210,7 +209,7 @@ class File_system::Session_component : public Session_rpc_object
throw Permission_denied(); throw Permission_denied();
File *file = new (&_md_alloc) File(dir, name.string(), mode, create); File *file = new (&_md_alloc) File(dir, name.string(), mode, create);
Node_lock_guard file_guard(*file); Node_lock_guard file_guard(file);
return _handle_registry.alloc(file); return _handle_registry.alloc(file);
} }
@ -226,7 +225,7 @@ class File_system::Session_component : public Session_rpc_object
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(*dir); Node_lock_guard dir_guard(dir);
PDBGV("dir: '%s' name: '%s'", dir->name(), name.string()); PDBGV("dir: '%s' name: '%s'", dir->name(), name.string());
@ -234,7 +233,7 @@ class File_system::Session_component : public Session_rpc_object
throw Permission_denied(); throw Permission_denied();
Symlink *symlink = new (&_md_alloc) Symlink(dir, name.string(), create); Symlink *symlink = new (&_md_alloc) Symlink(dir, name.string(), create);
Node_lock_guard symlink_guard(*symlink); Node_lock_guard symlink_guard(symlink);
return _handle_registry.alloc(symlink); return _handle_registry.alloc(symlink);
} }
@ -255,7 +254,7 @@ 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); Node_lock_guard guard(dir_node);
return _handle_registry.alloc(dir_node); return _handle_registry.alloc(dir_node);
} }
@ -272,7 +271,7 @@ class File_system::Session_component : public Session_rpc_object
PDBGV("path_str: '%s'", path_str); PDBGV("path_str: '%s'", path_str);
Node *node = _root.node(path_str + 1); Node *node = _root.node(path_str + 1);
Node_lock_guard guard(*node); Node_lock_guard guard(node);
return _handle_registry.alloc(node); return _handle_registry.alloc(node);
} }
@ -301,7 +300,7 @@ class File_system::Session_component : public Session_rpc_object
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup_and_lock(node_handle); Node *node = _handle_registry.lookup_and_lock(node_handle);
Node_lock_guard guard(*node); Node_lock_guard guard(node);
File *file = dynamic_cast<File *>(node); File *file = dynamic_cast<File *>(node);
if (file) if (file)
@ -329,7 +328,7 @@ class File_system::Session_component : public Session_rpc_object
throw Permission_denied(); throw Permission_denied();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(*dir); Node_lock_guard dir_guard(dir);
PDBGV("dir: '%s' name: '%s'", dir->name(), name.string()); PDBGV("dir: '%s' name: '%s'", dir->name(), name.string());
@ -361,7 +360,7 @@ class File_system::Session_component : public Session_rpc_object
try { file = _handle_registry.lookup_and_lock(file_handle); } try { file = _handle_registry.lookup_and_lock(file_handle); }
catch (Invalid_handle) { throw Lookup_failed(); } catch (Invalid_handle) { throw Lookup_failed(); }
Node_lock_guard file_guard(*file); Node_lock_guard file_guard(file);
file->truncate(size); file->truncate(size);
} }
@ -381,8 +380,8 @@ class File_system::Session_component : public Session_rpc_object
throw Lookup_failed(); throw Lookup_failed();
} }
Node_lock_guard from_dir_guard(*from_dir); Node_lock_guard from_dir_guard(from_dir);
Node_lock_guard to_dir_guard(*to_dir); Node_lock_guard to_dir_guard(to_dir);
PDBGV("from_dir: '%s' from_name: '%s', to_dir: '%s' to_name: '%s'", PDBGV("from_dir: '%s' from_name: '%s', to_dir: '%s' to_name: '%s'",
from_dir->name(), from_name.string(), to_dir->name(), to_name.string()); from_dir->name(), from_name.string(), to_dir->name(), to_name.string());

View File

@ -10,6 +10,7 @@
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <file_system/node.h>
#include <util/list.h> #include <util/list.h>
#include <base/lock.h> #include <base/lock.h>
#include <base/signal.h> #include <base/signal.h>
@ -20,111 +21,23 @@ namespace File_system {
typedef Genode::Path<MAX_PATH_LEN> Absolute_path; typedef Genode::Path<MAX_PATH_LEN> Absolute_path;
class Listener : public List<Listener>::Element class Node : public Node_base, public List<Node>::Element
{
private:
Lock _lock;
Signal_context_capability _sigh;
bool _marked_as_updated;
public:
Listener() : _marked_as_updated(false) { }
Listener(Signal_context_capability sigh)
: _sigh(sigh), _marked_as_updated(false) { }
void notify()
{
Lock::Guard guard(_lock);
if (_marked_as_updated && _sigh.valid())
Signal_transmitter(_sigh).submit();
_marked_as_updated = false;
}
void mark_as_updated()
{
Lock::Guard guard(_lock);
_marked_as_updated = true;
}
bool valid() const { return _sigh.valid(); }
};
class Node : public List<Node>::Element
{ {
protected: protected:
unsigned long _inode; unsigned long _inode;
Absolute_path _name; Absolute_path _name;
private:
Lock _lock;
List<Listener> _listeners;
public: public:
Node(char const *name) : _name(name) { } Node(char const *name) : _name(name) { }
virtual ~Node()
{
/* propagate event to listeners */
mark_as_updated();
notify_listeners();
while (_listeners.first())
_listeners.remove(_listeners.first());
}
char const *name() const { return _name.base(); } char const *name() const { return _name.base(); }
void lock() { _lock.lock(); }
void unlock() { _lock.unlock(); }
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;
void add_listener(Listener *listener)
{
_listeners.insert(listener);
}
void remove_listener(Listener *listener)
{
_listeners.remove(listener);
}
void notify_listeners()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->notify();
}
void mark_as_updated()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->mark_as_updated();
}
}; };
/**
* Guard used for properly releasing node locks
*/
struct Node_lock_guard
{
Node &node;
Node_lock_guard(Node &node) : node(node) { }
~Node_lock_guard() { node.unlock(); }
};
} }
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -1,198 +0,0 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_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
{
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Lock mutable _lock;
Node *_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 *node)
{
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)
{
Lock::Guard guard(_lock);
if (!_in_range(handle.value))
return;
/*
* Notify listeners about the changed file.
*/
Node *node = dynamic_cast<Node *>(_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
*
* 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)
{
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();
node->lock();
return node;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
Lock::Guard guard(_lock);
if (!_in_range(h1.value) || !_in_range(h2.value)) {
PDBG("refer_to_same_node -> Invalid_handle");
throw Invalid_handle();
}
return _nodes[h1.value] == _nodes[h2.value];
}
/**
* Register signal handler to be notified of node changes
*/
void sigh(Node_handle handle, Signal_context_capability sigh)
{
Lock::Guard guard(_lock);
if (!_in_range(handle.value))
throw Invalid_handle();
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) {
PDBG("Invalid_handle");
throw Invalid_handle();
}
node->lock();
Node_lock_guard node_lock_guard(*node);
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(sigh);
node->add_listener(&listener);
}
};
}
#endif /* _NODE_HANDLE_REGISTRY_H_ */

View File

@ -0,0 +1,55 @@
/*
* \brief File-system listener
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _FILE_SYSTEM__LISTENER_H_
#define _FILE_SYSTEM__LISTENER_H_
/* Genode includes */
#include <file_system_session/file_system_session.h>
#include <util/list.h>
#include <base/lock.h>
#include <base/signal.h>
namespace File_system {
class Listener : public Genode::List<Listener>::Element
{
private:
Genode::Lock _lock;
Genode::Signal_context_capability _sigh;
bool _marked_as_updated;
public:
Listener() : _marked_as_updated(false) { }
Listener(Signal_context_capability sigh)
: _sigh(sigh), _marked_as_updated(false) { }
void notify()
{
Genode::Lock::Guard guard(_lock);
if (_marked_as_updated && _sigh.valid())
Signal_transmitter(_sigh).submit();
_marked_as_updated = false;
}
void mark_as_updated()
{
Genode::Lock::Guard guard(_lock);
_marked_as_updated = true;
}
bool valid() const { return _sigh.valid(); }
};
}
#endif /* _FILE_SYSTEM__LISTENER_H_ */

View File

@ -0,0 +1,77 @@
/*
* \brief File-system node
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _FILE_SYSTEM__NODE_H_
#define _FILE_SYSTEM__NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <util/list.h>
#include <base/lock.h>
namespace File_system {
class Node_base
{
private:
Lock _lock;
List<Listener> _listeners;
public:
virtual ~Node_base()
{
/* propagate event to listeners */
mark_as_updated();
notify_listeners();
while (_listeners.first())
_listeners.remove(_listeners.first());
}
void lock() { _lock.lock(); }
void unlock() { _lock.unlock(); }
void add_listener(Listener *listener)
{
_listeners.insert(listener);
}
void remove_listener(Listener *listener)
{
_listeners.remove(listener);
}
void notify_listeners()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->notify();
}
void mark_as_updated()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
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_ */

View File

@ -4,8 +4,10 @@
* \date 2012-04-11 * \date 2012-04-11
*/ */
#ifndef _NODE_HANDLE_REGISTRY_H_ #ifndef _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_H_ #define _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_
#include <file_system/node.h>
namespace File_system { namespace File_system {
@ -43,7 +45,7 @@ namespace File_system {
Lock mutable _lock; Lock mutable _lock;
Node *_nodes[MAX_NODE_HANDLES]; Node_base *_nodes[MAX_NODE_HANDLES];
/** /**
* Each open node handle can act as a listener to be informed about * Each open node handle can act as a listener to be informed about
@ -56,7 +58,7 @@ namespace File_system {
* *
* \throw Out_of_node_handles * \throw Out_of_node_handles
*/ */
int _alloc(Node *node) int _alloc(Node_base *node)
{ {
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
@ -102,7 +104,7 @@ namespace File_system {
/* /*
* Notify listeners about the changed file. * Notify listeners about the changed file.
*/ */
Node *node = dynamic_cast<Node *>(_nodes[handle.value]); Node_base *node = dynamic_cast<Node_base *>(_nodes[handle.value]);
if (!node) { return; } if (!node) { return; }
node->lock(); node->lock();
@ -122,6 +124,27 @@ namespace File_system {
node->unlock(); 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)
{
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 * Lookup node using its handle as key
* *
@ -137,8 +160,8 @@ namespace File_system {
if (!_in_range(handle.value)) if (!_in_range(handle.value))
throw Invalid_handle(); throw Invalid_handle();
typedef typename Node_type<HANDLE_TYPE>::Type Node; typedef typename Node_type<HANDLE_TYPE>::Type Node_base;
Node *node = dynamic_cast<Node *>(_nodes[handle.value]); Node_base *node = dynamic_cast<Node_base *>(_nodes[handle.value]);
if (!node) if (!node)
throw Invalid_handle(); throw Invalid_handle();
@ -168,14 +191,14 @@ namespace File_system {
if (!_in_range(handle.value)) if (!_in_range(handle.value))
throw Invalid_handle(); throw Invalid_handle();
Node *node = dynamic_cast<Node *>(_nodes[handle.value]); Node_base *node = dynamic_cast<Node_base *>(_nodes[handle.value]);
if (!node) { if (!node) {
PDBG("Invalid_handle"); PDBG("Invalid_handle");
throw Invalid_handle(); throw Invalid_handle();
} }
node->lock(); node->lock();
Node_lock_guard node_lock_guard(*node); Node_lock_guard node_lock_guard(node);
Listener &listener = _listeners[handle.value]; Listener &listener = _listeners[handle.value];
@ -195,4 +218,4 @@ namespace File_system {
}; };
} }
#endif /* _NODE_HANDLE_REGISTRY_H_ */ #endif /* _FILE_SYSTEM__NODE_HANDLE_REGISTRY_H_ */

View File

@ -4,8 +4,8 @@
* \date 2012-04-11 * \date 2012-04-11
*/ */
#ifndef _UTIL_H_ #ifndef _FILE_SYSTEM__UTIL_H_
#define _UTIL_H_ #define _FILE_SYSTEM__UTIL_H_
/** /**
* Return base-name portion of null-terminated path string * Return base-name portion of null-terminated path string
@ -60,4 +60,4 @@ static inline bool valid_name(char const *str)
return true; return true;
} }
#endif /* _UTIL_H_ */ #endif /* _FILE_SYSTEM__UTIL_H_ */

View File

@ -37,8 +37,8 @@ namespace File_system {
*/ */
struct Packet_ref; struct Packet_ref;
typedef uint64_t seek_off_t; typedef Genode::uint64_t seek_off_t;
typedef uint64_t file_size_t; typedef Genode::uint64_t file_size_t;
class Packet_descriptor; class Packet_descriptor;

View File

@ -9,11 +9,11 @@
#define _DIRECTORY_H_ #define _DIRECTORY_H_
/* Genode include */ /* Genode include */
#include <file_system/util.h>
#include <os/path.h> #include <os/path.h>
/* local includes */ /* local includes */
#include <node.h> #include <node.h>
#include <util.h>
#include <file.h> #include <file.h>
#include <lx_util.h> #include <lx_util.h>

View File

@ -12,6 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <root/component.h> #include <root/component.h>
#include <os/attached_rom_dataspace.h> #include <os/attached_rom_dataspace.h>
@ -22,7 +23,6 @@
/* local includes */ /* local includes */
#include <directory.h> #include <directory.h>
#include <node_handle_registry.h>
namespace File_system { namespace File_system {
@ -92,7 +92,7 @@ class File_system::Session_component : public Session_rpc_object
try { try {
Node *node = _handle_registry.lookup_and_lock(packet.handle()); Node *node = _handle_registry.lookup_and_lock(packet.handle());
Node_lock_guard guard(*node); Node_lock_guard guard(node);
_process_packet_op(packet, *node); _process_packet_op(packet, *node);
} }
@ -191,7 +191,7 @@ class File_system::Session_component : public Session_rpc_object
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(*dir); Node_lock_guard dir_guard(dir);
if (!_writable) if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY)) if (create || (mode != STAT_ONLY && mode != READ_ONLY))
@ -199,7 +199,7 @@ class File_system::Session_component : public Session_rpc_object
File *file = dir->file(name.string(), mode, create); File *file = dir->file(name.string(), mode, create);
Node_lock_guard file_guard(*file); Node_lock_guard file_guard(file);
return _handle_registry.alloc(file); return _handle_registry.alloc(file);
} }
@ -225,7 +225,7 @@ 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); Node_lock_guard guard(dir);
return _handle_registry.alloc(dir); return _handle_registry.alloc(dir);
} }
@ -237,7 +237,7 @@ 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); Node_lock_guard guard(node);
return _handle_registry.alloc(node); return _handle_registry.alloc(node);
} }
@ -250,7 +250,7 @@ class File_system::Session_component : public Session_rpc_object
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup_and_lock(node_handle); Node *node = _handle_registry.lookup_and_lock(node_handle);
Node_lock_guard guard(*node); Node_lock_guard guard(node);
Status s; Status s;
s.inode = node->inode(); s.inode = node->inode();
@ -292,7 +292,7 @@ class File_system::Session_component : public Session_rpc_object
throw Permission_denied(); throw Permission_denied();
File *file = _handle_registry.lookup_and_lock(file_handle); File *file = _handle_registry.lookup_and_lock(file_handle);
Node_lock_guard file_guard(*file); Node_lock_guard file_guard(file);
file->truncate(size); file->truncate(size);
} }

View File

@ -9,50 +9,13 @@
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <util/list.h> #include <file_system/listener.h>
#include <base/lock.h> #include <file_system/node.h>
#include <base/signal.h>
namespace File_system { namespace File_system {
class Listener : public List<Listener>::Element class Node : public Node_base
{
private:
Lock _lock;
Signal_context_capability _sigh;
bool _marked_as_updated;
public:
Listener() : _marked_as_updated(false) { }
Listener(Signal_context_capability sigh)
: _sigh(sigh), _marked_as_updated(false) { }
void notify()
{
Lock::Guard guard(_lock);
if (_marked_as_updated && _sigh.valid())
Signal_transmitter(_sigh).submit();
_marked_as_updated = false;
}
void mark_as_updated()
{
Lock::Guard guard(_lock);
_marked_as_updated = true;
}
bool valid() const { return _sigh.valid(); }
};
class Node : public List<Node>::Element
{ {
public: public:
@ -60,26 +23,13 @@ namespace File_system {
private: private:
Lock _lock;
Name _name; Name _name;
unsigned long const _inode; unsigned long const _inode;
List<Listener> _listeners;
public: public:
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; } Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
virtual ~Node()
{
/* propagate event to listeners */
mark_as_updated();
notify_listeners();
while (_listeners.first())
_listeners.remove(_listeners.first());
}
unsigned long inode() const { return _inode; } unsigned long inode() const { return _inode; }
char const *name() const { return _name; } char const *name() const { return _name; }
@ -88,47 +38,10 @@ namespace File_system {
*/ */
void name(char const *name) { strncpy(_name, name, sizeof(_name)); } void name(char const *name) { strncpy(_name, name, sizeof(_name)); }
void lock() { _lock.lock(); }
void unlock() { _lock.unlock(); }
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;
void add_listener(Listener *listener)
{
_listeners.insert(listener);
}
void remove_listener(Listener *listener)
{
_listeners.remove(listener);
}
void notify_listeners()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->notify();
}
void mark_as_updated()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->mark_as_updated();
}
}; };
/**
* Guard used for properly releasing node locks
*/
struct Node_lock_guard
{
Node &node;
Node_lock_guard(Node &node) : node(node) { }
~Node_lock_guard() { node.unlock(); }
};
} }
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -7,9 +7,11 @@
#ifndef _DIRECTORY_H_ #ifndef _DIRECTORY_H_
#define _DIRECTORY_H_ #define _DIRECTORY_H_
/* Genode includes */
#include <file_system/util.h>
/* local includes */ /* local includes */
#include <node.h> #include <node.h>
#include <util.h>
#include <file.h> #include <file.h>
#include <symlink.h> #include <symlink.h>

View File

@ -12,6 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <root/component.h> #include <root/component.h>
#include <os/attached_rom_dataspace.h> #include <os/attached_rom_dataspace.h>
@ -22,7 +23,6 @@
/* local includes */ /* local includes */
#include <directory.h> #include <directory.h>
#include <node_handle_registry.h>
/************************* /*************************
@ -90,7 +90,7 @@ namespace File_system {
try { try {
Node *node = _handle_registry.lookup_and_lock(packet.handle()); Node *node = _handle_registry.lookup_and_lock(packet.handle());
Node_lock_guard guard(*node); Node_lock_guard guard(node);
_process_packet_op(packet, *node); _process_packet_op(packet, *node);
} }
@ -185,7 +185,7 @@ namespace File_system {
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(*dir); Node_lock_guard dir_guard(dir);
if (!_writable) if (!_writable)
if (mode != STAT_ONLY && mode != READ_ONLY) if (mode != STAT_ONLY && mode != READ_ONLY)
@ -209,7 +209,7 @@ namespace File_system {
} }
File *file = dir->lookup_and_lock_file(name.string()); File *file = dir->lookup_and_lock_file(name.string());
Node_lock_guard file_guard(*file); Node_lock_guard file_guard(file);
return _handle_registry.alloc(file); return _handle_registry.alloc(file);
} }
@ -219,7 +219,7 @@ namespace File_system {
throw Invalid_name(); throw Invalid_name();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(*dir); Node_lock_guard dir_guard(dir);
if (create) { if (create) {
@ -239,7 +239,7 @@ namespace File_system {
} }
Symlink *symlink = dir->lookup_and_lock_symlink(name.string()); Symlink *symlink = dir->lookup_and_lock_symlink(name.string());
Node_lock_guard file_guard(*symlink); Node_lock_guard file_guard(symlink);
return _handle_registry.alloc(symlink); return _handle_registry.alloc(symlink);
} }
@ -262,7 +262,7 @@ namespace File_system {
Directory *parent = _root.lookup_and_lock_parent(path_str); Directory *parent = _root.lookup_and_lock_parent(path_str);
Node_lock_guard guard(*parent); Node_lock_guard guard(parent);
char const *name = basename(path_str); char const *name = basename(path_str);
@ -277,7 +277,7 @@ namespace File_system {
} }
Directory *dir = _root.lookup_and_lock_dir(path_str); Directory *dir = _root.lookup_and_lock_dir(path_str);
Node_lock_guard guard(*dir); Node_lock_guard guard(dir);
return _handle_registry.alloc(dir); return _handle_registry.alloc(dir);
} }
@ -287,7 +287,7 @@ namespace File_system {
Node *node = _root.lookup_and_lock(path.string() + 1); Node *node = _root.lookup_and_lock(path.string() + 1);
Node_lock_guard guard(*node); Node_lock_guard guard(node);
return _handle_registry.alloc(node); return _handle_registry.alloc(node);
} }
@ -299,7 +299,7 @@ namespace File_system {
Status status(Node_handle node_handle) Status status(Node_handle node_handle)
{ {
Node *node = _handle_registry.lookup_and_lock(node_handle); Node *node = _handle_registry.lookup_and_lock(node_handle);
Node_lock_guard guard(*node); Node_lock_guard guard(node);
Status s; Status s;
s.inode = node->inode(); s.inode = node->inode();
@ -338,7 +338,7 @@ namespace File_system {
throw Permission_denied(); throw Permission_denied();
Directory *dir = _handle_registry.lookup_and_lock(dir_handle); Directory *dir = _handle_registry.lookup_and_lock(dir_handle);
Node_lock_guard dir_guard(*dir); Node_lock_guard dir_guard(dir);
Node *node = dir->lookup_and_lock(name.string()); Node *node = dir->lookup_and_lock(name.string());
@ -357,7 +357,7 @@ namespace File_system {
throw Permission_denied(); throw Permission_denied();
File *file = _handle_registry.lookup_and_lock(file_handle); File *file = _handle_registry.lookup_and_lock(file_handle);
Node_lock_guard file_guard(*file); Node_lock_guard file_guard(file);
file->truncate(size); file->truncate(size);
} }
@ -374,15 +374,15 @@ namespace File_system {
throw Invalid_name(); throw Invalid_name();
Directory *from_dir = _handle_registry.lookup_and_lock(from_dir_handle); Directory *from_dir = _handle_registry.lookup_and_lock(from_dir_handle);
Node_lock_guard from_dir_guard(*from_dir); Node_lock_guard from_dir_guard(from_dir);
Node *node = from_dir->lookup_and_lock(from_name.string()); Node *node = from_dir->lookup_and_lock(from_name.string());
Node_lock_guard node_guard(*node); Node_lock_guard node_guard(node);
node->name(to_name.string()); node->name(to_name.string());
if (!_handle_registry.refer_to_same_node(from_dir_handle, to_dir_handle)) { if (!_handle_registry.refer_to_same_node(from_dir_handle, to_dir_handle)) {
Directory *to_dir = _handle_registry.lookup_and_lock(to_dir_handle); Directory *to_dir = _handle_registry.lookup_and_lock(to_dir_handle);
Node_lock_guard to_dir_guard(*to_dir); Node_lock_guard to_dir_guard(to_dir);
from_dir->discard_unsynchronized(node); from_dir->discard_unsynchronized(node);
to_dir->adopt_unsynchronized(node); to_dir->adopt_unsynchronized(node);

View File

@ -8,49 +8,13 @@
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <file_system/listener.h>
#include <file_system/node.h>
#include <util/list.h> #include <util/list.h>
#include <base/lock.h>
#include <base/signal.h>
namespace File_system { namespace File_system {
class Listener : public List<Listener>::Element class Node : public Node_base, public List<Node>::Element
{
private:
Lock _lock;
Signal_context_capability _sigh;
bool _marked_as_updated;
public:
Listener() : _marked_as_updated(false) { }
Listener(Signal_context_capability sigh)
: _sigh(sigh), _marked_as_updated(false) { }
void notify()
{
Lock::Guard guard(_lock);
if (_marked_as_updated && _sigh.valid())
Signal_transmitter(_sigh).submit();
_marked_as_updated = false;
}
void mark_as_updated()
{
Lock::Guard guard(_lock);
_marked_as_updated = true;
}
bool valid() const { return _sigh.valid(); }
};
class Node : public List<Node>::Element
{ {
public: public:
@ -58,12 +22,9 @@ namespace File_system {
private: private:
Lock _lock;
int _ref_count; int _ref_count;
Name _name; Name _name;
unsigned long const _inode; unsigned long const _inode;
List<Listener> _listeners;
bool _modified;
/** /**
* Generate unique inode number * Generate unique inode number
@ -77,19 +38,9 @@ namespace File_system {
public: public:
Node() Node()
: _ref_count(0), _inode(_unique_inode()), _modified(false) : _ref_count(0), _inode(_unique_inode())
{ _name[0] = 0; } { _name[0] = 0; }
virtual ~Node()
{
/* propagate event to listeners */
mark_as_updated();
notify_listeners();
while (_listeners.first())
_listeners.remove(_listeners.first());
}
unsigned long inode() const { return _inode; } unsigned long inode() const { return _inode; }
char const *name() const { return _name; } char const *name() const { return _name; }
@ -98,47 +49,10 @@ namespace File_system {
*/ */
void name(char const *name) { strncpy(_name, name, sizeof(_name)); } void name(char const *name) { strncpy(_name, name, sizeof(_name)); }
void lock() { _lock.lock(); }
void unlock() { _lock.unlock(); }
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;
void add_listener(Listener *listener)
{
_listeners.insert(listener);
}
void remove_listener(Listener *listener)
{
_listeners.remove(listener);
}
void notify_listeners()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->notify();
}
void mark_as_updated()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->mark_as_updated();
}
}; };
/**
* Guard used for properly releasing node locks
*/
struct Node_lock_guard
{
Node &node;
Node_lock_guard(Node &node) : node(node) { }
~Node_lock_guard() { node.unlock(); }
};
} }
#endif /* _NODE_H_ */ #endif /* _NODE_H_ */

View File

@ -1,198 +0,0 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_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
{
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Lock mutable _lock;
Node *_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 *node)
{
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)
{
Lock::Guard guard(_lock);
if (!_in_range(handle.value))
return;
/*
* Notify listeners about the changed file.
*/
Node *node = dynamic_cast<Node *>(_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
*
* 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)
{
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();
node->lock();
return node;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
Lock::Guard guard(_lock);
if (!_in_range(h1.value) || !_in_range(h2.value)) {
PDBG("refer_to_same_node -> Invalid_handle");
throw Invalid_handle();
}
return _nodes[h1.value] == _nodes[h2.value];
}
/**
* Register signal handler to be notified of node changes
*/
void sigh(Node_handle handle, Signal_context_capability sigh)
{
Lock::Guard guard(_lock);
if (!_in_range(handle.value))
throw Invalid_handle();
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) {
PDBG("Invalid_handle");
throw Invalid_handle();
}
node->lock();
Node_lock_guard node_lock_guard(*node);
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(sigh);
node->add_listener(&listener);
}
};
}
#endif /* _NODE_HANDLE_REGISTRY_H_ */

View File

@ -1,63 +0,0 @@
/*
* \brief Utilities
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _UTIL_H_
#define _UTIL_H_
/**
* Return base-name portion of null-terminated path string
*/
static inline char const *basename(char const *path)
{
char const *start = path;
for (; *path; path++)
if (*path == '/')
start = path + 1;
return start;
}
/**
* Return true if specified path is a base name (contains no path delimiters)
*/
static inline bool is_basename(char const *path)
{
for (; *path; path++)
if (*path == '/')
return false;
return true;
}
/**
* Return true if character 'c' occurs in null-terminated string 'str'
*/
static inline bool string_contains(char const *str, char c)
{
for (; *str; str++)
if (*str == c)
return true;
return false;
}
/**
* Return true if 'str' is a valid node name
*/
static inline bool valid_name(char const *str)
{
if (string_contains(str, '/')) return false;
/* must have at least one character */
if (str[0] == 0) return false;
return true;
}
#endif /* _UTIL_H_ */

View File

@ -13,6 +13,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <root/component.h> #include <root/component.h>
#include <cap_session/connection.h> #include <cap_session/connection.h>
@ -24,7 +25,6 @@
#include <directory.h> #include <directory.h>
#include <file.h> #include <file.h>
#include <lookup.h> #include <lookup.h>
#include <node_handle_registry.h>
#include <symlink.h> #include <symlink.h>
#include <util.h> #include <util.h>

View File

@ -15,12 +15,15 @@
#ifndef _NODE_H_ #ifndef _NODE_H_
#define _NODE_H_ #define _NODE_H_
/* Genode includes */
#include <file_system/node.h>
/* local includes */ /* local includes */
#include <record.h> #include <record.h>
namespace File_system { namespace File_system {
class Node class Node : public Node_base
{ {
protected: protected:

View File

@ -1,137 +0,0 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_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
{
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Lock mutable _lock;
Node *_nodes[MAX_NODE_HANDLES];
/**
* Allocate node handle
*
* \throw Out_of_node_handles
*/
int _alloc(Node *node)
{
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)
{
Lock::Guard guard(_lock);
if (_in_range(handle.value))
_nodes[handle.value] = 0;
}
/**
* Lookup node using its handle as key
*
* \throw Invalid_handle
*/
template <typename HANDLE_TYPE>
typename Node_type<HANDLE_TYPE>::Type *lookup(HANDLE_TYPE handle)
{
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;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
Lock::Guard guard(_lock);
if (!_in_range(h1.value) || !_in_range(h2.value))
throw Invalid_handle();
return _nodes[h1.value] == _nodes[h2.value];
}
};
}
#endif /* _NODE_HANDLE_REGISTRY_H_ */

View File

@ -7,9 +7,11 @@
#ifndef _DIRECTORY_H_ #ifndef _DIRECTORY_H_
#define _DIRECTORY_H_ #define _DIRECTORY_H_
/* Genode includes */
#include <file_system/util.h>
/* local includes */ /* local includes */
#include <node.h> #include <node.h>
#include <util.h>
#include <file.h> #include <file.h>
#include <symlink.h> #include <symlink.h>

View File

@ -12,6 +12,7 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h>
#include <cap_session/connection.h> #include <cap_session/connection.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <os/attached_rom_dataspace.h> #include <os/attached_rom_dataspace.h>
@ -29,15 +30,30 @@
#include <buffer.h> #include <buffer.h>
#include <directory.h> #include <directory.h>
#include <followed_subject.h> #include <followed_subject.h>
#include <node_handle_registry.h>
#include <trace_files.h> #include <trace_files.h>
#include <util.h>
static bool const verbose = false; static bool const verbose = false;
#define PDBGV(...) if (verbose) PDBG(__VA_ARGS__) #define PDBGV(...) if (verbose) PDBG(__VA_ARGS__)
/**
* Return true if 'str' is a valid file name
*/
static inline bool valid_filename(char const *str)
{
if (!str) return false;
/* must have at least one character */
if (str[0] == 0) return false;
/* must not contain '/' or '\' or ':' */
if (string_contains(str, '/') ||
string_contains(str, '\\') ||
string_contains(str, ':'))
return false;
return true;
}
/** /**
* This class updates the file system * This class updates the file system

View File

@ -8,49 +8,14 @@
#define _NODE_H_ #define _NODE_H_
/* Genode includes */ /* Genode includes */
#include <file_system/node.h>
#include <util/list.h> #include <util/list.h>
#include <base/lock.h> #include <base/lock.h>
#include <base/signal.h> #include <base/signal.h>
namespace File_system { namespace File_system {
class Listener : public List<Listener>::Element class Node : public Node_base, public List<Node>::Element
{
private:
Lock _lock;
Signal_context_capability _sigh;
bool _marked_as_updated;
public:
Listener() : _marked_as_updated(false) { }
Listener(Signal_context_capability sigh)
: _sigh(sigh), _marked_as_updated(false) { }
void notify()
{
Lock::Guard guard(_lock);
if (_marked_as_updated && _sigh.valid())
Signal_transmitter(_sigh).submit();
_marked_as_updated = false;
}
void mark_as_updated()
{
Lock::Guard guard(_lock);
_marked_as_updated = true;
}
bool valid() const { return _sigh.valid(); }
};
class Node : public List<Node>::Element
{ {
public: public:
@ -60,8 +25,6 @@ namespace File_system {
Name _name; Name _name;
unsigned long const _inode; unsigned long const _inode;
List<Listener> _listeners;
bool _modified;
/** /**
* Generate unique inode number * Generate unique inode number
@ -75,19 +38,9 @@ namespace File_system {
public: public:
Node() Node()
: _inode(_unique_inode()), _modified(false) : _inode(_unique_inode())
{ _name[0] = 0; } { _name[0] = 0; }
virtual ~Node()
{
/* propagate event to listeners */
mark_as_updated();
notify_listeners();
while (_listeners.first())
_listeners.remove(_listeners.first());
}
unsigned long inode() const { return _inode; } unsigned long inode() const { return _inode; }
char const *name() const { return _name; } char const *name() const { return _name; }
@ -96,32 +49,10 @@ namespace File_system {
*/ */
void name(char const *name) { strncpy(_name, name, sizeof(_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() const = 0; virtual Status status() const = 0;
void add_listener(Listener *listener) 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;
_listeners.insert(listener);
}
void remove_listener(Listener *listener)
{
_listeners.remove(listener);
}
void notify_listeners()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->notify();
}
void mark_as_updated()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->mark_as_updated();
}
}; };
} }

View File

@ -1,181 +0,0 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_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
{
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Lock mutable _lock;
Node *_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 *node)
{
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)
{
if (!_in_range(handle.value))
return;
/*
* Notify listeners about the changed file.
*/
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) { return; }
node->notify_listeners();
/*
* De-allocate handle
*/
Listener &listener = _listeners[handle.value];
if (listener.valid())
node->remove_listener(&listener);
_nodes[handle.value] = 0;
listener = Listener();
}
/**
* Lookup node using its handle as key
*
* \throw Invalid_handle
*/
template <typename HANDLE_TYPE>
typename Node_type<HANDLE_TYPE>::Type *lookup(HANDLE_TYPE handle)
{
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;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
if (!_in_range(h1.value) || !_in_range(h2.value)) {
PDBG("refer_to_same_node -> Invalid_handle");
throw Invalid_handle();
}
return _nodes[h1.value] == _nodes[h2.value];
}
/**
* Register signal handler to be notified of node changes
*/
void sigh(Node_handle handle, Signal_context_capability sigh)
{
if (!_in_range(handle.value))
throw Invalid_handle();
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) {
PDBG("Invalid_handle");
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(sigh);
node->add_listener(&listener);
}
};
}
#endif /* _NODE_HANDLE_REGISTRY_H_ */

View File

@ -1,83 +0,0 @@
/*
* \brief Utilities
* \author Norman Feske
* \date 2012-04-11
*/
#ifndef _UTIL_H_
#define _UTIL_H_
/**
* Return base-name portion of null-terminated path string
*/
static inline char const *basename(char const *path)
{
char const *start = path;
for (; *path; path++)
if (*path == '/')
start = path + 1;
return start;
}
/**
* Return true if specified path is a base name (contains no path delimiters)
*/
static inline bool is_basename(char const *path)
{
for (; *path; path++)
if (*path == '/')
return false;
return true;
}
/**
* Return true if character 'c' occurs in null-terminated string 'str'
*/
static inline bool string_contains(char const *str, char c)
{
for (; *str; str++)
if (*str == c)
return true;
return false;
}
/**
* Return true if 'str' is a valid node name
*/
static inline bool valid_name(char const *str)
{
if (string_contains(str, '/')) return false;
/* must have at least one character */
if (str[0] == 0) return false;
return true;
}
/**
* Return true if 'str' is a valid file name
*/
static inline bool valid_filename(char const *str)
{
if (!str) return false;
/* must have at least one character */
if (str[0] == 0) return false;
/* must not contain '/' or '\' or ':' */
if (string_contains(str, '/') ||
string_contains(str, '\\') ||
string_contains(str, ':'))
return false;
return true;
}
#endif /* _UTIL_H_ */