genode/repos/gems/include/cbe/vfs/io_job.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

311 lines
6.7 KiB
C++

/*
* \brief Integration of the Consistent Block Encrypter (CBE)
* \author Martin Stein
* \author Josef Soentgen
* \date 2020-11-10
*/
/*
* Copyright (C) 2020 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 _CBE__VFS__IO_JOB_H_
#define _CBE__VFS__IO_JOB_H_
/* Genode includes */
#include <vfs/types.h>
#include <vfs/vfs_handle.h>
namespace Util {
using file_size = Vfs::file_size;
using file_offset = Vfs::file_offset;
using Byte_range_ptr = Vfs::Byte_range_ptr;
using Const_byte_range_ptr = Vfs::Const_byte_range_ptr;
using size_t = Genode::size_t;
struct Io_job
{
struct Buffer
{
char *base;
size_t size;
};
enum class Operation { INVALID, READ, WRITE, SYNC };
static char const *to_string(Operation op)
{
using Op = Operation;
switch (op) {
case Op::READ: return "READ";
case Op::WRITE: return "WRITE";
case Op::SYNC: return "SYNC";
default: return "INVALID";
}
}
struct Unsupported_Operation : Genode::Exception { };
struct Invalid_state : Genode::Exception { };
enum State { PENDING, IN_PROGRESS, COMPLETE, };
static State _initial_state(Operation const op)
{
using Op = Operation;
switch (op) {
case Op::READ: return State::PENDING;
case Op::WRITE: return State::PENDING;
case Op::SYNC: return State::PENDING;
default: throw Unsupported_Operation();
}
}
static char const *_state_to_string(State s)
{
switch (s) {
case State::PENDING: return "PENDING";
case State::IN_PROGRESS: return "IN_PROGRESS";
case State::COMPLETE: return "COMPLETE";
}
throw Invalid_state();
}
enum class Partial_result { ALLOW, DENY };
Vfs::Vfs_handle &_handle;
Operation const _op;
State _state;
char *_data;
file_offset const _base_offset;
file_offset _current_offset;
size_t _current_count;
bool const _allow_partial;
bool _success;
bool _complete;
bool _read()
{
bool progress = false;
switch (_state) {
case State::PENDING:
_handle.seek(_base_offset + _current_offset);
if (!_handle.fs().queue_read(&_handle, _current_count)) {
return progress;
}
_state = State::IN_PROGRESS;
progress = true;
[[fallthrough]];
case State::IN_PROGRESS:
{
using Result = Vfs::File_io_service::Read_result;
bool completed = false;
size_t out = 0;
Byte_range_ptr const dst { _data + _current_offset, _current_count };
Result const result = _handle.fs().complete_read(&_handle, dst, out);
if (result == Result::READ_QUEUED
|| result == Result::READ_ERR_WOULD_BLOCK) {
return progress;
} else
if (result == Result::READ_OK) {
_current_offset += out;
_current_count -= out;
_success = true;
} else
if ( result == Result::READ_ERR_IO
|| result == Result::READ_ERR_INVALID) {
_success = false;
completed = true;
}
if (_current_count == 0 || completed || (out == 0 && _allow_partial)) {
_state = State::COMPLETE;
} else {
_state = State::PENDING;
/* partial read, keep trying */
return true;
}
progress = true;
}
[[fallthrough]];
case State::COMPLETE:
_complete = true;
progress = true;
default: break;
}
return progress;
}
bool _write()
{
bool progress = false;
switch (_state) {
case State::PENDING:
_handle.seek(_base_offset + _current_offset);
_state = State::IN_PROGRESS;
progress = true;
[[fallthrough]];
case State::IN_PROGRESS:
{
using Result = Vfs::File_io_service::Write_result;
bool completed = false;
size_t out = 0;
Const_byte_range_ptr const src { _data + _current_offset, _current_count };
Result const result = _handle.fs().write(&_handle, src, out);
switch (result) {
case Result::WRITE_ERR_WOULD_BLOCK:
return progress;
case Result::WRITE_OK:
_current_offset += out;
_current_count -= out;
_success = true;
break;
case Result::WRITE_ERR_IO:
case Result::WRITE_ERR_INVALID:
_success = false;
completed = true;
break;
}
if (_current_count == 0 || completed || (out == 0 && _allow_partial)) {
_state = State::COMPLETE;
} else {
_state = State::PENDING;
/* partial write, keep trying */
return true;
}
progress = true;
}
[[fallthrough]];
case State::COMPLETE:
_complete = true;
progress = true;
default: break;
}
return progress;
}
bool _sync()
{
bool progress = false;
switch (_state) {
case State::PENDING:
if (!_handle.fs().queue_sync(&_handle)) {
return progress;
}
_state = State::IN_PROGRESS;
progress = true;
[[fallthrough]];
case State::IN_PROGRESS:
{
using Result = Vfs::File_io_service::Sync_result;
Result const result = _handle.fs().complete_sync(&_handle);
if (result == Result::SYNC_QUEUED) {
return progress;
} else
if (result == Result::SYNC_ERR_INVALID) {
_success = false;
} else
if (result == Result::SYNC_OK) {
_success = true;
}
_state = State::COMPLETE;
progress = true;
}
[[fallthrough]];
case State::COMPLETE:
_complete = true;
progress = true;
default: break;
}
return progress;
}
Io_job(Vfs::Vfs_handle &handle,
Operation op,
Buffer &buffer,
file_offset base_offset,
Partial_result partial_result = Partial_result::DENY)
:
_handle { handle },
_op { op },
_state { _initial_state(op) },
_data { buffer.base },
_base_offset { base_offset },
_current_offset { 0 },
_current_count { buffer.size },
_allow_partial { partial_result == Partial_result::ALLOW },
_success { false },
_complete { false }
{ }
bool completed() const { return _complete; }
bool succeeded() const { return _success; }
Operation op() const { return _op; }
void print(Genode::Output &out) const
{
Genode::print(out, "(", to_string(_op), ")",
" state: ", _state_to_string(_state),
" current_offset: ", _current_offset,
" current_count: ", _current_count,
" success: ", _success,
" complete: ", _complete);
}
bool execute()
{
using Op = Operation;
switch (_op) {
case Op::READ: return _read();
case Op::WRITE: return _write();
case Op::SYNC: return _sync();
default: return false;
}
}
Genode::size_t current_offset() const { return _current_offset; }
};
} /* namespace Util */
#endif /* _CBE__VFS__IO_JOB_H_ */