From 850c1e2c86be92b6f9a6978afad0139c616d1dc7 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 5 Mar 2025 20:07:06 +0000 Subject: [PATCH 01/14] refactor: :construction: add initial FileDriver class --- include/system/dev/vfs.hpp | 34 ++++++++++++++++++++++++++++++++++ src/system/dev/vfs.c | 9 ++++----- 2 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 include/system/dev/vfs.hpp diff --git a/include/system/dev/vfs.hpp b/include/system/dev/vfs.hpp new file mode 100644 index 00000000..1eb88c30 --- /dev/null +++ b/include/system/dev/vfs.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace zest { + +class FileDescriptor { + public: + FileDescriptor(int fd) + : m_fd(fd) {} + + std::strong_ordering operator<=>(const FileDescriptor&) const = default; + + private: + int m_fd; +}; + +class FileDriver { + public: + virtual FileDescriptor open(const char* path, int flags, int mode) = 0; + virtual ssize_t read(void* const, uint8_t*, const size_t) = 0; + virtual int write(void* const, uint8_t*, const size_t) = 0; + virtual int close(void* const) = 0; + virtual int fstat(void* const, struct stat*) = 0; + virtual int isatty(void* const) = 0; + virtual off_t lseek(void* const, off_t, int) = 0; + virtual int ctl(void* const, const uint32_t, void* const) = 0; + virtual ~FileDriver() = default; +}; +} // namespace zest \ No newline at end of file diff --git a/src/system/dev/vfs.c b/src/system/dev/vfs.c index 4e38ab15..83a939e7 100644 --- a/src/system/dev/vfs.c +++ b/src/system/dev/vfs.c @@ -21,17 +21,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "system/dev/vfs.h" +#include +#include +#include #include "common/gid.h" #include "kapi.h" #include "system/dev/dev.h" #include "system/dev/ser.h" #include "system/dev/usd.h" - -#include -#include -#include +#include "system/dev/vfs.h" #define MAX_FILELEN 128 #define MAX_FILES_OPEN 31 From 20ebbda1eb6a022510a2db4bcfafe4178ffa1fae Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 14 Mar 2025 17:21:26 +0000 Subject: [PATCH 02/14] refactor: :fire: Remove references to dev driver --- include/system/dev/dev.h | 20 -------------------- src/system/dev/vfs.c | 3 --- 2 files changed, 23 deletions(-) delete mode 100644 include/system/dev/dev.h diff --git a/include/system/dev/dev.h b/include/system/dev/dev.h deleted file mode 100644 index 112effa5..00000000 --- a/include/system/dev/dev.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * \file system/dev/dev.h - * - * Generic Serial Device driver header - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#pragma once - -#include "vfs.h" - -extern const struct fs_driver* const dev_driver; -int dev_open_r(struct _reent* r, const char* path, int flags, int mode); -void dev_initialize(void); diff --git a/src/system/dev/vfs.c b/src/system/dev/vfs.c index 83a939e7..9c5149bb 100644 --- a/src/system/dev/vfs.c +++ b/src/system/dev/vfs.c @@ -27,7 +27,6 @@ #include "common/gid.h" #include "kapi.h" -#include "system/dev/dev.h" #include "system/dev/ser.h" #include "system/dev/usd.h" #include "system/dev/vfs.h" @@ -108,8 +107,6 @@ int _open(const char* file, int flags, int mode) { return ser_open_r(r, file + strlen("/ser"), flags, mode); } else if (strstr(file, "/usd") == file) { return usd_open_r(r, file + strlen("/usd"), flags, mode); - } else if (strstr(file, "/dev") == file) { - return dev_open_r(r, file + strlen("/dev"), flags, mode); } else { return usd_open_r(r, file, flags, mode); } From d8880de5fe90467a9410624bb32930951c426c0c Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 14 Mar 2025 17:26:02 +0000 Subject: [PATCH 03/14] refactor: :label: Use more idiomatic c++ types in vfs, add FileEntry --- include/system/dev/vfs.hpp | 47 ++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/include/system/dev/vfs.hpp b/include/system/dev/vfs.hpp index 1eb88c30..ba63dc98 100644 --- a/include/system/dev/vfs.hpp +++ b/include/system/dev/vfs.hpp @@ -1,34 +1,57 @@ #pragma once +#include #include #include #include +#include +#include +#include #include #include -namespace zest { +namespace zest::fs { class FileDescriptor { public: - FileDescriptor(int fd) + constexpr FileDescriptor(int fd) : m_fd(fd) {} + explicit operator int() const { + return m_fd; + } + std::strong_ordering operator<=>(const FileDescriptor&) const = default; private: int m_fd; }; -class FileDriver { +inline constexpr FileDescriptor FD_STDIN{0}; +inline constexpr FileDescriptor FD_STDOUT{1}; +inline constexpr FileDescriptor FD_STDERR{2}; + +class FileDriver : public std::enable_shared_from_this { public: - virtual FileDescriptor open(const char* path, int flags, int mode) = 0; - virtual ssize_t read(void* const, uint8_t*, const size_t) = 0; - virtual int write(void* const, uint8_t*, const size_t) = 0; - virtual int close(void* const) = 0; - virtual int fstat(void* const, struct stat*) = 0; - virtual int isatty(void* const) = 0; - virtual off_t lseek(void* const, off_t, int) = 0; - virtual int ctl(void* const, const uint32_t, void* const) = 0; virtual ~FileDriver() = default; + + protected: + virtual void init() = 0; + virtual FileDescriptor open(const char* path, int flags, int mode) = 0; + virtual ssize_t read(std::any, std::span) = 0; + virtual int write(std::any, std::span) = 0; + virtual int close(std::any) = 0; + virtual int fstat(std::any, struct stat*) = 0; + virtual int isatty(std::any) = 0; + virtual off_t lseek(std::any, off_t, int) = 0; + virtual int ctl(std::any, const uint32_t, void* const) = 0; + FileDescriptor add_vfs_entry(std::any data); + int32_t update_vfs_entry(FileDescriptor fd, std::any data); +}; + +struct FileEntry { + std::shared_ptr driver; + std::any data; }; -} // namespace zest \ No newline at end of file + +} // namespace zest::fs \ No newline at end of file From 3489bfe4b989ca1bca88f0172c7243e99198bf8a Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 14 Mar 2025 17:27:06 +0000 Subject: [PATCH 04/14] feat: :construction: Start implementation of vfs --- src/system/dev/vfs.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/system/dev/vfs.cpp diff --git a/src/system/dev/vfs.cpp b/src/system/dev/vfs.cpp new file mode 100644 index 00000000..1f9a4b19 --- /dev/null +++ b/src/system/dev/vfs.cpp @@ -0,0 +1,33 @@ +#include "system/dev/vfs.hpp" + +#include "pros/rtos.hpp" + +#include +#include +#include + +constexpr static size_t MAX_FILE_DESCRIPTORS = 64; + +static constinit pros::RecursiveMutex vfs_mut{}; +static constinit std::array, MAX_FILE_DESCRIPTORS> fd_data{}; + +zest::fs::FileDescriptor zest::fs::FileDriver::add_vfs_entry(std::any data) { + std::lock_guard lock{vfs_mut}; + for (auto it = fd_data.begin(); it != fd_data.end(); ++it) { + if (!it->has_value()) { + *it = {.driver = this->shared_from_this(), .data = data}; + return it - fd_data.begin(); + } + } + return -1; +} + +int32_t zest::fs::FileDriver::update_vfs_entry(zest::fs::FileDescriptor fd, std::any data) { + std::lock_guard lock{vfs_mut}; + if (fd < 0 || fd >= fd_data.size()) + return -1; + if (fd_data[static_cast(fd)].has_value()) + return -1; + fd_data[static_cast(fd)] = {.driver = this->shared_from_this(), .data = data}; + return 0; +} \ No newline at end of file From 500241604dac936098010f7cf7360dbd9a8dc465 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Tue, 18 Mar 2025 16:54:26 +0000 Subject: [PATCH 05/14] feat: :construction: Add chdir and getcwd implementations --- src/system/dev/file_system_stubs.c | 5 +--- src/system/dev/vfs.cpp | 41 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/system/dev/file_system_stubs.c b/src/system/dev/file_system_stubs.c index c4e01c84..ab139cd4 100644 --- a/src/system/dev/file_system_stubs.c +++ b/src/system/dev/file_system_stubs.c @@ -17,10 +17,7 @@ #include #include -int chdir(const char* path) { - errno = ENOSYS; - return -1; -} + int mkdir(const char* pathname, mode_t mode) { errno = ENOSYS; diff --git a/src/system/dev/vfs.cpp b/src/system/dev/vfs.cpp index 1f9a4b19..00058f0e 100644 --- a/src/system/dev/vfs.cpp +++ b/src/system/dev/vfs.cpp @@ -3,13 +3,16 @@ #include "pros/rtos.hpp" #include +#include #include #include +#include constexpr static size_t MAX_FILE_DESCRIPTORS = 64; static constinit pros::RecursiveMutex vfs_mut{}; static constinit std::array, MAX_FILE_DESCRIPTORS> fd_data{}; +static constinit std::string working_directory = "/usd"; zest::fs::FileDescriptor zest::fs::FileDriver::add_vfs_entry(std::any data) { std::lock_guard lock{vfs_mut}; @@ -30,4 +33,42 @@ int32_t zest::fs::FileDriver::update_vfs_entry(zest::fs::FileDescriptor fd, std: return -1; fd_data[static_cast(fd)] = {.driver = this->shared_from_this(), .data = data}; return 0; +} + +// newlib stubs: these must be extern "C" to prevent name mangling, +// which would prevent newlib from linking to these functions properly + +extern "C" { +int chdir(const char* path) { + std::lock_guard lock{vfs_mut}; + std::string_view new_path = path; + if (new_path.empty()) { + // TODO: how should this be handled? + } + if (!new_path.ends_with('/')) { + errno = ENOTDIR; + return -1; + } + if (new_path.starts_with('/')) { + working_directory = new_path; + } else { + working_directory += new_path; + } + return 0; +} + +char* getcwd(char* buf, size_t size) { + std::lock_guard lock{vfs_mut}; + if (size == 0) { + // TODO: implement glibc extension? + errno = EINVAL; + return nullptr; + } + if (working_directory.size() + 1 > size) { + errno = ERANGE; + return nullptr; + } + std::copy(working_directory.cbegin(), working_directory.cend(), buf); + return buf; +} } \ No newline at end of file From 9c20ab70627b235301f103f0a45b79fdb3cfcd96 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Tue, 18 Mar 2025 17:43:55 +0000 Subject: [PATCH 06/14] fix: :bug: Fix duplicate definition of getcwd --- src/system/dev/file_system_stubs.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/system/dev/file_system_stubs.c b/src/system/dev/file_system_stubs.c index ab139cd4..452ac7d0 100644 --- a/src/system/dev/file_system_stubs.c +++ b/src/system/dev/file_system_stubs.c @@ -44,11 +44,6 @@ long pathconf(const char* path, int name) { return -1; } -char* getcwd(char* buf, size_t size) { - errno = ENOSYS; - return NULL; -} - int _unlink(const char* name) { errno = ENOSYS; return -1; From 294e04913febb66f48cf5a7989bc20fa29bac336 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Tue, 25 Mar 2025 20:09:58 +0000 Subject: [PATCH 07/14] feat: :construction: Implement _open function --- include/system/dev/vfs.hpp | 4 +--- src/system/dev/vfs.c | 2 ++ src/system/dev/vfs.cpp | 40 ++++++++++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/include/system/dev/vfs.hpp b/include/system/dev/vfs.hpp index ba63dc98..e9c9e8dc 100644 --- a/include/system/dev/vfs.hpp +++ b/include/system/dev/vfs.hpp @@ -33,9 +33,6 @@ inline constexpr FileDescriptor FD_STDERR{2}; class FileDriver : public std::enable_shared_from_this { public: - virtual ~FileDriver() = default; - - protected: virtual void init() = 0; virtual FileDescriptor open(const char* path, int flags, int mode) = 0; virtual ssize_t read(std::any, std::span) = 0; @@ -47,6 +44,7 @@ class FileDriver : public std::enable_shared_from_this { virtual int ctl(std::any, const uint32_t, void* const) = 0; FileDescriptor add_vfs_entry(std::any data); int32_t update_vfs_entry(FileDescriptor fd, std::any data); + virtual ~FileDriver() = default; }; struct FileEntry { diff --git a/src/system/dev/vfs.c b/src/system/dev/vfs.c index 9c5149bb..3cca8b62 100644 --- a/src/system/dev/vfs.c +++ b/src/system/dev/vfs.c @@ -89,6 +89,7 @@ int vfs_update_entry(int file, struct fs_driver const* const driver, void* arg) return 0; } +/* int _open(const char* file, int flags, int mode) { struct _reent* r = _REENT; // Check if the filename is too long or not NULL terminated @@ -111,6 +112,7 @@ int _open(const char* file, int flags, int mode) { return usd_open_r(r, file, flags, mode); } } +*/ ssize_t _write(int file, const void* buf, size_t len) { struct _reent* r = _REENT; diff --git a/src/system/dev/vfs.cpp b/src/system/dev/vfs.cpp index 00058f0e..d87c5b51 100644 --- a/src/system/dev/vfs.cpp +++ b/src/system/dev/vfs.cpp @@ -7,12 +7,15 @@ #include #include #include +#include constexpr static size_t MAX_FILE_DESCRIPTORS = 64; static constinit pros::RecursiveMutex vfs_mut{}; static constinit std::array, MAX_FILE_DESCRIPTORS> fd_data{}; static constinit std::string working_directory = "/usd"; +// FIXME: fix static initialization order fiasco +static std::unordered_map> drivers{}; zest::fs::FileDescriptor zest::fs::FileDriver::add_vfs_entry(std::any data) { std::lock_guard lock{vfs_mut}; @@ -35,17 +38,46 @@ int32_t zest::fs::FileDriver::update_vfs_entry(zest::fs::FileDescriptor fd, std: return 0; } -// newlib stubs: these must be extern "C" to prevent name mangling, +// newlib fs stubs: these must be extern "C" to prevent name mangling, // which would prevent newlib from linking to these functions properly extern "C" { + +int _open(const char* file, int flags, int mode) { + std::lock_guard lock{vfs_mut}; + struct _reent* r = _REENT; + + std::string path = file; + if (!path.starts_with("/")) path = working_directory + path; + + auto idx = path.find("/", 1); + if (idx == std::string::npos) { + idx = path.size() - 1; + } + + std::string_view trimmed_path = path; + trimmed_path.remove_prefix(idx + 1); + std::string driver_name = path.substr(1, idx); + + auto driver = [&] { + auto it = drivers.find(driver_name); + if (it != drivers.end()) return it->second; + return std::shared_ptr{nullptr}; + } (); + + if (driver == nullptr) { + r->_errno = ENOENT; + return -1; + } + + return static_cast(driver->open(trimmed_path.cbegin(), flags, mode)); +} + int chdir(const char* path) { std::lock_guard lock{vfs_mut}; std::string_view new_path = path; - if (new_path.empty()) { - // TODO: how should this be handled? - } if (!new_path.ends_with('/')) { + // TODO: should we append a slash? errno = ENOTDIR; return -1; } From 592b1dc489176a7ef4f949e363cec09a17f1c985 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 27 Mar 2025 18:10:34 +0000 Subject: [PATCH 08/14] feat: :construction: Start implementation of SD card driver --- include/system/dev/usd.hpp | 22 +++++++ include/system/dev/vfs.hpp | 4 +- src/system/dev/usd.cpp | 116 +++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 include/system/dev/usd.hpp create mode 100644 src/system/dev/usd.cpp diff --git a/include/system/dev/usd.hpp b/include/system/dev/usd.hpp new file mode 100644 index 00000000..06f44491 --- /dev/null +++ b/include/system/dev/usd.hpp @@ -0,0 +1,22 @@ +#include "pros/rtos.hpp" +#include "system/dev/vfs.hpp" + +namespace zest::fs { + +class UsdDriver : public FileDriver { + public: + void init() override {} + std::expected open(const char* path, int flags, int mode) override; + ssize_t read(std::any, std::span) override; + int write(std::any, std::span) override; + int close(std::any) override; + int fstat(std::any, struct stat*) override; + int isatty(std::any) override; + off_t lseek(std::any, off_t, int) override; + int ctl(std::any, const uint32_t, void* const) override; + ~UsdDriver() override = default; +private: + pros::RecursiveMutex mut{}; +}; + +} // namespace zest::fs \ No newline at end of file diff --git a/include/system/dev/vfs.hpp b/include/system/dev/vfs.hpp index e9c9e8dc..b3702b53 100644 --- a/include/system/dev/vfs.hpp +++ b/include/system/dev/vfs.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include namespace zest::fs { @@ -34,7 +36,7 @@ inline constexpr FileDescriptor FD_STDERR{2}; class FileDriver : public std::enable_shared_from_this { public: virtual void init() = 0; - virtual FileDescriptor open(const char* path, int flags, int mode) = 0; + virtual std::expected open(const char* path, int flags, int mode) = 0; virtual ssize_t read(std::any, std::span) = 0; virtual int write(std::any, std::span) = 0; virtual int close(std::any) = 0; diff --git a/src/system/dev/usd.cpp b/src/system/dev/usd.cpp new file mode 100644 index 00000000..7781c640 --- /dev/null +++ b/src/system/dev/usd.cpp @@ -0,0 +1,116 @@ +#include "system/dev/usd.hpp" + +#include "v5_api.h" +#include "v5_apitypes.h" + +#include +#include +#include + +// #include + +namespace zest::fs { +struct FileFlags { + FileFlags(int flags) + : read(flags & O_RDONLY), + write(flags & O_WRONLY || flags & O_CREAT), + append(flags & O_APPEND), + truncate(flags & O_TRUNC), + create_new(flags & O_CREAT && flags & O_EXCL) {} + + bool read : 1; + bool write : 1; + bool append : 1; + bool truncate : 1; + bool create_new : 1; +}; +} // namespace zest::fs + +static std::error_condition map_fresult(FRESULT result) { + // See http://elm-chan.org/fsw/ff/doc/rc.html for a description of FRESULT codes + switch (result) { + case FR_OK: + return {}; + case FR_DISK_ERR: + return std::errc::state_not_recoverable; + case FR_INT_ERR: + return std::errc::state_not_recoverable; + case FR_NOT_READY: + return std::errc::device_or_resource_busy; + case FR_NO_FILE: + return std::errc::no_such_file_or_directory; + case FR_NO_PATH: + return std::errc::no_such_file_or_directory; + case FR_INVALID_NAME: + return std::errc::invalid_argument; + case FR_DENIED: + return std::errc::permission_denied; + case FR_EXIST: + return std::errc::file_exists; + case FR_INVALID_OBJECT: + return std::errc::io_error; + case FR_WRITE_PROTECTED: + return std::errc::read_only_file_system; + case FR_INVALID_DRIVE: + return std::errc::no_such_device_or_address; + case FR_NOT_ENABLED: + return std::errc::io_error; + case FR_NO_FILESYSTEM: + return std::errc::no_such_device_or_address; + case FR_MKFS_ABORTED: + return std::errc::io_error; + case FR_TIMEOUT: + return std::errc::io_error; + case FR_LOCKED: + return std::errc::permission_denied; + case FR_NOT_ENOUGH_CORE: + return std::errc::not_enough_memory; + case FR_TOO_MANY_OPEN_FILES: + return std::errc::too_many_files_open_in_system; + case FR_INVALID_PARAMETER: + return std::errc::invalid_argument; + default: + __builtin_abort(); // TODO: log error + } +} + +std::expected +zest::fs::UsdDriver::open(const char* path, int _flags, int mode) { + FRESULT result = vexFileMountSD(); + FIL* file = nullptr; + if (result != FR_OK) { + return std::unexpected{map_fresult(result)}; + } + + const zest::fs::FileFlags flags{_flags}; + + if (flags.create_new && vexFileStatus(path) != 0) { + return std::unexpected{std::errc::file_exists}; + } + + if (flags.read && !flags.write) { + // Open in read-only mode + file = vexFileOpen(path, ""); // mode is ignored + } else if (flags.write && flags.append) { + // Open in write & append mode + file = vexFileOpenWrite(path); + } else if (flags.write && flags.truncate) { + // Open in write mode & truncate file + file = vexFileOpenCreate(path); + } else if (flags.write) { + // Open in write & overwrite mode + file = vexFileOpenWrite(path); + vexFileSeek(file, 0, 0); + } else { + return std::unexpected{std::errc::invalid_argument}; + } + if (file == nullptr) { + return std::unexpected{std::errc::too_many_files_open_in_system}; + } + return this->add_vfs_entry(std::any{file}); +} + +ssize_t zest::fs::UsdDriver::read(std::any _file, std::span output) { + FIL* file = std::any_cast(_file); + return vexFileRead(reinterpret_cast(&output.front()), 1, output.size(), file); +} \ No newline at end of file From b69f874c1f40c2ee762b790339da7db523b00932 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 27 Mar 2025 20:21:34 +0000 Subject: [PATCH 09/14] refactor: :truck: Rename system/dev directory to system/vfs --- include/system/{dev => vfs}/banners.h | 0 include/system/{dev => vfs}/ser.h | 0 include/system/{dev => vfs}/usd.h | 0 include/system/{dev => vfs}/usd.hpp | 2 +- include/system/{dev => vfs}/vfs.h | 0 include/system/{dev => vfs}/vfs.hpp | 0 src/system/{dev => vfs}/file_system_stubs.c | 0 src/system/{dev => vfs}/ser_daemon.c | 2 +- src/system/{dev => vfs}/ser_driver.c | 4 ++-- src/system/{dev => vfs}/usd.cpp | 2 +- src/system/{dev => vfs}/usd_driver.c | 4 ++-- src/system/{dev => vfs}/vfs.c | 6 +++--- src/system/{dev => vfs}/vfs.cpp | 12 +++++++----- 13 files changed, 17 insertions(+), 15 deletions(-) rename include/system/{dev => vfs}/banners.h (100%) rename include/system/{dev => vfs}/ser.h (100%) rename include/system/{dev => vfs}/usd.h (100%) rename include/system/{dev => vfs}/usd.hpp (95%) rename include/system/{dev => vfs}/vfs.h (100%) rename include/system/{dev => vfs}/vfs.hpp (100%) rename src/system/{dev => vfs}/file_system_stubs.c (100%) rename src/system/{dev => vfs}/ser_daemon.c (99%) rename src/system/{dev => vfs}/ser_driver.c (99%) rename src/system/{dev => vfs}/usd.cpp (99%) rename src/system/{dev => vfs}/usd_driver.c (98%) rename src/system/{dev => vfs}/vfs.c (98%) rename src/system/{dev => vfs}/vfs.cpp (93%) diff --git a/include/system/dev/banners.h b/include/system/vfs/banners.h similarity index 100% rename from include/system/dev/banners.h rename to include/system/vfs/banners.h diff --git a/include/system/dev/ser.h b/include/system/vfs/ser.h similarity index 100% rename from include/system/dev/ser.h rename to include/system/vfs/ser.h diff --git a/include/system/dev/usd.h b/include/system/vfs/usd.h similarity index 100% rename from include/system/dev/usd.h rename to include/system/vfs/usd.h diff --git a/include/system/dev/usd.hpp b/include/system/vfs/usd.hpp similarity index 95% rename from include/system/dev/usd.hpp rename to include/system/vfs/usd.hpp index 06f44491..939cd056 100644 --- a/include/system/dev/usd.hpp +++ b/include/system/vfs/usd.hpp @@ -1,5 +1,5 @@ #include "pros/rtos.hpp" -#include "system/dev/vfs.hpp" +#include "system/vfs/vfs.hpp" namespace zest::fs { diff --git a/include/system/dev/vfs.h b/include/system/vfs/vfs.h similarity index 100% rename from include/system/dev/vfs.h rename to include/system/vfs/vfs.h diff --git a/include/system/dev/vfs.hpp b/include/system/vfs/vfs.hpp similarity index 100% rename from include/system/dev/vfs.hpp rename to include/system/vfs/vfs.hpp diff --git a/src/system/dev/file_system_stubs.c b/src/system/vfs/file_system_stubs.c similarity index 100% rename from src/system/dev/file_system_stubs.c rename to src/system/vfs/file_system_stubs.c diff --git a/src/system/dev/ser_daemon.c b/src/system/vfs/ser_daemon.c similarity index 99% rename from src/system/dev/ser_daemon.c rename to src/system/vfs/ser_daemon.c index 638d84be..78780d25 100644 --- a/src/system/dev/ser_daemon.c +++ b/src/system/vfs/ser_daemon.c @@ -17,7 +17,7 @@ #include "kapi.h" #include "pros/version.h" -#include "system/dev/banners.h" +#include "system/vfs/banners.h" #include "system/hot.h" #include "v5_api.h" diff --git a/src/system/dev/ser_driver.c b/src/system/vfs/ser_driver.c similarity index 99% rename from src/system/dev/ser_driver.c rename to src/system/vfs/ser_driver.c index 5d7675aa..ff84a09f 100644 --- a/src/system/dev/ser_driver.c +++ b/src/system/vfs/ser_driver.c @@ -17,8 +17,8 @@ #include "common/cobs.h" #include "common/set.h" #include "kapi.h" -#include "system/dev/ser.h" -#include "system/dev/vfs.h" +#include "system/vfs/ser.h" +#include "system/vfs/vfs.h" #include "v5_api.h" #include diff --git a/src/system/dev/usd.cpp b/src/system/vfs/usd.cpp similarity index 99% rename from src/system/dev/usd.cpp rename to src/system/vfs/usd.cpp index 7781c640..bc859a6b 100644 --- a/src/system/dev/usd.cpp +++ b/src/system/vfs/usd.cpp @@ -1,4 +1,4 @@ -#include "system/dev/usd.hpp" +#include "system/vfs/usd.hpp" #include "v5_api.h" #include "v5_apitypes.h" diff --git a/src/system/dev/usd_driver.c b/src/system/vfs/usd_driver.c similarity index 98% rename from src/system/dev/usd_driver.c rename to src/system/vfs/usd_driver.c index 63b5a3d1..e2b5bedf 100644 --- a/src/system/dev/usd_driver.c +++ b/src/system/vfs/usd_driver.c @@ -13,8 +13,8 @@ // the pragma below is needed due to a FreeRTOS oversight #include "kapi.h" // IWYU pragma: keep -#include "system/dev/usd.h" -#include "system/dev/vfs.h" +#include "system/vfs/usd.h" +#include "system/vfs/vfs.h" #include "v5_api.h" #include diff --git a/src/system/dev/vfs.c b/src/system/vfs/vfs.c similarity index 98% rename from src/system/dev/vfs.c rename to src/system/vfs/vfs.c index 3cca8b62..9e7fb15e 100644 --- a/src/system/dev/vfs.c +++ b/src/system/vfs/vfs.c @@ -27,9 +27,9 @@ #include "common/gid.h" #include "kapi.h" -#include "system/dev/ser.h" -#include "system/dev/usd.h" -#include "system/dev/vfs.h" +#include "system/vfs/ser.h" +#include "system/vfs/usd.h" +#include "system/vfs/vfs.h" #define MAX_FILELEN 128 #define MAX_FILES_OPEN 31 diff --git a/src/system/dev/vfs.cpp b/src/system/vfs/vfs.cpp similarity index 93% rename from src/system/dev/vfs.cpp rename to src/system/vfs/vfs.cpp index d87c5b51..5afe559c 100644 --- a/src/system/dev/vfs.cpp +++ b/src/system/vfs/vfs.cpp @@ -1,4 +1,4 @@ -#include "system/dev/vfs.hpp" +#include "system/vfs/vfs.hpp" #include "pros/rtos.hpp" @@ -48,7 +48,8 @@ int _open(const char* file, int flags, int mode) { struct _reent* r = _REENT; std::string path = file; - if (!path.starts_with("/")) path = working_directory + path; + if (!path.starts_with("/")) + path = working_directory + path; auto idx = path.find("/", 1); if (idx == std::string::npos) { @@ -61,16 +62,17 @@ int _open(const char* file, int flags, int mode) { auto driver = [&] { auto it = drivers.find(driver_name); - if (it != drivers.end()) return it->second; + if (it != drivers.end()) + return it->second; return std::shared_ptr{nullptr}; - } (); + }(); if (driver == nullptr) { r->_errno = ENOENT; return -1; } - return static_cast(driver->open(trimmed_path.cbegin(), flags, mode)); + return static_cast(driver->open(trimmed_path.cbegin(), flags, mode).value_or(-1)); } int chdir(const char* path) { From 168f4e7c6e7086045527f988746106e03fe3b6f5 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Fri, 28 Mar 2025 16:32:24 +0000 Subject: [PATCH 10/14] refactor: :truck: Split header files into single class per header, rename files --- include/system/vfs/file_descriptor.hpp | 24 +++++++++++++ .../system/vfs/{vfs.hpp => file_driver.hpp} | 36 ++++--------------- include/system/vfs/file_flags.hpp | 20 +++++++++++ .../system/vfs/{usd.hpp => usd_driver.hpp} | 12 ++++--- src/system/vfs/{usd.cpp => usd_driver.cpp} | 28 +++------------ src/system/vfs/vfs.cpp | 12 +++++-- 6 files changed, 73 insertions(+), 59 deletions(-) create mode 100644 include/system/vfs/file_descriptor.hpp rename include/system/vfs/{vfs.hpp => file_driver.hpp} (58%) create mode 100644 include/system/vfs/file_flags.hpp rename include/system/vfs/{usd.hpp => usd_driver.hpp} (75%) rename src/system/vfs/{usd.cpp => usd_driver.cpp} (84%) diff --git a/include/system/vfs/file_descriptor.hpp b/include/system/vfs/file_descriptor.hpp new file mode 100644 index 00000000..94d1cd79 --- /dev/null +++ b/include/system/vfs/file_descriptor.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace zest::fs { +class FileDescriptor { + public: + constexpr FileDescriptor(int fd) + : m_fd(fd) {} + + explicit operator int() const { + return m_fd; + } + + std::strong_ordering operator<=>(const FileDescriptor&) const = default; + + private: + int m_fd; +}; + +inline constexpr FileDescriptor FD_STDIN{0}; +inline constexpr FileDescriptor FD_STDOUT{1}; +inline constexpr FileDescriptor FD_STDERR{2}; +} // namespace zest::fs \ No newline at end of file diff --git a/include/system/vfs/vfs.hpp b/include/system/vfs/file_driver.hpp similarity index 58% rename from include/system/vfs/vfs.hpp rename to include/system/vfs/file_driver.hpp index b3702b53..295e6b48 100644 --- a/include/system/vfs/vfs.hpp +++ b/include/system/vfs/file_driver.hpp @@ -1,42 +1,24 @@ #pragma once +#include "system/vfs/file_descriptor.hpp" + #include -#include #include #include #include +#include #include #include #include -#include -#include #include +#include namespace zest::fs { - -class FileDescriptor { - public: - constexpr FileDescriptor(int fd) - : m_fd(fd) {} - - explicit operator int() const { - return m_fd; - } - - std::strong_ordering operator<=>(const FileDescriptor&) const = default; - - private: - int m_fd; -}; - -inline constexpr FileDescriptor FD_STDIN{0}; -inline constexpr FileDescriptor FD_STDOUT{1}; -inline constexpr FileDescriptor FD_STDERR{2}; - class FileDriver : public std::enable_shared_from_this { public: virtual void init() = 0; - virtual std::expected open(const char* path, int flags, int mode) = 0; + virtual std::expected + open(const char* path, int flags, int mode) = 0; virtual ssize_t read(std::any, std::span) = 0; virtual int write(std::any, std::span) = 0; virtual int close(std::any) = 0; @@ -48,10 +30,4 @@ class FileDriver : public std::enable_shared_from_this { int32_t update_vfs_entry(FileDescriptor fd, std::any data); virtual ~FileDriver() = default; }; - -struct FileEntry { - std::shared_ptr driver; - std::any data; -}; - } // namespace zest::fs \ No newline at end of file diff --git a/include/system/vfs/file_flags.hpp b/include/system/vfs/file_flags.hpp new file mode 100644 index 00000000..c492c251 --- /dev/null +++ b/include/system/vfs/file_flags.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace zest::fs { + struct FileFlags { + FileFlags(int flags) + : read(flags & O_RDONLY), + write(flags & O_WRONLY || flags & O_CREAT), + append(flags & O_APPEND), + truncate(flags & O_TRUNC), + create_new(flags & O_CREAT && flags & O_EXCL) {} + + bool read : 1; + bool write : 1; + bool append : 1; + bool truncate : 1; + bool create_new : 1; + }; + } // namespace zest::fs \ No newline at end of file diff --git a/include/system/vfs/usd.hpp b/include/system/vfs/usd_driver.hpp similarity index 75% rename from include/system/vfs/usd.hpp rename to include/system/vfs/usd_driver.hpp index 939cd056..65dcac47 100644 --- a/include/system/vfs/usd.hpp +++ b/include/system/vfs/usd_driver.hpp @@ -1,12 +1,15 @@ +#pragma once + #include "pros/rtos.hpp" -#include "system/vfs/vfs.hpp" +#include "system/vfs/file_driver.hpp" namespace zest::fs { - class UsdDriver : public FileDriver { public: void init() override {} - std::expected open(const char* path, int flags, int mode) override; + + std::expected + open(const char* path, int flags, int mode) override; ssize_t read(std::any, std::span) override; int write(std::any, std::span) override; int close(std::any) override; @@ -15,7 +18,8 @@ class UsdDriver : public FileDriver { off_t lseek(std::any, off_t, int) override; int ctl(std::any, const uint32_t, void* const) override; ~UsdDriver() override = default; -private: + + private: pros::RecursiveMutex mut{}; }; diff --git a/src/system/vfs/usd.cpp b/src/system/vfs/usd_driver.cpp similarity index 84% rename from src/system/vfs/usd.cpp rename to src/system/vfs/usd_driver.cpp index bc859a6b..ecc247bf 100644 --- a/src/system/vfs/usd.cpp +++ b/src/system/vfs/usd_driver.cpp @@ -1,30 +1,11 @@ -#include "system/vfs/usd.hpp" +#include "system/vfs/usd_driver.hpp" +#include "system/vfs/file_flags.hpp" #include "v5_api.h" #include "v5_apitypes.h" #include #include -#include - -// #include - -namespace zest::fs { -struct FileFlags { - FileFlags(int flags) - : read(flags & O_RDONLY), - write(flags & O_WRONLY || flags & O_CREAT), - append(flags & O_APPEND), - truncate(flags & O_TRUNC), - create_new(flags & O_CREAT && flags & O_EXCL) {} - - bool read : 1; - bool write : 1; - bool append : 1; - bool truncate : 1; - bool create_new : 1; -}; -} // namespace zest::fs static std::error_condition map_fresult(FRESULT result) { // See http://elm-chan.org/fsw/ff/doc/rc.html for a description of FRESULT codes @@ -75,7 +56,7 @@ static std::error_condition map_fresult(FRESULT result) { } std::expected -zest::fs::UsdDriver::open(const char* path, int _flags, int mode) { +zest::fs::UsdDriver::open(const char* path, int _flags, int mode [[maybe_unused]]) { FRESULT result = vexFileMountSD(); FIL* file = nullptr; if (result != FR_OK) { @@ -85,6 +66,7 @@ zest::fs::UsdDriver::open(const char* path, int _flags, int mode) { const zest::fs::FileFlags flags{_flags}; if (flags.create_new && vexFileStatus(path) != 0) { + // User specified create_new but the file already exists return std::unexpected{std::errc::file_exists}; } @@ -112,5 +94,5 @@ zest::fs::UsdDriver::open(const char* path, int _flags, int mode) { ssize_t zest::fs::UsdDriver::read(std::any _file, std::span output) { FIL* file = std::any_cast(_file); - return vexFileRead(reinterpret_cast(&output.front()), 1, output.size(), file); + return vexFileRead(reinterpret_cast(output.data()), 1, output.size(), file); } \ No newline at end of file diff --git a/src/system/vfs/vfs.cpp b/src/system/vfs/vfs.cpp index 5afe559c..8fa705c7 100644 --- a/src/system/vfs/vfs.cpp +++ b/src/system/vfs/vfs.cpp @@ -1,6 +1,5 @@ -#include "system/vfs/vfs.hpp" - #include "pros/rtos.hpp" +#include "system/vfs/file_driver.hpp" #include #include @@ -9,6 +8,15 @@ #include #include +namespace zest::fs { +namespace { +struct FileEntry { + std::shared_ptr driver; + std::any data; +}; +} // namespace +} // namespace zest::fs + constexpr static size_t MAX_FILE_DESCRIPTORS = 64; static constinit pros::RecursiveMutex vfs_mut{}; From 9a56d9f764823b7736fc549260829ab74ec5d903 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 10 Apr 2025 18:17:21 +0000 Subject: [PATCH 11/14] feat: :sparkles: Implement all UsdDriver methods and add more error handling --- include/system/vfs/file_driver.hpp | 12 ++-- include/system/vfs/usd_driver.hpp | 26 +++++-- src/system/vfs/usd_driver.cpp | 110 +++++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 26 deletions(-) diff --git a/include/system/vfs/file_driver.hpp b/include/system/vfs/file_driver.hpp index 295e6b48..40402cdb 100644 --- a/include/system/vfs/file_driver.hpp +++ b/include/system/vfs/file_driver.hpp @@ -19,12 +19,12 @@ class FileDriver : public std::enable_shared_from_this { virtual void init() = 0; virtual std::expected open(const char* path, int flags, int mode) = 0; - virtual ssize_t read(std::any, std::span) = 0; - virtual int write(std::any, std::span) = 0; - virtual int close(std::any) = 0; - virtual int fstat(std::any, struct stat*) = 0; - virtual int isatty(std::any) = 0; - virtual off_t lseek(std::any, off_t, int) = 0; + virtual std::expected read(std::any, std::span) = 0; + virtual std::expected write(std::any, std::span) = 0; + virtual std::expected close(std::any) = 0; + virtual std::expected fstat(std::any, struct stat*) = 0; + virtual bool isatty(std::any) = 0; + virtual std::expected lseek(std::any, off_t, int) = 0; virtual int ctl(std::any, const uint32_t, void* const) = 0; FileDescriptor add_vfs_entry(std::any data); int32_t update_vfs_entry(FileDescriptor fd, std::any data); diff --git a/include/system/vfs/usd_driver.hpp b/include/system/vfs/usd_driver.hpp index 65dcac47..32e27873 100644 --- a/include/system/vfs/usd_driver.hpp +++ b/include/system/vfs/usd_driver.hpp @@ -2,6 +2,9 @@ #include "pros/rtos.hpp" #include "system/vfs/file_driver.hpp" +#include "v5_apitypes_patched.h" + +#include namespace zest::fs { class UsdDriver : public FileDriver { @@ -10,16 +13,27 @@ class UsdDriver : public FileDriver { std::expected open(const char* path, int flags, int mode) override; - ssize_t read(std::any, std::span) override; - int write(std::any, std::span) override; - int close(std::any) override; - int fstat(std::any, struct stat*) override; - int isatty(std::any) override; - off_t lseek(std::any, off_t, int) override; + std::expected read(std::any, std::span) override; + std::expected write(std::any, std::span) override; + std::expected close(std::any) override; + std::expected fstat(std::any, struct stat*) override; + bool isatty(std::any) override; + std::expected lseek(std::any, off_t, int) override; int ctl(std::any, const uint32_t, void* const) override; ~UsdDriver() override = default; private: + struct File { + FIL* fd; + bool is_writable; + }; + + template + auto inline with_lock(F&& fun, Args... args) { + std::lock_guard lock{this->mut}; + return fun(args...); + } + pros::RecursiveMutex mut{}; }; diff --git a/src/system/vfs/usd_driver.cpp b/src/system/vfs/usd_driver.cpp index ecc247bf..327ef4a0 100644 --- a/src/system/vfs/usd_driver.cpp +++ b/src/system/vfs/usd_driver.cpp @@ -1,8 +1,8 @@ #include "system/vfs/usd_driver.hpp" #include "system/vfs/file_flags.hpp" -#include "v5_api.h" -#include "v5_apitypes.h" +#include "v5_api_patched.h" +#include "v5_apitypes_patched.h" #include #include @@ -57,42 +57,124 @@ static std::error_condition map_fresult(FRESULT result) { std::expected zest::fs::UsdDriver::open(const char* path, int _flags, int mode [[maybe_unused]]) { - FRESULT result = vexFileMountSD(); - FIL* file = nullptr; + FRESULT result = this->with_lock(vexFileMountSD); if (result != FR_OK) { return std::unexpected{map_fresult(result)}; } const zest::fs::FileFlags flags{_flags}; + File file = {nullptr, flags.write}; - if (flags.create_new && vexFileStatus(path) != 0) { + if (flags.create_new && this->with_lock(vexFileStatus, path) != 0) { // User specified create_new but the file already exists return std::unexpected{std::errc::file_exists}; } if (flags.read && !flags.write) { // Open in read-only mode - file = vexFileOpen(path, ""); // mode is ignored + file.fd = this->with_lock(vexFileOpen, path, ""); // mode is ignored } else if (flags.write && flags.append) { // Open in write & append mode - file = vexFileOpenWrite(path); + file.fd = this->with_lock(vexFileOpenWrite, path); } else if (flags.write && flags.truncate) { // Open in write mode & truncate file - file = vexFileOpenCreate(path); + file.fd = this->with_lock(vexFileOpenCreate, path); } else if (flags.write) { // Open in write & overwrite mode - file = vexFileOpenWrite(path); - vexFileSeek(file, 0, 0); + file.fd = this->with_lock(vexFileOpenWrite, path); + this->with_lock(vexFileSeek, file.fd, 0, 0); } else { return std::unexpected{std::errc::invalid_argument}; } - if (file == nullptr) { + if (file.fd == nullptr) { return std::unexpected{std::errc::too_many_files_open_in_system}; } return this->add_vfs_entry(std::any{file}); } -ssize_t zest::fs::UsdDriver::read(std::any _file, std::span output) { - FIL* file = std::any_cast(_file); - return vexFileRead(reinterpret_cast(output.data()), 1, output.size(), file); +std::expected +zest::fs::UsdDriver::read(std::any _file, std::span output) { + auto [file, is_writable] = std::any_cast(_file); + if (is_writable) { + return std::unexpected{std::errc::operation_not_permitted}; + } + char* out_ptr = reinterpret_cast(output.data()); + return this->with_lock(vexFileRead, out_ptr, 1, output.size(), file); +} + +std::expected +zest::fs::UsdDriver::write(std::any _file, std::span input) { + auto [file, is_writable] = std::any_cast(_file); + if (!is_writable) { + return std::unexpected{std::errc::operation_not_permitted}; + } + char* in_ptr = reinterpret_cast(input.data()); + return this->with_lock(vexFileWrite, in_ptr, 1, input.size(), file); +} + +std::expected zest::fs::UsdDriver::close(std::any _file) { + FIL* file = std::any_cast(_file).fd; + this->with_lock(vexFileClose, file); + return {}; +} + +std::expected +zest::fs::UsdDriver::fstat(std::any _file, struct stat* stats) { + FIL* file = std::any_cast(_file).fd; + stats->st_size = this->with_lock(vexFileSize, file); + // TODO: set st_mode based to indicate file vs directory + return {}; +} + +bool zest::fs::UsdDriver::isatty(std::any _file [[maybe_unused]]) { + return false; +} + +std::expected +zest::fs::UsdDriver::lseek(std::any _file, off_t offset, int dir) { + FIL* file = std::any_cast(_file).fd; + FRESULT result; + switch (dir) { + case 0: { + result = this->with_lock(vexFileSeek, file, offset, 0); + break; + } + case 1: { + if (offset >= 0) { + result = this->with_lock(vexFileSeek, file, offset, 1); + } else { + // VEXos does not support negative seek offsets, so we calculate the offset from the + // start of the file ourselves. + auto stream_pos = this->with_lock(vexFileTell, file); + result = this->with_lock(vexFileSeek, file, stream_pos + offset, 0); + } + break; + } + case 2: { + if (offset >= 0) { + result = this->with_lock(vexFileSeek, file, offset, 2); + } else { + // VEXos does not support negative seek offsets, so we calculate the offset from the + // start of the file ourselves. + struct stat stats; + if (auto result = this->fstat(_file, &stats); !result.has_value()) { + return std::unexpected{result.error()}; + } + auto file_size = stats.st_size; + result = this->with_lock(vexFileSeek, file, offset + file_size, 0); + } + break; + } + default: { + return std::unexpected{std::errc::invalid_argument}; + } + } + if (auto err = map_fresult(result); err) { + return std::unexpected{err}; + } + return this->with_lock(vexFileTell, file); +} + +int zest::fs::UsdDriver::ctl(std::any _file [[maybe_unused]], uint32_t, void* const) { + return 0; } \ No newline at end of file From 180d2a66574afa432402031fb6f36cdbddffd49a Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Tue, 15 Apr 2025 19:34:32 +0000 Subject: [PATCH 12/14] refactor: :recycle: Reimplement _read and _write syscalls --- src/system/vfs/vfs.c | 8 +++---- src/system/vfs/vfs.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/system/vfs/vfs.c b/src/system/vfs/vfs.c index 9e7fb15e..19b027f0 100644 --- a/src/system/vfs/vfs.c +++ b/src/system/vfs/vfs.c @@ -113,7 +113,7 @@ int _open(const char* file, int flags, int mode) { } } */ - +/* ssize_t _write(int file, const void* buf, size_t len) { struct _reent* r = _REENT; if (file < 0 || !gid_check(&file_table_gids, file)) { @@ -122,8 +122,8 @@ ssize_t _write(int file, const void* buf, size_t len) { return -1; } return file_table[file].driver->write_r(r, file_table[file].arg, buf, len); -} - +}*/ +/* ssize_t _read(int file, void* buf, size_t len) { struct _reent* r = _REENT; if (file < 0 || !gid_check(&file_table_gids, file)) { @@ -132,7 +132,7 @@ ssize_t _read(int file, void* buf, size_t len) { return -1; } return file_table[file].driver->read_r(r, file_table[file].arg, buf, len); -} +}*/ int _close(int file) { struct _reent* r = _REENT; diff --git a/src/system/vfs/vfs.cpp b/src/system/vfs/vfs.cpp index 8fa705c7..bf1e48cc 100644 --- a/src/system/vfs/vfs.cpp +++ b/src/system/vfs/vfs.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -113,4 +114,52 @@ char* getcwd(char* buf, size_t size) { std::copy(working_directory.cbegin(), working_directory.cend(), buf); return buf; } + +ssize_t _write(int file, void* buf, size_t len) { + struct _reent* r = _REENT; + try { + auto file_entry = fd_data.at(file).value(); + auto result = file_entry.driver->write( + file_entry.data, + std::span{static_cast(buf), len} + ); + if (result) { + return result.value(); + } else { + r->_errno = result.error().value(); + return -1; + } + } catch (std::bad_optional_access) { + r->_errno = EBADF; + return -1; + } catch (std::out_of_range) { + r->_errno = EBADF; + return -1; + } +} + +ssize_t _read(int file, void* buf, size_t len) { + struct _reent* r = _REENT; + zest::fs::FileEntry file_entry; + try { + file_entry = fd_data.at(file).value(); + + } catch (std::bad_optional_access) { + r->_errno = EBADF; + return -1; + } catch (std::out_of_range) { + r->_errno = EBADF; + return -1; + } + auto result = file_entry.driver->read( + file_entry.data, + std::span{static_cast(buf), len} + ); + if (result) { + return result.value(); + } else { + r->_errno = result.error().value(); + return -1; + } +} } \ No newline at end of file From e0e2b453f30cd27c84904d004819b40471867f51 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Wed, 23 Apr 2025 20:46:30 +0000 Subject: [PATCH 13/14] refactor: :recycle: Move common logic for fs stubs into with_fd function --- src/system/vfs/vfs.cpp | 73 ++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/src/system/vfs/vfs.cpp b/src/system/vfs/vfs.cpp index bf1e48cc..606c2569 100644 --- a/src/system/vfs/vfs.cpp +++ b/src/system/vfs/vfs.cpp @@ -1,12 +1,15 @@ #include "pros/rtos.hpp" +#include "system/vfs/file_descriptor.hpp" #include "system/vfs/file_driver.hpp" #include #include +#include #include #include #include #include +#include #include namespace zest::fs { @@ -47,6 +50,28 @@ int32_t zest::fs::FileDriver::update_vfs_entry(zest::fs::FileDescriptor fd, std: return 0; } +static auto with_fd(int file, std::invocable auto func) { + using ReturnType = decltype(func(zest::fs::FileEntry{}))::value_type; + struct _reent* r = _REENT; + zest::fs::FileEntry file_entry; + try { + file_entry = fd_data.at(file).value(); + } catch (std::bad_optional_access) { + r->_errno = EBADF; + return ReturnType{-1}; + } catch (std::out_of_range) { + r->_errno = EBADF; + return ReturnType{-1}; + } + auto result = func(file_entry); + if (result) { + return result.value(); + } else { + r->_errno = result.error().value(); + return ReturnType{-1}; + } +} + // newlib fs stubs: these must be extern "C" to prevent name mangling, // which would prevent newlib from linking to these functions properly @@ -116,50 +141,20 @@ char* getcwd(char* buf, size_t size) { } ssize_t _write(int file, void* buf, size_t len) { - struct _reent* r = _REENT; - try { - auto file_entry = fd_data.at(file).value(); - auto result = file_entry.driver->write( + return with_fd(file, [=](zest::fs::FileEntry file_entry) { + return file_entry.driver->write( file_entry.data, std::span{static_cast(buf), len} ); - if (result) { - return result.value(); - } else { - r->_errno = result.error().value(); - return -1; - } - } catch (std::bad_optional_access) { - r->_errno = EBADF; - return -1; - } catch (std::out_of_range) { - r->_errno = EBADF; - return -1; - } + }); } ssize_t _read(int file, void* buf, size_t len) { - struct _reent* r = _REENT; - zest::fs::FileEntry file_entry; - try { - file_entry = fd_data.at(file).value(); - - } catch (std::bad_optional_access) { - r->_errno = EBADF; - return -1; - } catch (std::out_of_range) { - r->_errno = EBADF; - return -1; - } - auto result = file_entry.driver->read( - file_entry.data, - std::span{static_cast(buf), len} - ); - if (result) { - return result.value(); - } else { - r->_errno = result.error().value(); - return -1; - } + return with_fd(file, [=](zest::fs::FileEntry file_entry) { + return file_entry.driver->read( + file_entry.data, + std::span{static_cast(buf), len} + ); + }); } } \ No newline at end of file From 2b7851d9989d319550f07419f5525787fb29b421 Mon Sep 17 00:00:00 2001 From: ion098 <146852218+ion098@users.noreply.github.com> Date: Thu, 24 Apr 2025 18:32:35 +0000 Subject: [PATCH 14/14] refactor: :recycle: Reimplement all fs stubs, except _close --- src/system/vfs/vfs.c | 4 ++-- src/system/vfs/vfs.cpp | 43 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/system/vfs/vfs.c b/src/system/vfs/vfs.c index 19b027f0..d04add06 100644 --- a/src/system/vfs/vfs.c +++ b/src/system/vfs/vfs.c @@ -133,7 +133,7 @@ ssize_t _read(int file, void* buf, size_t len) { } return file_table[file].driver->read_r(r, file_table[file].arg, buf, len); }*/ - +/* int _close(int file) { struct _reent* r = _REENT; // NOTE: newlib automatically closes all open files for a given task when @@ -190,4 +190,4 @@ int32_t fdctl(int file, const uint32_t action, void* const extra_arg) { return -1; } return file_table[file].driver->ctl(file_table[file].arg, action, extra_arg); -} +}*/ diff --git a/src/system/vfs/vfs.cpp b/src/system/vfs/vfs.cpp index 606c2569..41b5731f 100644 --- a/src/system/vfs/vfs.cpp +++ b/src/system/vfs/vfs.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace zest::fs { @@ -56,10 +57,10 @@ static auto with_fd(int file, std::invocable auto func) { zest::fs::FileEntry file_entry; try { file_entry = fd_data.at(file).value(); - } catch (std::bad_optional_access) { + } catch (std::bad_optional_access&) { r->_errno = EBADF; return ReturnType{-1}; - } catch (std::out_of_range) { + } catch (std::out_of_range&) { r->_errno = EBADF; return ReturnType{-1}; } @@ -141,7 +142,7 @@ char* getcwd(char* buf, size_t size) { } ssize_t _write(int file, void* buf, size_t len) { - return with_fd(file, [=](zest::fs::FileEntry file_entry) { + return with_fd(file, [&](zest::fs::FileEntry file_entry) { return file_entry.driver->write( file_entry.data, std::span{static_cast(buf), len} @@ -150,11 +151,45 @@ ssize_t _write(int file, void* buf, size_t len) { } ssize_t _read(int file, void* buf, size_t len) { - return with_fd(file, [=](zest::fs::FileEntry file_entry) { + return with_fd(file, [&](zest::fs::FileEntry file_entry) { return file_entry.driver->read( file_entry.data, std::span{static_cast(buf), len} ); }); } + +int _close(int file) { + // TODO: implement + (void)file; + return 0; +} + +int _fstat(int file, struct stat* st) { + return with_fd(file, [&](zest::fs::FileEntry file_entry) { + return file_entry.driver->fstat(file_entry.data, st).transform([]() { + return 0; + }); + }); +} + +off_t _lseek(int file, off_t ptr, int dir) { + return with_fd(file, [&](zest::fs::FileEntry file_entry) { + return file_entry.driver->lseek(file_entry.data, ptr, dir); + }); +} + +int _isatty(int file) { + return with_fd(file, [&](zest::fs::FileEntry file_entry) { + bool is_atty = file_entry.driver->isatty(file_entry.data); + return std::expected{is_atty}; + }); +} + +int32_t fdctl(int file, uint32_t action, void* extra_arg) { + return with_fd(file, [&](zest::fs::FileEntry file_entry) { + int ret_val = file_entry.driver->ctl(file_entry.data, action, extra_arg); + return std::expected{ret_val}; + }); +} } \ No newline at end of file