genode/repos/os/include/vfs/single_file_system.h
Norman Feske bdf47785b8 vfs: remove 'file_size' from read/write interfaces
The 'file_size' type denotes the size of files on disk in bytes. On
32-bit architectures it is larger than the size_t, which refers to
in-memory object sizes.

Whereas the use of 'file_size' is appropriate for ftruncate and seek, it
is not a suitable type for the parameters of read/write operations
because those operations refer to in-memory buffers.

This patch replaces the use of 'file_size' by size_t. However, since it
affects all sites where the read/write interface is uses, it takes the
opportunity to replace the C-style (pointer, size) arguments by
'Byte_range_ptr' and 'Const_byte_range_ptr'.

Issue #4706
2023-02-27 08:22:49 +01:00

324 lines
7.3 KiB
C++

/*
* \brief File system that hosts a single node
* \author Norman Feske
* \date 2014-04-07
*/
/*
* Copyright (C) 2014-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 _INCLUDE__VFS__SINGLE_FILE_SYSTEM_H_
#define _INCLUDE__VFS__SINGLE_FILE_SYSTEM_H_
#include <vfs/file_system.h>
#include <vfs/vfs_handle.h>
namespace Vfs { class Single_file_system; }
class Vfs::Single_file_system : public File_system
{
private:
Node_type const _type;
Node_rwx const _rwx;
typedef String<64> Filename;
Filename _filename { };
protected:
struct Single_vfs_handle : Vfs_handle
{
using Vfs_handle::Vfs_handle;
virtual Read_result read(Byte_range_ptr const &, size_t &out_count) = 0;
virtual Write_result write(Const_byte_range_ptr const &, size_t &out_count) = 0;
virtual Sync_result sync()
{
return SYNC_OK;
}
virtual bool read_ready() const = 0;
virtual bool write_ready() const = 0;
virtual bool notify_read_ready() { return true; }
};
struct Single_vfs_dir_handle : Single_vfs_handle
{
private:
Node_type const _type;
Node_rwx const _rwx;
Filename const &_filename;
/*
* Noncopyable
*/
Single_vfs_dir_handle(Single_vfs_dir_handle const &);
Single_vfs_dir_handle &operator = (Single_vfs_dir_handle const &);
public:
Single_vfs_dir_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc,
Node_type type,
Node_rwx rwx,
Filename const &filename)
:
Single_vfs_handle(ds, fs, alloc, 0),
_type(type), _rwx(rwx), _filename(filename)
{ }
Read_result read(Byte_range_ptr const &dst, size_t &out_count) override
{
out_count = 0;
if (dst.num_bytes < sizeof(Dirent))
return READ_ERR_INVALID;
file_size index = seek() / sizeof(Dirent);
Dirent &out = *(Dirent*)dst.start;
auto dirent_type = [&] ()
{
switch (_type) {
case Node_type::DIRECTORY: return Dirent_type::DIRECTORY;
case Node_type::SYMLINK: return Dirent_type::SYMLINK;
case Node_type::CONTINUOUS_FILE: return Dirent_type::CONTINUOUS_FILE;
case Node_type::TRANSACTIONAL_FILE: return Dirent_type::TRANSACTIONAL_FILE;
}
return Dirent_type::END;
};
if (index == 0) {
out = {
.fileno = (Genode::addr_t)this,
.type = dirent_type(),
.rwx = _rwx,
.name = { _filename.string() }
};
} else {
out = {
.fileno = (Genode::addr_t)this,
.type = Dirent_type::END,
.rwx = { },
.name = { }
};
}
out_count = sizeof(Dirent);
return READ_OK;
}
Write_result write(Const_byte_range_ptr const &, size_t &) override
{
return WRITE_ERR_INVALID;
}
bool read_ready() const override { return true; }
bool write_ready() const override { return true; }
};
bool _root(const char *path)
{
return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
}
bool _single_file(const char *path)
{
return (strlen(path) == (strlen(_filename.string()) + 1)) &&
(strcmp(&path[1], _filename.string()) == 0);
}
public:
Single_file_system(Node_type node_type,
char const *type_name,
Node_rwx rwx,
Xml_node config)
:
_type(node_type), _rwx(rwx),
_filename(config.attribute_value("name", Filename(type_name)))
{ }
/*********************************
** Directory-service interface **
*********************************/
Dataspace_capability dataspace(char const *) override
{
return Dataspace_capability();
}
void release(char const *, Dataspace_capability) override { }
Stat_result stat(char const *path, Stat &out) override
{
out = Stat { };
out.device = (Genode::addr_t)this;
if (_root(path)) {
out.type = Node_type::DIRECTORY;
} else if (_single_file(path)) {
out.type = _type;
out.rwx = _rwx;
out.inode = 1;
} else {
return STAT_ERR_NO_ENTRY;
}
return STAT_OK;
}
file_size num_dirent(char const *path) override
{
if (_root(path))
return 1;
else
return 0;
}
bool directory(char const *path) override
{
if (_root(path))
return true;
return false;
}
char const *leaf_path(char const *path) override
{
return _single_file(path) ? path : 0;
}
Opendir_result opendir(char const *path, bool create,
Vfs_handle **out_handle,
Allocator &alloc) override
{
if (!_root(path))
return OPENDIR_ERR_LOOKUP_FAILED;
if (create)
return OPENDIR_ERR_PERMISSION_DENIED;
try {
*out_handle = new (alloc)
Single_vfs_dir_handle(*this, *this, alloc,
_type, _rwx, _filename);
return OPENDIR_OK;
}
catch (Genode::Out_of_ram) { return OPENDIR_ERR_OUT_OF_RAM; }
catch (Genode::Out_of_caps) { return OPENDIR_ERR_OUT_OF_CAPS; }
}
void close(Vfs_handle *handle) override
{
if (handle && (&handle->ds() == this))
destroy(handle->alloc(), handle);
}
Unlink_result unlink(char const *path) override
{
if (_single_file(path))
return UNLINK_ERR_NO_PERM;
return UNLINK_ERR_NO_ENTRY;
}
Rename_result rename(char const *from, char const *to) override
{
if (_single_file(from) || _single_file(to))
return RENAME_ERR_NO_PERM;
return RENAME_ERR_NO_ENTRY;
}
/********************************
** File I/O service interface **
********************************/
Read_result complete_read(Vfs_handle *vfs_handle, Byte_range_ptr const &dst,
size_t &out_count) override
{
Single_vfs_handle *handle =
static_cast<Single_vfs_handle*>(vfs_handle);
if (handle)
return handle->read(dst, out_count);
return READ_ERR_INVALID;
}
Write_result write(Vfs_handle *vfs_handle, Const_byte_range_ptr const &src,
size_t &out_count) override
{
Single_vfs_handle *handle =
static_cast<Single_vfs_handle*>(vfs_handle);
if (handle)
return handle->write(src, out_count);
return WRITE_ERR_INVALID;
}
bool read_ready(Vfs_handle const &vfs_handle) const override
{
Single_vfs_handle const &handle =
static_cast<Single_vfs_handle const &>(vfs_handle);
return handle.read_ready();
}
bool write_ready(Vfs_handle const &vfs_handle) const override
{
Single_vfs_handle const &handle =
static_cast<Single_vfs_handle const &>(vfs_handle);
return handle.write_ready();
}
bool notify_read_ready(Vfs_handle *vfs_handle) override
{
Single_vfs_handle *handle =
static_cast<Single_vfs_handle*>(vfs_handle);
if (handle)
return handle->notify_read_ready();
return false;
}
Ftruncate_result ftruncate(Vfs_handle *, file_size) override
{
return FTRUNCATE_ERR_NO_PERM;
}
Sync_result complete_sync(Vfs_handle *vfs_handle) override
{
Single_vfs_handle *handle =
static_cast<Single_vfs_handle*>(vfs_handle);
if (handle)
return handle->sync();
return SYNC_ERR_INVALID;
}
};
#endif /* _INCLUDE__VFS__SINGLE_FILE_SYSTEM_H_ */