#pragma once #include "gp/containers/array.hpp" #include #include // TODO: File locking and fsync/fdatasync namespace gp { /** * @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) {} }; }