diff --git a/sphaira/CMakeLists.txt b/sphaira/CMakeLists.txt index 6582349..f866269 100644 --- a/sphaira/CMakeLists.txt +++ b/sphaira/CMakeLists.txt @@ -110,6 +110,7 @@ add_executable(sphaira source/utils/devoptab_smb2.cpp source/utils/devoptab_ftp.cpp source/utils/devoptab_webdav.cpp + source/utils/devoptab_vfs.cpp source/usb/base.cpp source/usb/usbds.cpp diff --git a/sphaira/include/utils/devoptab.hpp b/sphaira/include/utils/devoptab.hpp index 7ad1228..c86b43e 100644 --- a/sphaira/include/utils/devoptab.hpp +++ b/sphaira/include/utils/devoptab.hpp @@ -33,6 +33,7 @@ void UmountBfsar(const fs::FsPath& mount); Result MountNro(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& out_path); void UmountNro(const fs::FsPath& mount); +Result MountVfsAll(); Result MountWebdavAll(); Result MountHttpAll(); Result MountFtpAll(); diff --git a/sphaira/include/utils/devoptab_common.hpp b/sphaira/include/utils/devoptab_common.hpp index 8648468..c6e4c9f 100644 --- a/sphaira/include/utils/devoptab_common.hpp +++ b/sphaira/include/utils/devoptab_common.hpp @@ -212,6 +212,6 @@ private: }; using CreateDeviceCallback = std::function(const MountConfig& config)>; -Result MountNetworkDevice(const CreateDeviceCallback& create_device, size_t file_size, size_t dir_size, const char* config_path, const char* name); +Result MountNetworkDevice(const CreateDeviceCallback& create_device, size_t file_size, size_t dir_size, const char* name); } // namespace sphaira::devoptab::common diff --git a/sphaira/source/app.cpp b/sphaira/source/app.cpp index 9aa45d8..c1126bd 100644 --- a/sphaira/source/app.cpp +++ b/sphaira/source/app.cpp @@ -1599,6 +1599,11 @@ App::App(const char* argv0) { } // this has to come after curl init as it inits curl global. + { + SCOPED_TIMESTAMP("vfs init"); + devoptab::MountVfsAll(); + } + { SCOPED_TIMESTAMP("http init"); devoptab::MountHttpAll(); diff --git a/sphaira/source/utils/devoptab_common.cpp b/sphaira/source/utils/devoptab_common.cpp index d2e5028..d48b79c 100644 --- a/sphaira/source/utils/devoptab_common.cpp +++ b/sphaira/source/utils/devoptab_common.cpp @@ -759,7 +759,7 @@ void update_devoptab_for_read_only(devoptab_t* devoptab, bool read_only) { } } -Result MountNetworkDevice(const CreateDeviceCallback& create_device, size_t file_size, size_t dir_size, const char* config_path, const char* name) { +Result MountNetworkDevice(const CreateDeviceCallback& create_device, size_t file_size, size_t dir_size, const char* name) { { static Mutex rw_lock_init_mutex{}; SCOPED_MUTEX(&rw_lock_init_mutex); @@ -817,7 +817,10 @@ Result MountNetworkDevice(const CreateDeviceCallback& create_device, size_t file return 1; }; - MountConfigs configs; + fs::FsPath config_path{}; + std::snprintf(config_path, sizeof(config_path), "/config/sphaira/mount/%s.ini", name); + + MountConfigs configs{}; ini_browse(cb, &configs, config_path); log_write("[DEVOPTAB] Found %zu mount configs\n", configs.size()); diff --git a/sphaira/source/utils/devoptab_ftp.cpp b/sphaira/source/utils/devoptab_ftp.cpp index e63928a..5a68c41 100644 --- a/sphaira/source/utils/devoptab_ftp.cpp +++ b/sphaira/source/utils/devoptab_ftp.cpp @@ -709,7 +709,6 @@ Result MountFtpAll() { return std::make_unique(config); }, sizeof(File), sizeof(Dir), - "/config/sphaira/ftp.ini", "FTP" ); } diff --git a/sphaira/source/utils/devoptab_http.cpp b/sphaira/source/utils/devoptab_http.cpp index 97e70d9..b6aecea 100644 --- a/sphaira/source/utils/devoptab_http.cpp +++ b/sphaira/source/utils/devoptab_http.cpp @@ -410,7 +410,6 @@ Result MountHttpAll() { return std::make_unique(config); }, sizeof(File), sizeof(Dir), - "/config/sphaira/http.ini", "HTTP" ); } diff --git a/sphaira/source/utils/devoptab_nfs.cpp b/sphaira/source/utils/devoptab_nfs.cpp index f3e949a..86dca79 100644 --- a/sphaira/source/utils/devoptab_nfs.cpp +++ b/sphaira/source/utils/devoptab_nfs.cpp @@ -1,9 +1,7 @@ #include "utils/devoptab_common.hpp" #include "defines.hpp" #include "log.hpp" -#include "location.hpp" -#include #include #include #include @@ -16,7 +14,7 @@ namespace sphaira::devoptab { namespace { struct Device final : common::MountDevice { - Device(const common::MountConfig& cfg) : MountDevice{cfg} {} + using MountDevice::MountDevice; ~Device(); private: @@ -155,11 +153,7 @@ int Device::devoptab_open(void *fileStruct, const char *path, int flags, int mod int Device::devoptab_close(void *fd) { auto file = static_cast(fd); - if (file && file->fd) { - nfs_close(nfs, file->fd); - file->fd = nullptr; - } - + nfs_close(nfs, file->fd); return 0; } @@ -308,9 +302,6 @@ int Device::devoptab_diropen(void* fd, const char *path) { int Device::devoptab_dirreset(void* fd) { auto dir = static_cast(fd); - if (!dir->dir) { - return -EINVAL; - } nfs_rewinddir(nfs, dir->dir); return 0; @@ -319,10 +310,6 @@ int Device::devoptab_dirreset(void* fd) { int Device::devoptab_dirnext(void* fd, char *filename, struct stat *filestat) { auto dir = static_cast(fd); - if (!dir->dir) { - return EINVAL; - } - const auto entry = nfs_readdir(nfs, dir->dir); if (!entry) { return -ENOENT; @@ -351,11 +338,7 @@ int Device::devoptab_dirnext(void* fd, char *filename, struct stat *filestat) { int Device::devoptab_dirclose(void* fd) { auto dir = static_cast(fd); - if (dir && dir->dir) { - nfs_closedir(nfs, dir->dir); - dir->dir = nullptr; - } - + nfs_closedir(nfs, dir->dir); return 0; } @@ -424,7 +407,6 @@ Result MountNfsAll() { return std::make_unique(cfg); }, sizeof(File), sizeof(Dir), - "/config/sphaira/nfs.ini", "NFS" ); } diff --git a/sphaira/source/utils/devoptab_smb2.cpp b/sphaira/source/utils/devoptab_smb2.cpp index e7bd9c2..6490582 100644 --- a/sphaira/source/utils/devoptab_smb2.cpp +++ b/sphaira/source/utils/devoptab_smb2.cpp @@ -15,7 +15,7 @@ namespace sphaira::devoptab { namespace { struct Device final : common::MountDevice { - Device(const common::MountConfig& cfg) : MountDevice{cfg} {} + using MountDevice::MountDevice; ~Device(); private: @@ -262,9 +262,6 @@ int Device::devoptab_diropen(void* fd, const char *path) { int Device::devoptab_dirreset(void* fd) { auto dir = static_cast(fd); - if (!dir->dir) { - return -EINVAL; - } smb2_rewinddir(this->smb2, dir->dir); return 0; @@ -362,7 +359,6 @@ Result MountSmb2All() { return std::make_unique(cfg); }, sizeof(File), sizeof(Dir), - "/config/sphaira/smb.ini", "SMB" ); } diff --git a/sphaira/source/utils/devoptab_vfs.cpp b/sphaira/source/utils/devoptab_vfs.cpp new file mode 100644 index 0000000..8beee0a --- /dev/null +++ b/sphaira/source/utils/devoptab_vfs.cpp @@ -0,0 +1,284 @@ +#include "utils/devoptab_common.hpp" +#include "defines.hpp" +#include "log.hpp" + +#include +#include +#include +#include +#include + +namespace sphaira::devoptab { +namespace { + +struct Device final : common::MountDevice { + Device(const common::MountConfig& _config) + : common::MountDevice{_config} + , m_root{config.url} { + } + +private: + bool fix_path(const char* str, char* out, bool strip_leading_slash = false) override { + char temp[PATH_MAX]{}; + if (!common::fix_path(str, temp, false)) { + return false; + } + + std::snprintf(out, PATH_MAX, "%s/%s", m_root.c_str(), temp); + log_write("[VFS] fixed path: %s -> %s\n", str, out); + return true; + } + + bool Mount() override; + int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override; + int devoptab_close(void *fd) override; + ssize_t devoptab_read(void *fd, char *ptr, size_t len) override; + ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override; + off_t devoptab_seek(void *fd, off_t pos, int dir) override; + int devoptab_fstat(void *fd, struct stat *st) override; + int devoptab_unlink(const char *path) override; + int devoptab_rename(const char *oldName, const char *newName) override; + int devoptab_mkdir(const char *path, int mode) override; + int devoptab_rmdir(const char *path) override; + int devoptab_diropen(void* fd, const char *path) override; + int devoptab_dirreset(void* fd) override; + int devoptab_dirnext(void* fd, char *filename, struct stat *filestat) override; + int devoptab_dirclose(void* fd) override; + int devoptab_lstat(const char *path, struct stat *st) override; + int devoptab_ftruncate(void *fd, off_t len) override; + int devoptab_statvfs(const char *path, struct statvfs *buf) override; + int devoptab_fsync(void *fd) override; + int devoptab_utimes(const char *path, const struct timeval times[2]) override; + +private: + const std::string m_root{}; + bool mounted{}; +}; + +struct File { + int fd; +}; + +struct Dir { + DIR* dir; +}; + +bool Device::Mount() { + if (mounted) { + return true; + } + + log_write("[VFS] Mounting %s\n", this->config.url.c_str()); + + if (m_root.empty()) { + log_write("[VFS] Empty root path\n"); + return false; + } + + log_write("[VFS] Mounted %s\n", this->config.url.c_str()); + return mounted = true; +} + +int return_errno(int err = EIO) { + return errno ? -errno : -err; +} + +int Device::devoptab_open(void *fileStruct, const char *path, int flags, int mode) { + auto file = static_cast(fileStruct); + + const auto ret = open(path, flags, mode); + if (ret < 0) { + return return_errno(); + } + + file->fd = ret; + return 0; +} + +int Device::devoptab_close(void *fd) { + auto file = static_cast(fd); + + close(file->fd); + return 0; +} + +ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) { + auto file = static_cast(fd); + + const auto ret = read(file->fd, ptr, len); + if (ret < 0) { + return return_errno(); + } + + return ret; +} + +ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) { + auto file = static_cast(fd); + + const auto ret = write(file->fd, ptr, len); + if (ret < 0) { + return return_errno(); + } + + return ret; +} + +off_t Device::devoptab_seek(void *fd, off_t pos, int dir) { + auto file = static_cast(fd); + + return lseek(file->fd, pos, dir); +} + +int Device::devoptab_fstat(void *fd, struct stat *st) { + auto file = static_cast(fd); + + const auto ret = fstat(file->fd, st); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_unlink(const char *path) { + const auto ret = unlink(path); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_rename(const char *oldName, const char *newName) { + const auto ret = rename(oldName, newName); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_mkdir(const char *path, int mode) { + const auto ret = mkdir(path, mode); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_rmdir(const char *path) { + const auto ret = rmdir(path); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_diropen(void* fd, const char *path) { + auto dir = static_cast(fd); + + auto ret = opendir(path); + if (!ret) { + return return_errno(); + } + + dir->dir = ret; + return 0; +} + +int Device::devoptab_dirreset(void* fd) { + auto dir = static_cast(fd); + + rewinddir(dir->dir); + return 0; +} + +int Device::devoptab_dirnext(void* fd, char *filename, struct stat *filestat) { + auto dir = static_cast(fd); + + const auto entry = readdir(dir->dir); + if (!entry) { + return return_errno(ENOENT); + } + + filestat->st_ino = entry->d_ino; + filestat->st_mode = entry->d_type << 12; // DT_* to S_IF* + filestat->st_nlink = 1; // unknown + + std::strncpy(filename, entry->d_name, NAME_MAX); + filename[NAME_MAX - 1] = '\0'; + + return 0; +} + +int Device::devoptab_dirclose(void* fd) { + auto dir = static_cast(fd); + + closedir(dir->dir); + return 0; +} + +int Device::devoptab_lstat(const char *path, struct stat *st) { + const auto ret = lstat(path, st); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_ftruncate(void *fd, off_t len) { + auto file = static_cast(fd); + + const auto ret = ftruncate(file->fd, len); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_statvfs(const char *path, struct statvfs *buf) { + const auto ret = statvfs(path, buf); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_fsync(void *fd) { + auto file = static_cast(fd); + + const auto ret = fsync(file->fd); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +int Device::devoptab_utimes(const char *path, const struct timeval times[2]) { + const auto ret = utimes(path, times); + if (ret < 0) { + return return_errno(); + } + + return 0; +} + +} // namespace + +Result MountVfsAll() { + return common::MountNetworkDevice([](const common::MountConfig& cfg) { + return std::make_unique(cfg); + }, + sizeof(File), sizeof(Dir), + "VFS" + ); +} + +} // namespace sphaira::devoptab diff --git a/sphaira/source/utils/devoptab_webdav.cpp b/sphaira/source/utils/devoptab_webdav.cpp index 13dc1d6..b6f9931 100644 --- a/sphaira/source/utils/devoptab_webdav.cpp +++ b/sphaira/source/utils/devoptab_webdav.cpp @@ -646,7 +646,6 @@ Result MountWebdavAll() { return std::make_unique(config); }, sizeof(File), sizeof(Dir), - "/config/sphaira/webdav.ini", "WEBDAV" ); }