2011-12-22 15:19:25 +00:00
|
|
|
/*
|
|
|
|
* \brief Service that provides files of a TAR archive as ROM sessions
|
|
|
|
* \author Martin stein
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2010-04-21
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2012-01-03 14:35:05 +00:00
|
|
|
* Copyright (C) 2010-2012 Genode Labs GmbH
|
2011-12-22 15:19:25 +00:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <rom_session/rom_session.h>
|
|
|
|
#include <root/component.h>
|
|
|
|
#include <cap_session/connection.h>
|
|
|
|
#include <util/arg_string.h>
|
|
|
|
#include <base/rpc_server.h>
|
|
|
|
#include <base/sleep.h>
|
|
|
|
#include <base/env.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <os/config.h>
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A 'Rom_session_component' exports a single file of the tar archive
|
|
|
|
*/
|
|
|
|
class Rom_session_component : public Genode::Rpc_object<Genode::Rom_session>
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
const char *_tar_addr, *_filename, *_file_addr;
|
|
|
|
Genode::size_t _file_size, _tar_size;
|
|
|
|
Genode::Ram_dataspace_capability _file_ds;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
/* length of on data block in tar */
|
|
|
|
_BLOCK_LEN = 512,
|
|
|
|
|
|
|
|
/* length of the header field "file-size" in tar */
|
|
|
|
_FIELD_SIZE_LEN = 124
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy file content into dataspace
|
|
|
|
*
|
|
|
|
* \param dst destination dataspace
|
|
|
|
*/
|
|
|
|
void _copy_content_to_dataspace(Genode::Dataspace_capability dst)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
/* map dataspace locally */
|
|
|
|
char *dst_addr = env()->rm_session()->attach(dst);
|
|
|
|
Dataspace_client dst_client(dst);
|
|
|
|
|
|
|
|
/* copy content */
|
|
|
|
size_t dst_ds_size = Dataspace_client(dst).size();
|
|
|
|
size_t bytes_to_copy = min(_file_size, dst_ds_size);
|
|
|
|
memcpy(dst_addr, _file_addr, bytes_to_copy);
|
|
|
|
|
|
|
|
/* unmap dataspace */
|
|
|
|
env()->rm_session()->detach(dst_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize dataspace containing the content of the archived file
|
|
|
|
*/
|
|
|
|
Genode::Ram_dataspace_capability _init_file_ds()
|
|
|
|
{
|
|
|
|
bool file_found = false;
|
|
|
|
|
|
|
|
/* measure size of archive in blocks */
|
|
|
|
unsigned block_id = 0, block_cnt = _tar_size/_BLOCK_LEN;
|
|
|
|
|
|
|
|
/* scan metablocks of archive */
|
|
|
|
while (block_id < block_cnt) {
|
|
|
|
|
|
|
|
unsigned long file_size = 0;
|
|
|
|
Genode::ascii_to(_tar_addr + block_id*_BLOCK_LEN + _FIELD_SIZE_LEN,
|
|
|
|
&file_size, 8);
|
|
|
|
|
|
|
|
/* get infos about current file */
|
|
|
|
if (Genode::strcmp(_filename, _tar_addr + block_id*_BLOCK_LEN) == 0) {
|
|
|
|
_file_size = file_size;
|
|
|
|
_file_addr = _tar_addr + (block_id+1) * _BLOCK_LEN;
|
|
|
|
file_found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* some datablocks */ /* one metablock */
|
|
|
|
block_id = block_id + (file_size / _BLOCK_LEN) + 1;
|
|
|
|
|
|
|
|
/* round up */
|
|
|
|
if (file_size % _BLOCK_LEN != 0) block_id++;
|
|
|
|
|
|
|
|
/* check for end of tar archive */
|
|
|
|
if (block_id*_BLOCK_LEN >= _tar_size)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* lookout for empty eof-blocks */
|
|
|
|
if (*(_tar_addr + (block_id*_BLOCK_LEN)) == 0x00)
|
|
|
|
if (*(_tar_addr + (block_id*_BLOCK_LEN + 1)) == 0x00)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file_found) {
|
|
|
|
PERR("couldn't find file '%s', empty result", _filename);
|
|
|
|
return Genode::Ram_dataspace_capability();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to allocate memory for file */
|
|
|
|
Genode::Ram_dataspace_capability file_ds;
|
|
|
|
try {
|
|
|
|
file_ds = Genode::env()->ram_session()->alloc(_file_size);
|
|
|
|
|
|
|
|
/* get content of file copied into dataspace and return */
|
|
|
|
_copy_content_to_dataspace(file_ds);
|
|
|
|
} catch (...) {
|
|
|
|
PERR("couldn't allocate memory for file, empty result\n");
|
|
|
|
return file_ds;
|
|
|
|
}
|
|
|
|
|
|
|
|
return file_ds;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor scans and seeks to file
|
|
|
|
*
|
|
|
|
* \param tar_addr local address to tar archive
|
|
|
|
* \param tar_size size of tar archive in bytes
|
|
|
|
* \param filename name of the requested file
|
|
|
|
*/
|
|
|
|
Rom_session_component(const char *tar_addr, unsigned tar_size,
|
|
|
|
const char *filename)
|
|
|
|
:
|
|
|
|
_tar_addr(tar_addr), _filename(filename), _file_addr(0), _file_size(0),
|
|
|
|
_tar_size(tar_size),
|
|
|
|
_file_ds(_init_file_ds())
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor
|
|
|
|
*/
|
|
|
|
~Rom_session_component() { Genode::env()->ram_session()->free(_file_ds); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return dataspace with content of file
|
|
|
|
*/
|
|
|
|
Genode::Rom_dataspace_capability dataspace()
|
|
|
|
{
|
|
|
|
Genode::Dataspace_capability ds = _file_ds;
|
|
|
|
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Rom_root : public Genode::Root_component<Rom_session_component>
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
char *_tar_addr;
|
|
|
|
unsigned _tar_size;
|
|
|
|
|
|
|
|
Rom_session_component *_create_session(const char *args)
|
|
|
|
{
|
|
|
|
enum { FILENAME_MAX_LEN = 128 };
|
|
|
|
char filename[FILENAME_MAX_LEN];
|
|
|
|
Genode::Arg_string::find_arg(args, "filename").string(filename, sizeof(filename), "");
|
|
|
|
|
|
|
|
PINF("connection for file '%s' requested\n", filename);
|
|
|
|
|
|
|
|
/* create new session for the requested file */
|
|
|
|
return new (md_alloc()) Rom_session_component(_tar_addr, _tar_size, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param entrypoint entrypoint to be used for ROM sessions
|
|
|
|
* \param md_alloc meta-data allocator used for ROM sessions
|
|
|
|
* \param tar_base local address of tar archive
|
|
|
|
* \param tar_size size of tar archive in bytes
|
|
|
|
*/
|
|
|
|
Rom_root(Genode::Rpc_entrypoint *entrypoint,
|
|
|
|
Genode::Allocator *md_alloc,
|
|
|
|
char *tar_addr, Genode::size_t tar_size)
|
|
|
|
:
|
|
|
|
Genode::Root_component<Rom_session_component>(entrypoint, md_alloc),
|
|
|
|
_tar_addr(tar_addr), _tar_size(tar_size)
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
/* read name of tar archive from config */
|
|
|
|
enum { TAR_FILENAME_MAX_LEN = 64 };
|
|
|
|
static char tar_filename[TAR_FILENAME_MAX_LEN];
|
|
|
|
try {
|
|
|
|
Xml_node archive_node =
|
|
|
|
config()->xml_node().sub_node("archive");
|
|
|
|
archive_node.attribute("name").value(tar_filename, sizeof(tar_filename));
|
|
|
|
} catch (...) {
|
|
|
|
PERR("Could not read 'filename' argument from config");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* obtain dataspace of tar archive from ROM service */
|
|
|
|
static char *tar_base = 0;
|
|
|
|
static size_t tar_size = 0;
|
|
|
|
try {
|
|
|
|
static Rom_connection tar_rom(tar_filename);
|
|
|
|
tar_base = env()->rm_session()->attach(tar_rom.dataspace());
|
|
|
|
tar_size = Dataspace_client(tar_rom.dataspace()).size();
|
|
|
|
} catch (...) {
|
|
|
|
PERR("Could not obtain tar archive from ROM service");
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
PINF("using tar archive '%s' with size %zd", tar_filename, tar_size);
|
|
|
|
|
|
|
|
/* connection to capability service needed to create capabilities */
|
|
|
|
static Cap_connection cap;
|
|
|
|
|
|
|
|
/* creation of the entrypoint and the root interface */
|
|
|
|
static Sliced_heap sliced_heap(env()->ram_session(),
|
|
|
|
env()->rm_session());
|
|
|
|
|
|
|
|
enum { STACK_SIZE = 8*1024 };
|
|
|
|
static Rpc_entrypoint ep(&cap, STACK_SIZE, "tar_rom_ep");
|
|
|
|
static Rom_root rom_root(&ep, &sliced_heap, tar_base, tar_size);
|
|
|
|
|
|
|
|
/* announce server*/
|
|
|
|
env()->parent()->announce(ep.manage(&rom_root));
|
|
|
|
|
|
|
|
/* wait for activation through client */
|
|
|
|
sleep_forever();
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|