diff --git a/include/gp/vfs/io/io_future.hpp b/include/gp/vfs/io/io_future.hpp new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/include/gp/vfs/io/io_future.hpp @@ -0,0 +1,2 @@ +#pragma once + diff --git a/include/gp/vfs/io/io_operation.hpp b/include/gp/vfs/io/io_operation.hpp new file mode 100644 index 0000000..ca7d2e4 --- /dev/null +++ b/include/gp/vfs/io/io_operation.hpp @@ -0,0 +1,446 @@ +#pragma once + +#include "gp/array.hpp" + +#include +#include + +// 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 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 destination; ///< the destination where the data is written + const gp::buffer root_path; ///< the path of the file system to query for version + const gp::optional 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 dest, + gp::buffer path, + gp::optional 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 root_path; ///< the path that is going to be flushed + const gp::optional 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 path, + gp::optional 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 target_path; ///< location where the filesystem is going to be attached + const gp::buffer format; ///< format string of the filesystem + const gp::buffer configuration; ///< configuration data + const gp::optional 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 path, + gp::buffer v_format, + gp::buffer config, + gp::optional 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 target_path; ///< the target master directory + const gp::optional 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 path, + gp::optional 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 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 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 target_path; + const create_type mode; + const gp::optional 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 path, + create_type v_mode, + gp::optional 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 target_path; ///< the specified path + open_mode mode; ///< the openning mode + const gp::optional 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 path, + open_mode v_mode, + gp::optional 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 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 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 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 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 target_path; ///< the target file + const gp::optional 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 path, + gp::optional 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 target_path; ///< the file to query metadata about + const gp::optional 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 path, + gp::optional 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 target_path; ///< the file to set metadata on + const gp::optional 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 path, + gp::optional v_fd + ) + : io_operation{operation_type::wstat} + , target_path(path) + , fd(v_fd) + {} +}; \ No newline at end of file