devoptab: add vfs, change mount.ini path location.

This commit is contained in:
ITotalJustice
2025-09-07 15:43:01 +01:00
parent 43969a773e
commit ba78fd0dc5
11 changed files with 301 additions and 32 deletions

View File

@@ -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

View File

@@ -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();

View File

@@ -212,6 +212,6 @@ private:
};
using CreateDeviceCallback = std::function<std::unique_ptr<MountDevice>(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

View File

@@ -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();

View File

@@ -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());

View File

@@ -709,7 +709,6 @@ Result MountFtpAll() {
return std::make_unique<Device>(config);
},
sizeof(File), sizeof(Dir),
"/config/sphaira/ftp.ini",
"FTP"
);
}

View File

@@ -410,7 +410,6 @@ Result MountHttpAll() {
return std::make_unique<Device>(config);
},
sizeof(File), sizeof(Dir),
"/config/sphaira/http.ini",
"HTTP"
);
}

View File

@@ -1,9 +1,7 @@
#include "utils/devoptab_common.hpp"
#include "defines.hpp"
#include "log.hpp"
#include "location.hpp"
#include <sys/iosupport.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
@@ -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<File*>(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<Dir*>(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<Dir*>(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<Dir*>(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<Device>(cfg);
},
sizeof(File), sizeof(Dir),
"/config/sphaira/nfs.ini",
"NFS"
);
}

View File

@@ -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<Dir*>(fd);
if (!dir->dir) {
return -EINVAL;
}
smb2_rewinddir(this->smb2, dir->dir);
return 0;
@@ -362,7 +359,6 @@ Result MountSmb2All() {
return std::make_unique<Device>(cfg);
},
sizeof(File), sizeof(Dir),
"/config/sphaira/smb.ini",
"SMB"
);
}

View File

@@ -0,0 +1,284 @@
#include "utils/devoptab_common.hpp"
#include "defines.hpp"
#include "log.hpp"
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <string>
#include <cstring>
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<File*>(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<File*>(fd);
close(file->fd);
return 0;
}
ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
auto file = static_cast<File*>(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<File*>(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<File*>(fd);
return lseek(file->fd, pos, dir);
}
int Device::devoptab_fstat(void *fd, struct stat *st) {
auto file = static_cast<File*>(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<Dir*>(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<Dir*>(fd);
rewinddir(dir->dir);
return 0;
}
int Device::devoptab_dirnext(void* fd, char *filename, struct stat *filestat) {
auto dir = static_cast<Dir*>(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<Dir*>(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<File*>(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<File*>(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<Device>(cfg);
},
sizeof(File), sizeof(Dir),
"VFS"
);
}
} // namespace sphaira::devoptab

View File

@@ -646,7 +646,6 @@ Result MountWebdavAll() {
return std::make_unique<Device>(config);
},
sizeof(File), sizeof(Dir),
"/config/sphaira/webdav.ini",
"WEBDAV"
);
}