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); }