genode/repos/os/src/lib/vfs/file_system_factory.cc

235 lines
6.2 KiB
C++
Raw Normal View History

/*
* \brief File-system factory implementation
* \author Norman Feske
* \date 2014-04-09
*/
/*
* Copyright (C) 2014-2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <vfs/file_system_factory.h>
#include <base/shared_object.h>
/* supported builtin file systems */
#include "block_file_system.h"
#include "fs_file_system.h"
#include "inline_file_system.h"
#include "log_file_system.h"
#include "null_file_system.h"
#include "ram_file_system.h"
#include "rom_file_system.h"
#include "rtc_file_system.h"
#include "symlink_file_system.h"
#include "tar_file_system.h"
#include "terminal_file_system.h"
#include "zero_file_system.h"
namespace Vfs {
using Vfs::Io_response_handler;
template <typename> struct Builtin_entry;
struct External_entry;
}
using Fs_type_name = Vfs::Global_file_system_factory::Fs_type_name;
using Node_name = Vfs::Global_file_system_factory::Node_name;
using Library_name = Vfs::Global_file_system_factory::Library_name;
struct Vfs::Global_file_system_factory::Entry_base : Vfs::File_system_factory,
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 Genode::List<Entry_base>::Element
{
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
friend class Genode::List<Entry_base>;
using Genode::List<Entry_base>::Element::next;
Fs_type_name name;
Entry_base(Fs_type_name const &name) : name(name) { }
bool matches(Genode::Xml_node node) const {
return node.has_type(name.string()); }
};
template <typename FILE_SYSTEM>
struct Vfs::Builtin_entry : Vfs::Global_file_system_factory::Entry_base
{
Builtin_entry() : Entry_base(FILE_SYSTEM::name()) { }
Vfs::File_system *create(Vfs::Env &env, Genode::Xml_node node) override {
return new (env.alloc()) FILE_SYSTEM(env, node); }
};
struct Vfs::External_entry : Vfs::Global_file_system_factory::Entry_base
{
File_system_factory &_fs_factory;
External_entry(Fs_type_name const &name,
File_system_factory &fs_factory)
:
Entry_base(name), _fs_factory(fs_factory) { }
File_system *create(Vfs::Env &env,
Genode::Xml_node config) override
{
return _fs_factory.create(env, config);
}
};
/**
* Add builtin File_system type
*/
template <typename FILE_SYSTEM>
void Vfs::Global_file_system_factory::_add_builtin_fs()
{
_list.insert(new (&_md_alloc) Builtin_entry<FILE_SYSTEM>());
}
/**
* Lookup and create File_system instance
*/
Vfs::File_system*
Vfs::Global_file_system_factory::_try_create(Vfs::Env &env,
Genode::Xml_node config)
{
for (Entry_base *e = _list.first(); e; e = e->next())
if (e->matches(config)) return e->create(env, config);
return nullptr;
}
/**
* Return matching library name for a given vfs node name
*/
Library_name Vfs::Global_file_system_factory::_library_name(Node_name const &node_name)
{
char lib_name [Library_name::capacity()];
Genode::snprintf(lib_name, sizeof(lib_name), "vfs_%s.lib.so",
node_name.string());
return Library_name(lib_name);
}
/**
* \throw Factory_not_available
*/
Vfs::File_system_factory &Vfs::Global_file_system_factory::_load_factory(Vfs::Env &env,
Library_name const &lib_name)
{
Genode::Shared_object *shared_object = nullptr;
try {
shared_object = new (env.alloc())
Genode::Shared_object(env.env(), env.alloc(), lib_name.string(),
Genode::Shared_object::BIND_LAZY,
Genode::Shared_object::DONT_KEEP);
typedef Vfs::File_system_factory *(*Query_fn)();
Query_fn query_fn = shared_object->lookup<Query_fn>(_factory_symbol());
return *query_fn();
} catch (Genode::Shared_object::Invalid_rom_module) {
Genode::warning("could not open '", lib_name, "'");
throw Factory_not_available();
} catch (Genode::Shared_object::Invalid_symbol) {
Genode::warning("could not find symbol '",
Genode::Cstring(_factory_symbol()),
"' in '", lib_name, "'");
Genode::destroy(env.alloc(), shared_object);
throw Factory_not_available();
}
}
/**
* Try to load external File_system_factory provider
*/
bool Vfs::Global_file_system_factory::_probe_external_factory(Vfs::Env &env,
Genode::Xml_node node)
{
Library_name const lib_name = _library_name(node.type());
try {
_list.insert(new (env.alloc())
External_entry(node.type().string(), _load_factory(env, lib_name)));
return true;
} catch (Factory_not_available) { return false; }
}
/**
* Create and return a new file-system
*/
Vfs::File_system *Vfs::Global_file_system_factory::create(Vfs::Env &env,
Genode::Xml_node node)
{
try {
/* try if type is handled by the currently registered fs types */
if (Vfs::File_system *fs = _try_create(env, node))
return fs;
/* if the builtin fails, do not try loading an external */
} catch (...) { return nullptr; }
try {
/* probe for file system implementation available as shared lib */
if (_probe_external_factory(env, node)) {
/* try again with the new file system type loaded */
if (Vfs::File_system *fs = _try_create(env, node))
return fs;
}
} catch (...) { }
return nullptr;
}
/**
* Register an additional factory for new file-system type
*/
void Vfs::Global_file_system_factory::extend(char const *name, File_system_factory &factory)
{
_list.insert(new (&_md_alloc)
External_entry(name, factory));
}
/**
* Constructor
*/
Vfs::Global_file_system_factory::Global_file_system_factory(Genode::Allocator &alloc)
:
_md_alloc(alloc)
{
_add_builtin_fs<Vfs::Tar_file_system>();
_add_builtin_fs<Vfs::Fs_file_system>();
_add_builtin_fs<Vfs::Terminal_file_system::Compound_file_system>();
_add_builtin_fs<Vfs::Null_file_system>();
_add_builtin_fs<Vfs::Zero_file_system>();
_add_builtin_fs<Vfs::Block_file_system>();
_add_builtin_fs<Vfs::Log_file_system>();
_add_builtin_fs<Vfs::Rom_file_system>();
_add_builtin_fs<Vfs::Inline_file_system>();
_add_builtin_fs<Vfs::Rtc_file_system>();
_add_builtin_fs<Vfs::Ram_file_system>();
_add_builtin_fs<Vfs::Symlink_file_system>();
}