/* * \brief Rom-session server for ISO file systems * \author Sebastian Sumpf * \date 2010-07-26 */ /* * Copyright (C) 2010-2017 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 #include #include #include #include #include #include #include #include #include #include /* local includes */ #include "iso9660.h" using namespace Genode; /***************** ** ROM service ** *****************/ namespace Iso { typedef Avl_string File_base; typedef Avl_tree File_cache; class File; class Rom_component; typedef Genode::Root_component Root_component; class Root; } /** * File abstraction */ class Iso::File : public File_base { private: /* * Noncopyable */ File(File const &); File &operator = (File const &); Genode::Allocator &_alloc; File_info *_info; Attached_ram_dataspace _ds; public: File(Genode::Env &env, Genode::Allocator &alloc, Block::Connection<> &block, char const *path) : File_base(path), _alloc(alloc), _info(Iso::file_info(_alloc, block, path)), _ds(env.ram(), env.rm(), align_addr(_info->page_sized(), 12)) { Iso::read_file(block, _info, 0, _ds.size(), _ds.local_addr()); } ~File() { destroy(_alloc, _info); } Dataspace_capability dataspace() { return _ds.cap(); } }; class Iso::Rom_component : public Genode::Rpc_object { private: /* * Noncopyable */ Rom_component(Rom_component const &); Rom_component &operator = (Rom_component const &); File *_file = nullptr; File *_lookup(File_cache &cache, char const *path) { return static_cast(cache.first() ? cache.first()->find_by_name(path) : 0); } public: Rom_dataspace_capability dataspace() override { return static_cap_cast(_file->dataspace()); } void sigh(Signal_context_capability) override { } Rom_component(Genode::Env &env, Genode::Allocator &alloc, File_cache &cache, Block::Connection<> &block, char const *path) { if ((_file = _lookup(cache, path))) { Genode::log("cache hit for file ", Genode::Cstring(path)); return; } _file = new (alloc) File(env, alloc, block, path); Genode::log("request for file ", Genode::Cstring(path)); cache.insert(_file); } }; class Iso::Root : public Iso::Root_component { private: Genode::Env &_env; Genode::Allocator &_alloc; Allocator_avl _block_alloc { &_alloc }; Block::Connection<> _block { _env, &_block_alloc }; /* * Entries in the cache are never freed, even if the ROM session * gets destroyed. */ File_cache _cache { }; char _path[PATH_LENGTH]; protected: Rom_component *_create_session(const char *args) override { size_t ram_quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0); size_t session_size = sizeof(Rom_component) + sizeof(File_info); if (ram_quota < session_size) throw Insufficient_ram_quota(); Session_label const label = label_from_args(args); copy_cstring(_path, label.last_element().string(), sizeof(_path)); if (verbose) Genode::log("Request for file ", Cstring(_path), " len ", strlen(_path)); try { return new (_alloc) Rom_component(_env, _alloc, _cache, _block, _path); } catch (Io_error) { throw Service_denied(); } catch (Non_data_disc) { throw Service_denied(); } catch (File_not_found) { throw Service_denied(); } } public: Root(Genode::Env &env, Allocator &alloc) : Root_component(&env.ep().rpc_ep(), &alloc), _env(env), _alloc(alloc) { } }; struct Main { Genode::Env &_env; Genode::Heap _heap { _env.ram(), _env.rm() }; Iso::Root _root { _env, _heap }; Main(Genode::Env &env) : _env(env) { _env.parent().announce(_env.ep().manage(_root)); } }; void Component::construct(Genode::Env &env) { static Main main(env); }