2014-04-07 16:15:40 +02:00
|
|
|
/*
|
|
|
|
* \brief TAR file system
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2011-02-17
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2011-2017 Genode Labs GmbH
|
2014-04-07 16:15:40 +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.
|
2014-04-07 16:15:40 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _INCLUDE__VFS__TAR_FILE_SYSTEM_H_
|
|
|
|
#define _INCLUDE__VFS__TAR_FILE_SYSTEM_H_
|
|
|
|
|
|
|
|
#include <rom_session/connection.h>
|
|
|
|
#include <vfs/file_system.h>
|
|
|
|
#include <vfs/vfs_handle.h>
|
2016-05-25 15:47:22 +02:00
|
|
|
#include <base/attached_rom_dataspace.h>
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
namespace Vfs { class Tar_file_system; }
|
|
|
|
|
|
|
|
|
|
|
|
class Vfs::Tar_file_system : public File_system
|
|
|
|
{
|
2016-05-25 15:47:22 +02:00
|
|
|
Genode::Env &_env;
|
|
|
|
Genode::Allocator &_alloc;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
typedef Genode::String<64> Rom_name;
|
|
|
|
Rom_name _rom_name;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
Genode::Attached_rom_dataspace _tar_ds { _env, _rom_name.string() };
|
|
|
|
char *_tar_base = _tar_ds.local_addr<char>();
|
|
|
|
file_size const _tar_size = _tar_ds.size();
|
2014-04-07 16:15:40 +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
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
Tar_file_system(Tar_file_system const &);
|
|
|
|
Tar_file_system &operator = (Tar_file_system const &);
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
class Record
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
char _name[100];
|
|
|
|
char _mode[8];
|
|
|
|
char _uid[8];
|
|
|
|
char _gid[8];
|
|
|
|
char _size[12];
|
|
|
|
char _mtime[12];
|
|
|
|
char _checksum[8];
|
|
|
|
char _type[1];
|
|
|
|
char _linked_name[100];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert ASCII-encoded octal number to unsigned value
|
|
|
|
*/
|
|
|
|
template <typename T>
|
|
|
|
unsigned long _read(T const &field) const
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Copy-out ASCII string to temporary buffer that is
|
|
|
|
* large enough to host an additional zero.
|
|
|
|
*/
|
|
|
|
char buf[sizeof(field) + 1];
|
|
|
|
strncpy(buf, field, sizeof(buf));
|
|
|
|
|
|
|
|
unsigned long value = 0;
|
2015-11-05 20:37:08 +01:00
|
|
|
Genode::ascii_to_unsigned(buf, value, 8);
|
2014-04-07 16:15:40 +02:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2017-09-11 18:01:11 +02:00
|
|
|
char const *_data_begin() const { return (char const *)this + BLOCK_LEN; }
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GNU extension for long path names, which support unlimited sizes using
|
|
|
|
* separate records
|
|
|
|
*/
|
|
|
|
bool _long_name() const
|
|
|
|
{
|
|
|
|
return _type[0] == TYPE_LONG_LINK || _type[0] == TYPE_LONG_NAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Round up up next block
|
|
|
|
*/
|
|
|
|
file_size _block_align(file_size size) const {
|
|
|
|
return Genode::align_addr(size, BLOCK_SHIFT); }
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Next record header
|
|
|
|
*/
|
|
|
|
Record *_next() const {
|
|
|
|
return (Record *)(_data_begin() + _block_align(_read(_size))); }
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
public:
|
|
|
|
|
2017-09-11 18:01:11 +02:00
|
|
|
/* length of one data block in tar */
|
|
|
|
enum {
|
|
|
|
BLOCK_SHIFT = 9, /* 512 bytes */
|
|
|
|
BLOCK_LEN = 1ul << BLOCK_SHIFT,
|
|
|
|
};
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
/* record type values */
|
2017-09-11 18:01:11 +02:00
|
|
|
enum {
|
|
|
|
TYPE_FILE = 0, TYPE_HARDLINK = 1, TYPE_SYMLINK = 2, TYPE_DIR = 5,
|
|
|
|
/* GNU extensions */
|
|
|
|
TYPE_LONG_LINK = 75, TYPE_LONG_NAME = 76
|
|
|
|
};
|
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
file_size size() const { return _long_name() ? _next()->size() : _read(_size); }
|
|
|
|
long long mtime() const { return _long_name() ? _next()->mtime() : _read(_mtime); }
|
|
|
|
unsigned uid() const { return _long_name() ? _next()->uid() : _read(_uid); }
|
|
|
|
unsigned gid() const { return _long_name() ? _next()->gid() : _read(_gid); }
|
|
|
|
unsigned mode() const { return _long_name() ? _next()->mode() : _read(_mode); }
|
|
|
|
unsigned type() const { return _long_name() ? _next()->type() : _read(_type); }
|
|
|
|
void *data() const { return _long_name() ? _next()->data() : (void *)_data_begin(); }
|
|
|
|
|
|
|
|
Node_rwx rwx() const
|
|
|
|
{
|
|
|
|
unsigned const mode_bits = mode();
|
|
|
|
|
|
|
|
return { .readable = (mode_bits & 0400) != 0,
|
|
|
|
.writeable = (mode_bits & 0200) != 0,
|
|
|
|
.executable = (mode_bits & 0100) != 0 };
|
|
|
|
}
|
2017-09-11 18:01:11 +02:00
|
|
|
|
2018-10-09 13:56:38 +02:00
|
|
|
char const *name() const { return _long_name() ? _data_begin() : _name; }
|
|
|
|
unsigned max_name_len() const { return _long_name() ? MAX_PATH_LEN : 100; }
|
|
|
|
char const *linked_name() const { return _long_name() ? _data_begin() : _linked_name; }
|
2017-09-11 18:01:11 +02:00
|
|
|
|
|
|
|
file_size storage_size()
|
|
|
|
{
|
|
|
|
if (_long_name()) {
|
|
|
|
/* this size + next header + next size */
|
|
|
|
return _block_align(_read(_size)) + BLOCK_LEN + _block_align(_next()->size());
|
|
|
|
}
|
|
|
|
|
|
|
|
return _read(_size);
|
|
|
|
}
|
2014-04-07 16:15:40 +02:00
|
|
|
};
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
class Node;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
class Tar_vfs_handle : public Vfs_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
|
|
|
private:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
Tar_vfs_handle(Tar_vfs_handle const &);
|
|
|
|
Tar_vfs_handle &operator = (Tar_vfs_handle const &);
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
protected:
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Node const *_node;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Tar_vfs_handle(File_system &fs, Allocator &alloc, int status_flags,
|
|
|
|
Node const *node)
|
|
|
|
: Vfs_handle(fs, fs, alloc, status_flags), _node(node)
|
2014-04-07 16:15:40 +02:00
|
|
|
{ }
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
virtual Read_result read(char *dst, file_size count,
|
|
|
|
file_size &out_count) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Tar_vfs_file_handle : Tar_vfs_handle
|
|
|
|
{
|
|
|
|
using Tar_vfs_handle::Tar_vfs_handle;
|
|
|
|
|
|
|
|
Read_result read(char *dst, file_size count,
|
|
|
|
file_size &out_count) override
|
|
|
|
{
|
|
|
|
file_size const record_size = _node->record->size();
|
|
|
|
|
|
|
|
file_size const record_bytes_left = record_size >= seek()
|
|
|
|
? record_size - seek() : 0;
|
|
|
|
|
|
|
|
count = min(record_bytes_left, count);
|
|
|
|
|
|
|
|
char const *data = (char *)_node->record->data() + seek();
|
|
|
|
|
|
|
|
memcpy(dst, data, count);
|
|
|
|
|
|
|
|
out_count = count;
|
|
|
|
return READ_OK;
|
|
|
|
}
|
2014-04-07 16:15:40 +02:00
|
|
|
};
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
struct Tar_vfs_dir_handle : Tar_vfs_handle
|
|
|
|
{
|
|
|
|
using Tar_vfs_handle::Tar_vfs_handle;
|
|
|
|
|
|
|
|
Read_result read(char *dst, file_size count,
|
|
|
|
file_size &out_count) override
|
|
|
|
{
|
|
|
|
if (count < sizeof(Dirent))
|
|
|
|
return READ_ERR_INVALID;
|
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
Dirent &dirent = *(Dirent*)dst;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
file_offset const index = seek() / sizeof(Dirent);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
Node const *node_ptr = _node->lookup_child(index);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
if (!node_ptr) {
|
|
|
|
dirent = Dirent { };
|
|
|
|
out_count = 0;
|
2017-08-15 20:51:53 +02:00
|
|
|
return READ_OK;
|
2019-09-25 17:13:29 +02:00
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
Node const &node = *node_ptr;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
Record const *record_ptr = node.record;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
while (record_ptr && (record_ptr->type() == Record::TYPE_HARDLINK)) {
|
2017-08-15 20:51:53 +02:00
|
|
|
Tar_file_system &tar_fs = static_cast<Tar_file_system&>(fs());
|
2019-09-25 17:13:29 +02:00
|
|
|
Node const *target = tar_fs.dereference(record_ptr->linked_name());
|
|
|
|
record_ptr = target ? target->record : 0;
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
using Dirent_type = Vfs::Directory_service::Dirent_type;
|
|
|
|
|
|
|
|
/* if no record exists, assume it is a directory */
|
|
|
|
if (!record_ptr) {
|
|
|
|
dirent = {
|
|
|
|
.fileno = (Genode::addr_t)node_ptr,
|
|
|
|
.type = Dirent_type::DIRECTORY,
|
|
|
|
.rwx = Node_rwx::rx(),
|
|
|
|
.name = { node.name }
|
|
|
|
};
|
|
|
|
out_count = sizeof(Dirent);
|
|
|
|
return READ_OK;
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
Record const &record = *record_ptr;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
auto node_type = [&] ()
|
|
|
|
{
|
|
|
|
switch (record.type()) {
|
|
|
|
case Record::TYPE_FILE: return Dirent_type::CONTINUOUS_FILE;
|
|
|
|
case Record::TYPE_SYMLINK: return Dirent_type::SYMLINK;
|
|
|
|
case Record::TYPE_DIR: return Dirent_type::DIRECTORY;
|
|
|
|
};
|
|
|
|
|
|
|
|
Genode::warning("unhandled record type ", record.type(), " "
|
|
|
|
"for ", node.name);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
return Dirent_type::END;
|
|
|
|
};
|
|
|
|
|
|
|
|
dirent = {
|
|
|
|
.fileno = (Genode::addr_t)node_ptr,
|
|
|
|
.type = node_type(),
|
|
|
|
.rwx = { .readable = true,
|
|
|
|
.writeable = false,
|
|
|
|
.executable = record.rwx().executable },
|
|
|
|
.name = { node.name }
|
|
|
|
};
|
|
|
|
out_count = sizeof(Dirent);
|
2017-08-15 20:51:53 +02:00
|
|
|
return READ_OK;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Tar_vfs_symlink_handle : Tar_vfs_handle
|
|
|
|
{
|
|
|
|
using Tar_vfs_handle::Tar_vfs_handle;
|
|
|
|
|
|
|
|
Read_result read(char *buf, file_size buf_size,
|
|
|
|
file_size &out_count) override
|
|
|
|
{
|
|
|
|
Record const *record = _node->record;
|
|
|
|
|
|
|
|
file_size const count = min(buf_size, 100ULL);
|
|
|
|
|
|
|
|
memcpy(buf, record->linked_name(), count);
|
|
|
|
|
|
|
|
out_count = count;
|
|
|
|
|
|
|
|
return READ_OK;
|
|
|
|
}
|
|
|
|
};
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
struct Scanner_policy_path_element
|
|
|
|
{
|
|
|
|
static bool identifier_char(char c, unsigned /* i */)
|
|
|
|
{
|
|
|
|
return (c != '/') && (c != 0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef Genode::Token<Scanner_policy_path_element> Path_element_token;
|
|
|
|
|
|
|
|
|
|
|
|
struct Node : List<Node>, List<Node>::Element
|
|
|
|
{
|
|
|
|
char const *name;
|
|
|
|
Record const *record;
|
|
|
|
|
|
|
|
Node(char const *name, Record const *record) : name(name), record(record) { }
|
|
|
|
|
|
|
|
Node *lookup(char const *name)
|
|
|
|
{
|
|
|
|
Absolute_path lookup_path(name);
|
|
|
|
|
|
|
|
Node *parent_node = this;
|
|
|
|
Node *child_node;
|
|
|
|
|
|
|
|
Path_element_token t(lookup_path.base());
|
|
|
|
|
|
|
|
while (t) {
|
|
|
|
|
|
|
|
if (t.type() != Path_element_token::IDENT) {
|
|
|
|
t = t.next();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
char path_element[MAX_PATH_LEN];
|
|
|
|
|
|
|
|
t.string(path_element, sizeof(path_element));
|
|
|
|
|
|
|
|
for (child_node = parent_node->first(); child_node; child_node = child_node->next()) {
|
|
|
|
if (strcmp(child_node->name, path_element) == 0) {
|
|
|
|
parent_node = child_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!child_node)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
t = t.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
return parent_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-05 15:45:08 +01:00
|
|
|
Node const *lookup_child(int index) const
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
2016-01-05 15:45:08 +01:00
|
|
|
for (Node const *child_node = first(); child_node; child_node = child_node->next(), index--) {
|
2014-04-07 16:15:40 +02:00
|
|
|
if (index == 0)
|
|
|
|
return child_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-09 14:32:31 +02:00
|
|
|
file_size num_dirent()
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
2014-09-09 14:32:31 +02:00
|
|
|
file_size count = 0;
|
2014-04-07 16:15:40 +02:00
|
|
|
for (Node *child_node = first(); child_node; child_node = child_node->next(), count++) ;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
} _root_node;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a Node for a tar record and insert it into the node list
|
|
|
|
*/
|
|
|
|
class Add_node_action
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
Genode::Allocator &_alloc;
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
Node &_root_node;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
Add_node_action(Genode::Allocator &alloc,
|
|
|
|
Node &root_node)
|
|
|
|
: _alloc(alloc), _root_node(root_node) { }
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
void operator()(Record const *record)
|
|
|
|
{
|
2018-10-09 13:56:38 +02:00
|
|
|
Absolute_path current_path;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
char path_element[MAX_PATH_LEN];
|
|
|
|
|
2018-10-09 13:56:38 +02:00
|
|
|
if (record->max_name_len() > 100 || record->name()[99] == 0)
|
|
|
|
current_path.import(record->name());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GNU tar does not null terminate names of length 100
|
|
|
|
*/
|
|
|
|
else {
|
|
|
|
strncpy(path_element, record->name(), 101);
|
|
|
|
current_path.import(path_element);
|
|
|
|
}
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
Path_element_token t(current_path.base());
|
|
|
|
|
|
|
|
Node *parent_node = &_root_node;
|
|
|
|
Node *child_node;
|
|
|
|
|
|
|
|
while(t) {
|
|
|
|
|
|
|
|
if (t.type() != Path_element_token::IDENT) {
|
|
|
|
t = t.next();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Absolute_path remaining_path(t.start());
|
|
|
|
|
|
|
|
t.string(path_element, sizeof(path_element));
|
|
|
|
|
|
|
|
for (child_node = parent_node->first(); child_node; child_node = child_node->next()) {
|
|
|
|
if (strcmp(child_node->name, path_element) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (child_node) {
|
|
|
|
|
|
|
|
if (remaining_path.has_single_element()) {
|
|
|
|
/* Found a node for the record to be inserted.
|
|
|
|
* This is usually a directory node without
|
|
|
|
* record. */
|
|
|
|
child_node->record = record;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (remaining_path.has_single_element()) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: find 'path_element' in 'record->name'
|
|
|
|
* and use the location in the record as name
|
|
|
|
* pointer to save some memory
|
|
|
|
*/
|
2014-09-09 14:32:31 +02:00
|
|
|
Genode::size_t name_size = strlen(path_element) + 1;
|
2016-05-25 15:47:22 +02:00
|
|
|
char *name = (char*)_alloc.alloc(name_size);
|
2014-04-07 16:15:40 +02:00
|
|
|
strncpy(name, path_element, name_size);
|
2016-05-25 15:47:22 +02:00
|
|
|
child_node = new (_alloc) Node(name, record);
|
2014-04-07 16:15:40 +02:00
|
|
|
} else {
|
|
|
|
|
|
|
|
/* create a directory node without record */
|
2014-09-09 14:32:31 +02:00
|
|
|
Genode::size_t name_size = strlen(path_element) + 1;
|
2016-05-25 15:47:22 +02:00
|
|
|
char *name = (char*)_alloc.alloc(name_size);
|
2014-04-07 16:15:40 +02:00
|
|
|
strncpy(name, path_element, name_size);
|
2016-05-25 15:47:22 +02:00
|
|
|
child_node = new (_alloc) Node(name, 0);
|
2014-04-07 16:15:40 +02:00
|
|
|
}
|
|
|
|
parent_node->insert(child_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
parent_node = child_node;
|
|
|
|
t = t.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Tar_record_action>
|
|
|
|
void _for_each_tar_record_do(Tar_record_action tar_record_action)
|
|
|
|
{
|
|
|
|
/* measure size of archive in blocks */
|
|
|
|
unsigned block_id = 0, block_cnt = _tar_size/Record::BLOCK_LEN;
|
|
|
|
|
|
|
|
/* scan metablocks of archive */
|
|
|
|
while (block_id < block_cnt) {
|
|
|
|
|
|
|
|
Record *record = (Record *)(_tar_base + block_id*Record::BLOCK_LEN);
|
|
|
|
|
|
|
|
tar_record_action(record);
|
|
|
|
|
2017-09-11 18:01:11 +02:00
|
|
|
file_size size = record->storage_size();
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
/* some datablocks */ /* one metablock */
|
2014-09-09 14:32:31 +02:00
|
|
|
block_id = block_id + (size / Record::BLOCK_LEN) + 1;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
/* round up */
|
2014-09-09 14:32:31 +02:00
|
|
|
if (size % Record::BLOCK_LEN != 0) block_id++;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
/* check for end of tar archive */
|
|
|
|
if (block_id*Record::BLOCK_LEN >= _tar_size)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* lookout for empty eof-blocks */
|
|
|
|
if (*(_tar_base + (block_id*Record::BLOCK_LEN)) == 0x00)
|
|
|
|
if (*(_tar_base + (block_id*Record::BLOCK_LEN + 1)) == 0x00)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct Num_dirent_cache
|
|
|
|
{
|
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
|
|
|
Lock lock { };
|
2014-04-07 16:15:40 +02:00
|
|
|
Node &root_node;
|
|
|
|
bool valid; /* true after first lookup */
|
|
|
|
char key[256]; /* key used for lookup */
|
2014-09-09 14:32:31 +02:00
|
|
|
file_size cached_num_dirent; /* cached value */
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
Num_dirent_cache(Node &root_node)
|
|
|
|
: root_node(root_node), valid(false), cached_num_dirent(0) { }
|
|
|
|
|
2014-09-09 14:32:31 +02:00
|
|
|
file_size num_dirent(char const *path)
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
|
|
|
Lock::Guard guard(lock);
|
|
|
|
|
|
|
|
/* check for cache miss */
|
|
|
|
if (!valid || strcmp(path, key) != 0) {
|
|
|
|
Node *node = root_node.lookup(path);
|
|
|
|
if (!node)
|
|
|
|
return 0;
|
|
|
|
strncpy(key, path, sizeof(key));
|
|
|
|
cached_num_dirent = node->num_dirent();
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
return cached_num_dirent;
|
|
|
|
}
|
|
|
|
} _cached_num_dirent;
|
|
|
|
|
2015-07-24 16:15:34 +02:00
|
|
|
/**
|
|
|
|
* Walk hardlinks until we reach a file
|
|
|
|
*/
|
|
|
|
Node const *dereference(char const *path)
|
|
|
|
{
|
|
|
|
Node const *node = _root_node.lookup(path);
|
2017-12-12 04:06:41 +01:00
|
|
|
Node const *slow_node = node;
|
|
|
|
int i = 0;
|
|
|
|
while (node) {
|
|
|
|
Record const *record = node->record;
|
|
|
|
if (!record || record->type() != Record::TYPE_HARDLINK)
|
|
|
|
break; /* got it */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The `node` pointer is followed every iteration and
|
|
|
|
* `slow_node` every-other iteration. If there is a
|
|
|
|
* loop then eventually we catch it as the faster
|
|
|
|
* laps the slower.
|
|
|
|
*/
|
|
|
|
node = _root_node.lookup(record->linked_name());
|
|
|
|
if (i++ & 1) {
|
|
|
|
slow_node = _root_node.lookup(slow_node->record->linked_name());
|
|
|
|
if (node == slow_node) {
|
|
|
|
Genode::error(_rom_name, " contains a hard-link loop at '", path, "'");
|
|
|
|
node = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return node;
|
2015-07-24 16:15:34 +02:00
|
|
|
}
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
Tar_file_system(Vfs::Env &env, Genode::Xml_node config)
|
2014-04-07 16:15:40 +02:00
|
|
|
:
|
2018-04-03 15:59:35 +02:00
|
|
|
_env(env.env()), _alloc(env.alloc()),
|
2016-05-25 15:47:22 +02:00
|
|
|
_rom_name(config.attribute_value("name", Rom_name())),
|
2014-04-07 16:15:40 +02:00
|
|
|
_root_node("", 0),
|
|
|
|
_cached_num_dirent(_root_node)
|
|
|
|
{
|
2016-05-25 15:47:22 +02:00
|
|
|
Genode::log("tar archive '", _rom_name, "' "
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
"local at ", (void *)_tar_base, ", size is ", _tar_size);
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
_for_each_tar_record_do(Add_node_action(_alloc, _root_node));
|
2014-04-07 16:15:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************
|
|
|
|
** Directory-service interface **
|
|
|
|
*********************************/
|
|
|
|
|
|
|
|
Dataspace_capability dataspace(char const *path) override
|
|
|
|
{
|
2015-07-24 16:15:34 +02:00
|
|
|
Node const *node = dereference(path);
|
|
|
|
if (!node || !node->record)
|
|
|
|
return Dataspace_capability();
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2015-07-24 16:15:34 +02:00
|
|
|
Record const *record = node->record;
|
|
|
|
if (record->type() != Record::TYPE_FILE) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::error("TAR record \"", path, "\" has "
|
|
|
|
"unsupported type ", record->type());
|
2014-04-07 16:15:40 +02:00
|
|
|
return Dataspace_capability();
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
Ram_dataspace_capability ds_cap =
|
2016-05-25 15:47:22 +02:00
|
|
|
_env.ram().alloc(record->size());
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
void *local_addr = _env.rm().attach(ds_cap);
|
2014-04-07 16:15:40 +02:00
|
|
|
memcpy(local_addr, record->data(), record->size());
|
2016-05-25 15:47:22 +02:00
|
|
|
_env.rm().detach(local_addr);
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
return ds_cap;
|
|
|
|
}
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
catch (...) { Genode::warning(__func__, " could not create new dataspace"); }
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
return Dataspace_capability();
|
|
|
|
}
|
|
|
|
|
|
|
|
void release(char const *, Dataspace_capability ds_cap) override
|
|
|
|
{
|
2016-05-25 15:47:22 +02:00
|
|
|
_env.ram().free(static_cap_cast<Genode::Ram_dataspace>(ds_cap));
|
2014-04-07 16:15:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Stat_result stat(char const *path, Stat &out) override
|
|
|
|
{
|
2019-09-25 17:13:29 +02:00
|
|
|
out = Stat { };
|
2016-06-22 15:38:42 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
Node const *node_ptr = dereference(path);
|
|
|
|
if (!node_ptr)
|
2015-07-24 16:15:34 +02:00
|
|
|
return STAT_ERR_NO_ENTRY;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
if (!node_ptr->record) {
|
|
|
|
out.type = Node_type::DIRECTORY;
|
|
|
|
out.rwx = Node_rwx::rx();
|
2015-07-24 16:15:34 +02:00
|
|
|
return STAT_OK;
|
2014-04-07 16:15:40 +02:00
|
|
|
}
|
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
Record const &record = *node_ptr->record;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
auto node_type = [&] ()
|
|
|
|
{
|
|
|
|
switch (record.type()) {
|
|
|
|
case Record::TYPE_FILE: return Node_type::CONTINUOUS_FILE;
|
|
|
|
case Record::TYPE_SYMLINK: return Node_type::SYMLINK;
|
|
|
|
case Record::TYPE_DIR: return Node_type::DIRECTORY;
|
|
|
|
};
|
|
|
|
return Node_type::DIRECTORY;
|
|
|
|
};
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2019-09-25 17:13:29 +02:00
|
|
|
out = {
|
|
|
|
.size = record.size(),
|
|
|
|
.type = node_type(),
|
|
|
|
.rwx = { .readable = true,
|
|
|
|
.writeable = false,
|
|
|
|
.executable = record.rwx().executable },
|
|
|
|
.inode = (Genode::addr_t)node_ptr,
|
|
|
|
.device = (Genode::addr_t)this,
|
|
|
|
.modification_time = { record.mtime() }
|
|
|
|
};
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
return STAT_OK;
|
|
|
|
}
|
|
|
|
|
2016-04-29 16:01:55 +02:00
|
|
|
Unlink_result unlink(char const *path) override
|
|
|
|
{
|
|
|
|
Node const *node = dereference(path);
|
|
|
|
if (!node)
|
|
|
|
return UNLINK_ERR_NO_ENTRY;
|
|
|
|
else
|
|
|
|
return UNLINK_ERR_NO_PERM;
|
|
|
|
}
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2016-03-02 14:32:43 +01:00
|
|
|
Rename_result rename(char const *from, char const *to) override
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
2016-03-02 14:32:43 +01:00
|
|
|
if (_root_node.lookup(from) || _root_node.lookup(to))
|
|
|
|
return RENAME_ERR_NO_PERM;
|
|
|
|
return RENAME_ERR_NO_ENTRY;
|
2014-04-07 16:15:40 +02:00
|
|
|
}
|
|
|
|
|
2014-09-09 14:32:31 +02:00
|
|
|
file_size num_dirent(char const *path) override
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
|
|
|
return _cached_num_dirent.num_dirent(path);
|
|
|
|
}
|
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
bool directory(char const *path) override
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
2016-01-05 15:45:08 +01:00
|
|
|
Node const *node = dereference(path);
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
if (!node)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Record const *record = node->record;
|
|
|
|
|
|
|
|
return record ? (record->type() == Record::TYPE_DIR) : true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char const *leaf_path(char const *path) override
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Check if path exists within the file system. If this is the
|
|
|
|
* case, return the whole path, which is relative to the root
|
|
|
|
* of this file system.
|
|
|
|
*/
|
|
|
|
Node *node = _root_node.lookup(path);
|
|
|
|
return node ? path : 0;
|
|
|
|
}
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Open_result open(char const *path, unsigned, Vfs_handle **out_handle,
|
|
|
|
Genode::Allocator& alloc) override
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
2015-07-24 16:15:34 +02:00
|
|
|
Node const *node = dereference(path);
|
|
|
|
if (!node || !node->record || node->record->type() != Record::TYPE_FILE)
|
2014-04-07 16:15:40 +02:00
|
|
|
return OPEN_ERR_UNACCESSIBLE;
|
|
|
|
|
2018-01-12 20:47:48 +01:00
|
|
|
try {
|
|
|
|
*out_handle = new (alloc)
|
|
|
|
Tar_vfs_file_handle(*this, alloc, 0, node);
|
|
|
|
return OPEN_OK;
|
|
|
|
}
|
|
|
|
catch (Genode::Out_of_ram) { return OPEN_ERR_OUT_OF_RAM; }
|
|
|
|
catch (Genode::Out_of_caps) { return OPEN_ERR_OUT_OF_CAPS; }
|
2014-04-07 16:15:40 +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
|
|
|
Opendir_result opendir(char const *path, bool /* create */,
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs_handle **out_handle,
|
|
|
|
Genode::Allocator& alloc) override
|
|
|
|
{
|
|
|
|
Node const *node = dereference(path);
|
|
|
|
|
|
|
|
if (!node ||
|
|
|
|
(node->record && (node->record->type() != Record::TYPE_DIR)))
|
|
|
|
return OPENDIR_ERR_LOOKUP_FAILED;
|
|
|
|
|
2018-01-12 20:47:48 +01:00
|
|
|
try {
|
|
|
|
*out_handle = new (alloc)
|
|
|
|
Tar_vfs_dir_handle(*this, alloc, 0, node);
|
|
|
|
return OPENDIR_OK;
|
|
|
|
}
|
|
|
|
catch (Genode::Out_of_ram) { return OPENDIR_ERR_OUT_OF_RAM; }
|
|
|
|
catch (Genode::Out_of_caps) { return OPENDIR_ERR_OUT_OF_CAPS; }
|
2017-08-15 20:51:53 +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
|
|
|
Openlink_result openlink(char const *path, bool /* create */,
|
2019-02-14 22:39:08 +01:00
|
|
|
Vfs_handle **out_handle, Allocator &alloc) override
|
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
|
|
|
{
|
2017-08-15 20:51:53 +02:00
|
|
|
Node const *node = dereference(path);
|
|
|
|
if (!node || !node->record ||
|
|
|
|
node->record->type() != Record::TYPE_SYMLINK)
|
|
|
|
return OPENLINK_ERR_LOOKUP_FAILED;
|
|
|
|
|
2018-01-12 20:47:48 +01:00
|
|
|
try {
|
|
|
|
*out_handle = new (alloc)
|
|
|
|
Tar_vfs_symlink_handle(*this, alloc, 0, node);
|
|
|
|
return OPENLINK_OK;
|
|
|
|
}
|
|
|
|
catch (Genode::Out_of_ram) { return OPENLINK_ERR_OUT_OF_RAM; }
|
|
|
|
catch (Genode::Out_of_caps) { return OPENLINK_ERR_OUT_OF_CAPS; }
|
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
|
|
|
}
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2016-03-30 15:24:19 +02:00
|
|
|
void close(Vfs_handle *vfs_handle) override
|
|
|
|
{
|
|
|
|
Tar_vfs_handle *tar_handle =
|
|
|
|
static_cast<Tar_vfs_handle *>(vfs_handle);
|
|
|
|
|
|
|
|
if (tar_handle)
|
|
|
|
destroy(vfs_handle->alloc(), tar_handle);
|
|
|
|
}
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
/***************************
|
|
|
|
** File_system interface **
|
|
|
|
***************************/
|
|
|
|
|
2017-02-07 19:03:23 +01:00
|
|
|
static char const *name() { return "tar"; }
|
|
|
|
char const *type() override { return "tar"; }
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
|
|
|
|
/********************************
|
|
|
|
** File I/O service interface **
|
|
|
|
********************************/
|
|
|
|
|
2014-09-09 14:32:31 +02:00
|
|
|
Write_result write(Vfs_handle *, char const *, file_size,
|
|
|
|
file_size &) override
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
|
|
|
return WRITE_ERR_INVALID;
|
|
|
|
}
|
|
|
|
|
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
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
2017-08-15 20:51:53 +02:00
|
|
|
out_count = 0;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Tar_vfs_handle *handle = static_cast<Tar_vfs_handle *>(vfs_handle);
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
if (!handle)
|
|
|
|
return READ_ERR_INVALID;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
return handle->read(dst, count, out_count);
|
2014-04-07 16:15:40 +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
|
|
|
Ftruncate_result ftruncate(Vfs_handle *, file_size) override
|
2014-04-07 16:15:40 +02:00
|
|
|
{
|
|
|
|
return FTRUNCATE_ERR_NO_PERM;
|
|
|
|
}
|
2017-02-01 11:28:15 +01:00
|
|
|
|
|
|
|
bool read_ready(Vfs_handle *) override { return true; }
|
2014-04-07 16:15:40 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* _INCLUDE__VFS__TAR_FILE_SYSTEM_H_ */
|