2016-03-30 20:14:15 +02:00
|
|
|
/*
|
|
|
|
* \brief Internal nodes of VFS server
|
|
|
|
* \author Emery Hemingway
|
2017-02-01 21:07:14 +01:00
|
|
|
* \author Christian Helmuth
|
2016-03-30 20:14:15 +02:00
|
|
|
* \date 2016-03-29
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2019-03-25 15:41:43 +01:00
|
|
|
* Copyright (C) 2016-2019 Genode Labs GmbH
|
2016-03-30 20:14:15 +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.
|
2016-03-30 20:14:15 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _VFS__NODE_H_
|
|
|
|
#define _VFS__NODE_H_
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <file_system/node.h>
|
|
|
|
#include <vfs/file_system.h>
|
|
|
|
#include <os/path.h>
|
2017-01-04 15:27:42 +01:00
|
|
|
#include <base/id_space.h>
|
2016-03-30 20:14:15 +02:00
|
|
|
|
|
|
|
/* Local includes */
|
|
|
|
#include "assert.h"
|
|
|
|
|
|
|
|
namespace Vfs_server {
|
|
|
|
|
|
|
|
using namespace File_system;
|
|
|
|
using namespace Vfs;
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
typedef Vfs::File_io_service::Write_result Write_result;
|
|
|
|
typedef Vfs::File_io_service::Read_result Read_result;
|
|
|
|
typedef Vfs::File_io_service::Sync_result Sync_result;
|
|
|
|
|
|
|
|
typedef ::File_system::Session::Tx::Sink Packet_stream;
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
class Node;
|
|
|
|
class Io_node;
|
|
|
|
class Watch_node;
|
|
|
|
class Directory;
|
|
|
|
class File;
|
|
|
|
class Symlink;
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2017-01-04 15:27:42 +01:00
|
|
|
typedef Genode::Id_space<Node> Node_space;
|
2019-03-25 15:41:43 +01:00
|
|
|
typedef Genode::Fifo<Node> Node_queue;
|
2017-02-12 10:58:27 +01:00
|
|
|
|
2016-03-30 20:14:15 +02:00
|
|
|
/* Vfs::MAX_PATH is shorter than File_system::MAX_PATH */
|
|
|
|
enum { MAX_PATH_LEN = Vfs::MAX_PATH_LEN };
|
|
|
|
|
|
|
|
typedef Genode::Path<MAX_PATH_LEN> Path;
|
|
|
|
|
|
|
|
typedef Genode::Allocator::Out_of_memory Out_of_memory;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Type trait for determining the node type for a given handle type
|
|
|
|
*/
|
|
|
|
template<typename T> struct Node_type;
|
2018-03-31 16:50:49 +02:00
|
|
|
template<> struct Node_type<Node_handle> { typedef Io_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; };
|
|
|
|
template<> struct Node_type<Watch_handle> { typedef Watch_node Type; };
|
2016-03-30 20:14:15 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Type trait for determining the handle type for a given node type
|
|
|
|
*/
|
|
|
|
template<typename T> struct Handle_type;
|
2018-03-31 16:50:49 +02:00
|
|
|
template<> struct Handle_type<Io_node> { typedef Node_handle Type; };
|
2016-03-30 20:14:15 +02:00
|
|
|
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; };
|
2018-03-31 16:50:49 +02:00
|
|
|
template<> struct Handle_type<Watch> { typedef Watch_handle Type; };
|
2016-03-30 20:14:15 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that the file objects are created at the
|
|
|
|
* VFS in the local node constructors, this is to
|
2019-03-25 15:41:43 +01:00
|
|
|
* ensure that in the case of file creating that the
|
|
|
|
* Out_of_ram exception is thrown before the VFS is
|
|
|
|
* modified.
|
2016-03-30 20:14:15 +02:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
|
2018-10-30 13:09:32 +01:00
|
|
|
class Vfs_server::Node : public ::File_system::Node_base,
|
2019-03-25 15:41:43 +01:00
|
|
|
private Node_space::Element,
|
|
|
|
private Node_queue::Element
|
2016-03-30 20:14:15 +02:00
|
|
|
{
|
2017-08-15 20:51:53 +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
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
Node(Node const &);
|
|
|
|
Node &operator = (Node const &);
|
|
|
|
|
|
|
|
Path const _path;
|
2018-03-31 16:50:49 +02:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/*
|
|
|
|
* Global queue of nodes that await
|
|
|
|
* some response from the VFS libray
|
|
|
|
*
|
|
|
|
* A global collection is perhaps dangerous
|
|
|
|
* but ensures fairness across sessions
|
2018-03-31 16:50:49 +02:00
|
|
|
*/
|
2019-03-25 15:41:43 +01:00
|
|
|
Node_queue &_response_queue;
|
|
|
|
|
|
|
|
/* stream used for reply packets */
|
|
|
|
Packet_stream &_stream;
|
2018-03-31 16:50:49 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
friend Node_queue;
|
|
|
|
using Node_queue::Element::enqueued;
|
|
|
|
|
|
|
|
Node(Node_space &space,
|
|
|
|
char const *node_path,
|
|
|
|
Node_queue &response_queue,
|
|
|
|
Packet_stream &stream)
|
|
|
|
: Node_space::Element(*this, space),
|
|
|
|
_path(node_path),
|
|
|
|
_response_queue(response_queue),
|
|
|
|
_stream(stream)
|
2018-03-31 16:50:49 +02:00
|
|
|
{ }
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
virtual ~Node()
|
|
|
|
{
|
|
|
|
if (enqueued())
|
|
|
|
_response_queue.remove(*this);
|
|
|
|
}
|
2018-03-31 16:50:49 +02:00
|
|
|
|
|
|
|
using Node_space::Element::id;
|
|
|
|
|
|
|
|
char const *path() const { return _path.base(); }
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/**
|
|
|
|
* Process pending activity, called by post-signal hook
|
|
|
|
*
|
|
|
|
* Default implementation is to return true so that the
|
|
|
|
* node is removed from the pending handle queue.
|
|
|
|
*/
|
|
|
|
virtual bool process_io() { return true; }
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
/**
|
|
|
|
* Print for debugging
|
|
|
|
*/
|
|
|
|
void print(Genode::Output &out) const {
|
|
|
|
out.out_string(_path.base()); }
|
|
|
|
};
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Super-class for nodes that process read/write packets
|
|
|
|
*/
|
|
|
|
class Vfs_server::Io_node : public Vfs_server::Node,
|
|
|
|
public Vfs::Io_response_handler{
|
2018-03-31 16:50:49 +02:00
|
|
|
public:
|
|
|
|
|
|
|
|
enum Op_state { IDLE, READ_QUEUED, SYNC_QUEUED };
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
Io_node(Io_node const &);
|
|
|
|
Io_node &operator = (Io_node const &);
|
|
|
|
|
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
|
|
|
Mode const _mode;
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
bool _packet_queued = false;
|
|
|
|
bool _packet_op_pending = false;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
Vfs::Vfs_handle &_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
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/**
|
|
|
|
* Packets that have been removed from the
|
|
|
|
* packet stream are transfered here
|
|
|
|
*/
|
|
|
|
Packet_descriptor _packet { };
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/**
|
|
|
|
* Abstract read implementation
|
|
|
|
*
|
|
|
|
* Returns true if the pending packet
|
|
|
|
* shall be returned to client
|
|
|
|
*/
|
|
|
|
bool _vfs_read(char *dst, file_size count,
|
|
|
|
file_offset seek_offset, file_size &out_count)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
if (!(_mode & READ_ONLY)) return true;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
_handle.seek(seek_offset);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
if (!_packet_op_pending) {
|
|
|
|
/* if the read cannot be queued with the VFS then stop here */
|
|
|
|
if (!_handle.fs().queue_read(&_handle, count)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
_packet_op_pending = true;
|
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
Read_result result = _handle.fs().complete_read(
|
|
|
|
&_handle, dst, count, out_count);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
switch (result) {
|
|
|
|
case Read_result::READ_OK:
|
|
|
|
_packet.succeeded(true);
|
|
|
|
break;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
case Read_result::READ_ERR_IO:
|
|
|
|
case Read_result::READ_ERR_INVALID:
|
|
|
|
_packet.length(out_count);
|
2017-08-15 20:51:53 +02:00
|
|
|
break;
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
case Read_result::READ_ERR_WOULD_BLOCK:
|
|
|
|
case Read_result::READ_ERR_AGAIN:
|
|
|
|
case Read_result::READ_ERR_INTERRUPT:
|
|
|
|
case Read_result::READ_QUEUED:
|
|
|
|
/* packet is still pending */
|
|
|
|
return false;
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/* packet is processed */
|
|
|
|
_packet_op_pending = false;
|
|
|
|
return true;
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/**
|
|
|
|
* Abstract write implementation
|
|
|
|
*
|
|
|
|
* Returns true if the pending packet
|
|
|
|
* shall be returned to client
|
|
|
|
*/
|
|
|
|
bool _vfs_write(char const *src, file_size count,
|
|
|
|
file_offset seek_offset, file_size &out_count)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
if (!(_mode & WRITE_ONLY))
|
|
|
|
return true;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
_handle.seek(seek_offset);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
try {
|
2019-03-25 15:41:43 +01:00
|
|
|
Write_result result = _handle.fs().write(
|
|
|
|
&_handle, src, count, out_count);
|
|
|
|
|
|
|
|
if (result == Write_result::WRITE_OK) {
|
|
|
|
mark_as_updated();
|
|
|
|
_packet.succeeded(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Vfs::File_io_service::Insufficient_buffer)
|
|
|
|
{
|
|
|
|
/* packet is pending */
|
|
|
|
return false;
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/* packet is processed */
|
|
|
|
return true;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/* No further error handling! */
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
inline
|
|
|
|
void _drop_packet()
|
|
|
|
{
|
|
|
|
_packet = Packet_descriptor();
|
|
|
|
_packet_queued = false;
|
|
|
|
}
|
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
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
inline
|
|
|
|
void _ack_packet(size_t count)
|
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
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
_packet.length(count);
|
|
|
|
_stream.acknowledge_packet(_packet);
|
|
|
|
_packet = Packet_descriptor();
|
|
|
|
_packet_queued = false;
|
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
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/**
|
|
|
|
* Abstract sync implementation
|
|
|
|
*/
|
|
|
|
bool _sync()
|
|
|
|
{
|
|
|
|
if (!_packet_op_pending) {
|
|
|
|
/* if the sync cannot be queued with the VFS then stop here */
|
|
|
|
if (!_handle.fs().queue_sync(&_handle)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
_packet_op_pending = true;
|
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
Sync_result result = _handle.fs().complete_sync(&_handle);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
switch (result) {
|
|
|
|
case Sync_result::SYNC_OK:
|
|
|
|
_packet.succeeded(true);
|
|
|
|
break;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
case Sync_result::SYNC_ERR_INVALID:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Sync_result::SYNC_QUEUED:
|
|
|
|
/* packet still pending */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* packet processed */
|
|
|
|
_ack_packet(0);
|
|
|
|
_packet_op_pending = false;
|
|
|
|
return true;
|
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
/**
|
2019-03-25 15:41:43 +01:00
|
|
|
* Virtual methods for specialized node-type I/O
|
2018-03-31 16:50:49 +02:00
|
|
|
*/
|
2019-03-25 15:41:43 +01:00
|
|
|
virtual bool _read() = 0;
|
|
|
|
virtual bool _write() = 0;
|
|
|
|
|
|
|
|
public:
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
Io_node(Node_space &space, char const *node_path, Mode node_mode,
|
|
|
|
Node_queue &response_queue, Packet_stream &stream,
|
|
|
|
Vfs_handle &handle)
|
|
|
|
: Node(space, node_path, response_queue, stream),
|
|
|
|
_mode(node_mode), _handle(handle)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
_handle.handler(this);
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
virtual ~Io_node()
|
|
|
|
{
|
|
|
|
_handle.handler(nullptr);
|
|
|
|
_handle.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
using Node_space::Element::id;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/**
|
|
|
|
* Process the packet that is queued at this handle
|
|
|
|
*
|
|
|
|
* Return true if the node was processed and is now idle.
|
|
|
|
*/
|
|
|
|
bool process_io() override
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
if (!_packet_queued) return true;
|
|
|
|
if (!_stream.ready_to_ack())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool result = true;
|
|
|
|
|
|
|
|
switch (_packet.operation()) {
|
|
|
|
case Packet_descriptor::READ: result = _read(); break;
|
|
|
|
case Packet_descriptor::WRITE: result = _write(); break;
|
|
|
|
case Packet_descriptor::SYNC: result = _sync(); break;
|
|
|
|
|
|
|
|
case Packet_descriptor::READ_READY:
|
|
|
|
/*
|
|
|
|
* the read-ready pending state is managed
|
|
|
|
* by the VFS, this packet can be discarded
|
|
|
|
*/
|
|
|
|
_drop_packet();
|
|
|
|
|
|
|
|
if (_handle.fs().read_ready(&_handle)) {
|
|
|
|
/* if the handle is ready, send a packet back immediately */
|
|
|
|
read_ready_response();
|
|
|
|
} else {
|
|
|
|
/* register to send READ_READY later */
|
|
|
|
_handle.fs().notify_read_ready(&_handle);
|
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
break;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
case Packet_descriptor::CONTENT_CHANGED:
|
|
|
|
/* discard this packet */
|
|
|
|
_drop_packet();
|
|
|
|
break;
|
2019-04-09 16:25:53 +02:00
|
|
|
|
|
|
|
case Packet_descriptor::WRITE_TIMESTAMP:
|
|
|
|
try {
|
|
|
|
_packet.with_timestamp([&] (File_system::Timestamp const time) {
|
|
|
|
Vfs::Timestamp ts { .value = time.value };
|
|
|
|
_handle.fs().update_modification_timestamp(&_handle, ts);
|
|
|
|
});
|
|
|
|
_packet.succeeded(true);
|
|
|
|
_ack_packet(0);
|
|
|
|
} catch (Vfs::File_io_service::Insufficient_buffer) {
|
|
|
|
/* packet is pending */
|
|
|
|
result = false;
|
|
|
|
}
|
|
|
|
break;
|
2019-03-25 15:41:43 +01:00
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
return result;
|
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/**
|
|
|
|
* Process a packet by queuing it locally or sending
|
|
|
|
* an immediate response. Return false if no progress
|
|
|
|
* can be made.
|
|
|
|
*
|
|
|
|
* Called by packet stream signal handler
|
|
|
|
*/
|
|
|
|
bool process_packet(Packet_descriptor const &packet)
|
|
|
|
{
|
|
|
|
/* attempt to clear any pending packet */
|
|
|
|
if (!process_io())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* otherwise store the packet locally and process */
|
|
|
|
_packet = packet;
|
|
|
|
_packet_queued = true;
|
|
|
|
process_io();
|
|
|
|
return true;
|
|
|
|
}
|
2018-07-23 19:53:09 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
Mode mode() const { return _mode; }
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/****************************************
|
|
|
|
** Vfs::Io_response_handler interface **
|
|
|
|
****************************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by the VFS plugin of this handle
|
|
|
|
*/
|
|
|
|
void read_ready_response() override
|
|
|
|
{
|
|
|
|
if (!_stream.ready_to_ack()) {
|
|
|
|
/* log a message to catch loops */
|
|
|
|
Genode::warning("deferring READ_READY response");
|
|
|
|
_handle.fs().notify_read_ready(&_handle);
|
|
|
|
return;
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
2019-03-25 15:41:43 +01:00
|
|
|
|
|
|
|
/* Send packet immediately, though this could be queued */
|
|
|
|
Packet_descriptor packet(Packet_descriptor(),
|
|
|
|
Node_handle { id().value },
|
|
|
|
Packet_descriptor::READ_READY,
|
|
|
|
0, 0);
|
|
|
|
packet.succeeded(true);
|
|
|
|
_stream.acknowledge_packet(packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by the VFS plugin of this handle
|
|
|
|
*/
|
|
|
|
void io_progress_response() override
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* do not process packet immediately,
|
|
|
|
* queue to maintain ordering (priorities?)
|
|
|
|
*/
|
|
|
|
if (!enqueued())
|
|
|
|
_response_queue.enqueue(*this);
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
};
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
class Vfs_server::Watch_node final : public Vfs_server::Node,
|
|
|
|
public Vfs::Watch_response_handler
|
2018-03-31 16:50:49 +02:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
Watch_node(Watch_node const &);
|
|
|
|
Watch_node &operator = (Watch_node const &);
|
|
|
|
|
|
|
|
Vfs::Vfs_watch_handle &_watch_handle;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Watch_node(Node_space &space, char const *path,
|
|
|
|
Vfs::Vfs_watch_handle &handle,
|
2019-03-25 15:41:43 +01:00
|
|
|
Node_queue &response_queue,
|
|
|
|
Packet_stream &stream)
|
|
|
|
: Node(space, path, response_queue, stream),
|
|
|
|
_watch_handle(handle)
|
2018-03-31 16:50:49 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
_watch_handle.handler(this);
|
2018-03-31 16:50:49 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
~Watch_node() {
|
|
|
|
_watch_handle.close(); }
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************
|
|
|
|
** Vfs::Watch_response_handler interface **
|
|
|
|
*******************************************/
|
2018-03-31 16:50:49 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
void watch_response() override
|
2018-03-31 16:50:49 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
/* send a packet immediately otherwise defer */
|
|
|
|
if (!process_io() && !enqueued())
|
|
|
|
_response_queue.enqueue(*this);
|
2018-03-31 16:50:49 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
|
|
|
|
/********************************
|
|
|
|
** Vfs_server::Node interface **
|
|
|
|
********************************/
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
/**
|
2019-03-25 15:41:43 +01:00
|
|
|
* Called by global I/O progress handler
|
2018-03-31 16:50:49 +02:00
|
|
|
*/
|
2019-03-25 15:41:43 +01:00
|
|
|
bool process_io() override
|
|
|
|
{
|
|
|
|
if (!_stream.ready_to_ack()) return false;
|
|
|
|
|
|
|
|
Packet_descriptor packet(Packet_descriptor(),
|
|
|
|
Node_handle { id().value },
|
|
|
|
Packet_descriptor::CONTENT_CHANGED,
|
|
|
|
0, 0);
|
|
|
|
packet.succeeded(true);
|
|
|
|
_stream.acknowledge_packet(packet);
|
|
|
|
return true;
|
|
|
|
}
|
2018-03-31 16:50:49 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Vfs_server::Symlink : Io_node
|
2016-03-30 20:14:15 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
protected:
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/********************
|
|
|
|
** Node interface **
|
|
|
|
********************/
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
bool _read() override
|
|
|
|
{
|
|
|
|
if (_packet.position() != 0) {
|
|
|
|
/* partial read is not supported */
|
|
|
|
_ack_packet(0);
|
|
|
|
return true;
|
|
|
|
}
|
2017-07-12 17:05:38 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
file_size out_count = 0;
|
|
|
|
bool result = _vfs_read(_stream.packet_content(_packet),
|
|
|
|
_packet.length(), 0, out_count);
|
|
|
|
if (result)
|
|
|
|
_ack_packet(out_count);
|
|
|
|
return result;
|
2017-07-12 17:05:38 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
bool _write() override
|
|
|
|
{
|
|
|
|
if (_packet.position() != 0) {
|
|
|
|
/* partial write is not supported */
|
|
|
|
_ack_packet(0);
|
|
|
|
return true;
|
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
file_size count = _packet.length();
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/*
|
|
|
|
* if the symlink target is too long return a short result
|
|
|
|
* because a competent File_system client will error on a
|
|
|
|
* length mismatch
|
|
|
|
*/
|
|
|
|
if (count > MAX_PATH_LEN) {
|
|
|
|
_ack_packet(1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ensure symlink gets something null-terminated */
|
|
|
|
Genode::String<MAX_PATH_LEN+1> target(Genode::Cstring(
|
|
|
|
_stream.packet_content(_packet), count));
|
|
|
|
size_t const target_len = target.length()-1;
|
|
|
|
|
|
|
|
file_size out_count = 0;
|
|
|
|
bool result = _vfs_write(target.string(), target_len, 0, out_count);
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
_ack_packet(out_count);
|
|
|
|
if (out_count > 0) {
|
|
|
|
mark_as_updated();
|
|
|
|
notify_listeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Vfs_handle &_open(Vfs::File_system &vfs, Genode::Allocator &alloc,
|
|
|
|
char const *link_path, bool create)
|
|
|
|
{
|
|
|
|
Vfs_handle *h = nullptr;
|
|
|
|
assert_openlink(vfs.openlink(link_path, create, &h, alloc));
|
|
|
|
return *h;
|
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
Symlink(Node_space &space,
|
|
|
|
Vfs::File_system &vfs,
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
Node_queue &response_queue,
|
|
|
|
Packet_stream &stream,
|
|
|
|
char const *link_path,
|
|
|
|
Mode mode,
|
|
|
|
bool create)
|
|
|
|
: Io_node(space, link_path, mode, response_queue, stream,
|
|
|
|
_open(vfs, alloc, link_path, create))
|
|
|
|
{ }
|
2016-03-30 20:14:15 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
class Vfs_server::File : public Io_node
|
2016-03-30 20:14:15 +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
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
File(File const &);
|
|
|
|
File &operator = (File const &);
|
|
|
|
|
|
|
|
char const *_leaf_path = nullptr; /* offset pointer to Node::_path */
|
2017-02-12 10:58:27 +01:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
inline
|
|
|
|
seek_off_t seek_tail(file_size count)
|
2016-03-30 20:14:15 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
typedef Directory_service::Stat_result Result;
|
|
|
|
Vfs::Directory_service::Stat st;
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/* if stat fails, try and see if the VFS will seek to the end */
|
|
|
|
return (_handle.ds().stat(_leaf_path, st) == Result::STAT_OK)
|
|
|
|
? ((count < st.size) ? (st.size - count) : 0)
|
|
|
|
: (seek_off_t)SEEK_TAIL;
|
2016-03-30 20:14:15 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
protected:
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
bool _read() override
|
2016-03-30 20:14:15 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
file_size out_count = 0;
|
|
|
|
file_size count = _packet.length();
|
|
|
|
seek_off_t seek_offset = _packet.position();
|
|
|
|
|
|
|
|
if (seek_offset == (seek_off_t)SEEK_TAIL)
|
|
|
|
seek_offset = seek_tail(count);
|
|
|
|
|
|
|
|
bool result = _vfs_read(_stream.packet_content(_packet),
|
|
|
|
count, seek_offset, out_count);
|
|
|
|
if (result)
|
|
|
|
_ack_packet(out_count);
|
|
|
|
return result;
|
|
|
|
}
|
2016-04-26 16:28:07 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
bool _write() override
|
|
|
|
{
|
|
|
|
file_size out_count = 0;
|
|
|
|
file_size count = _packet.length();
|
|
|
|
seek_off_t seek_offset = _packet.position();
|
|
|
|
|
|
|
|
if (seek_offset == (seek_off_t)SEEK_TAIL)
|
|
|
|
seek_offset = seek_tail(count);
|
|
|
|
|
|
|
|
bool result = _vfs_write(_stream.packet_content(_packet),
|
|
|
|
count, seek_offset, out_count);
|
|
|
|
if (result) {
|
|
|
|
_ack_packet(out_count);
|
|
|
|
if (out_count > 0) {
|
|
|
|
mark_as_updated();
|
|
|
|
notify_listeners();
|
|
|
|
}
|
2016-04-26 16:28:07 +02:00
|
|
|
}
|
2019-03-25 15:41:43 +01:00
|
|
|
return result;
|
2016-03-30 20:14:15 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
static
|
|
|
|
Vfs_handle &_open(Vfs::File_system &vfs, Genode::Allocator &alloc,
|
|
|
|
char const *file_path, Mode fs_mode, bool create)
|
2016-03-30 20:14:15 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
Vfs_handle *h = nullptr;
|
|
|
|
unsigned vfs_mode = (fs_mode-1) |
|
|
|
|
(create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
|
2016-04-26 16:28:07 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
assert_open(vfs.open(file_path, vfs_mode, &h, alloc));
|
|
|
|
return *h;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2016-04-26 16:28:07 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
File(Node_space &space,
|
|
|
|
Vfs::File_system &vfs,
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
Node_queue &response_queue,
|
|
|
|
Packet_stream &stream,
|
|
|
|
char const *file_path,
|
|
|
|
Mode fs_mode,
|
|
|
|
bool create)
|
|
|
|
:
|
|
|
|
Io_node(space, file_path, fs_mode, response_queue, stream,
|
|
|
|
_open(vfs, alloc, file_path, fs_mode, create))
|
|
|
|
{
|
|
|
|
_leaf_path = vfs.leaf_path(path());
|
2016-03-30 20:14:15 +02:00
|
|
|
}
|
2017-02-01 21:07:14 +01:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
void truncate(file_size_t size)
|
2017-02-01 21:07:14 +01:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
assert_truncate(_handle.fs().ftruncate(&_handle, size));
|
2017-08-15 20:51:53 +02:00
|
|
|
mark_as_updated();
|
2017-02-01 21:07:14 +01:00
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-03-31 16:50:49 +02:00
|
|
|
struct Vfs_server::Directory : Io_node
|
2016-03-30 20:14:15 +02:00
|
|
|
{
|
2019-03-25 15:41:43 +01:00
|
|
|
protected:
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
/********************
|
|
|
|
** Node interface **
|
|
|
|
********************/
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
bool _read() override
|
|
|
|
{
|
|
|
|
if (_packet.length() < sizeof(Directory_entry)) {
|
|
|
|
_ack_packet(0);
|
|
|
|
return true;
|
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
seek_off_t const seek_offset = _packet.position();
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
size_t const blocksize = sizeof(::File_system::Directory_entry);
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
unsigned const index = (seek_offset / blocksize);
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
file_size out_count = 0;
|
2019-09-25 17:13:29 +02:00
|
|
|
|
|
|
|
Directory_service::Dirent vfs_dirent { };
|
|
|
|
|
|
|
|
bool const result = _vfs_read((char*)&vfs_dirent,
|
|
|
|
sizeof(vfs_dirent),
|
|
|
|
index * sizeof(vfs_dirent),
|
|
|
|
out_count);
|
|
|
|
vfs_dirent.sanitize();
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
if (result) {
|
|
|
|
if (out_count != sizeof(vfs_dirent)) {
|
|
|
|
_ack_packet(0);
|
|
|
|
return true;
|
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
auto fs_dirent_type = [&] (Vfs::Directory_service::Dirent_type type)
|
|
|
|
{
|
|
|
|
using From = Vfs::Directory_service::Dirent_type;
|
|
|
|
using To = ::File_system::Node_type;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This should never be taken because 'END' is checked as a
|
|
|
|
* precondition prior the call to of this function.
|
|
|
|
*/
|
|
|
|
To const default_result = To::CONTINUOUS_FILE;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case From::END: return default_result;
|
|
|
|
case From::DIRECTORY: return To::DIRECTORY;
|
|
|
|
case From::SYMLINK: return To::SYMLINK;
|
|
|
|
case From::CONTINUOUS_FILE: return To::CONTINUOUS_FILE;
|
|
|
|
case From::TRANSACTIONAL_FILE: return To::TRANSACTIONAL_FILE;
|
|
|
|
}
|
|
|
|
return default_result;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (vfs_dirent.type == Vfs::Directory_service::Dirent_type::END) {
|
2019-03-25 15:41:43 +01:00
|
|
|
_ack_packet(0);
|
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
} else {
|
2019-03-25 15:41:43 +01:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
::File_system::Directory_entry &fs_dirent =
|
|
|
|
*(Directory_entry *)_stream.packet_content(_packet);
|
2019-03-25 15:41:43 +01:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
fs_dirent = {
|
|
|
|
.inode = vfs_dirent.fileno,
|
|
|
|
.type = fs_dirent_type(vfs_dirent.type),
|
|
|
|
.rwx = {
|
|
|
|
.readable = vfs_dirent.rwx.readable,
|
|
|
|
.writeable = vfs_dirent.rwx.writeable,
|
|
|
|
.executable = vfs_dirent.rwx.executable },
|
|
|
|
.name = { vfs_dirent.name.buf }
|
|
|
|
};
|
|
|
|
|
|
|
|
_ack_packet(sizeof(Directory_entry));
|
|
|
|
}
|
2019-03-25 15:41:43 +01:00
|
|
|
return true;
|
2016-03-30 20:14:15 +02:00
|
|
|
}
|
2019-03-25 15:41:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool _write() override
|
|
|
|
{
|
|
|
|
_ack_packet(0);
|
|
|
|
return true;
|
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
static
|
|
|
|
Vfs_handle &_open(Vfs::File_system &vfs, Genode::Allocator &alloc,
|
|
|
|
char const *dir_path, bool create)
|
|
|
|
{
|
|
|
|
Vfs_handle *h = nullptr;
|
|
|
|
assert_opendir(vfs.opendir(dir_path, create, &h, alloc));
|
|
|
|
return *h;
|
2016-03-30 20:14:15 +02:00
|
|
|
}
|
2017-02-01 21:07:14 +01:00
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
Directory(Node_space &space,
|
|
|
|
Vfs::File_system &vfs,
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
Node_queue &response_queue,
|
|
|
|
Packet_stream &stream,
|
|
|
|
char const *dir_path,
|
|
|
|
bool create)
|
|
|
|
: Io_node(space, dir_path, READ_ONLY, response_queue, stream,
|
|
|
|
_open(vfs, alloc, dir_path, create))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open a file handle at this directory
|
|
|
|
*/
|
|
|
|
Node_space::Id file(Node_space &space,
|
|
|
|
Vfs::File_system &vfs,
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
char const *file_path,
|
|
|
|
Mode mode,
|
|
|
|
bool create)
|
|
|
|
{
|
|
|
|
Path subpath(file_path, path());
|
|
|
|
char const *path_str = subpath.base();
|
|
|
|
|
|
|
|
File *file;
|
|
|
|
try {
|
|
|
|
file = new (alloc) File(space, vfs, alloc,
|
|
|
|
_response_queue, _stream,
|
|
|
|
path_str, mode, create);
|
|
|
|
} catch (Out_of_memory) { throw Out_of_ram(); }
|
|
|
|
|
|
|
|
if (create)
|
|
|
|
mark_as_updated();
|
|
|
|
return file->id();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open a symlink handle at this directory
|
|
|
|
*/
|
|
|
|
Node_space::Id symlink(Node_space &space,
|
|
|
|
Vfs::File_system &vfs,
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
char const *link_path,
|
|
|
|
Mode mode,
|
|
|
|
bool create)
|
|
|
|
{
|
|
|
|
Path subpath(link_path, path());
|
|
|
|
char const *path_str = subpath.base();
|
|
|
|
|
|
|
|
Symlink *link;
|
|
|
|
try { link = new (alloc) Symlink(space, vfs, alloc,
|
|
|
|
_response_queue, _stream,
|
|
|
|
path_str, mode, create); }
|
|
|
|
catch (Out_of_memory) { throw Out_of_ram(); }
|
|
|
|
if (create)
|
|
|
|
mark_as_updated();
|
|
|
|
return link->id();
|
|
|
|
}
|
2016-03-30 20:14:15 +02:00
|
|
|
};
|
|
|
|
|
2016-05-25 22:11:09 +02:00
|
|
|
#endif /* _VFS__NODE_H_ */
|