2015-07-22 07:32:42 +02:00
|
|
|
/*
|
|
|
|
* \brief Embedded RAM VFS
|
|
|
|
* \author Emery Hemingway
|
|
|
|
* \date 2015-07-21
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2018-07-05 17:55:24 +02:00
|
|
|
* Copyright (C) 2015-2018 Genode Labs GmbH
|
2015-07-22 07:32:42 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-07-22 07:32:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _INCLUDE__VFS__RAM_FILE_SYSTEM_H_
|
|
|
|
#define _INCLUDE__VFS__RAM_FILE_SYSTEM_H_
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
#include <ram_fs/chunk.h>
|
2019-03-17 13:37:02 +01:00
|
|
|
#include <ram_fs/param.h>
|
2015-10-24 22:01:16 +02:00
|
|
|
#include <vfs/file_system.h>
|
|
|
|
#include <dataspace/client.h>
|
|
|
|
#include <util/avl_tree.h>
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
namespace Vfs { class Ram_file_system; }
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
namespace Vfs_ram {
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
using namespace Vfs;
|
2019-09-06 12:34:12 +02:00
|
|
|
|
|
|
|
using Ram_fs::Chunk;
|
|
|
|
using Ram_fs::Chunk_index;
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
struct Io_handle;
|
|
|
|
struct Watch_handle;
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
class Node;
|
|
|
|
class File;
|
|
|
|
class Symlink;
|
|
|
|
class Directory;
|
|
|
|
|
|
|
|
enum { MAX_NAME_LEN = 128 };
|
|
|
|
|
2016-03-31 01:15:12 +02:00
|
|
|
typedef Genode::Allocator::Out_of_memory Out_of_memory;
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
|
|
|
|
struct Vfs_ram::Io_handle final : public Vfs_handle,
|
|
|
|
private Genode::List<Io_handle>::Element
|
|
|
|
{
|
|
|
|
friend Genode::List<Io_handle>;
|
|
|
|
|
|
|
|
Vfs_ram::Node &node;
|
|
|
|
|
|
|
|
/* Track if this handle has modified its node */
|
|
|
|
bool modifying = false;
|
|
|
|
|
|
|
|
Io_handle(Vfs::File_system &fs,
|
|
|
|
Allocator &alloc,
|
|
|
|
int status_flags,
|
|
|
|
Vfs_ram::Node &node)
|
|
|
|
: Vfs_handle(fs, fs, alloc, status_flags), node(node)
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Vfs_ram::Watch_handle final : public Vfs_watch_handle,
|
|
|
|
private Genode::List<Watch_handle>::Element
|
|
|
|
{
|
|
|
|
friend Genode::List<Watch_handle>;
|
|
|
|
using Genode::List<Watch_handle>::Element::next;
|
|
|
|
|
|
|
|
Vfs_ram::Node &node;
|
|
|
|
|
|
|
|
Watch_handle(Vfs::File_system &fs,
|
|
|
|
Allocator &alloc,
|
|
|
|
Node &node)
|
|
|
|
: Vfs_watch_handle(fs, alloc), node(node) { }
|
|
|
|
};
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
class Vfs_ram::Node : private Genode::Avl_node<Node>, private Genode::Lock
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
friend class Genode::Avl_node<Node>;
|
|
|
|
friend class Genode::Avl_tree<Node>;
|
2018-03-31 16:50:49 +02:00
|
|
|
friend class Genode::List<Io_handle>;
|
|
|
|
friend class Genode::List<Io_handle>::Element;
|
|
|
|
friend class Genode::List<Watch_handle>;
|
|
|
|
friend class Genode::List<Watch_handle>::Element;
|
|
|
|
friend class Watch_handle;
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
friend class Directory;
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
char _name[MAX_NAME_LEN];
|
2018-03-31 16:50:49 +02:00
|
|
|
Genode::List<Io_handle> _io_handles { };
|
|
|
|
Genode::List<Watch_handle> _watch_handles { };
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate unique inode number
|
|
|
|
*/
|
2016-03-31 01:15:12 +02:00
|
|
|
static unsigned _unique_inode()
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
static unsigned long inode_count;
|
|
|
|
return ++inode_count;
|
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
public:
|
2015-07-22 07:32:42 +02:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
using Lock::lock;
|
|
|
|
using Lock::unlock;
|
|
|
|
|
2016-03-31 01:15:12 +02:00
|
|
|
unsigned inode;
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Node(char const *node_name)
|
2016-03-31 01:15:12 +02:00
|
|
|
: inode(_unique_inode()) { name(node_name); }
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-11-17 16:02:33 +01:00
|
|
|
virtual ~Node() { }
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
char const *name() { return _name; }
|
|
|
|
void name(char const *name) { strncpy(_name, name, MAX_NAME_LEN); }
|
|
|
|
|
|
|
|
virtual Vfs::file_size length() = 0;
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
void open(Io_handle &handle) { _io_handles.insert(&handle); }
|
|
|
|
void open(Watch_handle &handle) { _watch_handles.insert(&handle); }
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
bool opened() const
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
2018-03-31 16:50:49 +02:00
|
|
|
return _io_handles.first() != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void close(Io_handle &handle) { _io_handles.remove(&handle); }
|
|
|
|
void close(Watch_handle &handle) { _watch_handles.remove(&handle); }
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
void notify()
|
2018-03-31 16:50:49 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
for (Watch_handle *h = _watch_handles.first(); h; h = h->next())
|
|
|
|
h->watch_response();
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
void unlink() { inode = 0; }
|
|
|
|
bool unlinked() const { return inode == 0; }
|
|
|
|
|
|
|
|
virtual size_t read(char*, size_t, file_size)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
|
|
|
Genode::error("Vfs_ram::Node::read() called");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
virtual Vfs::File_io_service::Read_result complete_read(char *,
|
|
|
|
file_size,
|
|
|
|
file_size,
|
|
|
|
file_size &)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
|
|
|
Genode::error("Vfs_ram::Node::complete_read() called");
|
|
|
|
return Vfs::File_io_service::READ_ERR_INVALID;
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
virtual size_t write(char const *, size_t, file_size)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
|
|
|
Genode::error("Vfs_ram::Node::write() called");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
virtual void truncate(file_size)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
|
|
|
Genode::error("Vfs_ram::Node::truncate() called");
|
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
/************************
|
|
|
|
** Avl node interface **
|
|
|
|
************************/
|
|
|
|
|
|
|
|
bool higher(Node *c) { return (strcmp(c->_name, _name) > 0); }
|
2015-07-22 07:32:42 +02:00
|
|
|
|
|
|
|
/**
|
2015-10-24 22:01:16 +02:00
|
|
|
* Find index N by walking down the tree N times,
|
|
|
|
* not the most efficient way to do this.
|
2015-07-22 07:32:42 +02:00
|
|
|
*/
|
2015-10-24 22:01:16 +02:00
|
|
|
Node *index(file_offset &i)
|
|
|
|
{
|
|
|
|
if (i-- == 0)
|
|
|
|
return this;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Node *n;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
n = child(LEFT);
|
|
|
|
if (n)
|
|
|
|
n = n->index(i);
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
if (n) return n;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
n = child(RIGHT);
|
|
|
|
if (n)
|
|
|
|
n = n->index(i);
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
return n;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Node *sibling(const char *name)
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
if (strcmp(name, _name) == 0) return this;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Node *c =
|
|
|
|
Avl_node<Node>::child(strcmp(name, _name) > 0);
|
2017-06-12 04:27:47 +02:00
|
|
|
return c ? c->sibling(name) : nullptr;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
struct Guard
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Node &node;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Guard(Node *guard_node) : node(*guard_node) { node.lock(); }
|
2015-07-22 07:32:42 +02:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
~Guard() { node.unlock(); }
|
2015-10-24 22:01:16 +02:00
|
|
|
};
|
|
|
|
};
|
2015-07-22 07:32:42 +02:00
|
|
|
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
class Vfs_ram::File : public Vfs_ram::Node
|
|
|
|
{
|
|
|
|
private:
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2019-09-06 12:34:12 +02:00
|
|
|
typedef Chunk <Ram_fs::num_level_3_entries()> Chunk_level_3;
|
|
|
|
typedef Chunk_index<Ram_fs::num_level_2_entries(), Chunk_level_3> Chunk_level_2;
|
|
|
|
typedef Chunk_index<Ram_fs::num_level_1_entries(), Chunk_level_2> Chunk_level_1;
|
|
|
|
typedef Chunk_index<Ram_fs::num_level_0_entries(), Chunk_level_1> Chunk_level_0;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Chunk_level_0 _chunk;
|
2016-03-31 01:15:12 +02:00
|
|
|
file_size _length = 0;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
public:
|
|
|
|
|
|
|
|
File(char const *name, Allocator &alloc)
|
2015-11-17 16:02:33 +01:00
|
|
|
: Node(name), _chunk(alloc, 0) { }
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
size_t read(char *dst, size_t len, file_size seek_offset) override
|
2015-10-24 22:01:16 +02:00
|
|
|
{
|
|
|
|
file_size 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 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;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
_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;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs::File_io_service::Read_result complete_read(char *dst,
|
|
|
|
file_size count,
|
|
|
|
file_size seek_offset,
|
|
|
|
file_size &out_count) override
|
|
|
|
{
|
|
|
|
out_count = read(dst, count, seek_offset);
|
|
|
|
return Vfs::File_io_service::READ_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t write(char const *src, size_t len, file_size seek_offset) override
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
if (seek_offset == (file_size)(~0))
|
|
|
|
seek_offset = _chunk.used_size();
|
|
|
|
|
|
|
|
if (seek_offset + len >= Chunk_level_0::SIZE)
|
|
|
|
len = Chunk_level_0::SIZE - (seek_offset + len);
|
|
|
|
|
2016-03-31 01:15:12 +02:00
|
|
|
try { _chunk.write(src, len, (size_t)seek_offset); }
|
|
|
|
catch (Out_of_memory) { return 0; }
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
|
|
|
return len;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
file_size length() override { return _length; }
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
void truncate(file_size size) override
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
if (size < _chunk.used_size())
|
|
|
|
_chunk.truncate(size);
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
_length = size;
|
|
|
|
}
|
|
|
|
};
|
2015-07-22 07:32:42 +02:00
|
|
|
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
class Vfs_ram::Symlink : public Vfs_ram::Node
|
|
|
|
{
|
|
|
|
private:
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
char _target[MAX_PATH_LEN];
|
2015-11-17 16:02:33 +01:00
|
|
|
size_t _len = 0;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
public:
|
|
|
|
|
2015-11-17 16:02:33 +01:00
|
|
|
Symlink(char const *name) : Node(name) { }
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
file_size length() override { return _len; }
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
void set(char const *target, size_t len)
|
|
|
|
{
|
2017-08-15 20:51:53 +02:00
|
|
|
for (size_t i = 0; i < len; ++i) {
|
|
|
|
if (target[i] == '\0') {
|
|
|
|
len = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-12 17:05:38 +02:00
|
|
|
_len = len;
|
2015-10-24 22:01:16 +02:00
|
|
|
memcpy(_target, target, _len);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t get(char *buf, size_t len)
|
|
|
|
{
|
|
|
|
size_t out = min(len, _len);
|
|
|
|
memcpy(buf, _target, out);
|
|
|
|
return out;
|
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
Vfs::File_io_service::Read_result complete_read(char *dst,
|
|
|
|
file_size count,
|
2018-03-31 16:50:49 +02:00
|
|
|
file_size,
|
|
|
|
file_size &out_count) override
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
|
|
|
out_count = get(dst, count);
|
|
|
|
return Vfs::File_io_service::READ_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t write(char const *src, size_t len, file_size) override
|
|
|
|
{
|
|
|
|
if (len > MAX_PATH_LEN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
set(src, len);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Vfs_ram::Directory : public Vfs_ram::Node
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Avl_tree<Node> _entries { };
|
2016-03-31 01:15:12 +02:00
|
|
|
file_size _count = 0;
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2016-03-31 01:15:12 +02:00
|
|
|
Directory(char const *name)
|
|
|
|
: Node(name) { }
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-31 01:15:12 +02:00
|
|
|
void empty(Allocator &alloc)
|
2015-10-24 22:01:16 +02:00
|
|
|
{
|
|
|
|
while (Node *node = _entries.first()) {
|
|
|
|
_entries.remove(node);
|
2016-03-31 01:15:12 +02:00
|
|
|
if (File *file = dynamic_cast<File*>(node)) {
|
2018-03-31 16:50:49 +02:00
|
|
|
if (file->opened())
|
2016-03-31 01:15:12 +02:00
|
|
|
continue;
|
|
|
|
} else if (Directory *dir = dynamic_cast<Directory*>(node)) {
|
|
|
|
dir->empty(alloc);
|
|
|
|
}
|
|
|
|
destroy(alloc, node);
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
void adopt(Node *node)
|
|
|
|
{
|
|
|
|
_entries.insert(node);
|
|
|
|
++_count;
|
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Node *child(char const *name)
|
|
|
|
{
|
|
|
|
Node *node = _entries.first();
|
2017-06-12 04:27:47 +02:00
|
|
|
return node ? node->sibling(name) : nullptr;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
void release(Node *node)
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
_entries.remove(node);
|
|
|
|
--_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_size length() override { return _count; }
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs::File_io_service::Read_result complete_read(char *dst,
|
|
|
|
file_size count,
|
|
|
|
file_size seek_offset,
|
|
|
|
file_size &out_count) override
|
2015-10-24 22:01:16 +02:00
|
|
|
{
|
2017-08-15 20:51:53 +02:00
|
|
|
typedef Vfs::Directory_service::Dirent Dirent;
|
|
|
|
|
|
|
|
if (count < sizeof(Dirent))
|
|
|
|
return Vfs::File_io_service::READ_ERR_INVALID;
|
|
|
|
|
|
|
|
file_offset index = seek_offset / sizeof(Dirent);
|
|
|
|
|
|
|
|
Dirent *dirent = (Dirent*)dst;
|
|
|
|
*dirent = Dirent();
|
|
|
|
out_count = sizeof(Dirent);
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Node *node = _entries.first();
|
2016-04-01 16:10:40 +02:00
|
|
|
if (node) node = node->index(index);
|
|
|
|
if (!node) {
|
2017-08-15 20:51:53 +02:00
|
|
|
dirent->type = Directory_service::DIRENT_TYPE_END;
|
|
|
|
return Vfs::File_io_service::READ_OK;
|
2016-04-01 16:10:40 +02:00
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
dirent->fileno = node->inode;
|
|
|
|
strncpy(dirent->name, node->name(), sizeof(dirent->name));
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2016-04-01 16:10:40 +02:00
|
|
|
File *file = dynamic_cast<File *>(node);
|
|
|
|
if (file) {
|
2017-08-15 20:51:53 +02:00
|
|
|
dirent->type = Directory_service::DIRENT_TYPE_FILE;
|
|
|
|
return Vfs::File_io_service::READ_OK;
|
2016-04-01 16:10:40 +02:00
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2016-04-01 16:10:40 +02:00
|
|
|
Directory *dir = dynamic_cast<Directory *>(node);
|
|
|
|
if (dir) {
|
2017-08-15 20:51:53 +02:00
|
|
|
dirent->type = Directory_service::DIRENT_TYPE_DIRECTORY;
|
|
|
|
return Vfs::File_io_service::READ_OK;
|
2016-04-01 16:10:40 +02:00
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2016-04-01 16:10:40 +02:00
|
|
|
Symlink *symlink = dynamic_cast<Symlink *>(node);
|
|
|
|
if (symlink) {
|
2017-08-15 20:51:53 +02:00
|
|
|
dirent->type = Directory_service::DIRENT_TYPE_SYMLINK;
|
|
|
|
return Vfs::File_io_service::READ_OK;
|
2015-10-24 22:01:16 +02:00
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
return Vfs::File_io_service::READ_ERR_INVALID;
|
2015-10-24 22:01:16 +02:00
|
|
|
}
|
|
|
|
};
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
class Vfs::Ram_file_system : public Vfs::File_system
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
friend class Genode::List<Vfs_ram::Watch_handle>;
|
2016-03-30 15:24:19 +02:00
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
Vfs::Env &_env;
|
|
|
|
Vfs_ram::Directory _root = { "" };
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Vfs_ram::Node *lookup(char const *path, bool return_parent = false)
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
using namespace Vfs_ram;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
if (*path == '/') ++path;
|
|
|
|
if (*path == '\0') return &_root;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
char buf[Vfs::MAX_PATH_LEN];
|
|
|
|
strncpy(buf, path, Vfs::MAX_PATH_LEN);
|
|
|
|
Directory *dir = &_root;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
char *name = &buf[0];
|
2016-03-02 14:32:43 +01:00
|
|
|
for (size_t i = 0; i < MAX_PATH_LEN; ++i) {
|
2015-10-24 22:01:16 +02:00
|
|
|
if (buf[i] == '/') {
|
|
|
|
buf[i] = '\0';
|
|
|
|
|
|
|
|
Node *node = dir->child(name);
|
2017-06-12 04:27:47 +02:00
|
|
|
if (!node) return nullptr;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
dir = dynamic_cast<Directory *>(node);
|
2017-06-12 04:27:47 +02:00
|
|
|
if (!dir) return nullptr;
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
/* set the current name aside */
|
|
|
|
name = &buf[i+1];
|
|
|
|
} else if (buf[i] == '\0') {
|
|
|
|
if (return_parent)
|
|
|
|
return dir;
|
|
|
|
else
|
|
|
|
return dir->child(name);
|
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
2017-06-12 04:27:47 +02:00
|
|
|
return nullptr;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Vfs_ram::Directory *lookup_parent(char const *path)
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
Node *node = lookup(path, true);
|
|
|
|
if (node)
|
|
|
|
return dynamic_cast<Directory *>(node);
|
2017-06-12 04:27:47 +02:00
|
|
|
return nullptr;
|
2015-10-24 22:01:16 +02:00
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2016-03-31 01:15:12 +02:00
|
|
|
void remove(Vfs_ram::Node *node)
|
|
|
|
{
|
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
if (File *file = dynamic_cast<File*>(node)) {
|
2018-03-31 16:50:49 +02:00
|
|
|
if (file->opened()) {
|
|
|
|
file->unlink();
|
2016-03-31 01:15:12 +02:00
|
|
|
return;
|
2018-03-31 16:50:49 +02:00
|
|
|
}
|
2016-03-31 01:15:12 +02:00
|
|
|
} else if (Directory *dir = dynamic_cast<Directory*>(node)) {
|
2018-04-03 15:59:35 +02:00
|
|
|
dir->empty(_env.alloc());
|
2016-03-31 01:15:12 +02:00
|
|
|
}
|
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
destroy(_env.alloc(), node);
|
2016-03-31 01:15:12 +02:00
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
public:
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
Ram_file_system(Vfs::Env &env, Genode::Xml_node) : _env(env) { }
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
~Ram_file_system() { _root.empty(_env.alloc()); }
|
2016-03-31 01:15:12 +02:00
|
|
|
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
/*********************************
|
|
|
|
** Directory service interface **
|
|
|
|
*********************************/
|
|
|
|
|
|
|
|
file_size num_dirent(char const *path) override
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
using namespace Vfs_ram;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
if (Node *node = lookup(path)) {
|
|
|
|
Node::Guard guard(node);
|
|
|
|
if (Directory *dir = dynamic_cast<Directory *>(node))
|
|
|
|
return dir->length();
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
return 0;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
bool directory(char const *path) override
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
Node *node = lookup(path);
|
2017-06-12 04:27:47 +02:00
|
|
|
return node
|
|
|
|
? (dynamic_cast<Directory *>(node) != nullptr)
|
|
|
|
: false;
|
2015-10-24 22:01:16 +02:00
|
|
|
}
|
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
char const *leaf_path(char const *path) override {
|
2017-06-12 04:27:47 +02:00
|
|
|
return lookup(path) ? path : nullptr; }
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-31 01:15:12 +02:00
|
|
|
Open_result open(char const *path, unsigned mode,
|
|
|
|
Vfs_handle **handle,
|
|
|
|
Allocator &alloc) override
|
2015-10-24 22:01:16 +02:00
|
|
|
{
|
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
File *file;
|
|
|
|
char const *name = basename(path);
|
2018-01-12 20:47:48 +01:00
|
|
|
bool const create = mode & OPEN_MODE_CREATE;
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2018-01-12 20:47:48 +01:00
|
|
|
if (create) {
|
2015-10-24 22:01:16 +02:00
|
|
|
Directory *parent = lookup_parent(path);
|
2017-06-12 04:27:47 +02:00
|
|
|
if (!parent) return OPEN_ERR_UNACCESSIBLE;
|
2015-10-24 22:01:16 +02:00
|
|
|
Node::Guard guard(parent);
|
|
|
|
|
|
|
|
if (parent->child(name)) return OPEN_ERR_EXISTS;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
if (strlen(name) >= MAX_NAME_LEN)
|
|
|
|
return OPEN_ERR_NAME_TOO_LONG;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
try { file = new (_env.alloc()) File(name, _env.alloc()); }
|
2016-03-31 01:15:12 +02:00
|
|
|
catch (Out_of_memory) { return OPEN_ERR_NO_SPACE; }
|
2015-10-24 22:01:16 +02:00
|
|
|
parent->adopt(file);
|
2019-03-25 15:41:43 +01:00
|
|
|
parent->notify();
|
2015-10-24 22:01:16 +02:00
|
|
|
} else {
|
|
|
|
Node *node = lookup(path);
|
|
|
|
if (!node) return OPEN_ERR_UNACCESSIBLE;
|
|
|
|
|
|
|
|
file = dynamic_cast<File *>(node);
|
|
|
|
if (!file) return OPEN_ERR_UNACCESSIBLE;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2018-01-12 20:47:48 +01:00
|
|
|
try {
|
2018-03-31 16:50:49 +02:00
|
|
|
*handle = new (alloc) Io_handle(*this, alloc, mode, *file);
|
2018-01-12 20:47:48 +01:00
|
|
|
return OPEN_OK;
|
|
|
|
} catch (Genode::Out_of_ram) {
|
|
|
|
if (create) {
|
|
|
|
lookup_parent(path)->release(file);
|
|
|
|
remove(file);
|
|
|
|
}
|
|
|
|
return OPEN_ERR_OUT_OF_RAM;
|
|
|
|
} catch (Genode::Out_of_caps) {
|
|
|
|
if (create) {
|
|
|
|
lookup_parent(path)->release(file);
|
|
|
|
remove(file);
|
|
|
|
}
|
|
|
|
return OPEN_ERR_OUT_OF_CAPS;
|
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Opendir_result opendir(char const *path, bool create,
|
|
|
|
Vfs_handle **handle,
|
|
|
|
Allocator &alloc) override
|
|
|
|
{
|
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
Directory *parent = lookup_parent(path);
|
|
|
|
if (!parent) return OPENDIR_ERR_LOOKUP_FAILED;
|
|
|
|
Node::Guard guard(parent);
|
|
|
|
|
|
|
|
char const *name = basename(path);
|
|
|
|
|
|
|
|
Directory *dir;
|
|
|
|
|
|
|
|
if (create) {
|
2018-03-31 16:50:49 +02:00
|
|
|
if (*name == '\0')
|
|
|
|
return OPENDIR_ERR_NODE_ALREADY_EXISTS;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
if (strlen(name) >= MAX_NAME_LEN)
|
|
|
|
return OPENDIR_ERR_NAME_TOO_LONG;
|
|
|
|
|
|
|
|
if (parent->child(name))
|
|
|
|
return OPENDIR_ERR_NODE_ALREADY_EXISTS;
|
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
try { dir = new (_env.alloc()) Directory(name); }
|
2018-01-12 20:47:48 +01:00
|
|
|
catch (Out_of_memory) { return OPENDIR_ERR_NO_SPACE; }
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
parent->adopt(dir);
|
2019-03-25 15:41:43 +01:00
|
|
|
parent->notify();
|
2017-08-15 20:51:53 +02:00
|
|
|
} else {
|
|
|
|
|
|
|
|
Node *node = lookup(path);
|
|
|
|
if (!node) return OPENDIR_ERR_LOOKUP_FAILED;
|
|
|
|
|
|
|
|
dir = dynamic_cast<Directory *>(node);
|
|
|
|
if (!dir) return OPENDIR_ERR_LOOKUP_FAILED;
|
|
|
|
}
|
|
|
|
|
2018-01-12 20:47:48 +01:00
|
|
|
try {
|
2018-03-31 16:50:49 +02:00
|
|
|
*handle = new (alloc) Io_handle(
|
|
|
|
*this, alloc, Io_handle::STATUS_RDONLY, *dir);
|
2018-01-12 20:47:48 +01:00
|
|
|
return OPENDIR_OK;
|
|
|
|
} catch (Genode::Out_of_ram) {
|
|
|
|
if (create) {
|
|
|
|
parent->release(dir);
|
|
|
|
remove(dir);
|
|
|
|
}
|
|
|
|
return OPENDIR_ERR_OUT_OF_RAM;
|
|
|
|
} catch (Genode::Out_of_caps) {
|
|
|
|
if (create) {
|
|
|
|
parent->release(dir);
|
|
|
|
remove(dir);
|
|
|
|
}
|
|
|
|
return OPENDIR_ERR_OUT_OF_CAPS;
|
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Openlink_result openlink(char const *path, bool create,
|
|
|
|
Vfs_handle **handle, Allocator &alloc) override
|
|
|
|
{
|
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
Directory *parent = lookup_parent(path);
|
|
|
|
if (!parent) return OPENLINK_ERR_LOOKUP_FAILED;
|
|
|
|
Node::Guard guard(parent);
|
|
|
|
|
|
|
|
char const *name = basename(path);
|
|
|
|
|
|
|
|
Symlink *link;
|
|
|
|
|
|
|
|
Node *node = parent->child(name);
|
|
|
|
|
|
|
|
if (create) {
|
|
|
|
|
|
|
|
if (node)
|
|
|
|
return OPENLINK_ERR_NODE_ALREADY_EXISTS;
|
|
|
|
|
|
|
|
if (strlen(name) >= MAX_NAME_LEN)
|
|
|
|
return OPENLINK_ERR_NAME_TOO_LONG;
|
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
try { link = new (_env.alloc()) Symlink(name); }
|
2017-08-15 20:51:53 +02:00
|
|
|
catch (Out_of_memory) { return OPENLINK_ERR_NO_SPACE; }
|
|
|
|
|
|
|
|
link->lock();
|
|
|
|
parent->adopt(link);
|
|
|
|
link->unlock();
|
2019-03-25 15:41:43 +01:00
|
|
|
parent->notify();
|
2017-08-15 20:51:53 +02:00
|
|
|
} else {
|
|
|
|
|
|
|
|
if (!node) return OPENLINK_ERR_LOOKUP_FAILED;
|
|
|
|
Node::Guard guard(node);
|
|
|
|
|
|
|
|
link = dynamic_cast<Symlink *>(node);
|
|
|
|
if (!link) return OPENLINK_ERR_LOOKUP_FAILED;
|
|
|
|
}
|
|
|
|
|
2018-01-12 20:47:48 +01:00
|
|
|
try {
|
2018-03-31 16:50:49 +02:00
|
|
|
*handle = new (alloc)
|
|
|
|
Io_handle(*this, alloc, Io_handle::STATUS_RDWR, *link);
|
2018-01-12 20:47:48 +01:00
|
|
|
return OPENLINK_OK;
|
|
|
|
} catch (Genode::Out_of_ram) {
|
|
|
|
if (create) {
|
|
|
|
parent->release(link);
|
|
|
|
remove(link);
|
|
|
|
}
|
|
|
|
return OPENLINK_ERR_OUT_OF_RAM;
|
|
|
|
} catch (Genode::Out_of_caps) {
|
|
|
|
if (create) {
|
|
|
|
parent->release(link);
|
|
|
|
remove(link);
|
|
|
|
}
|
|
|
|
return OPENLINK_ERR_OUT_OF_CAPS;
|
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2016-03-30 15:24:19 +02:00
|
|
|
void close(Vfs_handle *vfs_handle) override
|
|
|
|
{
|
2018-03-31 16:50:49 +02:00
|
|
|
Vfs_ram::Io_handle *ram_handle =
|
|
|
|
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
|
|
|
|
|
|
|
Vfs_ram::Node &node = ram_handle->node;
|
|
|
|
bool node_modified = ram_handle->modifying;
|
2016-03-30 15:24:19 +02:00
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
ram_handle->node.close(*ram_handle);
|
|
|
|
destroy(vfs_handle->alloc(), ram_handle);
|
|
|
|
|
|
|
|
if (ram_handle->node.unlinked() && !ram_handle->node.opened()) {
|
2018-04-03 15:59:35 +02:00
|
|
|
destroy(_env.alloc(), &ram_handle->node);
|
2018-03-31 16:50:49 +02:00
|
|
|
} else if (node_modified) {
|
2019-03-25 15:41:43 +01:00
|
|
|
node.notify();
|
2016-03-30 15:24:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Stat_result stat(char const *path, Stat &stat) override
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
using namespace Vfs_ram;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Node *node = lookup(path);
|
|
|
|
if (!node) return STAT_ERR_NO_ENTRY;
|
|
|
|
Node::Guard guard(node);
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
stat.size = node->length();
|
2016-04-01 16:10:40 +02:00
|
|
|
stat.inode = node->inode;
|
|
|
|
stat.device = (Genode::addr_t)this;
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
File *file = dynamic_cast<File *>(node);
|
|
|
|
if (file) {
|
|
|
|
stat.mode = STAT_MODE_FILE | 0777;
|
|
|
|
return STAT_OK;
|
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Directory *dir = dynamic_cast<Directory *>(node);
|
|
|
|
if (dir) {
|
|
|
|
stat.mode = STAT_MODE_DIRECTORY | 0777;
|
|
|
|
return STAT_OK;
|
|
|
|
}
|
2015-07-22 07:32:42 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Symlink *symlink = dynamic_cast<Symlink *>(node);
|
|
|
|
if (symlink) {
|
|
|
|
stat.mode = STAT_MODE_SYMLINK | 0777;
|
|
|
|
return STAT_OK;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
/* this should never happen */
|
2015-10-24 22:01:16 +02:00
|
|
|
return STAT_ERR_NO_ENTRY;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Rename_result rename(char const *from, char const *to) override
|
|
|
|
{
|
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
if ((strcmp(from, to) == 0) && lookup(from))
|
|
|
|
return RENAME_OK;
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
char const *new_name = basename(to);
|
|
|
|
if (strlen(new_name) >= MAX_NAME_LEN)
|
|
|
|
return RENAME_ERR_NO_PERM;
|
|
|
|
|
|
|
|
Directory *from_dir = lookup_parent(from);
|
|
|
|
if (!from_dir) return RENAME_ERR_NO_ENTRY;
|
|
|
|
Node::Guard from_guard(from_dir);
|
|
|
|
|
|
|
|
Directory *to_dir = lookup_parent(to);
|
|
|
|
if (!to_dir) return RENAME_ERR_NO_ENTRY;
|
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
/* unlock the node so a second guard can be constructed */
|
|
|
|
if (from_dir == to_dir)
|
|
|
|
from_dir->unlock();
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
Node::Guard to_guard(to_dir);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
Node *from_node = from_dir->child(basename(from));
|
|
|
|
if (!from_node) return RENAME_ERR_NO_ENTRY;
|
|
|
|
Node::Guard guard(from_node);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
Node *to_node = to_dir->child(new_name);
|
|
|
|
if (to_node) {
|
|
|
|
to_node->lock();
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
if (Directory *dir = dynamic_cast<Directory*>(to_node))
|
|
|
|
if (dir->length() || (!dynamic_cast<Directory*>(from_node)))
|
|
|
|
return RENAME_ERR_NO_PERM;
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2018-08-21 19:19:43 +02:00
|
|
|
/* detach node to be replaced from directory */
|
2016-03-02 14:32:43 +01:00
|
|
|
to_dir->release(to_node);
|
2018-08-21 19:19:43 +02:00
|
|
|
|
|
|
|
/* notify the node being replaced */
|
2019-03-25 15:41:43 +01:00
|
|
|
to_node->notify();
|
2018-08-21 19:19:43 +02:00
|
|
|
|
|
|
|
/* free the node that is replaced */
|
2016-03-31 01:15:12 +02:00
|
|
|
remove(to_node);
|
2016-03-02 14:32:43 +01:00
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
from_dir->release(from_node);
|
|
|
|
from_node->name(new_name);
|
|
|
|
to_dir->adopt(from_node);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
from_dir->notify();
|
|
|
|
to_dir->notify();
|
2018-03-31 16:50:49 +02:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
return RENAME_OK;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Unlink_result unlink(char const *path) override
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2015-10-24 22:01:16 +02:00
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
Directory *parent = lookup_parent(path);
|
|
|
|
if (!parent) return UNLINK_ERR_NO_ENTRY;
|
|
|
|
Node::Guard guard(parent);
|
|
|
|
|
|
|
|
Node *node = parent->child(basename(path));
|
|
|
|
if (!node) return UNLINK_ERR_NO_ENTRY;
|
|
|
|
|
2015-11-17 16:02:33 +01:00
|
|
|
node->lock();
|
2015-10-24 22:01:16 +02:00
|
|
|
parent->release(node);
|
2019-03-25 15:41:43 +01:00
|
|
|
node->notify();
|
|
|
|
parent->notify();
|
2016-03-31 01:15:12 +02:00
|
|
|
remove(node);
|
2015-10-24 22:01:16 +02:00
|
|
|
return UNLINK_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dataspace_capability dataspace(char const *path) override
|
|
|
|
{
|
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
Ram_dataspace_capability ds_cap;
|
|
|
|
|
|
|
|
Node *node = lookup(path);
|
|
|
|
if (!node) return ds_cap;
|
|
|
|
Node::Guard guard(node);
|
|
|
|
|
|
|
|
File *file = dynamic_cast<File *>(node);
|
|
|
|
if (!file) return ds_cap;
|
|
|
|
|
|
|
|
size_t len = file->length();
|
|
|
|
|
|
|
|
char *local_addr = nullptr;
|
2015-07-22 07:32:42 +02:00
|
|
|
try {
|
2018-04-03 15:59:35 +02:00
|
|
|
ds_cap = _env.env().ram().alloc(len);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
local_addr = _env.env().rm().attach(ds_cap);
|
2015-10-24 22:01:16 +02:00
|
|
|
file->read(local_addr, file->length(), 0);
|
2018-04-03 15:59:35 +02:00
|
|
|
_env.env().rm().detach(local_addr);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
} catch(...) {
|
2018-04-03 15:59:35 +02:00
|
|
|
_env.env().rm().detach(local_addr);
|
|
|
|
_env.env().ram().free(ds_cap);
|
2015-10-24 22:01:16 +02:00
|
|
|
return Dataspace_capability();
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
return ds_cap;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
void release(char const *, Dataspace_capability ds_cap) override {
|
2018-04-03 15:59:35 +02:00
|
|
|
_env.env().ram().free(
|
2015-10-24 22:01:16 +02:00
|
|
|
static_cap_cast<Genode::Ram_dataspace>(ds_cap)); }
|
|
|
|
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
Watch_result watch(char const *path,
|
|
|
|
Vfs_watch_handle **handle,
|
|
|
|
Allocator &alloc) override
|
|
|
|
{
|
|
|
|
using namespace Vfs_ram;
|
|
|
|
|
|
|
|
Node *node = lookup(path);
|
|
|
|
if (!node) return WATCH_ERR_UNACCESSIBLE;
|
|
|
|
Node::Guard guard(node);
|
|
|
|
|
|
|
|
try {
|
|
|
|
Vfs_ram::Watch_handle *watch_handle = new(alloc)
|
|
|
|
Vfs_ram::Watch_handle(*this, alloc, *node);
|
|
|
|
node->open(*watch_handle);
|
|
|
|
*handle = watch_handle;
|
|
|
|
return WATCH_OK;
|
|
|
|
}
|
|
|
|
catch (Genode::Out_of_ram) { return WATCH_ERR_OUT_OF_RAM; }
|
|
|
|
catch (Genode::Out_of_caps) { return WATCH_ERR_OUT_OF_CAPS; }
|
|
|
|
}
|
|
|
|
|
|
|
|
void close(Vfs_watch_handle *vfs_handle) override
|
|
|
|
{
|
|
|
|
Vfs_ram::Watch_handle *watch_handle =
|
|
|
|
static_cast<Vfs_ram::Watch_handle *>(vfs_handle);
|
|
|
|
watch_handle->node.close(*watch_handle);
|
|
|
|
destroy(watch_handle->alloc(), watch_handle);
|
|
|
|
};
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
/************************
|
|
|
|
** File I/O interface **
|
|
|
|
************************/
|
|
|
|
|
|
|
|
Write_result write(Vfs_handle *vfs_handle,
|
|
|
|
char const *buf, file_size len,
|
|
|
|
Vfs::file_size &out) override
|
2015-07-22 07:32:42 +02:00
|
|
|
{
|
2016-03-31 01:15:12 +02:00
|
|
|
if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY)
|
2015-10-24 22:01:16 +02:00
|
|
|
return WRITE_ERR_INVALID;
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
Vfs_ram::Io_handle *handle =
|
|
|
|
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs_ram::Node::Guard guard(&handle->node);
|
|
|
|
out = handle->node.write(buf, len, handle->seek());
|
2018-03-31 16:50:49 +02:00
|
|
|
handle->modifying = true;
|
2015-11-17 16:02:33 +01:00
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
return WRITE_OK;
|
2015-07-22 07:32:42 +02:00
|
|
|
}
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Read_result complete_read(Vfs_handle *vfs_handle, char *dst, file_size count,
|
|
|
|
file_size &out_count) override
|
2015-10-24 22:01:16 +02:00
|
|
|
{
|
2017-08-15 20:51:53 +02:00
|
|
|
out_count = 0;
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
Vfs_ram::Io_handle const *handle =
|
|
|
|
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs_ram::Node::Guard guard(&handle->node);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
return handle->node.complete_read(dst, count, handle->seek(), out_count);
|
2015-10-24 22:01:16 +02:00
|
|
|
}
|
|
|
|
|
2017-02-01 11:28:15 +01:00
|
|
|
bool read_ready(Vfs_handle *) override { return true; }
|
|
|
|
|
2015-10-24 22:01:16 +02:00
|
|
|
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size len) override
|
|
|
|
{
|
2016-03-31 01:15:12 +02:00
|
|
|
if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY)
|
2015-10-24 22:01:16 +02:00
|
|
|
return FTRUNCATE_ERR_NO_PERM;
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
Vfs_ram::Io_handle const *handle =
|
|
|
|
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
2015-10-24 22:01:16 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs_ram::Node::Guard guard(&handle->node);
|
2016-03-31 01:15:12 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
try { handle->node.truncate(len); }
|
2016-03-31 01:15:12 +02:00
|
|
|
catch (Vfs_ram::Out_of_memory) { return FTRUNCATE_ERR_NO_SPACE; }
|
2015-10-24 22:01:16 +02:00
|
|
|
return FTRUNCATE_OK;
|
|
|
|
}
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
/**
|
|
|
|
* Notify other handles if this handle has modified the node
|
|
|
|
*/
|
|
|
|
Sync_result complete_sync(Vfs_handle *vfs_handle) override
|
|
|
|
{
|
|
|
|
Vfs_ram::Io_handle *handle =
|
|
|
|
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
|
|
|
if (handle->modifying) {
|
|
|
|
handle->modifying = false;
|
|
|
|
handle->node.close(*handle);
|
2019-03-25 15:41:43 +01:00
|
|
|
handle->node.notify();
|
2018-03-31 16:50:49 +02:00
|
|
|
handle->node.open(*handle);
|
|
|
|
}
|
|
|
|
return SYNC_OK;
|
|
|
|
}
|
2015-10-24 22:01:16 +02:00
|
|
|
|
|
|
|
/***************************
|
|
|
|
** File_system interface **
|
|
|
|
***************************/
|
|
|
|
|
2017-02-07 19:03:23 +01:00
|
|
|
static char const *name() { return "ram"; }
|
|
|
|
char const *type() override { return "ram"; }
|
2015-07-22 07:32:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* _INCLUDE__VFS__RAM_FILE_SYSTEM_H_ */
|