committed by
Christian Helmuth
parent
b35caec726
commit
6a33ecac84
3
recipes/pkg/lwext4_fs/README
Normal file
3
recipes/pkg/lwext4_fs/README
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
Lwext4 file system server
|
||||
|
||||
1
recipes/pkg/lwext4_fs/archives
Normal file
1
recipes/pkg/lwext4_fs/archives
Normal file
@@ -0,0 +1 @@
|
||||
_/src/lwext4_fs
|
||||
1
recipes/pkg/lwext4_fs/hash
Normal file
1
recipes/pkg/lwext4_fs/hash
Normal file
@@ -0,0 +1 @@
|
||||
2018-11-27 786449fb4897510db9d96f975499afd6a1767592
|
||||
12
recipes/pkg/lwext4_fs/runtime
Normal file
12
recipes/pkg/lwext4_fs/runtime
Normal file
@@ -0,0 +1,12 @@
|
||||
<runtime ram="8M" caps="100" binary="lwext4_fs">
|
||||
|
||||
<requires> <block/> </requires>
|
||||
|
||||
<config/>
|
||||
|
||||
<content>
|
||||
<rom label="ld.lib.so"/>
|
||||
<rom label="lwext4_fs"/>
|
||||
</content>
|
||||
|
||||
</runtime>
|
||||
21
recipes/src/lwext4_fs/content.mk
Normal file
21
recipes/src/lwext4_fs/content.mk
Normal file
@@ -0,0 +1,21 @@
|
||||
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/lwext4)
|
||||
|
||||
MIRROR_FROM_REP_DIR := lib/mk/lwext4.mk \
|
||||
lib/import/import-lwext4.mk \
|
||||
src/server/lwext4_fs \
|
||||
include/lwext4
|
||||
|
||||
content: $(MIRROR_FROM_REP_DIR) src/lib/lwext4
|
||||
|
||||
$(MIRROR_FROM_REP_DIR):
|
||||
$(mirror_from_rep_dir)
|
||||
|
||||
src/lib/lwext4:
|
||||
mkdir -p $@
|
||||
cp -r $(PORT_DIR)/src/lib/lwext4/* $@
|
||||
cp -r $(REP_DIR)/src/lib/lwext4/* $@
|
||||
|
||||
content: LICENSE
|
||||
LICENSE:
|
||||
( echo "Lwext4 is subject to GNU General Public License version 2, see:"; \
|
||||
echo " src/lib/lwext4/LICENSE" ) > $@
|
||||
1
recipes/src/lwext4_fs/hash
Normal file
1
recipes/src/lwext4_fs/hash
Normal file
@@ -0,0 +1 @@
|
||||
2018-11-27 6ec429b6a4a6e364c916fae3de25663ce3fccdde
|
||||
8
recipes/src/lwext4_fs/used_apis
Normal file
8
recipes/src/lwext4_fs/used_apis
Normal file
@@ -0,0 +1,8 @@
|
||||
base
|
||||
os
|
||||
block_session
|
||||
file_system
|
||||
file_system_session
|
||||
timer_session
|
||||
report_session
|
||||
vfs
|
||||
109
run/lwext4_fs.run
Normal file
109
run/lwext4_fs.run
Normal file
@@ -0,0 +1,109 @@
|
||||
assert_spec linux
|
||||
|
||||
#
|
||||
# Check used commands
|
||||
#
|
||||
set mke4fs [installed_command mkfs.ext4]
|
||||
set dd [installed_command dd]
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
set build_components {
|
||||
core init
|
||||
drivers/timer
|
||||
server/lwext4_fs
|
||||
server/lx_block
|
||||
server/report_rom
|
||||
test/libc_vfs
|
||||
}
|
||||
|
||||
build $build_components
|
||||
|
||||
#
|
||||
# Build EXT2-file-system image
|
||||
#
|
||||
set image_size 262144
|
||||
catch { exec $dd if=/dev/zero of=bin/ext4.raw bs=1M seek=$image_size count=0 }
|
||||
catch { exec $mke4fs -F bin/ext4.raw }
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<default caps="100"/>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config verbose="yes"/>
|
||||
</start>
|
||||
|
||||
<start name="lx_block" ld="no">
|
||||
<resource name="RAM" quantum="1G"/>
|
||||
<provides><service name="Block"/></provides>
|
||||
<config file="ext4.raw" block_size="512" writeable="yes"/>
|
||||
</start>
|
||||
|
||||
<start name="lwext4_fs" caps="100">
|
||||
<resource name="RAM" quantum="4M" />
|
||||
<provides><service name="File_system"/></provides>
|
||||
<config cache_write_back="yes">
|
||||
<report stats="yes"/>
|
||||
<policy label_prefix="test-libc_vfs" root="/" writeable="yes"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="test-libc_vfs">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config>
|
||||
<large seek="yes"/>
|
||||
<vfs>
|
||||
<dir name="dev"> <log/> </dir>
|
||||
<fs/>
|
||||
</vfs>
|
||||
<libc stdout="/dev/log" stderr="/dev/log"/>
|
||||
</config>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core ld.lib.so init timer report_rom lx_block
|
||||
lwext4_fs ext4.raw libc.lib.so test-libc_vfs vfs.lib.so
|
||||
}
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic"
|
||||
|
||||
run_genode_until {.*child "test-libc_vfs" exited with exit value 0.*} 600
|
||||
|
||||
#exec rm -f bin/ext4.raw
|
||||
128
src/server/lwext4_fs/directory.h
Normal file
128
src/server/lwext4_fs/directory.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* \brief Lwext4 file system directory node
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-08-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _DIRECTORY_H_
|
||||
#define _DIRECTORY_H_
|
||||
|
||||
/* lwext4 includes */
|
||||
#include <ext4.h>
|
||||
|
||||
/* local includes */
|
||||
#include <node.h>
|
||||
|
||||
|
||||
namespace Lwext4_fs {
|
||||
using namespace Genode;
|
||||
class Directory;
|
||||
}
|
||||
|
||||
class Lwext4_fs::Directory : public Node
|
||||
{
|
||||
private:
|
||||
|
||||
ext4_dir _dir { };
|
||||
int64_t _prev_index { -1 };
|
||||
|
||||
void _open(char const *path, bool create)
|
||||
{
|
||||
/* always try to open the directory first */
|
||||
int err = ext4_dir_open(&_dir, path);
|
||||
if (err && !create) {
|
||||
error("ext4_dir_open failed: ", err);
|
||||
throw Permission_denied();
|
||||
} else if (err && create) {
|
||||
err = ext4_dir_mk(path);
|
||||
if (err) {
|
||||
error("ext4_dir_mk failed: ", err);
|
||||
throw Permission_denied();
|
||||
}
|
||||
err = ext4_mode_set(path, 0777);
|
||||
if (err) {
|
||||
error("ext4_mode_set failed: ", err);
|
||||
ext4_dir_rm(path);
|
||||
throw Permission_denied();
|
||||
}
|
||||
} else if (!err && create) {
|
||||
/* it already exists but we were advised to create it */
|
||||
ext4_dir_close(&_dir);
|
||||
throw Node_already_exists();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Directory(char const *name, bool create = false) : Node(name, create)
|
||||
{
|
||||
_open(name, create);
|
||||
}
|
||||
|
||||
size_t read(char *dest, size_t len, seek_off_t seek_offset)
|
||||
{
|
||||
if (len < sizeof(Directory_entry)) {
|
||||
error("read buffer too small for directory entry");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seek_offset % sizeof(Directory_entry)) {
|
||||
error("seek offset not alighed to sizeof(Directory_entry)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Directory_entry * const e = (Directory_entry *)(dest);
|
||||
|
||||
int64_t const index = seek_offset / sizeof(Directory_entry);
|
||||
|
||||
/*
|
||||
* Manipulate ext4_dir struct directly which AFAICT is
|
||||
* okay and let lwext4 deal with it to safe CPU time.
|
||||
*/
|
||||
if (index != (_prev_index + 1)) {
|
||||
_dir.next_off = index > 0 ? index : 0;
|
||||
}
|
||||
|
||||
ext4_direntry const *dentry = nullptr;
|
||||
while (true) {
|
||||
dentry = ext4_dir_entry_next(&_dir);
|
||||
if (!dentry) { break; }
|
||||
|
||||
/* ignore entries without proper inode */
|
||||
if (!dentry->inode) {
|
||||
warning("skip dentry with empty inode");
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t const len = (size_t)(dentry->name_length + 1) > sizeof(e->name)
|
||||
? sizeof(e->name) : dentry->name_length + 1;
|
||||
strncpy(e->name, reinterpret_cast<char const*>(dentry->name), len);
|
||||
|
||||
e->inode = dentry->inode;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dentry) { throw Node::Eof(); }
|
||||
|
||||
_prev_index = index;
|
||||
|
||||
switch (dentry->inode_type) {
|
||||
case EXT4_DE_DIR: e->type = Directory_entry::TYPE_DIRECTORY; break;
|
||||
case EXT4_DE_SYMLINK: e->type = Directory_entry::TYPE_SYMLINK; break;
|
||||
default: e->type = Directory_entry::TYPE_FILE; break;
|
||||
}
|
||||
|
||||
return sizeof(Directory_entry);
|
||||
}
|
||||
|
||||
size_t write(char const *src, size_t len, seek_off_t) { return 0; }
|
||||
};
|
||||
|
||||
#endif /* _DIRECTORY_H_ */
|
||||
120
src/server/lwext4_fs/file.h
Normal file
120
src/server/lwext4_fs/file.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* \brief Lwext4 file system file node
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-08-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _FILE_H_
|
||||
#define _FILE_H_
|
||||
|
||||
/* local includes */
|
||||
#include <node.h>
|
||||
|
||||
/* lwext4 includes */
|
||||
#include <ext4.h>
|
||||
|
||||
namespace Lwext4_fs {
|
||||
using namespace Genode;
|
||||
class File;
|
||||
}
|
||||
|
||||
class Lwext4_fs::File : public Node
|
||||
{
|
||||
private:
|
||||
|
||||
ext4_file _file;
|
||||
|
||||
public:
|
||||
|
||||
File(const char *name, Mode mode, bool create) : Node(name, create)
|
||||
{
|
||||
int flags = 0;
|
||||
if (create) { flags |= O_CREAT; }
|
||||
|
||||
switch (mode) {
|
||||
case READ_ONLY: flags |= O_RDONLY; break;
|
||||
case WRITE_ONLY: flags |= O_WRONLY; break;
|
||||
case READ_WRITE: flags |= O_RDWR; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
int err = ext4_fopen2(&_file, name, flags);
|
||||
if (err) {
|
||||
error("ext4_fopen2: error: ", err);
|
||||
throw Permission_denied();
|
||||
}
|
||||
|
||||
if (create) {
|
||||
err = ext4_mode_set(name, 0666);
|
||||
if (err) {
|
||||
error("ext4_mode_set: error: ", err);
|
||||
throw Permission_denied();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~File()
|
||||
{
|
||||
ext4_fclose(&_file);
|
||||
}
|
||||
|
||||
size_t read(char *dest, size_t len, seek_off_t seek_offset) override
|
||||
{
|
||||
bool const to_end = seek_offset == (seek_off_t)(~0);
|
||||
|
||||
int err = ext4_fseek(&_file, to_end ? 0 : seek_offset,
|
||||
to_end ? SEEK_END : SEEK_SET);
|
||||
if (err) {
|
||||
error(__func__, ": invalid seek offset");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Genode::size_t bytes = 0;
|
||||
err = ext4_fread(&_file, dest, len, &bytes);
|
||||
if (err) {
|
||||
error(__func__, ": error: ", err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bytes) { throw Node::Eof(); }
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
size_t write(char const *src, size_t len, seek_off_t seek_offset) override
|
||||
{
|
||||
bool const to_end = seek_offset == (seek_off_t)(~0);
|
||||
|
||||
int err = ext4_fseek(&_file, to_end ? 0 : seek_offset,
|
||||
to_end ? SEEK_END : SEEK_SET);
|
||||
if (err) {
|
||||
error(__func__, ": invalid seek offset: ", seek_offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Genode::size_t bytes = 0;
|
||||
err = ext4_fwrite(&_file, src, len, &bytes);
|
||||
if (err) {
|
||||
error(__func__, ": error: ", err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void truncate(file_size_t size) override
|
||||
{
|
||||
int const err = ext4_ftruncate(&_file, size);
|
||||
if (err) { error(__func__, ": error: ", err); }
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* _FILE_H_ */
|
||||
125
src/server/lwext4_fs/file_system.cc
Normal file
125
src/server/lwext4_fs/file_system.cc
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* \brief Lwext4 file system
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-08-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* library includes */
|
||||
#include <ext4.h>
|
||||
|
||||
/* local includes */
|
||||
#include <file_system.h>
|
||||
|
||||
|
||||
static char const *_fs_name = "ext4";
|
||||
static char const *_fs_mp = "/";
|
||||
static bool _cache_write_back = false;
|
||||
|
||||
|
||||
void File_system::init(ext4_blockdev *bd)
|
||||
{
|
||||
int err = ext4_device_register(bd, _fs_name);
|
||||
if (err) { throw Init_failed(); }
|
||||
}
|
||||
|
||||
|
||||
void File_system::mount_fs(Genode::Xml_node config)
|
||||
{
|
||||
int err = ext4_mount(_fs_name, _fs_mp, false);
|
||||
if (err) {
|
||||
Genode::error("could not mount file system, err: ", err);
|
||||
throw Mount_failed();
|
||||
}
|
||||
|
||||
_cache_write_back = config.attribute_value("cache_write_back", false);
|
||||
if (_cache_write_back) {
|
||||
err = ext4_cache_write_back(_fs_mp, 1);
|
||||
if (err) {
|
||||
Genode::warning("could not enable cache write-back mode, err: ", err);
|
||||
_cache_write_back = false;
|
||||
}
|
||||
}
|
||||
|
||||
err = ext4_recover(_fs_mp);
|
||||
if (err && err != ENOTSUP) {
|
||||
Genode::error("could not recover file system (FSCK needed!), err:", err);
|
||||
throw Mount_failed();
|
||||
}
|
||||
|
||||
err = ext4_journal_start(_fs_mp);
|
||||
if (err) {
|
||||
Genode::error("could not start journal, err: ", err);
|
||||
throw Mount_failed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void File_system::unmount_fs()
|
||||
{
|
||||
int err = ext4_journal_stop(_fs_mp);
|
||||
if (err) {
|
||||
Genode::error("could not stop journal, err: ", err);
|
||||
// throw Genode::Exception();
|
||||
}
|
||||
|
||||
if (_cache_write_back) {
|
||||
err = ext4_cache_write_back(_fs_mp, 0);
|
||||
if (err) {
|
||||
Genode::error("could not disable cache write-back mode, err: ", err);
|
||||
}
|
||||
}
|
||||
|
||||
err = ext4_umount(_fs_mp);
|
||||
if (err) {
|
||||
Genode::error("could not unmount file system, err: ", err);
|
||||
throw Unmount_failed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void File_system::sync()
|
||||
{
|
||||
int const err = ext4_cache_flush(_fs_mp);
|
||||
if (err) {
|
||||
Genode::error("could not flush cache, err: ", err);
|
||||
throw Sync_failed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void File_system::stats_update(Genode::Reporter &reporter)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
struct ext4_mount_stats stats { };
|
||||
int const err = ext4_mount_point_stats(_fs_mp, &stats);
|
||||
if (err) {
|
||||
Genode::error("could not get mount point stats");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Reporter::Xml_generator xml(reporter, [&] () {
|
||||
xml.node("blocks", [&] () {
|
||||
xml.attribute("used", stats.blocks_count-stats.free_blocks_count);
|
||||
xml.attribute("avail", stats.free_blocks_count);
|
||||
xml.attribute("size", stats.block_size);
|
||||
});
|
||||
xml.node("inodes", [&] () {
|
||||
xml.attribute("used", stats.inodes_count);
|
||||
xml.attribute("avail", stats.free_inodes_count);
|
||||
});
|
||||
});
|
||||
} catch (...) { }
|
||||
}
|
||||
38
src/server/lwext4_fs/file_system.h
Normal file
38
src/server/lwext4_fs/file_system.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* \brief Lwext4 file system initialization
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-08-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
#ifndef _FILE_SYSTEM_H_
|
||||
#define _FILE_SYSTEM_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/exception.h>
|
||||
#include <os/reporter.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
|
||||
struct ext4_blockdev;
|
||||
|
||||
namespace File_system {
|
||||
|
||||
struct Init_failed : Genode::Exception { };
|
||||
struct Mount_failed : Genode::Exception { };
|
||||
struct Unmount_failed : Genode::Exception { };
|
||||
struct Sync_failed : Genode::Exception { };
|
||||
|
||||
void init(ext4_blockdev*);
|
||||
void mount_fs(Genode::Xml_node);
|
||||
void unmount_fs();
|
||||
void sync();
|
||||
void stats_update(Genode::Reporter &);
|
||||
}
|
||||
|
||||
#endif /* _FILE_SYSTEM_H_ */
|
||||
682
src/server/lwext4_fs/main.cc
Normal file
682
src/server/lwext4_fs/main.cc
Normal file
@@ -0,0 +1,682 @@
|
||||
/**
|
||||
* \brief Lwext4 file system interface implementation
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-08-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <base/component.h>
|
||||
#include <base/heap.h>
|
||||
#include <file_system/util.h>
|
||||
#include <file_system_session/rpc_object.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <root/component.h>
|
||||
|
||||
/* library includes */
|
||||
#include <lwext4/init.h>
|
||||
#include <ext4.h>
|
||||
|
||||
/* local includes */
|
||||
#include <directory.h>
|
||||
#include <file.h>
|
||||
#include <file_system.h>
|
||||
#include <open_node.h>
|
||||
#include <symlink.h>
|
||||
|
||||
namespace Lwext4_fs {
|
||||
|
||||
using File_system::Packet_descriptor;
|
||||
using File_system::Path;
|
||||
|
||||
struct Main;
|
||||
struct Root;
|
||||
struct Session_component;
|
||||
}
|
||||
|
||||
class Lwext4_fs::Session_component : public File_system::Session_rpc_object
|
||||
{
|
||||
private:
|
||||
|
||||
typedef File_system::Open_node<Node> Open_node;
|
||||
|
||||
Genode::Env &_env;
|
||||
|
||||
Allocator &_md_alloc;
|
||||
Directory &_root;
|
||||
Id_space<File_system::Node> _open_node_registry;
|
||||
bool _writable;
|
||||
|
||||
Signal_handler<Session_component> _process_packet_handler;
|
||||
|
||||
Genode::Reporter _stats_reporter { _env , "file_system_stats", "stats" };
|
||||
|
||||
/******************************
|
||||
** Packet-stream processing **
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Perform packet operation
|
||||
*
|
||||
* \return true on success, false on failure
|
||||
*/
|
||||
void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
|
||||
{
|
||||
void * const content = tx_sink()->packet_content(packet);
|
||||
size_t const length = packet.length();
|
||||
|
||||
/* resulting length */
|
||||
size_t res_length = 0;
|
||||
bool succeeded = false;
|
||||
|
||||
switch (packet.operation()) {
|
||||
|
||||
case Packet_descriptor::READ:
|
||||
if (content && (packet.length() <= packet.size())) {
|
||||
try {
|
||||
res_length = open_node.node().read((char *)content, length,
|
||||
packet.position());
|
||||
succeeded = res_length;
|
||||
} catch (Node::Eof) { succeeded = true; }
|
||||
}
|
||||
break;
|
||||
|
||||
case Packet_descriptor::WRITE:
|
||||
if (content && (packet.length() <= packet.size())) {
|
||||
res_length = open_node.node().write((char const *)content,
|
||||
length, packet.position());
|
||||
if (res_length != length) {
|
||||
Genode::error("partial write detected ",
|
||||
res_length, " vs ", length);
|
||||
/* do not acknowledge */
|
||||
return;
|
||||
}
|
||||
succeeded = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CONTENT_CHANGED:
|
||||
open_node.register_notify(*tx_sink());
|
||||
/* notify_listeners may bounce the packet back*/
|
||||
open_node.node().notify_listeners();
|
||||
/* otherwise defer acknowledgement of this packet */
|
||||
return;
|
||||
|
||||
case Packet_descriptor::READ_READY:
|
||||
succeeded = true;
|
||||
/* not supported */
|
||||
break;
|
||||
|
||||
case Packet_descriptor::SYNC:
|
||||
/* for future failure handling */
|
||||
try { File_system::sync(); }
|
||||
catch (...) { }
|
||||
|
||||
File_system::stats_update(_stats_reporter);
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
packet.length(res_length);
|
||||
packet.succeeded(succeeded);
|
||||
tx_sink()->acknowledge_packet(packet);
|
||||
}
|
||||
|
||||
void _process_packet()
|
||||
{
|
||||
Packet_descriptor packet = tx_sink()->get_packet();
|
||||
|
||||
/* assume failure by default */
|
||||
packet.succeeded(false);
|
||||
|
||||
auto process_packet_fn = [&] (Open_node &open_node) {
|
||||
_process_packet_op(packet, open_node);
|
||||
};
|
||||
|
||||
try {
|
||||
_open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
Genode::error("Invalid_handle");
|
||||
tx_sink()->acknowledge_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void _process_packets()
|
||||
{
|
||||
while (tx_sink()->packet_avail()) {
|
||||
|
||||
if (!tx_sink()->ready_to_ack())
|
||||
return;
|
||||
|
||||
_process_packet();
|
||||
}
|
||||
}
|
||||
|
||||
static void _assert_valid_path(char const *path)
|
||||
{
|
||||
if (!path || path[0] != '/')
|
||||
throw Lookup_failed();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Genode::Env &env,
|
||||
size_t tx_buf_size,
|
||||
char const *root_dir,
|
||||
bool writeable,
|
||||
Allocator &md_alloc,
|
||||
bool report_stats)
|
||||
:
|
||||
Session_rpc_object(env.ram().alloc(tx_buf_size), env.rm(), env.ep().rpc_ep()),
|
||||
_env(env),
|
||||
_md_alloc(md_alloc),
|
||||
_root(*new (&_md_alloc) Directory(root_dir, false)),
|
||||
_writable(writeable),
|
||||
_process_packet_handler(env.ep(), *this, &Session_component::_process_packets)
|
||||
{
|
||||
_tx.sigh_packet_avail(_process_packet_handler);
|
||||
_tx.sigh_ready_to_ack(_process_packet_handler);
|
||||
|
||||
_stats_reporter.enabled(report_stats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Session_component()
|
||||
{
|
||||
Dataspace_capability ds = tx_sink()->dataspace();
|
||||
_env.ram().free(static_cap_cast<Ram_dataspace>(ds));
|
||||
destroy(&_md_alloc, &_root);
|
||||
}
|
||||
|
||||
/***************************
|
||||
** File_system interface **
|
||||
***************************/
|
||||
|
||||
File_handle file(Dir_handle dir_handle, Name const &name, Mode mode, bool create)
|
||||
{
|
||||
if (!valid_name(name.string()))
|
||||
throw Invalid_name();
|
||||
|
||||
auto file_fn = [&] (Open_node &open_node) {
|
||||
|
||||
Node &dir = open_node.node();
|
||||
|
||||
if (!_writable) {
|
||||
if (create || (mode != STAT_ONLY && mode != READ_ONLY)) {
|
||||
throw Permission_denied();
|
||||
}
|
||||
}
|
||||
|
||||
/* should already contain _root_dir */
|
||||
Absolute_path absolute_path(dir.name());
|
||||
|
||||
try {
|
||||
absolute_path.append("/");
|
||||
absolute_path.append(name.string());
|
||||
} catch (Path_base::Path_too_long) {
|
||||
throw Invalid_name();
|
||||
}
|
||||
|
||||
File *file = new (&_md_alloc) File(absolute_path.base(),
|
||||
mode, create);
|
||||
|
||||
Open_node *open_file =
|
||||
new (&_md_alloc) Open_node(*file, _open_node_registry);
|
||||
|
||||
return open_file->id();
|
||||
};
|
||||
|
||||
try {
|
||||
return File_handle {
|
||||
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
|
||||
};
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
}
|
||||
|
||||
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
|
||||
{
|
||||
if (!valid_name(name.string())) { throw Invalid_name(); }
|
||||
|
||||
auto file_fn = [&] (Open_node &open_node) {
|
||||
|
||||
Node &dir = open_node.node();
|
||||
|
||||
if (!_writable && create) { throw Permission_denied(); }
|
||||
|
||||
Absolute_path absolute_path(_root.name());
|
||||
|
||||
try {
|
||||
absolute_path.append(dir.name());
|
||||
absolute_path.append("/");
|
||||
absolute_path.append(name.string());
|
||||
} catch (Path_base::Path_too_long) {
|
||||
throw Invalid_name();
|
||||
}
|
||||
|
||||
Symlink *link = new (&_md_alloc) Symlink(absolute_path.base(), create);
|
||||
|
||||
Open_node *open_file =
|
||||
new (&_md_alloc) Open_node(*link, _open_node_registry);
|
||||
|
||||
return open_file->id();
|
||||
};
|
||||
|
||||
try {
|
||||
return Symlink_handle {
|
||||
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
|
||||
};
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
}
|
||||
|
||||
Dir_handle dir(Path const &path, bool create)
|
||||
{
|
||||
char const *path_str = path.string();
|
||||
_assert_valid_path(path_str);
|
||||
|
||||
/* skip leading '/' */
|
||||
path_str++;
|
||||
|
||||
if (!_writable && create)
|
||||
throw Permission_denied();
|
||||
|
||||
if (!path.valid_string())
|
||||
throw Name_too_long();
|
||||
|
||||
Absolute_path absolute_path(_root.name());
|
||||
|
||||
try {
|
||||
absolute_path.append(path_str);
|
||||
absolute_path.remove_trailing('/');
|
||||
} catch (Path_base::Path_too_long) {
|
||||
throw Name_too_long();
|
||||
}
|
||||
|
||||
Directory *dir = new (&_md_alloc) Directory(absolute_path.base(), create);
|
||||
|
||||
Open_node *open_dir =
|
||||
new (_md_alloc) Open_node(*dir, _open_node_registry);
|
||||
|
||||
return Dir_handle { open_dir->id().value };
|
||||
}
|
||||
|
||||
Node_handle node(Path const &path)
|
||||
{
|
||||
char const *path_str = path.string();
|
||||
|
||||
_assert_valid_path(path_str);
|
||||
|
||||
Absolute_path absolute_path(_root.name());
|
||||
|
||||
try {
|
||||
absolute_path.append(path.string());
|
||||
absolute_path.remove_trailing('/');
|
||||
} catch (Path_base::Path_too_long) {
|
||||
throw Lookup_failed();
|
||||
}
|
||||
|
||||
try {
|
||||
Node *node = new (&_md_alloc) Node(absolute_path.base());
|
||||
|
||||
Open_node *open_node =
|
||||
new (_md_alloc) Open_node(*node, _open_node_registry);
|
||||
|
||||
return open_node->id();
|
||||
} catch (...) { throw; }
|
||||
}
|
||||
|
||||
void close(Node_handle handle)
|
||||
{
|
||||
auto close_fn = [&] (Open_node &open_node) {
|
||||
|
||||
try {
|
||||
Absolute_path absolute_path(_root.name());
|
||||
absolute_path.append(open_node.node().name());
|
||||
} catch (Path_base::Path_too_long) { }
|
||||
Node &node = open_node.node();
|
||||
destroy(_md_alloc, &open_node);
|
||||
destroy(_md_alloc, &node);
|
||||
};
|
||||
|
||||
try {
|
||||
_open_node_registry.apply<Open_node>(handle, close_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
}
|
||||
|
||||
Status status(Node_handle node_handle)
|
||||
{
|
||||
auto status_fn = [&] (Open_node &open_node) {
|
||||
return open_node.node().status();
|
||||
};
|
||||
|
||||
try {
|
||||
return _open_node_registry.apply<Open_node>(node_handle, status_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
}
|
||||
|
||||
void control(Node_handle, Control) override { }
|
||||
|
||||
void unlink(Dir_handle dir_handle, Name const &name)
|
||||
{
|
||||
if (!valid_name(name.string()))
|
||||
throw Invalid_name();
|
||||
|
||||
if (!_writable)
|
||||
throw Permission_denied();
|
||||
|
||||
auto unlink_fn = [&] (Open_node &open_node) {
|
||||
|
||||
Absolute_path absolute_path(_root.name());
|
||||
|
||||
try {
|
||||
absolute_path.append(open_node.node().name());
|
||||
absolute_path.append("/");
|
||||
absolute_path.append(name.string());
|
||||
} catch (Path_base::Path_too_long) {
|
||||
throw Invalid_name();
|
||||
}
|
||||
|
||||
/* XXX do not call ext4_ functions directly */
|
||||
{
|
||||
struct ext4_inode _inode;
|
||||
unsigned int _ino;
|
||||
int err = ext4_raw_inode_fill(absolute_path.base(), &_ino, &_inode);
|
||||
/* silent error because the look up is allowed to fail */
|
||||
if (err) { throw Lookup_failed(); }
|
||||
|
||||
unsigned int const v = _inode.mode & 0xf000;
|
||||
switch (v) {
|
||||
case EXT4_INODE_MODE_DIRECTORY:
|
||||
err = ext4_dir_rm(absolute_path.base());
|
||||
break;
|
||||
case EXT4_INODE_MODE_FILE:
|
||||
default:
|
||||
err = ext4_fremove(absolute_path.base());
|
||||
break;
|
||||
}
|
||||
if (err) {
|
||||
Genode::error("unlink: error: ", err);
|
||||
throw Invalid_name();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
}
|
||||
|
||||
void truncate(File_handle file_handle, file_size_t size)
|
||||
{
|
||||
if (!_writable)
|
||||
throw Permission_denied();
|
||||
|
||||
auto truncate_fn = [&] (Open_node &open_node) {
|
||||
open_node.node().truncate(size);
|
||||
};
|
||||
|
||||
try {
|
||||
_open_node_registry.apply<Open_node>(file_handle, truncate_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
}
|
||||
|
||||
void move(Dir_handle from_dir_handle, Name const &from_name,
|
||||
Dir_handle to_dir_handle, Name const &to_name)
|
||||
{
|
||||
if (!_writable) { throw Permission_denied(); }
|
||||
|
||||
auto move_fn = [&] (Open_node &open_from_dir_node) {
|
||||
|
||||
auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
|
||||
|
||||
Node &from_dir = open_from_dir_node.node();
|
||||
Node &to_dir = open_to_dir_node.node();
|
||||
|
||||
char const *from_str = from_name.string();
|
||||
char const *to_str = to_name.string();
|
||||
|
||||
Absolute_path absolute_from_path(_root.name());
|
||||
Absolute_path absolute_to_path(_root.name());
|
||||
|
||||
try {
|
||||
absolute_from_path.append(from_dir.name());
|
||||
absolute_from_path.append("/");
|
||||
absolute_from_path.append(from_name.string());
|
||||
absolute_to_path.append(to_dir.name());
|
||||
absolute_to_path.append("/");
|
||||
absolute_to_path.append(to_name.string());
|
||||
} catch (Path_base::Path_too_long) {
|
||||
throw Invalid_name();
|
||||
}
|
||||
|
||||
char const *from_base = absolute_from_path.base();
|
||||
char const *to_base = absolute_to_path.base();
|
||||
|
||||
if (!(valid_name(from_str) && valid_name(to_str)))
|
||||
throw Lookup_failed();
|
||||
|
||||
/* lwext4 will complain if target and source are the same */
|
||||
int const err = ext4_frename(from_base, to_base);
|
||||
if (err && err != EEXIST) {
|
||||
Genode::error("move: error: ", err);
|
||||
throw Permission_denied();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
_open_node_registry.apply<Open_node>(to_dir_handle, inner_move_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
|
||||
} catch (Id_space<File_system::Node>::Unknown_id const &) {
|
||||
throw Invalid_handle();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Lwext4_fs::Root : public Root_component<Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Env &_env;
|
||||
|
||||
int _sessions { 0 };
|
||||
|
||||
bool _report_stats { false };
|
||||
bool _verbose { false };
|
||||
|
||||
Genode::Attached_rom_dataspace _config_rom { _env, "config" };
|
||||
|
||||
Genode::Signal_handler<Lwext4_fs::Root> _config_sigh {
|
||||
_env.ep(), *this, &Lwext4_fs::Root::_handle_config_update };
|
||||
|
||||
void _handle_config_update()
|
||||
{
|
||||
_config_rom.update();
|
||||
|
||||
if (!_config_rom.valid()) { return; }
|
||||
|
||||
Genode::Xml_node config = _config_rom.xml();
|
||||
|
||||
_verbose = config.attribute_value("verbose", false);
|
||||
|
||||
try {
|
||||
_report_stats = config.sub_node("report")
|
||||
.attribute_value("stats", false);
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
if (!_config_rom.valid()) {
|
||||
Genode::error("no valid config found");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/*
|
||||
* Determine client-specific policy defined implicitly by
|
||||
* the client's label.
|
||||
*/
|
||||
|
||||
Genode::Path<MAX_PATH_LEN> session_root;
|
||||
bool writeable = false;
|
||||
|
||||
Session_label const label = label_from_args(args);
|
||||
|
||||
size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota").aligned_size();
|
||||
size_t tx_buf_size =
|
||||
Arg_string::find_arg(args, "tx_buf_size").aligned_size();
|
||||
|
||||
if (!tx_buf_size)
|
||||
throw Service_denied();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for session data,
|
||||
* and communication buffer.
|
||||
*/
|
||||
|
||||
size_t const session_size =
|
||||
max((size_t)4096, sizeof(Session_component)) +
|
||||
tx_buf_size;
|
||||
|
||||
if (session_size > ram_quota) {
|
||||
Genode::error("insufficient 'ram_quota' from ", label.string(),
|
||||
" got ", ram_quota, "need ", session_size);
|
||||
throw Insufficient_ram_quota();
|
||||
}
|
||||
ram_quota -= session_size;
|
||||
|
||||
char tmp[MAX_PATH_LEN];
|
||||
try {
|
||||
Session_policy policy(label, _config_rom.xml());
|
||||
|
||||
/* determine policy root offset */
|
||||
try {
|
||||
policy.attribute("root").value(tmp, sizeof(tmp));
|
||||
session_root.import(tmp, "/mnt");
|
||||
} catch (Xml_node::Nonexistent_attribute) { }
|
||||
|
||||
/*
|
||||
* Determine if the session is writeable.
|
||||
* Policy overrides client argument, both default to false.
|
||||
*/
|
||||
if (policy.attribute_value("writeable", false))
|
||||
writeable = Arg_string::find_arg(args, "writeable").bool_value(false);
|
||||
}
|
||||
catch (Session_policy::No_policy_defined) { throw Service_denied(); }
|
||||
|
||||
/* apply client's root offset */
|
||||
Arg_string::find_arg(args, "root").string(tmp, sizeof(tmp), "/");
|
||||
if (Genode::strcmp("/", tmp, sizeof(tmp))) {
|
||||
session_root.append("/");
|
||||
session_root.append(tmp);
|
||||
}
|
||||
session_root.remove_trailing('/');
|
||||
|
||||
char const *root_dir = session_root.base();
|
||||
|
||||
try {
|
||||
if (++_sessions == 1) {
|
||||
File_system::mount_fs(_config_rom.xml());
|
||||
}
|
||||
} catch (...) { throw Service_denied(); }
|
||||
|
||||
try {
|
||||
return new (md_alloc())
|
||||
Session_component(_env, tx_buf_size, root_dir, writeable, *md_alloc(),
|
||||
_report_stats);
|
||||
|
||||
} catch (Lookup_failed) {
|
||||
Genode::error("File system root directory \"", root_dir, "\" does not exist");
|
||||
throw Service_denied();
|
||||
}
|
||||
}
|
||||
|
||||
void _destroy_session(Session_component *session)
|
||||
{
|
||||
Genode::destroy(md_alloc(), session);
|
||||
|
||||
try {
|
||||
if (--_sessions == 0) { File_system::unmount_fs(); }
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Root(Genode::Env &env, Allocator &md_alloc)
|
||||
:
|
||||
Root_component<Session_component>(env.ep(), md_alloc),
|
||||
_env(env)
|
||||
{
|
||||
_config_rom.sigh(_config_sigh);
|
||||
_handle_config_update();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Lwext4_fs::Main
|
||||
{
|
||||
Genode::Env &_env;
|
||||
|
||||
Heap _heap { _env.ram(), _env.rm() };
|
||||
|
||||
Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
|
||||
|
||||
Root fs_root { _env, _sliced_heap };
|
||||
|
||||
Main(Genode::Env &env) : _env(env)
|
||||
{
|
||||
Lwext4::malloc_init(_env, _heap);
|
||||
|
||||
ext4_blockdev *bd = Lwext4::block_init(_env, _heap);
|
||||
File_system::init(bd);
|
||||
|
||||
env.parent().announce(env.ep().manage(fs_root));
|
||||
Genode::log("--- lwext4 started ---");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
env.exec_static_constructors();
|
||||
|
||||
static Lwext4_fs::Main inst(env);
|
||||
}
|
||||
110
src/server/lwext4_fs/node.h
Normal file
110
src/server/lwext4_fs/node.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* \brief Lwext4 file system node
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-08-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _NODE_H_
|
||||
#define _NODE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
#include <file_system/node.h>
|
||||
#include <os/path.h>
|
||||
|
||||
/* lwext4 includes */
|
||||
#include <ext4.h>
|
||||
#include <ext4_inode.h>
|
||||
|
||||
|
||||
namespace Lwext4_fs {
|
||||
using namespace File_system;
|
||||
|
||||
typedef Genode::Path<2047 + 1> Absolute_path;
|
||||
|
||||
class Node;
|
||||
}
|
||||
|
||||
#define NODE_DEBUG_MSG() \
|
||||
Genode::error(__func__, " called on generic Node object")
|
||||
|
||||
class Lwext4_fs::Node : public Node_base
|
||||
{
|
||||
protected:
|
||||
|
||||
struct ext4_inode _inode;
|
||||
unsigned int _ino;
|
||||
|
||||
Absolute_path _name;
|
||||
|
||||
public:
|
||||
|
||||
struct Eof : Genode::Exception { };
|
||||
|
||||
Node(char const *name, bool create = false) : _name(name)
|
||||
{
|
||||
if (!create) {
|
||||
int const err = ext4_raw_inode_fill(_name.base(), &_ino, &_inode);
|
||||
/* silent error because the look up is allowed to fail */
|
||||
if (err) { throw Lookup_failed(); }
|
||||
}
|
||||
}
|
||||
|
||||
virtual Status status()
|
||||
{
|
||||
int err = ext4_raw_inode_fill(_name.base(), &_ino, &_inode);
|
||||
if (err) {
|
||||
Genode::error(__func__, " ext4_raw_inode_fill: error: ", err);
|
||||
throw Lookup_failed();
|
||||
}
|
||||
|
||||
struct ext4_sblock *sb;
|
||||
err = ext4_get_sblock(_name.base(), &sb);
|
||||
if (err) {
|
||||
Genode::error(__func__, " ext4_get_sblock: error: ", err);
|
||||
throw Lookup_failed();
|
||||
}
|
||||
|
||||
Status status;
|
||||
status.size = ext4_inode_get_size(sb, &_inode);
|
||||
status.inode = _ino;
|
||||
|
||||
unsigned int const v = ext4_inode_get_mode(sb, &_inode) & 0xf000;
|
||||
|
||||
switch (v) {
|
||||
case EXT4_INODE_MODE_DIRECTORY: status.mode = Status::MODE_DIRECTORY; break;
|
||||
case EXT4_INODE_MODE_SOFTLINK: status.mode = Status::MODE_SYMLINK; break;
|
||||
case EXT4_INODE_MODE_FILE:
|
||||
default: status.mode = Status::MODE_FILE; break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
char const *name() { return _name.base(); }
|
||||
|
||||
virtual size_t read(char *, size_t, seek_off_t)
|
||||
{
|
||||
NODE_DEBUG_MSG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual size_t write(char const *, size_t, seek_off_t)
|
||||
{
|
||||
NODE_DEBUG_MSG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void truncate(file_size_t) { NODE_DEBUG_MSG(); }
|
||||
};
|
||||
|
||||
#undef NODE_DEBUG_MSG
|
||||
|
||||
#endif /* _NODE_H_ */
|
||||
95
src/server/lwext4_fs/open_node.h
Normal file
95
src/server/lwext4_fs/open_node.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* \brief Representation of an open file system node within the component (deprecated)
|
||||
* \author Christian Prochaska
|
||||
* \date 2017-06-09
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _OPEN_NODE_H_
|
||||
#define _OPEN_NODE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <file_system/listener.h>
|
||||
#include <file_system_session/file_system_session.h>
|
||||
|
||||
namespace File_system {
|
||||
/*
|
||||
* \param NODE component-specific node type
|
||||
*/
|
||||
template <typename NODE> class Open_node;
|
||||
}
|
||||
|
||||
template <typename NODE>
|
||||
class File_system::Open_node : public File_system::Node
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Id_space<File_system::Node>::Element _element;
|
||||
|
||||
NODE &_node;
|
||||
Genode::Constructible<File_system::Listener> _listener;
|
||||
|
||||
Listener::Version const _version_when_opened = _node.curr_version();
|
||||
|
||||
/*
|
||||
* Flag to track whether the underlying file-system node was
|
||||
* modified via this 'Open_node'. That is, if closing the 'Open_node'
|
||||
* should notify listeners of the file.
|
||||
*/
|
||||
bool _was_written = false;
|
||||
|
||||
public:
|
||||
|
||||
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space)
|
||||
: _element(*this, id_space), _node(node) { }
|
||||
|
||||
~Open_node()
|
||||
{
|
||||
if (_listener.constructed()) {
|
||||
_node.remove_listener(&*_listener);
|
||||
_listener.destruct();
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify remaining listeners about the changed file
|
||||
*/
|
||||
if (_was_written)
|
||||
_node.notify_listeners();
|
||||
}
|
||||
|
||||
NODE &node() { return _node; }
|
||||
File_system::Listener &listener() { return *_listener; }
|
||||
|
||||
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
|
||||
|
||||
/**
|
||||
* Register packet stream sink to be notified of node changes
|
||||
*/
|
||||
void register_notify(File_system::Sink &sink)
|
||||
{
|
||||
/*
|
||||
* If there was already a handler registered for the node,
|
||||
* remove the old handler.
|
||||
*/
|
||||
if (_listener.constructed()) {
|
||||
_node.remove_listener(&*_listener);
|
||||
_listener.destruct();
|
||||
}
|
||||
|
||||
/*
|
||||
* Register new handler
|
||||
*/
|
||||
_listener.construct(sink, id(), _version_when_opened);
|
||||
_node.add_listener(&*_listener);
|
||||
}
|
||||
|
||||
void mark_as_written() { _was_written = true; }
|
||||
};
|
||||
|
||||
#endif /* _OPEN_NODE_H_ */
|
||||
55
src/server/lwext4_fs/symlink.h
Normal file
55
src/server/lwext4_fs/symlink.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* \brief Lwext4 file system symlink node
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-08-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SYMLINK_H_
|
||||
#define _SYMLINK_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <file_system/util.h>
|
||||
#include <os/path.h>
|
||||
|
||||
/* lwext4 includes */
|
||||
#include <ext4.h>
|
||||
|
||||
/* local includes */
|
||||
#include <node.h>
|
||||
|
||||
namespace Lwext4_fs {
|
||||
class Symlink;
|
||||
}
|
||||
|
||||
class Lwext4_fs::Symlink : public Node
|
||||
{
|
||||
public:
|
||||
|
||||
Symlink(char const *name, bool create) : Node(name, create) { }
|
||||
|
||||
size_t write(char const *src, size_t len, seek_off_t) override
|
||||
{
|
||||
/* src may not be null-terminated */
|
||||
Genode::String<MAX_PATH_LEN> target(Genode::Cstring(src, len));
|
||||
|
||||
int const err = ext4_fsymlink(target.string(), Node::name());
|
||||
/* on success return len to make _process_packet happy */
|
||||
return err == -1 ? 0 : len;
|
||||
}
|
||||
|
||||
size_t read(char *dst, size_t len, seek_off_t) override
|
||||
{
|
||||
size_t bytes = 0;
|
||||
int const err = ext4_readlink(Node::name(), dst, len, &bytes);
|
||||
return err == -1 ? 0 : bytes;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SYMLINK_H_ */
|
||||
12
src/server/lwext4_fs/target.mk
Normal file
12
src/server/lwext4_fs/target.mk
Normal file
@@ -0,0 +1,12 @@
|
||||
TARGET = lwext4_fs
|
||||
SRC_CC = main.cc file_system.cc
|
||||
LIBS = base lwext4
|
||||
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
||||
CC_OPT += -DCONFIG_USE_DEFAULT_CFG=1
|
||||
CC_OPT += -DCONFIG_HAVE_OWN_ERRNO=1
|
||||
CC_OPT += -DCONFIG_HAVE_OWN_ASSERT=1
|
||||
CC_OPT += -DCONFIG_BLOCK_DEV_CACHE_SIZE=256
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
Reference in New Issue
Block a user