diff --git a/repos/os/src/server/iso9660/backing_store.h b/repos/os/src/server/iso9660/backing_store.h deleted file mode 100644 index a25e37b1f5..0000000000 --- a/repos/os/src/server/iso9660/backing_store.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * \brief Backing store for on-demand-paged managed dataspaces - * \author Norman Feske - * \date 2010-10-31 - */ - -/* - * Copyright (C) 2010-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _BACKING_STORE_H_ -#define _BACKING_STORE_H_ - -#include - -/** - * Fifo-based physical backing-store allocator - * - * \param UMD user-specific metadata attached to each backing-store block, - * for example the corresponding offset within a managed - * dataspace - */ -template -class Backing_store -{ - public: - - /** - * Interface to be implemented by the user of the backing store - */ - struct User - { - virtual void detach_block(UMD umd) - { - Genode::warning(__func__, " this should never be called"); - } - }; - - /** - * Pseudo user for marking a block as used during the - * time between the allocation and the assignment to the - * actual user - */ - User _not_yet_assigned; - - /** - * Meta data of a backing-store block - */ - class Block - { - private: - - friend class Backing_store; - - /** - * User of the block, 0 if block is unused - */ - User *_user; - - /** - * User-specific meta data. It is not used by the - * 'Backing_store', just handed back to the user with the - * 'detach_block' function. - */ - UMD _user_meta_data; - - /** - * Default constructor used for array allocation - */ - Block() : _user(0) { } - - /** - * Used by 'Backing_store::assign' - */ - void assign_user(User *user, UMD user_meta_data) { - _user = user, _user_meta_data = user_meta_data; } - - /** - * Used by 'Backing_store::alloc' - */ - void assign_pseudo_user(User *user) { _user = user; } - - /** - * Return true if block is in use - */ - bool occupied() const { return _user != 0; } - - /** - * Return user of the block - */ - const User *user() const { return _user; } - - /** - * Evict block, preparing to for reuse - */ - void evict() - { - if (_user) - _user->detach_block(_user_meta_data); - _user = 0; - } - }; - - private: - - /** - * Lock for synchronizing the block allocator - */ - Genode::Lock _alloc_lock; - - const Genode::size_t _block_size; - - /** - * Number of physical blocks - */ - const Genode::size_t _num_blocks; - - /** - * RAM dataspace holding the physical backing store - */ - const Genode::Dataspace_capability _ds; - - /** - * Local address of physical backing store - */ - const void *_ds_addr; - - /** - * Array of block meta data - */ - Block *_blocks; - - /** - * Block index for next allocation (used for fifo) - */ - unsigned long _curr_block_idx; - - /** - * Return meta data of next-to-be-allocated block - */ - Block *_curr_block() const { return &_blocks[_curr_block_idx]; } - - /** - * Advance fifo allocation index - */ - void _advance_curr_block() - { - _curr_block_idx++; - if (_curr_block_idx == _num_blocks) - _curr_block_idx = 0; - } - - /** - * Calculate number of blocks that fit into specified amount of RAM, - * taking the costs for meta data into account - */ - Genode::size_t _calc_num_blocks(Genode::size_t ram_size) const - { - return ram_size / (sizeof(Block) + _block_size); - } - - public: - - /** - * Constructor - * - * \param ram_size number of bytes of physical RAM to be used as - * backing store for both the meta data and the - * payload - */ - Backing_store(Genode::size_t ram_size, Genode::size_t block_size) - : - _block_size(block_size), - _num_blocks(_calc_num_blocks(ram_size)), - _ds(Genode::env()->ram_session()->alloc(_block_size*_num_blocks)), - _ds_addr(Genode::env()->rm_session()->attach(_ds)), - _blocks(new (Genode::env()->heap()) Block[_num_blocks]), - _curr_block_idx(0) - { } - - Block *alloc() - { - Genode::Lock::Guard guard(_alloc_lock); - - /* skip blocks that are currently in the process of being assigned */ - while (_curr_block()->user() == &_not_yet_assigned) { - _advance_curr_block(); - } - - /* evict block if needed */ - if (_curr_block()->occupied()) - _curr_block()->evict(); - - /* reserve allocated block (prevent eviction prior assignment) */ - Block *block = _curr_block(); - block->assign_pseudo_user(&_not_yet_assigned); - - _advance_curr_block(); - return block; - } - - /** - * Return dataspace containing the backing store payload - */ - Genode::Dataspace_capability dataspace() const { return _ds; } - - /** - * Return block size used by the backing store - */ - Genode::size_t block_size() const { return _block_size; } - - /** - * Return block index of specified block - */ - Genode::off_t index(const Block *b) const { return b - _blocks; } - - /** - * Return offset of block within physical backing store - */ - Genode::off_t offset(const Block *b) const { - return index(b)*_block_size; } - - /** - * Return local address of physical backing-store block - */ - void *local_addr(const Block *b) const { - return (void *)((Genode::addr_t)_ds_addr + offset(b)); } - - /** - * Assign final user of a block - * - * After calling this function, the block will be subjected to - * eviction, if needed. - */ - void assign(Block *block, User *user, UMD user_meta_data) - { - Genode::Lock::Guard guard(_alloc_lock); - block->assign_user(user, user_meta_data); - } - - /** - * Evict all blocks currently in use by the specified user - */ - void flush(const User *user) - { - Genode::Lock::Guard guard(_alloc_lock); - for (unsigned i = 0; i < _num_blocks; i++) - if (_blocks[i].user() == user) - _blocks[i].evict(); - } -}; - -#endif /* _BACKING_STORE_H_ */ diff --git a/repos/os/src/server/iso9660/iso9660.cc b/repos/os/src/server/iso9660/iso9660.cc index 116e131991..7ba8f31ba8 100644 --- a/repos/os/src/server/iso9660/iso9660.cc +++ b/repos/os/src/server/iso9660/iso9660.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2010-2013 Genode Labs GmbH + * 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 General Public License version 2. @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -25,367 +24,361 @@ using namespace Genode; namespace Iso { - - /* - * Sector reads one or more packets from the block interface - */ - class Sector { - - public: - - enum { - MAX_SECTORS = 32, /* max. number sectors that can be read in one - transaction */ - }; - - static Block::Connection *_blk; - static Block::Session::Tx::Source *_source; - static size_t _blk_size; - static Lock _lock; - - private: - - Block::Packet_descriptor _p; - - public: - - Sector(unsigned long blk_nr, unsigned long count) - { - Lock::Guard lock_guard(_lock); - - try { - _p = Block::Packet_descriptor( - _blk->dma_alloc_packet(blk_size() * count), - Block::Packet_descriptor::READ, - blk_nr * ((float)blk_size() / _blk_size), - count * ((float)blk_size() / _blk_size)); - _source->submit_packet(_p); - _p = _source->get_acked_packet(); - - if (!_p.succeeded()) { - Genode::error("Could not read block ", blk_nr); - throw Io_error(); - } - - } catch (Block::Session::Tx::Source::Packet_alloc_failed) { - Genode::error("packet overrun!"); - _p = _source->get_acked_packet(); - throw Io_error(); - } - } - - ~Sector() { - Lock::Guard lock_guard(_lock); - _source->release_packet(_p); - } - - /** - * Return address of packet content - */ - template - T addr() { return reinterpret_cast(_source->packet_content(_p)); } - - static size_t blk_size() { return 2048; } - - static unsigned long to_blk(unsigned long bytes) { - return ((bytes + blk_size() - 1) & ~(blk_size() - 1)) / blk_size(); } - }; - - /** - * Rock ridge extension (see IEEE P1282) - */ - class Rock_ridge - { - public: - - enum { - NM = 0x4d4e, /* POSIX name system use entry (little endian) */ - }; - - private: - - uint16_t _signature; - uint8_t _length; - uint8_t _version; - uint8_t _flags; - char _name; - - public: - - char *name() { return &_name; } - uint8_t length() { return _length - 5; } - - static Rock_ridge* scan_name(uint8_t *ptr, uint8_t size) - { - Rock_ridge *rr = (Rock_ridge *)ptr; - - while (rr->_length && ((uint8_t *)rr < ptr + size - 4)) { - if (rr->_signature == NM) - return rr; - rr = rr->next(); - } - - return 0; - } - - Rock_ridge *next() { return (Rock_ridge *)((uint8_t *)this + _length); } - }; + class Sector; + class Rock_ridge; + class Iso_base; +} - /********************* - ** ISO9660 classes ** - *********************/ +/* + * Sector reads one or more packets from the block interface + */ +class Iso::Sector { - /** - * Access memory using offsets - */ - class Iso_base - { - protected: + public: - template - T value(int offset) { return *((T *)(this + offset)); } - - template - T ptr(int offset) { return (T)(this + offset); } - }; - - - /** - * Class representing a directory descriptions (see ECMA 119) - */ - class Directory_record : public Iso_base - { enum { - TABLE_LENGTH = 33, /* fixed length of directory record */ - - ROOT_DIR = 0x0, /* special names of root and parent directories */ - PARENT_DIR = 0x1, - - DIR_FLAG = 0x2, /* directory flag in attributes */ + MAX_SECTORS = 32, /* max. number sectors that can be read in one + transaction */ + BLOCK_SIZE = 2048, }; - public: + static Lock _lock; - /* total length of this record */ - uint8_t record_length() { return value(0); } + private: - /* starting block of extent */ - uint32_t blk_nr() { return value(2); } + Block::Session::Tx::Source &_source; + Block::Packet_descriptor _p; - /* length in bytes of extent */ - uint32_t data_length() { return value(10); } + public: - /* attributes */ - uint8_t file_flags() { return value(25); } + Sector(Block::Connection &block, + unsigned long blk_nr, unsigned long count) + : _source(*block.tx()) + { + // Lock::Guard lock_guard(_lock); - /* length of file name */ - uint8_t file_name_length() { return value(32); } + try { + _p = Block::Packet_descriptor( + block.dma_alloc_packet(blk_size() * count), + Block::Packet_descriptor::READ, + blk_nr * ((float)blk_size() / BLOCK_SIZE), + count * ((float)blk_size() / BLOCK_SIZE)); - /* retrieve the file name */ - void file_name(char *buf) - { - buf[0] = 0; + _source.submit_packet(_p); + _p = _source.get_acked_packet(); - /* try Rock Ridge name */ - Rock_ridge *rr = Rock_ridge::scan_name(system_use(), - system_use_size()); + if (!_p.succeeded()) { + Genode::error("Could not read block ", blk_nr); + throw Io_error(); + } - if (rr) { - memcpy(buf, rr->name(), rr->length()); - buf[rr->length()] = 0; + } catch (Block::Session::Tx::Source::Packet_alloc_failed) { + Genode::error("packet overrun!"); + _p = _source.get_acked_packet(); + throw Io_error(); + } + } + + ~Sector() { + // Lock::Guard lock_guard(_lock); + _source.release_packet(_p); + } + + /** + * Return address of packet content + */ + template + T addr() { return reinterpret_cast(_source.packet_content(_p)); } + + static size_t blk_size() { return BLOCK_SIZE; } + + static unsigned long to_blk(unsigned long bytes) { + return ((bytes + blk_size() - 1) & ~(blk_size() - 1)) / blk_size(); } +}; + + +/* + * Static members of Sector + */ +Lock Iso::Sector::_lock; + + +/** + * Rock ridge extension (see IEEE P1282) + */ +class Iso::Rock_ridge +{ + public: + + enum { + NM = 0x4d4e, /* POSIX name system use entry (little endian) */ + }; + + private: + + uint16_t _signature; + uint8_t _length; + uint8_t _version; + uint8_t _flags; + char _name; + + public: + + char *name() { return &_name; } + uint8_t length() { return _length - 5; } + + static Rock_ridge* scan_name(uint8_t *ptr, uint8_t size) + { + Rock_ridge *rr = (Rock_ridge *)ptr; + + while (rr->_length && ((uint8_t *)rr < ptr + size - 4)) { + if (rr->_signature == NM) + return rr; + rr = rr->next(); + } + + return 0; + } + + Rock_ridge *next() { return (Rock_ridge *)((uint8_t *)this + _length); } +}; + + +/********************* + ** ISO9660 classes ** + *********************/ + +/** + * Access memory using offsets + */ +class Iso::Iso_base +{ + protected: + + template + T value(int offset) { return *((T *)(this + offset)); } + + template + T ptr(int offset) { return (T)(this + offset); } +}; + + +/** + * Class representing a directory descriptions (see ECMA 119) + */ +class Directory_record : public Iso::Iso_base +{ + enum { + TABLE_LENGTH = 33, /* fixed length of directory record */ + + ROOT_DIR = 0x0, /* special names of root and parent directories */ + PARENT_DIR = 0x1, + + DIR_FLAG = 0x2, /* directory flag in attributes */ + }; + + public: + + /* total length of this record */ + uint8_t record_length() { return value(0); } + + /* starting block of extent */ + uint32_t blk_nr() { return value(2); } + + /* length in bytes of extent */ + uint32_t data_length() { return value(10); } + + /* attributes */ + uint8_t file_flags() { return value(25); } + + /* length of file name */ + uint8_t file_name_length() { return value(32); } + + /* retrieve the file name */ + void file_name(char *buf) + { + buf[0] = 0; + + /* try Rock Ridge name */ + Iso::Rock_ridge *rr = Iso::Rock_ridge::scan_name(system_use(), + system_use_size()); + + if (rr) { + memcpy(buf, rr->name(), rr->length()); + buf[rr->length()] = 0; + return; + } + + /* retrieve iso name */ + char *name = ptr(33); + + /* + * Check for root and parent directory names and modify them + * to '.' and '..' respectively. + */ + if (file_name_length() == 1) + + switch (name[0]) { + + case PARENT_DIR: + + buf[2] = 0; + buf[1] = '.'; + buf[0] = '.'; + return; + + case ROOT_DIR: + + buf[1] = 0; + buf[0] = '.'; return; } - /* retrieve iso name */ - char *name = ptr(33); + memcpy(buf, name, file_name_length()); + buf[file_name_length()] = 0; + } - /* - * Check for root and parent directory names and modify them - * to '.' and '..' respectively. - */ - if (file_name_length() == 1) + /* pad byte after file name (if file name length is even, only) */ + uint8_t pad_byte() { return !(file_name_length() % 2) ? 1 : 0; } - switch (name[0]) { + /* system use area */ + uint8_t *system_use() + { + return (uint8_t*)this + TABLE_LENGTH + + file_name_length() + pad_byte(); + } - case PARENT_DIR: + /* length in bytes of system use area */ + uint8_t system_use_size() + { + return record_length() - file_name_length() + - TABLE_LENGTH - pad_byte(); + } - buf[2] = 0; - buf[1] = '.'; - buf[0] = '.'; - return; + /* retrieve next record */ + Directory_record *next() + { + Directory_record *_next = this + record_length(); - case ROOT_DIR: + if (_next->record_length()) + return _next; - buf[1] = 0; - buf[0] = '.'; - return; - } + return 0; + } - memcpy(buf, name, file_name_length()); - buf[file_name_length()] = 0; + /* find a directory record with file name matching 'level' */ + Directory_record *locate(char const *level) + { + Directory_record *dir = this; + + while (dir) { + + char name[Iso::LEVEL_LENGTH]; + dir->file_name(name); + + if (!strcmp(name, level)) + return dir; + + dir = dir->next(); } - /* pad byte after file name (if file name length is even, only) */ - uint8_t pad_byte() { return !(file_name_length() % 2) ? 1 : 0; } + return 0; + } - /* system use area */ - uint8_t *system_use() - { - return (uint8_t*)this + TABLE_LENGTH - + file_name_length() + pad_byte(); - } + /* describes this record a directory */ + bool directory() { return file_flags() & DIR_FLAG; } +}; - /* length in bytes of system use area */ - uint8_t system_use_size() - { - return record_length() - file_name_length() - - TABLE_LENGTH - pad_byte(); - } - /* retrieve next record */ - Directory_record *next() - { - Directory_record *_next = this + record_length(); +/** + * Volume descriptor (see ECMA 119) + */ +class Volume_descriptor : public Iso::Iso_base +{ + enum { + /* volume types */ + PRIMARY = 0x01, /* type of primary volume descriptor */ + TERMINATOR = 0xff, /* type of terminating descriptor */ - if (_next->record_length()) - return _next; - - return 0; - } - - /* find a directory record with file name matching 'level' */ - Directory_record *locate(char *level) - { - Directory_record *dir = this; - - while (dir) { - - char name[LEVEL_LENGTH]; - dir->file_name(name); - - if (!strcmp(name, level)) - return dir; - - dir = dir->next(); - } - - return 0; - } - - /* describes this record a directory */ - bool directory() { return file_flags() & DIR_FLAG; } + /* constants */ + ROOT_SIZE = 34, /* the root directory record has a fixed length */ }; + public: - /** - * Volume descriptor (see ECMA 119) - */ - class Volume_descriptor : public Iso_base - { - enum { - /* volume types */ - PRIMARY = 0x01, /* type of primary volume descriptor */ - TERMINATOR = 0xff, /* type of terminating descriptor */ + /* descriptor type */ + uint8_t type() { return value(0); } - /* constants */ - ROOT_SIZE = 34, /* the root directory record has a fixed length */ - }; + /* root directory record */ + Directory_record * root_record() { return ptr(156); } - public: + /* check for primary descriptor */ + bool primary() { return type() == PRIMARY; } - /* descriptor type */ - uint8_t type() { return value(0); } + /* check for terminating descriptor */ + bool terminator() { return type() == TERMINATOR; } - /* root directory record */ - Directory_record * root_record() { return ptr(156); } + /* copy the root record */ + Directory_record *copy_root_record(Genode::Allocator &alloc) + { + Directory_record *buf; - /* check for primary descriptor */ - bool primary() { return type() == PRIMARY; } + if (!(alloc.alloc(ROOT_SIZE, &buf))) + throw Root::Quota_exceeded(); - /* check for terminating descriptor */ - bool terminator() { return type() == TERMINATOR; } + memcpy(buf, root_record(), ROOT_SIZE); - /* copy the root record */ - Directory_record *copy_root_record() - { - Directory_record *buf; - - if (!(env()->heap()->alloc(ROOT_SIZE, &buf))) - throw Root::Quota_exceeded(); - - memcpy(buf, root_record(), ROOT_SIZE); - - return buf; - } - }; - - - /** - * Locate the root-directory record in the primary volume descriptor - */ - Directory_record *locate_root() - { - /* volume descriptors in ISO9660 start at block 16 */ - for (unsigned long blk_nr = 16;; blk_nr++) { - Sector sec(blk_nr, 1); - Volume_descriptor *vol = sec.addr(); - - if (vol->primary()) - return vol->copy_root_record(); - - if (vol->terminator()) - return 0; + return buf; } +}; + + +/** + * Locate the root-directory record in the primary volume descriptor + */ +static Directory_record *locate_root(Genode::Allocator &alloc, + Block::Connection &block) +{ + /* volume descriptors in ISO9660 start at block 16 */ + for (unsigned long blk_nr = 16;; blk_nr++) { + Iso::Sector sec(block, blk_nr, 1); + Volume_descriptor *vol = sec.addr(); + + if (vol->primary()) + return vol->copy_root_record(alloc); + + if (vol->terminator()) + return nullptr; } +} - /** - * Return root directory record - */ - Directory_record *root_dir() - { - static Directory_record *root = locate_root(); +/** + * Return root directory record + */ +static Directory_record *root_dir(Genode::Allocator &alloc, + Block::Connection &block) +{ + Directory_record *root = locate_root(alloc, block); - if (!root) - throw Non_data_disc(); + if (!root) { throw Iso::Non_data_disc(); } - return root; - } + return root; +} - unsigned long read_file(File_info *info, off_t file_offset, uint32_t length, void *buf_ptr) - { - uint8_t *buf = (uint8_t *)buf_ptr; - if (info->size() <= (size_t)(length + file_offset)) - length = info->size() - file_offset - 1; +/******************* + ** Iso interface ** + *******************/ - unsigned long total_blk_count = ((length + (Sector::blk_size() - 1)) & - ~((Sector::blk_size()) - 1)) / Sector::blk_size(); - unsigned long ret = total_blk_count; - unsigned long blk_count; - unsigned long blk_nr = info->blk_nr() + (file_offset / Sector::blk_size()); +static Directory_record *_root_dir; - while ((blk_count = min(Sector::MAX_SECTORS, total_blk_count))) { - Sector sec(blk_nr, blk_count); - - total_blk_count -= blk_count; - blk_nr += blk_count; - - unsigned long copy_length = blk_count * Sector::blk_size(); - memcpy(buf, sec.addr(), copy_length); - - length -= copy_length; - buf += copy_length; - - /* zero out rest of page */ - if (!total_blk_count && (blk_count % 2)) - memset(buf, 0, Sector::blk_size()); - } - - return ret * Sector::blk_size(); - } +Iso::File_info *Iso::file_info(Genode::Allocator &alloc, Block::Connection &block, + char const *path) +{ + char level[PATH_LENGTH]; struct Scanner_policy_file { @@ -394,97 +387,100 @@ namespace Iso { return c != '/' && c != 0; } }; - typedef ::Genode::Token Token; + Token t(path); - /** - * ISO interface - */ - File_info *file_info(char *path) - { - char level[PATH_LENGTH]; + if (!_root_dir) { + _root_dir = root_dir(alloc, block); + } - Token t(path); - Directory_record *dir = root_dir(); - uint32_t blk_nr = 0, data_length = 0; + Directory_record *dir = _root_dir; + uint32_t blk_nr = 0, data_length = 0; - /* determine block nr and file length on disk, parse directory records */ - while (t) { - - if (t.type() != Token::IDENT) { - t = t.next(); - continue; - } - - t.string(level, PATH_LENGTH); - - /* - * Save current block number in a variable because successive - * iterations might override the memory location where dir points - * to when a directory entry spans several sectors. - */ - uint32_t current_blk_nr = dir->blk_nr(); - - /* load extent of directory record and search for level */ - for (unsigned long i = 0; i < Sector::to_blk(dir->data_length()); i++) { - Sector sec(current_blk_nr + i, 1); - Directory_record *tmp = sec.addr()->locate(level); - - if (!tmp && i == Sector::to_blk(dir->data_length()) - 1) { - Genode::error("file not found: ", Genode::Cstring(path)); - throw File_not_found(); - } - - if (!tmp) continue; - - dir = tmp; - current_blk_nr = dir->blk_nr(); - - if (!dir->directory()) { - blk_nr = current_blk_nr; - data_length = dir->data_length(); - } - - break; - } + /* determine block nr and file length on disk, parse directory records */ + while (t) { + if (t.type() != Token::IDENT) { t = t.next(); + continue; } - /* Warning: Don't access 'dir' after this point, since the sector is gone */ + t.string(level, PATH_LENGTH); - if (!blk_nr && !data_length) { - Genode::error("file not found: ", Genode::Cstring(path)); - throw File_not_found(); + /* + * Save current block number in a variable because successive + * iterations might override the memory location where dir points + * to when a directory entry spans several sectors. + */ + uint32_t current_blk_nr = dir->blk_nr(); + + /* load extent of directory record and search for level */ + for (unsigned long i = 0; i < Sector::to_blk(dir->data_length()); i++) { + Sector sec(block, current_blk_nr + i, 1); + Directory_record *tmp = sec.addr()->locate(level); + + if (!tmp && i == Sector::to_blk(dir->data_length()) - 1) { + Genode::error("file not found: ", Genode::Cstring(path)); + throw File_not_found(); + } + + if (!tmp) continue; + + dir = tmp; + current_blk_nr = dir->blk_nr(); + + if (!dir->directory()) { + blk_nr = current_blk_nr; + data_length = dir->data_length(); + } + + break; } - return new(env()->heap()) File_info(blk_nr, data_length); + t = t.next(); } + /* Warning: Don't access 'dir' after this point, since the sector is gone */ - /* - * Static members of Sector - */ - Block::Connection *Sector::_blk; - Block::Session::Tx::Source *Sector::_source; - size_t Sector::_blk_size; - Lock Sector::_lock; - - - /** - * Initialize globals - */ - void __attribute__((constructor)) init() - { - static Allocator_avl block_alloc(env()->heap()); - static Block::Connection _blk(&block_alloc); - - Sector::_blk = &_blk; - Sector::_source = _blk.tx(); - - Block::sector_t blk_cnt = 0; - Block::Session::Operations ops; - _blk.info(&blk_cnt, &Sector::_blk_size, &ops); + if (!blk_nr && !data_length) { + Genode::error("file not found: ", Genode::Cstring(path)); + throw File_not_found(); } -} /* end of namespace Iso */ + + return new (alloc) File_info(blk_nr, data_length); +} + + +unsigned long Iso::read_file(Block::Connection &block, File_info *info, + off_t file_offset, uint32_t length, void *buf_ptr) +{ + uint8_t *buf = (uint8_t *)buf_ptr; + if (info->size() <= (size_t)(length + file_offset)) + length = info->size() - file_offset - 1; + + unsigned long total_blk_count = ((length + (Sector::blk_size() - 1)) & + ~((Sector::blk_size()) - 1)) / Sector::blk_size(); + unsigned long ret = total_blk_count; + unsigned long blk_count; + unsigned long blk_nr = info->blk_nr() + (file_offset / Sector::blk_size()); + + while ((blk_count = min(Sector::MAX_SECTORS, total_blk_count))) { + Sector sec(block, blk_nr, blk_count); + + total_blk_count -= blk_count; + blk_nr += blk_count; + + unsigned long copy_length = blk_count * Sector::blk_size(); + memcpy(buf, sec.addr(), copy_length); + + length -= copy_length; + buf += copy_length; + + /* zero out rest of page */ + if (!total_blk_count && (blk_count % 2)) + memset(buf, 0, Sector::blk_size()); + } + + return ret * Sector::blk_size(); +} diff --git a/repos/os/src/server/iso9660/iso9660.h b/repos/os/src/server/iso9660/iso9660.h index e249a10890..78e7f7f8e1 100644 --- a/repos/os/src/server/iso9660/iso9660.h +++ b/repos/os/src/server/iso9660/iso9660.h @@ -5,14 +5,15 @@ */ /* - * Copyright (C) 2010-2013 Genode Labs GmbH + * 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 General Public License version 2. */ -#include +/* Genode includes */ #include +#include namespace Iso { @@ -51,10 +52,16 @@ namespace Iso { }; + /******************* + ** Iso interface ** + *******************/ + /** * Retrieve file information * - * \param path absolute path of the file (slash separated) + * \param alloc allocator used for File_info object + * \param block Block session used to read sectors from ISO + * \param path absolute path of the file (slash separated) * * \throw File_not_found * \throw Io_error @@ -62,11 +69,12 @@ namespace Iso { * * \return Pointer to File_info class */ - File_info *file_info(char *path); + File_info *file_info(Genode::Allocator &alloc, Block::Connection &block, char const *path); /** * Read data from ISO * + * \param block Block session used to read sectors from ISO * \param info File Info of file to read the data from * \param file_offset Offset in file * \param length Number of bytes to read @@ -76,6 +84,6 @@ namespace Iso { * * \return Number of bytes read */ - unsigned long read_file(File_info *info, Genode::off_t file_offset, + unsigned long read_file(Block::Connection &block, File_info *info, Genode::off_t file_offset, Genode::uint32_t length, void *buf); -} +} /* namespace Iso */ diff --git a/repos/os/src/server/iso9660/main.cc b/repos/os/src/server/iso9660/main.cc index e3bc4ab11f..7cd2b94743 100644 --- a/repos/os/src/server/iso9660/main.cc +++ b/repos/os/src/server/iso9660/main.cc @@ -12,22 +12,20 @@ */ /* Genode includes */ +#include +#include #include -#include #include -#include #include -#include #include -#include #include -#include #include #include +#include +#include /* local includes */ #include "iso9660.h" -#include "backing_store.h" using namespace Genode; @@ -38,140 +36,150 @@ using namespace Genode; namespace Iso { - typedef Backing_store Backing_store; - typedef Avl_string File_base; + typedef Avl_string File_base; + typedef Avl_tree File_cache; - /** - * File abstraction - */ - class File : public File_base - { - private: + class File; + class Rom_component; - File_info *_info; - Attached_ram_dataspace _ds; - - public: - - File(char *path) : File_base(path), - _info(Iso::file_info(path)), - _ds(env()->ram_session(), align_addr(_info->page_sized(), 12)) - { - Iso::read_file(_info, 0, _ds.size(), _ds.local_addr()); - } - - ~File() - { - destroy(env()->heap(), _info); - } - - Dataspace_capability dataspace() { return _ds.cap(); } + typedef Genode::Root_component Root_component; - /************************** - ** File cache interface ** - **************************/ - - /** - * File cache that holds files in order to re-use - * them in different sessions that request already cached files - */ - static Avl_tree *cache() - { - static Avl_tree _avl; - return &_avl; - } - - static File *scan_cache(const char *path) { - return static_cast(cache()->first() ? - cache()->first()->find_by_name(path) : - 0); - } - }; - - - class Rom_component : public Genode::Rpc_object - { - private: - - File *_file; - - public: - - Rom_dataspace_capability dataspace() { - return static_cap_cast(_file->dataspace()); } - - void sigh(Signal_context_capability) { } - - Rom_component(char *path) - { - if ((_file = File::scan_cache(path))) { - Genode::log("cache hit for file ", Genode::Cstring(path)); - return; - } - - _file = new(env()->heap()) File(path); - Genode::log("request for file ", Genode::Cstring(path)); - - File::cache()->insert(_file); - } - }; - - - typedef Root_component Root_component; - - class Root : public Root_component - { - private: - - char _path[PATH_LENGTH]; - - protected: - - Rom_component *_create_session(const char *args) - { - 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 Root::Quota_exceeded(); - - Session_label const label = label_from_args(args); - strncpy(_path, label.last_element().string(), sizeof(_path)); - - if (verbose) - Genode::log("Request for file ", Cstring(_path), " len ", strlen(_path)); - - try { - return new (md_alloc()) Rom_component(_path); - } - catch (Io_error) { throw Root::Unavailable(); } - catch (Non_data_disc) { throw Root::Unavailable(); } - catch (File_not_found) { throw Root::Invalid_args(); } - } - - public: - - Root(Rpc_entrypoint *ep, Allocator *md_alloc) - : - Root_component(ep, md_alloc) - { } - }; + class Root; } -int main() +/** + * File abstraction + */ +class Iso::File : public File_base { - /* initialize ROM service */ - enum { STACK_SIZE = sizeof(long)*4096 }; - static Cap_connection cap; - static Rpc_entrypoint ep(&cap, STACK_SIZE, "iso9660_ep"); + private: - static Iso::Root root(&ep, env()->heap()); - env()->parent()->announce(ep.manage(&root)); + Genode::Allocator &_alloc; - sleep_forever(); - return 0; -} + 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: + + File *_file; + + 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() { + return static_cap_cast(_file->dataspace()); } + + void sigh(Signal_context_capability) { } + + 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) + { + 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 Root::Quota_exceeded(); + + Session_label const label = label_from_args(args); + strncpy(_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 Root::Unavailable(); } + catch (Non_data_disc) { throw Root::Unavailable(); } + catch (File_not_found) { throw Root::Invalid_args(); } + } + + 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); }