mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-19 15:43:56 +00:00
committed by
Norman Feske
parent
b87a82784c
commit
a9a8bb0d8f
@ -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 <base/env.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 <typename UMD>
|
|
||||||
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_ */
|
|
@ -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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -16,7 +16,6 @@
|
|||||||
#include <base/exception.h>
|
#include <base/exception.h>
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
#include <base/stdint.h>
|
#include <base/stdint.h>
|
||||||
#include <block_session/connection.h>
|
|
||||||
#include <util/misc_math.h>
|
#include <util/misc_math.h>
|
||||||
#include <util/token.h>
|
#include <util/token.h>
|
||||||
|
|
||||||
@ -25,367 +24,361 @@
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
namespace Iso {
|
namespace Iso {
|
||||||
|
class Sector;
|
||||||
/*
|
class Rock_ridge;
|
||||||
* Sector reads one or more packets from the block interface
|
class Iso_base;
|
||||||
*/
|
}
|
||||||
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 <typename T>
|
|
||||||
T addr() { return reinterpret_cast<T>(_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); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*********************
|
/*
|
||||||
** ISO9660 classes **
|
* Sector reads one or more packets from the block interface
|
||||||
*********************/
|
*/
|
||||||
|
class Iso::Sector {
|
||||||
|
|
||||||
/**
|
public:
|
||||||
* Access memory using offsets
|
|
||||||
*/
|
|
||||||
class Iso_base
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T value(int offset) { return *((T *)(this + offset)); }
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T ptr(int offset) { return (T)(this + offset); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class representing a directory descriptions (see ECMA 119)
|
|
||||||
*/
|
|
||||||
class Directory_record : public Iso_base
|
|
||||||
{
|
|
||||||
enum {
|
enum {
|
||||||
TABLE_LENGTH = 33, /* fixed length of directory record */
|
MAX_SECTORS = 32, /* max. number sectors that can be read in one
|
||||||
|
transaction */
|
||||||
ROOT_DIR = 0x0, /* special names of root and parent directories */
|
BLOCK_SIZE = 2048,
|
||||||
PARENT_DIR = 0x1,
|
|
||||||
|
|
||||||
DIR_FLAG = 0x2, /* directory flag in attributes */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
static Lock _lock;
|
||||||
|
|
||||||
/* total length of this record */
|
private:
|
||||||
uint8_t record_length() { return value<uint8_t>(0); }
|
|
||||||
|
|
||||||
/* starting block of extent */
|
Block::Session::Tx::Source &_source;
|
||||||
uint32_t blk_nr() { return value<uint32_t>(2); }
|
Block::Packet_descriptor _p;
|
||||||
|
|
||||||
/* length in bytes of extent */
|
public:
|
||||||
uint32_t data_length() { return value<uint32_t>(10); }
|
|
||||||
|
|
||||||
/* attributes */
|
Sector(Block::Connection &block,
|
||||||
uint8_t file_flags() { return value<uint8_t>(25); }
|
unsigned long blk_nr, unsigned long count)
|
||||||
|
: _source(*block.tx())
|
||||||
|
{
|
||||||
|
// Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
/* length of file name */
|
try {
|
||||||
uint8_t file_name_length() { return value<uint8_t>(32); }
|
_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 */
|
_source.submit_packet(_p);
|
||||||
void file_name(char *buf)
|
_p = _source.get_acked_packet();
|
||||||
{
|
|
||||||
buf[0] = 0;
|
|
||||||
|
|
||||||
/* try Rock Ridge name */
|
if (!_p.succeeded()) {
|
||||||
Rock_ridge *rr = Rock_ridge::scan_name(system_use(),
|
Genode::error("Could not read block ", blk_nr);
|
||||||
system_use_size());
|
throw Io_error();
|
||||||
|
}
|
||||||
|
|
||||||
if (rr) {
|
} catch (Block::Session::Tx::Source::Packet_alloc_failed) {
|
||||||
memcpy(buf, rr->name(), rr->length());
|
Genode::error("packet overrun!");
|
||||||
buf[rr->length()] = 0;
|
_p = _source.get_acked_packet();
|
||||||
|
throw Io_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Sector() {
|
||||||
|
// Lock::Guard lock_guard(_lock);
|
||||||
|
_source.release_packet(_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return address of packet content
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
T addr() { return reinterpret_cast<T>(_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 <typename T>
|
||||||
|
T value(int offset) { return *((T *)(this + offset)); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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<uint8_t>(0); }
|
||||||
|
|
||||||
|
/* starting block of extent */
|
||||||
|
uint32_t blk_nr() { return value<uint32_t>(2); }
|
||||||
|
|
||||||
|
/* length in bytes of extent */
|
||||||
|
uint32_t data_length() { return value<uint32_t>(10); }
|
||||||
|
|
||||||
|
/* attributes */
|
||||||
|
uint8_t file_flags() { return value<uint8_t>(25); }
|
||||||
|
|
||||||
|
/* length of file name */
|
||||||
|
uint8_t file_name_length() { return value<uint8_t>(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<char*>(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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* retrieve iso name */
|
memcpy(buf, name, file_name_length());
|
||||||
char *name = ptr<char*>(33);
|
buf[file_name_length()] = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buf, name, file_name_length());
|
|
||||||
buf[file_name_length()] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pad byte after file name (if file name length is even, only) */
|
|
||||||
uint8_t pad_byte() { return !(file_name_length() % 2) ? 1 : 0; }
|
|
||||||
|
|
||||||
/* system use area */
|
|
||||||
uint8_t *system_use()
|
|
||||||
{
|
|
||||||
return (uint8_t*)this + TABLE_LENGTH
|
|
||||||
+ file_name_length() + pad_byte();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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();
|
|
||||||
|
|
||||||
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; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 */
|
|
||||||
|
|
||||||
/* constants */
|
|
||||||
ROOT_SIZE = 34, /* the root directory record has a fixed length */
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* descriptor type */
|
|
||||||
uint8_t type() { return value<uint8_t>(0); }
|
|
||||||
|
|
||||||
/* root directory record */
|
|
||||||
Directory_record * root_record() { return ptr<Directory_record *>(156); }
|
|
||||||
|
|
||||||
/* check for primary descriptor */
|
|
||||||
bool primary() { return type() == PRIMARY; }
|
|
||||||
|
|
||||||
/* check for terminating descriptor */
|
|
||||||
bool terminator() { return type() == TERMINATOR; }
|
|
||||||
|
|
||||||
/* 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<Volume_descriptor *>();
|
|
||||||
|
|
||||||
if (vol->primary())
|
|
||||||
return vol->copy_root_record();
|
|
||||||
|
|
||||||
if (vol->terminator())
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return root directory record
|
|
||||||
*/
|
|
||||||
Directory_record *root_dir()
|
|
||||||
{
|
|
||||||
static Directory_record *root = locate_root();
|
|
||||||
|
|
||||||
if (!root)
|
|
||||||
throw Non_data_disc();
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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<unsigned long>(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<void *>(), 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();
|
/* pad byte after file name (if file name length is even, only) */
|
||||||
}
|
uint8_t pad_byte() { return !(file_name_length() % 2) ? 1 : 0; }
|
||||||
|
|
||||||
|
/* system use area */
|
||||||
|
uint8_t *system_use()
|
||||||
|
{
|
||||||
|
return (uint8_t*)this + TABLE_LENGTH
|
||||||
|
+ file_name_length() + pad_byte();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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();
|
||||||
|
|
||||||
|
if (_next->record_length())
|
||||||
|
return _next;
|
||||||
|
|
||||||
|
return 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* describes this record a directory */
|
||||||
|
bool directory() { return file_flags() & DIR_FLAG; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */
|
||||||
|
|
||||||
|
/* constants */
|
||||||
|
ROOT_SIZE = 34, /* the root directory record has a fixed length */
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/* descriptor type */
|
||||||
|
uint8_t type() { return value<uint8_t>(0); }
|
||||||
|
|
||||||
|
/* root directory record */
|
||||||
|
Directory_record * root_record() { return ptr<Directory_record *>(156); }
|
||||||
|
|
||||||
|
/* check for primary descriptor */
|
||||||
|
bool primary() { return type() == PRIMARY; }
|
||||||
|
|
||||||
|
/* check for terminating descriptor */
|
||||||
|
bool terminator() { return type() == TERMINATOR; }
|
||||||
|
|
||||||
|
/* copy the root record */
|
||||||
|
Directory_record *copy_root_record(Genode::Allocator &alloc)
|
||||||
|
{
|
||||||
|
Directory_record *buf;
|
||||||
|
|
||||||
|
if (!(alloc.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
|
||||||
|
*/
|
||||||
|
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<Volume_descriptor *>();
|
||||||
|
|
||||||
|
if (vol->primary())
|
||||||
|
return vol->copy_root_record(alloc);
|
||||||
|
|
||||||
|
if (vol->terminator())
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 Iso::Non_data_disc(); }
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
** Iso interface **
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
static Directory_record *_root_dir;
|
||||||
|
|
||||||
|
|
||||||
|
Iso::File_info *Iso::file_info(Genode::Allocator &alloc, Block::Connection &block,
|
||||||
|
char const *path)
|
||||||
|
{
|
||||||
|
char level[PATH_LENGTH];
|
||||||
|
|
||||||
struct Scanner_policy_file
|
struct Scanner_policy_file
|
||||||
{
|
{
|
||||||
@ -394,97 +387,100 @@ namespace Iso {
|
|||||||
return c != '/' && c != 0;
|
return c != '/' && c != 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ::Genode::Token<Scanner_policy_file> Token;
|
typedef ::Genode::Token<Scanner_policy_file> Token;
|
||||||
|
|
||||||
|
Token t(path);
|
||||||
|
|
||||||
/**
|
if (!_root_dir) {
|
||||||
* ISO interface
|
_root_dir = root_dir(alloc, block);
|
||||||
*/
|
}
|
||||||
File_info *file_info(char *path)
|
|
||||||
{
|
|
||||||
char level[PATH_LENGTH];
|
|
||||||
|
|
||||||
Token t(path);
|
Directory_record *dir = _root_dir;
|
||||||
Directory_record *dir = root_dir();
|
uint32_t blk_nr = 0, data_length = 0;
|
||||||
uint32_t blk_nr = 0, data_length = 0;
|
|
||||||
|
|
||||||
/* determine block nr and file length on disk, parse directory records */
|
/* determine block nr and file length on disk, parse directory records */
|
||||||
while (t) {
|
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<Directory_record *>()->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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (t.type() != Token::IDENT) {
|
||||||
t = t.next();
|
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));
|
* Save current block number in a variable because successive
|
||||||
throw File_not_found();
|
* 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<Directory_record *>()->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 */
|
||||||
|
|
||||||
/*
|
if (!blk_nr && !data_length) {
|
||||||
* Static members of Sector
|
Genode::error("file not found: ", Genode::Cstring(path));
|
||||||
*/
|
throw File_not_found();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
} /* 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<unsigned long>(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<void *>(), 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();
|
||||||
|
}
|
||||||
|
@ -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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rom_session/rom_session.h>
|
/* Genode includes */
|
||||||
#include <base/stdint.h>
|
#include <base/stdint.h>
|
||||||
|
#include <block_session/connection.h>
|
||||||
|
|
||||||
namespace Iso {
|
namespace Iso {
|
||||||
|
|
||||||
@ -51,10 +52,16 @@ namespace Iso {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
** Iso interface **
|
||||||
|
*******************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve file information
|
* 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 File_not_found
|
||||||
* \throw Io_error
|
* \throw Io_error
|
||||||
@ -62,11 +69,12 @@ namespace Iso {
|
|||||||
*
|
*
|
||||||
* \return Pointer to File_info class
|
* \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
|
* 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 info File Info of file to read the data from
|
||||||
* \param file_offset Offset in file
|
* \param file_offset Offset in file
|
||||||
* \param length Number of bytes to read
|
* \param length Number of bytes to read
|
||||||
@ -76,6 +84,6 @@ namespace Iso {
|
|||||||
*
|
*
|
||||||
* \return Number of bytes read
|
* \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);
|
Genode::uint32_t length, void *buf);
|
||||||
}
|
} /* namespace Iso */
|
||||||
|
@ -12,22 +12,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/heap.h>
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
#include <base/sleep.h>
|
|
||||||
#include <base/rpc_server.h>
|
#include <base/rpc_server.h>
|
||||||
#include <cap_session/connection.h>
|
|
||||||
#include <dataspace/client.h>
|
#include <dataspace/client.h>
|
||||||
#include <rom_session/connection.h>
|
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
#include <rm_session/connection.h>
|
|
||||||
#include <util/avl_string.h>
|
#include <util/avl_string.h>
|
||||||
#include <util/misc_math.h>
|
|
||||||
#include <os/attached_ram_dataspace.h>
|
#include <os/attached_ram_dataspace.h>
|
||||||
#include <base/session_label.h>
|
#include <base/session_label.h>
|
||||||
|
#include <block_session/connection.h>
|
||||||
|
#include <rom_session/rom_session.h>
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
#include "iso9660.h"
|
#include "iso9660.h"
|
||||||
#include "backing_store.h"
|
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
@ -38,140 +36,150 @@ using namespace Genode;
|
|||||||
|
|
||||||
namespace Iso {
|
namespace Iso {
|
||||||
|
|
||||||
typedef Backing_store<Genode::off_t> Backing_store;
|
typedef Avl_string<PATH_LENGTH> File_base;
|
||||||
typedef Avl_string<PATH_LENGTH> File_base;
|
typedef Avl_tree<Avl_string_base> File_cache;
|
||||||
|
|
||||||
/**
|
class File;
|
||||||
* File abstraction
|
class Rom_component;
|
||||||
*/
|
|
||||||
class File : public File_base
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
File_info *_info;
|
typedef Genode::Root_component<Rom_component> Root_component;
|
||||||
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<void>());
|
|
||||||
}
|
|
||||||
|
|
||||||
~File()
|
|
||||||
{
|
|
||||||
destroy(env()->heap(), _info);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dataspace_capability dataspace() { return _ds.cap(); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************
|
class Root;
|
||||||
** 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<Avl_string_base> *cache()
|
|
||||||
{
|
|
||||||
static Avl_tree<Avl_string_base> _avl;
|
|
||||||
return &_avl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static File *scan_cache(const char *path) {
|
|
||||||
return static_cast<File *>(cache()->first() ?
|
|
||||||
cache()->first()->find_by_name(path) :
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Rom_component : public Genode::Rpc_object<Rom_session>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
File *_file;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Rom_dataspace_capability dataspace() {
|
|
||||||
return static_cap_cast<Rom_dataspace>(_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<Rom_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)
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main()
|
/**
|
||||||
|
* File abstraction
|
||||||
|
*/
|
||||||
|
class Iso::File : public File_base
|
||||||
{
|
{
|
||||||
/* initialize ROM service */
|
private:
|
||||||
enum { STACK_SIZE = sizeof(long)*4096 };
|
|
||||||
static Cap_connection cap;
|
|
||||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "iso9660_ep");
|
|
||||||
|
|
||||||
static Iso::Root root(&ep, env()->heap());
|
Genode::Allocator &_alloc;
|
||||||
env()->parent()->announce(ep.manage(&root));
|
|
||||||
|
|
||||||
sleep_forever();
|
File_info *_info;
|
||||||
return 0;
|
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<void>());
|
||||||
|
}
|
||||||
|
|
||||||
|
~File() { destroy(_alloc, _info); }
|
||||||
|
|
||||||
|
Dataspace_capability dataspace() { return _ds.cap(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Iso::Rom_component : public Genode::Rpc_object<Rom_session>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
File *_file;
|
||||||
|
|
||||||
|
File *_lookup(File_cache &cache, char const *path)
|
||||||
|
{
|
||||||
|
return static_cast<File *>(cache.first() ?
|
||||||
|
cache.first()->find_by_name(path) :
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Rom_dataspace_capability dataspace() {
|
||||||
|
return static_cap_cast<Rom_dataspace>(_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); }
|
||||||
|
Reference in New Issue
Block a user