From 699c1fc8ae8134ded1b24a3fdb9958a409b78629 Mon Sep 17 00:00:00 2001 From: Edgaru089 Date: Thu, 28 Oct 2021 22:36:23 +0800 Subject: [PATCH] driver/filesystem: filesystem interface mostly from FUSE (https://github.com/libfuse/libfuse/blob/master/include/fuse.h) --- driver/filesystem/filesystem.hpp | 256 +++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 driver/filesystem/filesystem.hpp diff --git a/driver/filesystem/filesystem.hpp b/driver/filesystem/filesystem.hpp new file mode 100644 index 0000000..40567a5 --- /dev/null +++ b/driver/filesystem/filesystem.hpp @@ -0,0 +1,256 @@ +#pragma once + +#include "../../cppruntime/runtime.hpp" + +namespace helos { + + +// Filesystems are created per-mount. +// +// Paths always begin with "/". +// Functions return negative numbers on error. +class Filesystem { +public: + typedef uint16_t uid_t, gid_t; // User and group ID types + typedef uint16_t mode_t; // UNIX permission mode type + + enum OpenFlag { + O_APPEND = 1 << 0, // File opened in append mode + O_ASYNC = 1 << 1, // Enable signal-driver I/O + O_CREAT = 1 << 2, // Create the file if it does not exist + O_DIRECTORY = 1 << 3, // Fail if not a directory + O_DSYNC = 1 << 4, // Operation data synced on return + O_EXCL = 1 << 5, // Fail if the file exists in conjunction with O_CREAT + O_LARGEFILE = 1 << 6, // Allow use of off64_t + O_NOCTTY = 1 << 7, // Does not switch process's controlling terminal + O_NOFOLLOW = 1 << 8, // Does not follow symbolic link on the trailing component (basename) + O_NONBLOCK = 1 << 9, // Open file in nonblocking mode + O_SYNC = 1 << 10, // Writes synced by file on return + O_TRUNC = 1 << 11, // Thuncate existing file to size 0 if it exists + + O_RDONLY = 1 << 12, // Read-only + O_WRONLY = 1 << 13, // Write-only + O_RDWR = O_RDONLY | O_WRONLY, // Read and write + O_EXEC = 1 << 14, // Execute + }; + +public: + static constexpr char Seperator = '/'; + + // Error enums are positive, so use something like "return -EPERM;" + enum Error { + EPERM = 1, // Operation not permitted + ENOENT = 2, // No such file or directory + EAGAIN = 11, // Resource temporarily unavailable + EACCES = 13, // Permission denied + ENOTBLK = 15, // Blockdevice required + EBUSY = 16, // Device or resource busy + EEXIST = 17, // File exists + EXDEV = 18, // No such device + ENODEV = 19, // No such device + ENOTDIR = 20, // Not a directory + EISDIR = 21, // Is a directory + EINVAL = 22, // Invalid argument + ETXTBSY = 26, // Text file busy + EFBIG = 27, // File too large + ENOSPC = 28, // No space left on device + ESPIPE = 29, // Illegal seek + EROFS = 30, // Read-only file system + EMLINK = 31, // Too many links + EPIPE = 32, // Broken pipe + ENAMETOOLONG = 36, // File name too long + ENOLCK = 37, // No locks available + ENOSYS = 38, // Function not implemented + ENOTEMPTY = 39, // Directory not empty + ELOOP = 40, // Too many levels of symbolic links + EWOULDBLOCK = 11, // Resource temporarily unavailable (call would block) + + }; + // Configuration passed to New() from the kernel. + struct Config { + bool setgid, setuid; // If true, GID/UID of each file is overwritten with gid/uid. + gid_t gid; + uid_t uid; + + bool setfmask, setdmask; // If true, file/directory permissions are masked with the given values. + mode_t fmask, dmask; // (Corresponding bits cleared) + }; + + // Information on an open file. + struct OpenFile { + // File open flags. + OpenFlag flags; + + // Filled in by open(), to indicate the file is not seekable. + bool nonseekable : 1; + unsigned int padding : 31; + unsigned int padding2 : 32; + + // File handle. Filled in by Create(), Open(), Opendir(). + uint64_t handle; + }; + + enum RenameType { + Rename_Exchange, // Atomically swaps the 2 files if the target file exists. + Rename_NoReplace, // Return with error if the target file exists. + }; + + // POSIX file types + static constexpr mode_t S_IFMT = 0170000; // Bit mask for the file type bit field + static constexpr mode_t S_IFIFO = 0010000; // FIFO + static constexpr mode_t S_IFCHR = 0020000; // Character device + static constexpr mode_t S_IFDIR = 0040000; // Directory + static constexpr mode_t S_IFBLK = 0060000; // Block device + static constexpr mode_t S_IFREG = 0100000; // Regular file + static constexpr mode_t S_IFLNK = 0120000; // Symbolic link + static constexpr mode_t S_IFSOCK = 0140000; // Socket + + // File status + struct Stat { + mode_t Mode; // File type and mode + uint32_t NumLinks; // Number of hard links on the same file + uid_t Uid; // User ID of owner + gid_t Gid; // Group ID of owner + uint64_t Size; // Total size of file in bytes + uint64_t Blocks; // Number of 512Byte blocks allocated + uint64_t TimeAccess, TimeModification; // UNIX time of last access/modification + }; + + // New is called to create a new Filesystem instance from a given source. + // + // The source paramater is quite special. + // Beginning with "/" means a local file source (device or image). + // Beginning with a "//" means a network target (URL). + // Otherwise, this string is non-canonical and its behavior is implementation-depedent. + typedef Filesystem *(*New)(const char *source, Config *config); + +public: + // Filesystem implementation capabilitiy bits + enum Capability { + Capability_AtomicTruncate = 1 << 0, // supports O_TRUNC open flag. If disabled, kernel calls Truncate() and Open() on O_TRUNC. + Capability_Export = 1 << 1, // supports lookup of "." and "..". + Capability_NoOpen = 1 << 2, // does not use Open() (returning ENOSYS), using stateless file I/O + }; + + virtual Capability Capabilities() { return Capability_NoOpen; } + +public: + virtual ~Filesystem() {} + + // Getattr is similar to stat(), returning file status. + // + // file is NULL if the file is not opened, but may too be NULL + // if the file is opened. + virtual int Getattr(const char *path, Stat *stat, OpenFile *file) { return -ENOSYS; } + + // Readlink reads the target of a symbolic link. + // + // If the linkname is too long to fit in the target, it should be truncated, + // returning the required size of the new buffer. + // + // Returns 0 on success. + virtual int Readlink(const char *link, char *buffer, uint64_t bufferSize) { return -ENOSYS; } + + // Create a new file node (empty file), without opening it. + // + // This is called for non-directory, non-symlink nodes. + virtual int Mknod(const char *file, mode_t mode) { return -ENOSYS; } + + // Create a new directory. + // + // The mode argument might not have the S_IFDIR bits set. + virtual int Mkdir(const char *path, mode_t mode) { return -ENOSYS; } + + // Remove a file or node. + virtual int Unlink(const char *path) { return -ENOSYS; } + + // Remove an empty directory. + virtual int Rmdir(const char *path) { return -ENOSYS; } + + // Create a symbolic link. + virtual int Symlink(const char *target, const char *path) { return -ENOSYS; } + + // Rename (move) a file. + // + // The Type argument should be honored. + virtual int Rename(const char *from, const char *to, RenameType type) { return -ENOSYS; } + + // Create a hard link to file. + virtual int Link(const char *from, const char *to) { return -ENOSYS; } + + // Change the owner/group of a file. + // + // file is NULL if the file is not opened, but may too be NULL + // if the file is opened. + // + // This function is never called if setuid/gid bits are set. + virtual int Chown(const char *path, uid_t uid, gid_t gid, OpenFile *file) { return -ENOSYS; } + + // Change the permissions of a file. + // + // file is NULL if the file is not opened, but may too be NULL + // if the file is opened. + virtual int Chmod(const char *path, mode_t mode, OpenFile *file) { return -ENOSYS; } + + // Change the size of a file. + // + // file is NULL if the file is not opened, but may too be NULL + // if the file is opened. + virtual int Truncate(const char *path, uint64_t size, OpenFile *file) { return -ENOSYS; } + + // Opens a file, with flags in file->flags. + // + // - Creation flags (O_CREAT, O_EXCL, O_NOCTTY) are handled by the kernel and filtered out. + // - Access modes (O_RDONLY, O_WRONLY,O_RDWR,O_EXEC) should be checked if the operation is permitted. + // + // Driver may store arbitrary value in file->handle and other flags to change the way the file is opened. + virtual int Open(const char *path, OpenFile *file) { return -ENOSYS; } + + // Read data from an open file. + // + // Read should return exactly the number of bytes requested except + // on EOF or error, when the rest of the data will be zeroed. + virtual int Read(const char *path, char *buffer, uint64_t count, uint64_t offset, OpenFile *file) { return -ENOSYS; } + + // Write data to an open file. + // Read should return exactly the number of bytes requested except on error. + virtual int Write(const char *path, const char *buffer, uint64_t count, uint64_t offset, OpenFile *file) { return -ENOSYS; } + + // Syncs file data to disk. + // + // If syncOnlyUserData is true, sync only user data, not the metadata + virtual int Fsync(const char *path, bool syncOnlyUserData, OpenFile *file) { return -ENOSYS; } + + // Closes an open file. + // + // For each Open() call there is exactly one Close() call with the same file->flags/handle. + // It is possible that one same file has been opened several times. + virtual int Close(const char *path, OpenFile *file) { return -ENOSYS; } + + // Open a directory for reading. + // + // This function should check for permissions in file->flags. + virtual int Opendir(const char *path, OpenFile *file) { return -ENOSYS; } + + enum Readdir_CallbackFlags { + Readdir_CallbackFlags_StatValid = 1 << 0, // All stat members are valid + }; + // typedef of the callback Readdir() uses to emit directory entries + typedef int (*Readdir_Callback)(void *user, const char *name, const Stat *stat, Readdir_CallbackFlags flags); + + // Read an open directory. + // + // The implementation calls Callback() on all directory entries. + virtual int Readdir(const char *path, void *user, Readdir_Callback callback, OpenFile *file) { return -ENOSYS; } + + // Syncs the contents of a directory. + // + // If syncOnlyUserData is true, sync only user data, not the metadata + virtual int Fsyncdir(const char *path, bool syncOnlyUserData, OpenFile *file) { return -ENOSYS; } + + // Close an open directory. + virtual int Closedir(const char *path, OpenFile *file) { return -ENOSYS; } +}; + + +} // namespace helos