|
|
@ -0,0 +1,446 @@ |
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "gp/array.hpp"
|
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
// TODO: File locking and fsync/fdatasync
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief this enum represents the types of operations available |
|
|
|
*/ |
|
|
|
enum class operation_type { |
|
|
|
version, ///< this operation queries properties of the filesystem
|
|
|
|
flush, ///< flushes any buffer for writing on the filesystem
|
|
|
|
attach, ///< adds a filesystem to the system
|
|
|
|
detach, ///< remove a filesystem from the system
|
|
|
|
walk, ///< change the current directory
|
|
|
|
create, ///< creates a file
|
|
|
|
open, ///< opens a file, yielding a fid
|
|
|
|
read, ///< reads from a file
|
|
|
|
write, ///< writes to a file
|
|
|
|
clunk, ///< relinquishes a fid
|
|
|
|
remove, ///< removes a file
|
|
|
|
stat, ///< reads a file metadata
|
|
|
|
wstat ///< writes a file metadata
|
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief this enum represent the type of file handled |
|
|
|
*/ |
|
|
|
enum class file_type { |
|
|
|
directory, ///< the file is a normal directory
|
|
|
|
master_directory, ///< the file is the root directory of a non-root filesystem
|
|
|
|
device_directory, ///< the file is a driver mapped to a directory
|
|
|
|
root_directory, ///< the file is the root directory
|
|
|
|
file, ///< the file is a normal file
|
|
|
|
file_device, ///< the file is a driver mapped to a file
|
|
|
|
message_pipe ///< the file is a channel to read and write messages to
|
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief represents file permissions |
|
|
|
*/ |
|
|
|
struct permission_list { |
|
|
|
bool |
|
|
|
read : 1, |
|
|
|
write : 1, |
|
|
|
execute : 1; |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief represents all levels of permissions in a file |
|
|
|
*/ |
|
|
|
struct file_permissions { |
|
|
|
permission_list |
|
|
|
user, ///< list of permissions for the owner
|
|
|
|
group, ///< list of permissions for the owning group
|
|
|
|
others; ///< list of permissions for other users
|
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief represent a value that should be unique for every entity of the system |
|
|
|
*/ |
|
|
|
using unique_node = uint64_t; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief represent a timestamp in seconds |
|
|
|
*/ |
|
|
|
using timestamp = uint64_t; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief represent a value that represent an offset into a file |
|
|
|
*/ |
|
|
|
using file_offset = uint64_t; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief the expected return type of a stat query, as well as its writing counterpart |
|
|
|
*/ |
|
|
|
struct f_stats { |
|
|
|
file_type type; ///< the type of file
|
|
|
|
unique_node file_id; ///< the unique file id
|
|
|
|
unique_node owner_user_id; ///< the user id of the owner of the file
|
|
|
|
unique_node owner_group_id; ///< the group id of the file
|
|
|
|
unique_node last_modifier_id; ///< the user id of the last user that wrote data to the file
|
|
|
|
timestamp last_access; ///< the timestamp for the last time the file was opened or created. If the current user is not root, it is replaced by the system on wstat
|
|
|
|
timestamp last_modification; ///< the last modification timestamp. If the current user is not root, it is replaced by the system on wstat
|
|
|
|
file_offset file_size; ///< the filesize in bytes
|
|
|
|
gp::array<char, 255> filename; ///< the filename, padded with null characters
|
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Represent an IO operation as sent to the system, this is an abstract class. |
|
|
|
*/ |
|
|
|
struct io_operation { |
|
|
|
const operation_type type; ///< the discriminant for the operation type
|
|
|
|
protected: |
|
|
|
io_operation(operation_type a) : type(a) {} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation obtains the version of the targeted filesystem |
|
|
|
*/ |
|
|
|
struct version_operation : public io_operation { |
|
|
|
const gp::buffer<char> destination; ///< the destination where the data is written
|
|
|
|
const gp::buffer<char> root_path; ///< the path of the file system to query for version
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new version operation object |
|
|
|
* |
|
|
|
* @param dest the destination where the data is written |
|
|
|
* @param path the path to the target filesystem |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
version_operation( |
|
|
|
gp::buffer<char> dest, |
|
|
|
gp::buffer<char> path, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::version} |
|
|
|
, destination(dest) |
|
|
|
, root_path(path) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation flushes a filesystem, writing the data to the associated medium |
|
|
|
*/ |
|
|
|
struct flush_operation : public io_operation { |
|
|
|
const gp::buffer<char> root_path; ///< the path that is going to be flushed
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new flush operation object |
|
|
|
* |
|
|
|
* @param path the path to a file or to a master directory that is to be flushed |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
flush_operation( |
|
|
|
gp::buffer<char> path, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::flush} |
|
|
|
, root_path(path) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation mounts a filesystem given a format and a configuration data. |
|
|
|
* |
|
|
|
* It also mounts devices. |
|
|
|
*/ |
|
|
|
struct attach_operation : public io_operation { |
|
|
|
const gp::buffer<char> target_path; ///< location where the filesystem is going to be attached
|
|
|
|
const gp::buffer<char> format; ///< format string of the filesystem
|
|
|
|
const gp::buffer<char> configuration; ///< configuration data
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new attach operation object |
|
|
|
* |
|
|
|
* @param path path where the filesystem will be attached, must be either not existing or an empty directory |
|
|
|
* @param v_format the format name that will be invoked with the config |
|
|
|
* @param config the configuration to send |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
attach_operation( |
|
|
|
gp::buffer<char> path, |
|
|
|
gp::buffer<char> v_format, |
|
|
|
gp::buffer<char> config, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::attach} |
|
|
|
, target_path(path) |
|
|
|
, format(v_format) |
|
|
|
, configuration(config) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation removes the master status of a directory and dismounts the |
|
|
|
* filesystem attached to it after flushing it. Will fail if any file is still attached |
|
|
|
* in the filesystem. |
|
|
|
* |
|
|
|
* This applies to the devices too. |
|
|
|
*/ |
|
|
|
struct detach_operation : public io_operation { |
|
|
|
const gp::buffer<char> target_path; ///< the target master directory
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new detach operation object |
|
|
|
* |
|
|
|
* @param path the item to be detached |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
detach_operation( |
|
|
|
gp::buffer<char> path, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::attach} |
|
|
|
, target_path(path) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation will move the focus of the target directory relative to itself or absolutely |
|
|
|
*/ |
|
|
|
struct walk_operation : public io_operation { |
|
|
|
const gp::buffer<char> target_path; ///< the target to move to
|
|
|
|
const gp_config::file_descriptor_t fd_to_alter; ///< the fd that will be modified
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new walk operation object |
|
|
|
* |
|
|
|
* @param path the target to move to |
|
|
|
* @param dir the original file descriptor |
|
|
|
*/ |
|
|
|
walk_operation( |
|
|
|
gp::buffer<char> path, |
|
|
|
gp_config::file_descriptor_t dir |
|
|
|
) |
|
|
|
: io_operation{operation_type::walk} |
|
|
|
, target_path(path) |
|
|
|
, fd_to_alter(dir) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief selector for the type of file to be created in a given environment |
|
|
|
*/ |
|
|
|
enum class create_type { |
|
|
|
file, ///< normal file
|
|
|
|
directory, ///< directory file
|
|
|
|
temporary, ///< file which is to be remove upon all of his descriptors being closed
|
|
|
|
pipe_read_side, ///< pipe, read side returned
|
|
|
|
pipe_write_side ///< pipe, write side returned
|
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation will attempt to create a file at the specified destination |
|
|
|
*/ |
|
|
|
struct create_operation : public io_operation { |
|
|
|
const gp::buffer<char> target_path; |
|
|
|
const create_type mode; |
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Create a new create operation object |
|
|
|
* |
|
|
|
* @param path the new file that is created |
|
|
|
* @param v_mode the type of file to create |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
create_operation( |
|
|
|
gp::buffer<char> path, |
|
|
|
create_type v_mode, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::create} |
|
|
|
, target_path(path) |
|
|
|
, mode(v_mode) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief selector for the properties expected from an opened file descriptor |
|
|
|
*/ |
|
|
|
enum class open_mode { |
|
|
|
read_only, ///< the descriptor will be read only, will fail if no read permissions
|
|
|
|
read_write, ///< the descriptor is read-write, will fail if no write permissions, but not if no read permissions
|
|
|
|
read_write_create ///< the descriptor is read-write, and has the same proterties as the read-write. The file will be created if it does not exist.
|
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation will attempt to open a file at the specified destination |
|
|
|
*/ |
|
|
|
struct open_operation : public io_operation { |
|
|
|
const gp::buffer<char> target_path; ///< the specified path
|
|
|
|
open_mode mode; ///< the openning mode
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new open operation object |
|
|
|
* |
|
|
|
* @param path the path where to open a file |
|
|
|
* @param v_mode the mode of opening |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
open_operation( |
|
|
|
gp::buffer<char> path, |
|
|
|
open_mode v_mode, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::create} |
|
|
|
, target_path(path) |
|
|
|
, mode(v_mode) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation will attempt to read a file into the destination starting at the specified offset in the file |
|
|
|
*/ |
|
|
|
struct read_operation : public io_operation { |
|
|
|
const gp_config::file_descriptor_t fd; ///< the file to read
|
|
|
|
const file_offset offset; ///< the offset to start reading at
|
|
|
|
const gp::buffer<char> destination; ///< the destination where to write the data
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new read operation object |
|
|
|
* |
|
|
|
* @param v_fd the descriptor to read |
|
|
|
* @param off the offset to read |
|
|
|
* @param v_destination the location where the data will be written |
|
|
|
*/ |
|
|
|
read_operation( |
|
|
|
gp_config::file_descriptor_t v_fd, |
|
|
|
file_offset off, |
|
|
|
gp::buffer<char> v_destination |
|
|
|
) |
|
|
|
: io_operation{operation_type::read} |
|
|
|
, fd{v_fd} |
|
|
|
, offset(off) |
|
|
|
, destination(v_destination) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation will attempt to write in file from the source starting at the specified offset in the file |
|
|
|
*/ |
|
|
|
struct write_operation : public io_operation { |
|
|
|
const gp_config::file_descriptor_t fd; ///< the descriptor of the file where writing happens
|
|
|
|
const file_offset offset; ///< the offset in the file where writing starts
|
|
|
|
const gp::buffer<char> source; ///< the source data
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new write operation object |
|
|
|
* |
|
|
|
* @param v_fd the target file |
|
|
|
* @param off the target offset |
|
|
|
* @param v_source the data source buffer |
|
|
|
*/ |
|
|
|
write_operation( |
|
|
|
gp_config::file_descriptor_t v_fd, |
|
|
|
file_offset off, |
|
|
|
gp::buffer<char> v_source |
|
|
|
) |
|
|
|
: io_operation{operation_type::write} |
|
|
|
, fd{v_fd} |
|
|
|
, offset(off) |
|
|
|
, source(v_source) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation closes a file by relinquishing its file descriptor |
|
|
|
*/ |
|
|
|
struct clunk_operation : public io_operation { |
|
|
|
const gp_config::file_descriptor_t fd; ///< The descriptor that will be disposed of
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new clunk operation object |
|
|
|
* |
|
|
|
* @param v_fd the fd to close |
|
|
|
*/ |
|
|
|
clunk_operation(gp_config::file_descriptor_t v_fd) |
|
|
|
: io_operation{operation_type::clunk} |
|
|
|
, fd{v_fd} |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation removes a fileas soon as all its file descriptors are given back |
|
|
|
*/ |
|
|
|
struct remove_operation : public io_operation { |
|
|
|
const gp::buffer<char*> target_path; ///< the target file
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new remove operation object |
|
|
|
* |
|
|
|
* @param path the path to the file to remove |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
remove_operation( |
|
|
|
gp::buffer<char*> path, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::remove} |
|
|
|
, target_path(path) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation fetches metadata about a file |
|
|
|
*/ |
|
|
|
struct stat_operation : public io_operation { |
|
|
|
const gp::buffer<char*> target_path; ///< the file to query metadata about
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new stat operation object |
|
|
|
* |
|
|
|
* @param path the path to the file to query about |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
stat_operation( |
|
|
|
gp::buffer<char*> path, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::stat} |
|
|
|
, target_path(path) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief This operation writes metadata about a file |
|
|
|
*/ |
|
|
|
struct wstat_operation : public io_operation { |
|
|
|
const gp::buffer<char*> target_path; ///< the file to set metadata on
|
|
|
|
const gp::optional<gp_config::file_descriptor_t> fd; ///< the relative root to use
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Construct a new wstat operation object |
|
|
|
* |
|
|
|
* @param path the path to the file to write about |
|
|
|
* @param v_fd a relative root that is used |
|
|
|
*/ |
|
|
|
wstat_operation( |
|
|
|
gp::buffer<char*> path, |
|
|
|
gp::optional<gp_config::file_descriptor_t> v_fd |
|
|
|
) |
|
|
|
: io_operation{operation_type::wstat} |
|
|
|
, target_path(path) |
|
|
|
, fd(v_fd) |
|
|
|
{} |
|
|
|
}; |