From db4fe2169d24b37097c70078cbfec6b9b329e282 Mon Sep 17 00:00:00 2001 From: TotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:21:40 +0000 Subject: [PATCH] add timeout for data transfer loop, Nx mounting bis, hdd, save_system, save_cache. the data transfer loop now has a timeout of 1ms. this was added based on the theory that if the disk speed was slower than the network, then the data loop would block until the entire file / directory is sent. usually this wouldnt be the case, until i was transfering files from a hdd. the seek time can be pretty bad, and thus the network is faster. many new nx mount options were added, the biggest one being hdd. the impl isn't perfect yet, and it can block the main thread for quite a while as the disk starts to spin up for the first time. however i decided that blocking is the best as otherwise opening a folder would return an error as it isn;t ready yet, however to the user, there is no clear reason as to why it didnt open. by blocking, the user will likely hear the disk spinning up and flashing, and understand why its taking some time. --- CMakeLists.txt | 62 ++++- assets/config.ini.template | 6 +- src/ftpsrv.c | 13 + src/log/log.c | 13 + src/log/log.h | 1 + src/platform/nx/main.c | 23 +- src/platform/nx/main_sysmod.c | 19 +- src/platform/nx/utils.c | 2 +- src/platform/nx/vfs/vfs_nx_fs.c | 153 ++++++----- src/platform/nx/vfs/vfs_nx_fs.h | 58 ++--- src/platform/nx/vfs/vfs_nx_hdd.c | 251 ++++++++++++++++++ src/platform/nx/vfs/vfs_nx_hdd.h | 36 +++ src/platform/nx/vfs/vfs_nx_ncm.c | 191 -------------- src/platform/nx/vfs/vfs_nx_ncm.h | 57 ---- src/platform/nx/vfs/vfs_nx_root.c | 97 ++++--- src/platform/nx/vfs/vfs_nx_root.h | 39 +-- src/platform/nx/vfs/vfs_nx_save.c | 200 ++++++++++---- src/platform/nx/vfs/vfs_nx_save.h | 41 +-- src/platform/nx/vfs_nx.c | 417 +++++++++++++++++++----------- src/platform/nx/vfs_nx.h | 69 +++-- src/platform/unistd/main.c | 4 +- 21 files changed, 1045 insertions(+), 707 deletions(-) create mode 100644 src/platform/nx/vfs/vfs_nx_hdd.c create mode 100644 src/platform/nx/vfs/vfs_nx_hdd.h delete mode 100644 src/platform/nx/vfs/vfs_nx_ncm.c delete mode 100644 src/platform/nx/vfs/vfs_nx_ncm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 49cbb15..738f844 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,9 +184,64 @@ ftp_set_compile_definitions(ftpsrv) if (NINTENDO_SWITCH) ftp_set_options(ftpsrv 769 128 1024*64) - # ftp_set_options(ftpsrv 769 5 1024*16) fetch_minini() + set(USBHSFS_GPL ON) + FetchContent_Declare(libusbhsfs + GIT_REPOSITORY https://github.com/DarkMatterCore/libusbhsfs.git + GIT_TAG v0.2.9 + ) + + FetchContent_MakeAvailable(libusbhsfs) + add_library(libusbhsfs + ${libusbhsfs_SOURCE_DIR}/source/usbhsfs_drive.c + ${libusbhsfs_SOURCE_DIR}/source/usbhsfs_log.c + ${libusbhsfs_SOURCE_DIR}/source/usbhsfs_manager.c + ${libusbhsfs_SOURCE_DIR}/source/usbhsfs_mount.c + ${libusbhsfs_SOURCE_DIR}/source/usbhsfs_request.c + ${libusbhsfs_SOURCE_DIR}/source/usbhsfs_scsi.c + ${libusbhsfs_SOURCE_DIR}/source/usbhsfs_utils.c + ) + + target_include_directories(libusbhsfs PUBLIC ${libusbhsfs_SOURCE_DIR}/include) + + # fatfs stuff + target_sources(libusbhsfs PRIVATE + ${libusbhsfs_SOURCE_DIR}/source/fatfs/diskio.c + ${libusbhsfs_SOURCE_DIR}/source/fatfs/ff_dev.c + ${libusbhsfs_SOURCE_DIR}/source/fatfs/ff.c + ${libusbhsfs_SOURCE_DIR}/source/fatfs/ffsystem.c + ${libusbhsfs_SOURCE_DIR}/source/fatfs/ffunicode.c + ) + + # sxos stuff + target_sources(libusbhsfs PRIVATE + ${libusbhsfs_SOURCE_DIR}/source/sxos/usbfs_dev.c + ${libusbhsfs_SOURCE_DIR}/source/sxos/usbfs.c + ) + + if (USBHSFS_GPL) + target_sources(libusbhsfs PRIVATE + ${libusbhsfs_SOURCE_DIR}/source/lwext4/ext_dev.c + ${libusbhsfs_SOURCE_DIR}/source/lwext4/ext_disk_io.c + ${libusbhsfs_SOURCE_DIR}/source/lwext4/ext.c + + ${libusbhsfs_SOURCE_DIR}/source/ntfs-3g/ntfs_dev.c + ${libusbhsfs_SOURCE_DIR}/source/ntfs-3g/ntfs_disk_io.c + ${libusbhsfs_SOURCE_DIR}/source/ntfs-3g/ntfs.c + ) + + find_library(ntfs-3g_lib ntfs-3g REQUIRED) + find_path(ntfs-3g_inc ntfs-3g REQUIRED) + + find_library(lwext4_lib lwext4 REQUIRED) + find_path(lwext4_inc lwext4 REQUIRED) + + target_link_libraries(libusbhsfs PRIVATE ${ntfs-3g_lib} ${lwext4_lib}) + target_include_directories(libusbhsfs PRIVATE ${ntfs-3g_inc} ${lwext4_inc} ${lwext4_inc}/lwext4) + target_compile_definitions(libusbhsfs PRIVATE GPL_BUILD) + endif() + target_compile_definitions(ftpsrv PUBLIC FTP_VFS_HEADER="${CMAKE_CURRENT_SOURCE_DIR}/src/platform/nx/vfs_nx.h" FTP_SOCKET_HEADER="${CMAKE_CURRENT_SOURCE_DIR}/src/platform/unistd/socket_unistd.h" @@ -197,7 +252,6 @@ if (NINTENDO_SWITCH) src/platform/nx/vfs_nx.c src/platform/nx/vfs/vfs_nx_root.c src/platform/nx/vfs/vfs_nx_fs.c - src/platform/nx/vfs/vfs_nx_ncm.c src/platform/nx/vfs/vfs_nx_save.c src/platform/nx/utils.c src/log/log.c @@ -205,10 +259,12 @@ if (NINTENDO_SWITCH) add_executable(ftpexe src/platform/nx/main.c + src/platform/nx/vfs/vfs_nx_hdd.c ${NX_SRC} ) + target_compile_definitions(ftpexe PUBLIC USE_USBHSFS=1) ftp_add(ftpexe) - target_link_libraries(ftpexe PRIVATE ftpsrv minIni) + target_link_libraries(ftpexe PRIVATE ftpsrv minIni libusbhsfs) nx_generate_nacp( OUTPUT ftpexe.nacp diff --git a/assets/config.ini.template b/assets/config.ini.template index 167c0fb..5fd67ad 100644 --- a/assets/config.ini.template +++ b/assets/config.ini.template @@ -32,11 +32,15 @@ log = 0 [Nx] # enables showing all available mount points at root "/" # for example, SdCard is as at "/sdmc:" -mount_devices = 1 +mount_devices = 0 # allows save data to be writable, needs mount_devices = 1 save_writable = 0 +# allows for bis partitions to be mounted, needs mount_devices = 1 +# WARNING: modifying bis files can soft brick your switch! +mount_bis = 0 + # uncomment to override the port for application # app_port = 21 diff --git a/src/ftpsrv.c b/src/ftpsrv.c index 93f87e2..eb06a56 100644 --- a/src/ftpsrv.c +++ b/src/ftpsrv.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #if defined(HAVE_IPTOS_THROUGHPUT) && HAVE_IPTOS_THROUGHPUT @@ -180,6 +181,12 @@ static int strncasecmp(const char* a, const char* b, size_t len) { } #endif +static size_t ftp_get_timestamp_ms(void) { + struct timeval ts; + gettimeofday(&ts, NULL); + return (ts.tv_sec * 1000000UL + ts.tv_usec) / 1000UL; +} + static void ftp_log_callback(enum FTP_API_LOG_TYPE type, const char* msg) { if (g_ftp.cfg.log_callback) { g_ftp.cfg.log_callback(type, msg); @@ -640,6 +647,7 @@ static enum FTP_FILE_TRANSFER_STATE ftp_file_data_transfer_progress(struct FtpSe static void ftp_data_transfer_progress(struct FtpSession* session) { struct FtpTransfer* transfer = &session->transfer; enum FTP_FILE_TRANSFER_STATE state = FTP_FILE_TRANSFER_STATE_CONTINUE; + const size_t start = ftp_get_timestamp_ms(); while (state == FTP_FILE_TRANSFER_STATE_CONTINUE) { if (transfer->mode == FTP_TRANSFER_MODE_RETR || transfer->mode == FTP_TRANSFER_MODE_STOR) { @@ -651,6 +659,11 @@ static void ftp_data_transfer_progress(struct FtpSession* session) { if (g_ftp.cfg.progress_callback) { g_ftp.cfg.progress_callback(); } + + // break out if 1ms has elapsed as to not block for too long. + if (ftp_get_timestamp_ms() - start >= 1) { + break; + } } if (state == FTP_FILE_TRANSFER_STATE_ERROR) { diff --git a/src/log/log.c b/src/log/log.c index 412fbf0..55315f9 100644 --- a/src/log/log.c +++ b/src/log/log.c @@ -1,5 +1,7 @@ #include "log.h" #include "ftpsrv_vfs.h" +#include +#include #include static struct FtpVfsFile g_log_file = {0}; @@ -17,6 +19,17 @@ void log_file_write(const char* msg) { } } +void log_file_fwrite(const char* fmt, ...) { + if (g_has_log_file) { + char buf[256]; + va_list va; + va_start(va, fmt); + vsnprintf(buf, sizeof(buf), fmt, va); + va_end(va); + log_file_write(buf); + } +} + void log_file_init(const char* path, const char* init_msg) { if (!g_has_log_file) { ftp_vfs_unlink(path); diff --git a/src/log/log.h b/src/log/log.h index f07768a..964b661 100644 --- a/src/log/log.h +++ b/src/log/log.h @@ -10,6 +10,7 @@ extern "C" { #endif void log_file_write(const char* msg); +void log_file_fwrite(const char* fmt, ...); void log_file_init(const char* path, const char* init_msg); void log_file_exit(void); diff --git a/src/platform/nx/main.c b/src/platform/nx/main.c index a773f95..76b7a0e 100644 --- a/src/platform/nx/main.c +++ b/src/platform/nx/main.c @@ -145,6 +145,7 @@ int main(int argc, char** argv) { g_ftpsrv_config.timeout = ini_getl("Network", "timeout", 0, INI_PATH); const bool log_enabled = ini_getbool("Log", "log", 0, INI_PATH); const bool mount_devices = ini_getbool("Nx", "mount_devices", 1, INI_PATH); + const bool mount_bis = ini_getbool("Nx", "mount_bis", 0, INI_PATH); const bool save_writable = ini_getbool("Nx", "save_writable", 0, INI_PATH); g_led_enabled = ini_getbool("Nx", "led", 1, INI_PATH); g_ftpsrv_config.port = ini_getl("Nx", "app_port", g_ftpsrv_config.port, INI_PATH); @@ -153,19 +154,6 @@ int main(int argc, char** argv) { log_file_init(LOG_PATH, "ftpsrv - " FTPSRV_VERSION_HASH " - NX-app"); } - vfs_nx_init(mount_devices, save_writable); - if (mount_devices) { - fsdev_wrapMountImage("image_nand", FsImageDirectoryId_Nand); - fsdev_wrapMountImage("image_sd", FsImageDirectoryId_Sd); - - // add some shortcuts. - FsFileSystem* sdmc = fsdev_wrapGetDeviceFileSystem("sdmc"); - if (sdmc) { - fsdev_wrapMountDevice("switch", "/switch", *sdmc, false); - fsdev_wrapMountDevice("contents", "/atmosphere/contents", *sdmc, false); - } - } - if (!user_len && !pass_len && !g_ftpsrv_config.anon) { return error_loop("User / Pass / Anon not set in config!"); } @@ -179,6 +167,8 @@ int main(int argc, char** argv) { return error_loop("failed to get current ip address"); } + vfs_nx_init(mount_devices, save_writable, mount_bis); + const struct in_addr addr = {ip}; printf(TEXT_YELLOW "ip: %s\n", inet_ntoa(addr)); printf(TEXT_YELLOW "port: %d" TEXT_NORMAL "\n", g_ftpsrv_config.port); @@ -229,8 +219,6 @@ int main(int argc, char** argv) { } } -u32 __nx_fs_num_sessions = 2; - #define TCP_TX_BUF_SIZE (1024 * 64) #define TCP_RX_BUF_SIZE (1024 * 64) #define TCP_TX_BUF_SIZE_MAX (1024 * 1024 * 4) @@ -320,10 +308,11 @@ void userAppInit(void) { diagAbortWithResult(rc); if (R_FAILED(rc = ncmInitialize())) diagAbortWithResult(rc); + if (R_FAILED(rc = setInitialize())) + diagAbortWithResult(rc); if (R_FAILED(rc = fsdev_wrapMountSdmc())) diagAbortWithResult(rc); - // the below doesnt matter if they fail to init. hidsysInitialize(); appletSetAutoSleepDisabled(true); @@ -334,7 +323,9 @@ void userAppExit(void) { log_file_exit(); vfs_nx_exit(); consoleExit(NULL); + hidsysExit(); + setExit(); ncmExit(); accountExit(); socketExit(); diff --git a/src/platform/nx/main_sysmod.c b/src/platform/nx/main_sysmod.c index f682d30..809b854 100644 --- a/src/platform/nx/main_sysmod.c +++ b/src/platform/nx/main_sysmod.c @@ -36,6 +36,7 @@ int main(void) { g_ftpsrv_config.timeout = ini_getl("Network", "timeout", 0, INI_PATH); const bool log_enabled = ini_getbool("Log", "log", 0, INI_PATH); const bool mount_devices = ini_getbool("Nx", "mount_devices", 1, INI_PATH); + const bool mount_bis = ini_getbool("Nx", "mount_bis", 0, INI_PATH); const bool save_writable = ini_getbool("Nx", "save_writable", 0, INI_PATH); g_led_enabled = ini_getbool("Nx", "led", 1, INI_PATH); g_ftpsrv_config.port = ini_getl("Nx", "sys_port", g_ftpsrv_config.port, INI_PATH); @@ -44,25 +45,14 @@ int main(void) { log_file_init(LOG_PATH, "ftpsrv - " FTPSRV_VERSION_HASH " - NX-sys"); } - vfs_nx_init(mount_devices, save_writable); - if (mount_devices) { - fsdev_wrapMountImage("image_nand", FsImageDirectoryId_Nand); - fsdev_wrapMountImage("image_sd", FsImageDirectoryId_Sd); - - // add some shortcuts. - FsFileSystem* sdmc = fsdev_wrapGetDeviceFileSystem("sdmc"); - if (sdmc) { - fsdev_wrapMountDevice("switch", "/switch", *sdmc, false); - fsdev_wrapMountDevice("contents", "/atmosphere/contents", *sdmc, false); - } - } - // exit early as this is a security risk due to ldn-mitm. if (!user_len && !pass_len && !g_ftpsrv_config.anon) { log_file_write("User / Pass / Anon not set in config!"); return EXIT_FAILURE; } + vfs_nx_init(mount_devices, save_writable, mount_bis); + int timeout = -1; if (g_ftpsrv_config.timeout) { timeout = 1000 * g_ftpsrv_config.timeout; @@ -199,6 +189,8 @@ void __appInit(void) { diagAbortWithResult(rc); if (R_FAILED(rc = ncmInitialize())) diagAbortWithResult(rc); + if (R_FAILED(rc = setInitialize())) + diagAbortWithResult(rc); hidsysInitialize(); __libnx_init_time(); @@ -210,6 +202,7 @@ void __appExit(void) { vfs_nx_exit(); log_file_exit(); hidsysExit(); + setExit(); ncmExit(); accountExit(); socketExit(); diff --git a/src/platform/nx/utils.c b/src/platform/nx/utils.c index 2d30f44..673df5c 100644 --- a/src/platform/nx/utils.c +++ b/src/platform/nx/utils.c @@ -173,7 +173,7 @@ int fsdev_wrapMountDevice(const char *name, const char* shortcut, FsFileSystem f g_fsdev_entries[i].fs = fs; g_fsdev_entries[i].shortcut = shortcut; g_fsdev_entries[i].own = own; - strncpy(g_fsdev_entries[i].path, name, sizeof(g_fsdev_entries[i].path)); + snprintf(g_fsdev_entries[i].path, sizeof(g_fsdev_entries[i].path), name); return 0; } } diff --git a/src/platform/nx/vfs/vfs_nx_fs.c b/src/platform/nx/vfs/vfs_nx_fs.c index a946ec3..3e39658 100644 --- a/src/platform/nx/vfs/vfs_nx_fs.c +++ b/src/platform/nx/vfs/vfs_nx_fs.c @@ -300,8 +300,9 @@ enum FsError { FsError_DbmInvalidOperation = 0x3DD402, }; -static int set_errno_and_return_minus1(Result rc) { +int vfs_fs_set_errno(Result rc) { switch (rc) { + case FsError_TargetLocked: errno = EBUSY; break; case FsError_PathNotFound: errno = ENOENT; break; case FsError_PathAlreadyExists: errno = EEXIST; break; case FsError_UsableSpaceNotEnoughMmcCalibration: errno = ENOSPC; break; @@ -341,7 +342,7 @@ static time_t fsdev_converttimetoutc(u64 timestamp) } #if VFS_NX_BUFFER_WRITES -static Result flush_buffered_write(struct FtpVfsFsFile* f) { +static Result flush_buffered_write(struct VfsFsFile* f) { Result rc; if (R_SUCCEEDED(rc = fsFileSetSize(&f->fd, f->off + f->buf_off))) { rc = fsFileWrite(&f->fd, f->off, f->buf, f->buf_off, FsWriteOption_None); @@ -356,7 +357,7 @@ static int fstat_internal(FsFileSystem* fs, FsFile* file, const char nxpath[stat Result rc; s64 size; if (R_FAILED(rc = fsFileGetSize(file, &size))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } st->st_nlink = 1; @@ -374,7 +375,7 @@ static int fstat_internal(FsFileSystem* fs, FsFile* file, const char nxpath[stat return 0; } -int vfs_fs_internal_open(FsFileSystem* fs, struct FtpVfsFsFile* f, const char nxpath[static FS_MAX_PATH], enum FtpVfsOpenMode mode) { +int vfs_fs_internal_open(FsFileSystem* fs, struct VfsFsFile* f, const char nxpath[static FS_MAX_PATH], enum FtpVfsOpenMode mode) { u32 open_mode; if (mode == FtpVfsOpenMode_READ) { open_mode = FsOpenMode_Read; @@ -385,7 +386,7 @@ int vfs_fs_internal_open(FsFileSystem* fs, struct FtpVfsFsFile* f, const char nx Result rc; if (R_FAILED(rc = fsFsOpenFile(fs, nxpath, open_mode, &f->fd))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } f->off = f->chunk_size = 0; @@ -409,21 +410,21 @@ int vfs_fs_internal_open(FsFileSystem* fs, struct FtpVfsFsFile* f, const char nx fail_close: fsFileClose(&f->fd); - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } -int vfs_fs_internal_read(struct FtpVfsFsFile* f, void* buf, size_t size) { +int vfs_fs_internal_read(struct VfsFsFile* f, void* buf, size_t size) { Result rc; u64 bytes_read; if (R_FAILED(rc = fsFileRead(&f->fd, f->off, buf, size, FsReadOption_None, &bytes_read))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } f->off += bytes_read; return bytes_read; } -int vfs_fs_internal_write(struct FtpVfsFsFile* f, const void* buf, size_t size) { +int vfs_fs_internal_write(struct VfsFsFile* f, const void* buf, size_t size) { Result rc; #if VFS_NX_BUFFER_WRITES @@ -435,7 +436,7 @@ int vfs_fs_internal_write(struct FtpVfsFsFile* f, const void* buf, size_t size) f->buf_off += sz; if (R_FAILED(rc = flush_buffered_write(f))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } buf += sz; @@ -454,12 +455,12 @@ int vfs_fs_internal_write(struct FtpVfsFsFile* f, const void* buf, size_t size) if (f->chunk_size < f->off + size) { f->chunk_size += NX_WRITE_CHUNK_SIZE; if (R_FAILED(rc = fsFileSetSize(&f->fd, f->chunk_size))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } } if (R_FAILED(rc = fsFileWrite(&f->fd, f->off, buf, size, FsWriteOption_None))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } f->off += size; @@ -467,16 +468,16 @@ int vfs_fs_internal_write(struct FtpVfsFsFile* f, const void* buf, size_t size) #endif } -int vfs_fs_internal_seek(struct FtpVfsFsFile* f, size_t off) { +int vfs_fs_internal_seek(struct VfsFsFile* f, size_t off) { f->off = off; return 0; } -int vfs_fs_internal_fstat(FsFileSystem* fs, struct FtpVfsFsFile* f, const char nxpath[static FS_MAX_PATH], struct stat* st) { +int vfs_fs_internal_fstat(FsFileSystem* fs, struct VfsFsFile* f, const char nxpath[static FS_MAX_PATH], struct stat* st) { return fstat_internal(fs, &f->fd, nxpath, st); } -int vfs_fs_internal_close(struct FtpVfsFsFile* f) { +int vfs_fs_internal_close(struct VfsFsFile* f) { if (!vfs_fs_internal_isfile_open(f)) { return -1; } @@ -499,25 +500,25 @@ int vfs_fs_internal_close(struct FtpVfsFsFile* f) { return 0; } -int vfs_fs_internal_isfile_open(struct FtpVfsFsFile* f) { +int vfs_fs_internal_isfile_open(struct VfsFsFile* f) { return f->is_valid; } -int vfs_fs_internal_opendir(FsFileSystem* fs, struct FtpVfsFsDir* f, const char nxpath[static FS_MAX_PATH]) { +int vfs_fs_internal_opendir(FsFileSystem* fs, struct VfsFsDir* f, const char nxpath[static FS_MAX_PATH]) { Result rc; if (R_FAILED(rc = fsFsOpenDirectory(fs, nxpath, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &f->dir))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } f->is_valid = 1; return 0; } -const char* vfs_fs_internal_readdir(struct FtpVfsFsDir* f, struct FtpVfsFsDirEntry* entry) { +const char* vfs_fs_internal_readdir(struct VfsFsDir* f, struct VfsFsDirEntry* entry) { Result rc; s64 total_entries; if (R_FAILED(rc = fsDirRead(&f->dir, &total_entries, 1, &entry->buf))) { - set_errno_and_return_minus1(rc); + vfs_fs_set_errno(rc); return NULL; } @@ -528,7 +529,7 @@ const char* vfs_fs_internal_readdir(struct FtpVfsFsDir* f, struct FtpVfsFsDirEnt return entry->buf.name; } -int vfs_fs_internal_dirstat(FsFileSystem* fs, struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st) { +int vfs_fs_internal_dirstat(FsFileSystem* fs, struct VfsFsDir* f, const struct VfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st) { memset(st, 0, sizeof(*st)); st->st_nlink = 1; @@ -550,11 +551,11 @@ int vfs_fs_internal_dirstat(FsFileSystem* fs, struct FtpVfsFsDir* f, const struc return 0; } -int vfs_fs_internal_dirlstat(FsFileSystem* fs, struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st) { +int vfs_fs_internal_dirlstat(FsFileSystem* fs, struct VfsFsDir* f, const struct VfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st) { return vfs_fs_internal_dirstat(fs, f, entry, nxpath, st); } -int vfs_fs_internal_closedir(struct FtpVfsFsDir* f) { +int vfs_fs_internal_closedir(struct VfsFsDir* f) { if (!vfs_fs_internal_isdir_open(f)) { return -1; } @@ -564,7 +565,7 @@ int vfs_fs_internal_closedir(struct FtpVfsFsDir* f) { return 0; } -int vfs_fs_internal_isdir_open(struct FtpVfsFsDir* f) { +int vfs_fs_internal_isdir_open(struct VfsFsDir* f) { return f->is_valid; } @@ -574,13 +575,13 @@ int vfs_fs_internal_stat(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH] Result rc; FsDirEntryType type; if (R_FAILED(rc = fsFsGetEntryType(fs, nxpath, &type))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } if (type == FsDirEntryType_File) { FsFile file; if (R_FAILED(rc = fsFsOpenFile(fs, nxpath, FsOpenMode_Read, &file))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } const int rci = fstat_internal(fs, &file, nxpath, st); @@ -601,7 +602,7 @@ int vfs_fs_internal_lstat(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH int vfs_fs_internal_mkdir(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH]) { Result rc; if (R_FAILED(rc = fsFsCreateDirectory(fs, nxpath))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } return 0; @@ -610,7 +611,7 @@ int vfs_fs_internal_mkdir(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH int vfs_fs_internal_unlink(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH]) { Result rc; if (R_FAILED(rc = fsFsDeleteFile(fs, nxpath))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } return 0; @@ -619,7 +620,7 @@ int vfs_fs_internal_unlink(FsFileSystem* fs, const char nxpath[static FS_MAX_PAT int vfs_fs_internal_rmdir(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH]) { Result rc; if (R_FAILED(rc = fsFsDeleteDirectory(fs, nxpath))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } return 0; @@ -629,16 +630,16 @@ int vfs_fs_internal_rename(FsFileSystem* fs, const char nxpath_src[static FS_MAX Result rc; FsDirEntryType type; if (R_FAILED(rc = fsFsGetEntryType(fs, nxpath_src, &type))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } if (type == FsDirEntryType_File) { if (R_FAILED(rc = fsFsRenameFile(fs, nxpath_src, nxpath_dst))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } } else { if (R_FAILED(rc = fsFsRenameDirectory(fs, nxpath_src, nxpath_dst))) { - return set_errno_and_return_minus1(rc); + return vfs_fs_set_errno(rc); } } @@ -647,7 +648,8 @@ int vfs_fs_internal_rename(FsFileSystem* fs, const char nxpath_src[static FS_MAX //////////////////// -int ftp_vfs_fs_open(struct FtpVfsFsFile* f, const char* path, enum FtpVfsOpenMode mode) { +static int vfs_fs_open(void* user, const char* path, enum FtpVfsOpenMode mode) { + struct VfsFsFile* f = user; FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -656,19 +658,23 @@ int ftp_vfs_fs_open(struct FtpVfsFsFile* f, const char* path, enum FtpVfsOpenMod return vfs_fs_internal_open(fs, f, nxpath, mode); } -int ftp_vfs_fs_read(struct FtpVfsFsFile* f, void* buf, size_t size) { +static int vfs_fs_read(void* user, void* buf, size_t size) { + struct VfsFsFile* f = user; return vfs_fs_internal_read(f, buf, size); } -int ftp_vfs_fs_write(struct FtpVfsFsFile* f, const void* buf, size_t size) { +static int vfs_fs_write(void* user, const void* buf, size_t size) { + struct VfsFsFile* f = user; return vfs_fs_internal_write(f, buf, size); } -int ftp_vfs_fs_seek(struct FtpVfsFsFile* f, size_t off) { +static int vfs_fs_seek(void* user, size_t off) { + struct VfsFsFile* f = user; return vfs_fs_internal_seek(f, off); } -int ftp_vfs_fs_fstat(struct FtpVfsFsFile* f, const char* path, struct stat* st) { +static int vfs_fs_fstat(void* user, const char* path, struct stat* st) { + struct VfsFsFile* f = user; FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -677,18 +683,21 @@ int ftp_vfs_fs_fstat(struct FtpVfsFsFile* f, const char* path, struct stat* st) return fstat_internal(fs, &f->fd, nxpath, st); } -int ftp_vfs_fs_close(struct FtpVfsFsFile* f) { - if (!ftp_vfs_fs_isfile_open(f)) { +static int vfs_fs_isfile_open(void* user) { + struct VfsFsFile* f = user; + return vfs_fs_internal_isfile_open(f); +} + +static int vfs_fs_close(void* user) { + struct VfsFsFile* f = user; + if (!vfs_fs_isfile_open(f)) { return -1; } return vfs_fs_internal_close(f); } -int ftp_vfs_fs_isfile_open(struct FtpVfsFsFile* f) { - return vfs_fs_internal_isfile_open(f); -} - -int ftp_vfs_fs_opendir(struct FtpVfsFsDir* f, const char* path) { +static int vfs_fs_opendir(void* user, const char* path) { + struct VfsFsDir* f = user; FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -697,11 +706,15 @@ int ftp_vfs_fs_opendir(struct FtpVfsFsDir* f, const char* path) { return vfs_fs_internal_opendir(fs, f, nxpath); } -const char* ftp_vfs_fs_readdir(struct FtpVfsFsDir* f, struct FtpVfsFsDirEntry* entry) { +const char* vfs_fs_readdir(void* user, void* user_entry) { + struct VfsFsDir* f = user; + struct VfsFsDirEntry* entry = user_entry; return vfs_fs_internal_readdir(f, entry); } -int ftp_vfs_fs_dirstat(struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char* path, struct stat* st) { +static int vfs_fs_dirstat(void* user, const void* user_entry, const char* path, struct stat* st) { + struct VfsFsDir* f = user; + const struct VfsFsDirEntry* entry = user_entry; FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -710,19 +723,17 @@ int ftp_vfs_fs_dirstat(struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* ent return vfs_fs_internal_dirstat(fs, f, entry, nxpath, st); } -int ftp_vfs_fs_dirlstat(struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char* path, struct stat* st) { - return ftp_vfs_fs_dirstat(f, entry, path, st); +static int vfs_fs_isdir_open(void* user) { + struct VfsFsDir* f = user; + return vfs_fs_internal_isdir_open(f); } -int ftp_vfs_fs_closedir(struct FtpVfsFsDir* f) { +static int vfs_fs_closedir(void* user) { + struct VfsFsDir* f = user; return vfs_fs_internal_closedir(f); } -int ftp_vfs_fs_isdir_open(struct FtpVfsFsDir* f) { - return vfs_fs_internal_isdir_open(f); -} - -int ftp_vfs_fs_stat(const char* path, struct stat* st) { +static int vfs_fs_stat(const char* path, struct stat* st) { FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -731,11 +742,7 @@ int ftp_vfs_fs_stat(const char* path, struct stat* st) { return vfs_fs_internal_stat(fs, nxpath, st); } -int ftp_vfs_fs_lstat(const char* path, struct stat* st) { - return ftp_vfs_fs_stat(path, st); -} - -int ftp_vfs_fs_mkdir(const char* path) { +static int vfs_fs_mkdir(const char* path) { FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -744,7 +751,7 @@ int ftp_vfs_fs_mkdir(const char* path) { return vfs_fs_internal_mkdir(fs, nxpath); } -int ftp_vfs_fs_unlink(const char* path) { +static int vfs_fs_unlink(const char* path) { FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -753,7 +760,7 @@ int ftp_vfs_fs_unlink(const char* path) { return vfs_fs_internal_unlink(fs, nxpath); } -int ftp_vfs_fs_rmdir(const char* path) { +static int vfs_fs_rmdir(const char* path) { FsFileSystem* fs = NULL; char nxpath[FS_MAX_PATH]; if (fsdev_wrapTranslatePath(path, &fs, nxpath)) { @@ -762,7 +769,7 @@ int ftp_vfs_fs_rmdir(const char* path) { return vfs_fs_internal_rmdir(fs, nxpath); } -int ftp_vfs_fs_rename(const char* src, const char* dst) { +static int vfs_fs_rename(const char* src, const char* dst) { FsFileSystem* fs = NULL; FsFileSystem* fs_dst = NULL; char nxpath_src[FS_MAX_PATH]; @@ -779,3 +786,25 @@ int ftp_vfs_fs_rename(const char* src, const char* dst) { return vfs_fs_internal_rename(fs, nxpath_src, nxpath_dst); } + +const FtpVfs g_vfs_fs = { + .open = vfs_fs_open, + .read = vfs_fs_read, + .write = vfs_fs_write, + .seek = vfs_fs_seek, + .fstat = vfs_fs_fstat, + .close = vfs_fs_close, + .isfile_open = vfs_fs_isfile_open, + .opendir = vfs_fs_opendir, + .readdir = vfs_fs_readdir, + .dirstat = vfs_fs_dirstat, + .dirlstat = vfs_fs_dirstat, + .closedir = vfs_fs_closedir, + .isdir_open = vfs_fs_isdir_open, + .stat = vfs_fs_stat, + .lstat = vfs_fs_stat, + .mkdir = vfs_fs_mkdir, + .unlink = vfs_fs_unlink, + .rmdir = vfs_fs_rmdir, + .rename = vfs_fs_rename, +}; diff --git a/src/platform/nx/vfs/vfs_nx_fs.h b/src/platform/nx/vfs/vfs_nx_fs.h index 96b3a56..318a217 100644 --- a/src/platform/nx/vfs/vfs_nx_fs.h +++ b/src/platform/nx/vfs/vfs_nx_fs.h @@ -10,7 +10,7 @@ extern "C" { #include #include -struct FtpVfsFsFile { +struct VfsFsFile { FsFile fd; s64 off; s64 chunk_size; @@ -21,29 +21,30 @@ struct FtpVfsFsFile { #endif }; -struct FtpVfsFsDir { +struct VfsFsDir { FsDir dir; bool is_valid; }; -struct FtpVfsFsDirEntry { +struct VfsFsDirEntry { FsDirectoryEntry buf; }; -int vfs_fs_internal_open(FsFileSystem* fs, struct FtpVfsFsFile* f, const char nxpath[static FS_MAX_PATH], enum FtpVfsOpenMode mode); -int vfs_fs_internal_read(struct FtpVfsFsFile* f, void* buf, size_t size); -int vfs_fs_internal_write(struct FtpVfsFsFile* f, const void* buf, size_t size); -int vfs_fs_internal_seek(struct FtpVfsFsFile* f, size_t off); -int vfs_fs_internal_fstat(FsFileSystem* fs, struct FtpVfsFsFile* f, const char nxpath[static FS_MAX_PATH], struct stat* st); -int vfs_fs_internal_close(struct FtpVfsFsFile* f); -int vfs_fs_internal_isfile_open(struct FtpVfsFsFile* f); - -int vfs_fs_internal_opendir(FsFileSystem* fs, struct FtpVfsFsDir* f, const char nxpath[static FS_MAX_PATH]); -const char* vfs_fs_internal_readdir(struct FtpVfsFsDir* f, struct FtpVfsFsDirEntry* entry); -int vfs_fs_internal_dirstat(FsFileSystem* fs, struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st); -int vfs_fs_internal_dirlstat(FsFileSystem* fs, struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st); -int vfs_fs_internal_closedir(struct FtpVfsFsDir* f); -int vfs_fs_internal_isdir_open(struct FtpVfsFsDir* f); +int vfs_fs_set_errno(Result rc); +int vfs_fs_internal_open(FsFileSystem* fs, struct VfsFsFile* f, const char nxpath[static FS_MAX_PATH], enum FtpVfsOpenMode mode); +int vfs_fs_internal_read(struct VfsFsFile* f, void* buf, size_t size); +int vfs_fs_internal_write(struct VfsFsFile* f, const void* buf, size_t size); +int vfs_fs_internal_seek(struct VfsFsFile* f, size_t off); +int vfs_fs_internal_fstat(FsFileSystem* fs, struct VfsFsFile* f, const char nxpath[static FS_MAX_PATH], struct stat* st); +int vfs_fs_internal_close(struct VfsFsFile* f); +int vfs_fs_internal_isfile_open(struct VfsFsFile* f); + +int vfs_fs_internal_opendir(FsFileSystem* fs, struct VfsFsDir* f, const char nxpath[static FS_MAX_PATH]); +const char* vfs_fs_internal_readdir(struct VfsFsDir* f, struct VfsFsDirEntry* entry); +int vfs_fs_internal_dirstat(FsFileSystem* fs, struct VfsFsDir* f, const struct VfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st); +int vfs_fs_internal_dirlstat(FsFileSystem* fs, struct VfsFsDir* f, const struct VfsFsDirEntry* entry, const char nxpath[static FS_MAX_PATH], struct stat* st); +int vfs_fs_internal_closedir(struct VfsFsDir* f); +int vfs_fs_internal_isdir_open(struct VfsFsDir* f); int vfs_fs_internal_stat(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH], struct stat* st); int vfs_fs_internal_lstat(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH], struct stat* st); @@ -52,27 +53,8 @@ int vfs_fs_internal_unlink(FsFileSystem* fs, const char nxpath[static FS_MAX_PAT int vfs_fs_internal_rmdir(FsFileSystem* fs, const char nxpath[static FS_MAX_PATH]); int vfs_fs_internal_rename(FsFileSystem* fs, const char nxpath_src[static FS_MAX_PATH], const char nxpath_dst[static FS_MAX_PATH]); -int ftp_vfs_fs_open(struct FtpVfsFsFile* f, const char* path, enum FtpVfsOpenMode mode); -int ftp_vfs_fs_read(struct FtpVfsFsFile* f, void* buf, size_t size); -int ftp_vfs_fs_write(struct FtpVfsFsFile* f, const void* buf, size_t size); -int ftp_vfs_fs_seek(struct FtpVfsFsFile* f, size_t off); -int ftp_vfs_fs_fstat(struct FtpVfsFsFile* f, const char* path, struct stat* st); -int ftp_vfs_fs_close(struct FtpVfsFsFile* f); -int ftp_vfs_fs_isfile_open(struct FtpVfsFsFile* f); - -int ftp_vfs_fs_opendir(struct FtpVfsFsDir* f, const char* path); -const char* ftp_vfs_fs_readdir(struct FtpVfsFsDir* f, struct FtpVfsFsDirEntry* entry); -int ftp_vfs_fs_dirstat(struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_fs_dirlstat(struct FtpVfsFsDir* f, const struct FtpVfsFsDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_fs_closedir(struct FtpVfsFsDir* f); -int ftp_vfs_fs_isdir_open(struct FtpVfsFsDir* f); - -int ftp_vfs_fs_stat(const char* path, struct stat* st); -int ftp_vfs_fs_lstat(const char* path, struct stat* st); -int ftp_vfs_fs_mkdir(const char* path); -int ftp_vfs_fs_unlink(const char* path); -int ftp_vfs_fs_rmdir(const char* path); -int ftp_vfs_fs_rename(const char* src, const char* dst); +struct FtpVfs; +const extern struct FtpVfs g_vfs_fs; #ifdef __cplusplus } diff --git a/src/platform/nx/vfs/vfs_nx_hdd.c b/src/platform/nx/vfs/vfs_nx_hdd.c new file mode 100644 index 0000000..c9ddd7f --- /dev/null +++ b/src/platform/nx/vfs/vfs_nx_hdd.c @@ -0,0 +1,251 @@ +/** + * Copyright 2024 TotalJustice. + * SPDX-License-Identifier: MIT + */ + +#include "ftpsrv_vfs.h" +#include "log/log.h" +#include +#include +#include +#include +#include +#include +#include + +static UsbHsFsDevice g_device[0x20]; +static s32 g_count; + +static const char* fix_path(const char* path) { + return path + strlen("hdd:/"); +} + +static void poll_usbhsfs(void) { + g_count = usbHsFsListMountedDevices(g_device, sizeof(g_device)/sizeof(g_device[0])); +} + +static int vfs_hdd_open(void* user, const char* path, enum FtpVfsOpenMode mode) { + poll_usbhsfs(); + + path = fix_path(path); + if (strncmp(path, "ums", strlen("ums"))) { + return -1; + } + + struct VfsHddFile* f = user; + int flags = 0, args = 0; + + switch (mode) { + case FtpVfsOpenMode_READ: + flags = O_RDONLY; + args = 0; + break; + case FtpVfsOpenMode_WRITE: + flags = O_WRONLY | O_CREAT | O_TRUNC; + args = 0666; + break; + case FtpVfsOpenMode_APPEND: + flags = O_WRONLY | O_CREAT | O_APPEND; + args = 0666; + break; + } + + f->fd = open(path, flags, args); + if (f->fd >= 0) { + f->valid = 1; + } + return f->fd; +} + +static int vfs_hdd_read(void* user, void* buf, size_t size) { + struct VfsHddFile* f = user; + return read(f->fd, buf, size); +} + +static int vfs_hdd_write(void* user, const void* buf, size_t size) { + struct VfsHddFile* f = user; + return write(f->fd, buf, size); +} + +static int vfs_hdd_seek(void* user, size_t off) { + struct VfsHddFile* f = user; + return lseek(f->fd, off, SEEK_SET); +} + +static int vfs_hdd_fstat(void* user, const char* path, struct stat* st) { + struct VfsHddFile* f = user; + // fstat is not available with fatfs (fat32/exfat). + if (fstat(f->fd, st) && errno == ENOSYS) { + return stat(fix_path(path), st); + } + return 0; +} + +static int vfs_hdd_isfile_open(void* user) { + struct VfsHddFile* f = user; + return f->valid && f->fd >= 0; +} + +static int vfs_hdd_close(void* user) { + struct VfsHddFile* f = user; + if (!vfs_hdd_isfile_open(f)) { + return -1; + } + int rc = close(f->fd); + f->fd = -1; + f->valid = 0; + return rc; +} + +static int vfs_hdd_opendir(void* user, const char* path) { + poll_usbhsfs(); + struct VfsHddDir* f = user; + path = fix_path(path); + if (!strncmp(path, "ums", strlen("ums"))) { + f->fd = opendir(path); + if (!f->fd) { + return -1; + } + } + + f->index = 0; + f->is_valid = 1; + return 0; +} + +static const char* vfs_hdd_readdir(void* user, void* user_entry) { + struct VfsHddDir* f = user; + struct VfsHddDirEntry* entry = user_entry; + + if (f->fd) { + entry->d = readdir(f->fd); + if (!entry->d) { + return NULL; + } + return entry->d->d_name; + } else { + if (f->index >= g_count) { + return NULL; + } + return g_device[f->index++].name; + } +} + +static int vfs_hdd_dirstat(void* user, const void* user_entry, const char* path, struct stat* st) { + struct VfsHddDir* f = user; + path = fix_path(path); + if (f->fd) { + return stat(path, st); + } else { + memset(st, 0, sizeof(*st)); + st->st_nlink = 1; + st->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; + return 0; + } +} + +static int vfs_hdd_isdir_open(void* user) { + struct VfsHddDir* f = user; + return f->is_valid; +} + +static int vfs_hdd_closedir(void* user) { + struct VfsHddDir* f = user; + if (!vfs_hdd_isdir_open(f)) { + return -1; + } + if (f->fd) { + closedir(f->fd); + } + memset(f, 0, sizeof(*f)); + return 0; +} + +static int vfs_hdd_stat(const char* path, struct stat* st) { + poll_usbhsfs(); + path = fix_path(path); + if (strncmp(path, "ums", strlen("ums"))) { + return -1; + } + + if (strlen(path) == 5) { + memset(st, 0, sizeof(*st)); + st->st_nlink = 1; + st->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; + return 0; + } else { + return stat(path, st); + } +} + +static int vfs_hdd_mkdir(const char* path) { + poll_usbhsfs(); + path = fix_path(path); + if (strlen(path) <= 5 || strncmp(path, "ums", strlen("ums"))) { + return -1; + } + return mkdir(path, 0777); +} + +static int vfs_hdd_unlink(const char* path) { + poll_usbhsfs(); + path = fix_path(path); + if (strlen(path) <= 5 || strncmp(path, "ums", strlen("ums"))) { + return -1; + } + return unlink(path); +} + +static int vfs_hdd_rmdir(const char* path) { + poll_usbhsfs(); + path = fix_path(path); + if (strlen(path) <= 5 || strncmp(path, "ums", strlen("ums"))) { + return -1; + } + return rmdir(path); +} + +static int vfs_hdd_rename(const char* src, const char* dst) { + poll_usbhsfs(); + const char* path_src = fix_path(src); + const char* path_dst = fix_path(dst); + if (strlen(path_src) <= 5 || strncmp(path_src, "ums", strlen("ums"))) { + return -1; + } + + if (strncmp(path_src, path_dst, 6)) { + return -1; + } + + return rename(path_src, path_dst); +} + +Result vfs_hdd_init(void) { + return usbHsFsInitialize(0); +} + +void vfs_hdd_exit(void) { + usbHsFsExit(); +} + +const FtpVfs g_vfs_hdd = { + .open = vfs_hdd_open, + .read = vfs_hdd_read, + .write = vfs_hdd_write, + .seek = vfs_hdd_seek, + .fstat = vfs_hdd_fstat, + .close = vfs_hdd_close, + .isfile_open = vfs_hdd_isfile_open, + .opendir = vfs_hdd_opendir, + .readdir = vfs_hdd_readdir, + .dirstat = vfs_hdd_dirstat, + .dirlstat = vfs_hdd_dirstat, + .closedir = vfs_hdd_closedir, + .isdir_open = vfs_hdd_isdir_open, + .stat = vfs_hdd_stat, + .lstat = vfs_hdd_stat, + .mkdir = vfs_hdd_mkdir, + .unlink = vfs_hdd_unlink, + .rmdir = vfs_hdd_rmdir, + .rename = vfs_hdd_rename, +}; diff --git a/src/platform/nx/vfs/vfs_nx_hdd.h b/src/platform/nx/vfs/vfs_nx_hdd.h new file mode 100644 index 0000000..3c36e42 --- /dev/null +++ b/src/platform/nx/vfs/vfs_nx_hdd.h @@ -0,0 +1,36 @@ +// Copyright 2024 TotalJustice. +// SPDX-License-Identifier: MIT +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +struct VfsHddFile { + int fd; + int valid; +}; + +struct VfsHddDir { + DIR* fd; + size_t index; + bool is_valid; +}; + +struct VfsHddDirEntry { + struct dirent* d; +}; + +struct FtpVfs; +const extern struct FtpVfs g_vfs_hdd; + +Result vfs_hdd_init(void); +void vfs_hdd_exit(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/platform/nx/vfs/vfs_nx_ncm.c b/src/platform/nx/vfs/vfs_nx_ncm.c deleted file mode 100644 index 4bc3679..0000000 --- a/src/platform/nx/vfs/vfs_nx_ncm.c +++ /dev/null @@ -1,191 +0,0 @@ -/** - * Copyright 2024 TotalJustice. - * SPDX-License-Identifier: MIT - */ - -#include "ftpsrv_vfs.h" -#include -#include -#include -#include - -static NcmContentStorage g_cs; - -static char* hexIdToStr(char* buf, NcmContentId* id) { - const u64 id_lower = __builtin_bswap64(*(u64*)id->c); - const u64 id_upper = __builtin_bswap64(*(u64*)(id->c + 0x8)); - snprintf(buf, 0x21, "%016lx%016lx", id_lower, id_upper); - return buf; -} - -static NcmContentId parse_hex_key(const char* hex) { - NcmContentId id = {0}; - char low[0x11] = {0}; - char upp[0x11] = {0}; - memcpy(low, hex, 0x10); - memcpy(upp, hex + 0x10, 0x10); - *(u64*)id.c = __builtin_bswap64(strtoull(low, NULL, 0x10)); - *(u64*)(id.c + 8) = __builtin_bswap64(strtoull(upp, NULL, 0x10)); - return id; -} - -int ftp_vfs_ncm_open(struct FtpVfsNcmFile* f, const char* path, enum FtpVfsOpenMode mode) { - if (mode != FtpVfsOpenMode_READ) { - errno = EACCES; - return -1; - } - - const char* dilem = strchr(path, '/'); - if (!dilem) { - errno = ENOENT; - return -1; - } - - Result rc; - f->id = parse_hex_key(dilem + 1); - if (R_FAILED(rc = ncmContentStorageGetSizeFromContentId(&g_cs, &f->size, &f->id))) { - errno = ENOENT; - return -1; - } - - f->is_valid = 1; - return 0; -} - -int ftp_vfs_ncm_read(struct FtpVfsNcmFile* f, void* buf, size_t size) { - #define min(x, y) ((x) < (y) ? (x) : (y)) - size = min(size, f->size - f->offset); - - Result rc; - if (R_FAILED(rc = ncmContentStorageReadContentIdFile(&g_cs, buf, size, &f->id, f->offset))) { - errno = EIO; - return -1; - } - - f->offset += size; - return size; -} - -int ftp_vfs_ncm_write(struct FtpVfsNcmFile* f, const void* buf, size_t size) { - errno = EACCES; - return -1; -} - -int ftp_vfs_ncm_seek(struct FtpVfsNcmFile* f, size_t off) { - f->offset = off; - return 0; -} - -int ftp_vfs_ncm_fstat(struct FtpVfsNcmFile* f, const char* path, struct stat* st) { - memset(st, 0, sizeof(*st)); - st->st_nlink = 1; - st->st_size = f->size; - st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; - return 0; -} - -int ftp_vfs_ncm_close(struct FtpVfsNcmFile* f) { - if (!ftp_vfs_ncm_isfile_open(f)) { - return -1; - } - - memset(f, 0, sizeof(*f)); - return 0; -} - -int ftp_vfs_ncm_isfile_open(struct FtpVfsNcmFile* f) { - return f->is_valid; -} - -int ftp_vfs_ncm_opendir(struct FtpVfsNcmDir* f, const char* path) { - f->index = 0; - f->is_valid = 1; - return 0; -} - -const char* ftp_vfs_ncm_readdir(struct FtpVfsNcmDir* f, struct FtpVfsNcmDirEntry* entry) { - Result rc; - s32 count; - if (R_FAILED(rc = ncmContentStorageListContentId(&g_cs, &entry->id, 1, &count, f->index))) { - errno = EIO; - return NULL; - } - - if (count <= 0) { - return NULL; - } - - f->index++; - return hexIdToStr(entry->name, &entry->id); -} - -int ftp_vfs_ncm_dirstat(struct FtpVfsNcmDir* f, const struct FtpVfsNcmDirEntry* entry, const char* path, struct stat* st) { - memset(st, 0, sizeof(*st)); - - Result rc; - s64 out_size; - if (R_FAILED(rc = ncmContentStorageGetSizeFromContentId(&g_cs, &out_size, &entry->id))) { - errno = EIO; - return -1; - } - - st->st_nlink = 1; - st->st_size = out_size; - st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; - return 0; -} - -int ftp_vfs_ncm_dirlstat(struct FtpVfsNcmDir* f, const struct FtpVfsNcmDirEntry* entry, const char* path, struct stat* st) { - return ftp_vfs_ncm_dirstat(f, entry, path, st); -} - -int ftp_vfs_ncm_closedir(struct FtpVfsNcmDir* f) { - if (!ftp_vfs_ncm_isdir_open(f)) { - return -1; - } - memset(f, 0, sizeof(*f)); - return 0; -} - -int ftp_vfs_ncm_isdir_open(struct FtpVfsNcmDir* f) { - return f->is_valid; -} - -int ftp_vfs_ncm_stat(const char* path, struct stat* st) { - memset(st, 0, sizeof(*st)); - st->st_nlink = 1; - st->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; - return 0; -} - -int ftp_vfs_ncm_lstat(const char* path, struct stat* st) { - return ftp_vfs_ncm_stat(path, st); -} - -int ftp_vfs_ncm_mkdir(const char* path) { - errno = EACCES; - return -1; -} - -int ftp_vfs_ncm_unlink(const char* path) { - errno = EACCES; - return -1; -} - -int ftp_vfs_ncm_rmdir(const char* path) { - errno = EACCES; - return -1; -} - -int ftp_vfs_ncm_rename(const char* src, const char* dst) { - errno = EACCES; - return -1; -} - -void ftp_vfs_ncm_init(void) { - ncmOpenContentStorage(&g_cs, NcmStorageId_BuiltInSystem); -} - -void ftp_vfs_ncm_exit(void) { - ncmContentStorageClose(&g_cs); -} diff --git a/src/platform/nx/vfs/vfs_nx_ncm.h b/src/platform/nx/vfs/vfs_nx_ncm.h deleted file mode 100644 index 771d167..0000000 --- a/src/platform/nx/vfs/vfs_nx_ncm.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2024 TotalJustice. -// SPDX-License-Identifier: MIT -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -struct FtpVfsNcmFile { - NcmContentId id; - s64 size; - s64 offset; - bool is_valid; -}; - -struct FtpVfsNcmDir { - s32 index; - bool is_valid; -}; - -struct FtpVfsNcmDirEntry { - NcmContentId id; - char name[128]; -}; - -int ftp_vfs_ncm_open(struct FtpVfsNcmFile* f, const char* path, enum FtpVfsOpenMode mode); -int ftp_vfs_ncm_read(struct FtpVfsNcmFile* f, void* buf, size_t size); -int ftp_vfs_ncm_write(struct FtpVfsNcmFile* f, const void* buf, size_t size); -int ftp_vfs_ncm_seek(struct FtpVfsNcmFile* f, size_t off); -int ftp_vfs_ncm_fstat(struct FtpVfsNcmFile* f, const char* path, struct stat* st); -int ftp_vfs_ncm_close(struct FtpVfsNcmFile* f); -int ftp_vfs_ncm_isfile_open(struct FtpVfsNcmFile* f); - -int ftp_vfs_ncm_opendir(struct FtpVfsNcmDir* f, const char* path); -const char* ftp_vfs_ncm_readdir(struct FtpVfsNcmDir* f, struct FtpVfsNcmDirEntry* entry); -int ftp_vfs_ncm_dirstat(struct FtpVfsNcmDir* f, const struct FtpVfsNcmDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_ncm_dirlstat(struct FtpVfsNcmDir* f, const struct FtpVfsNcmDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_ncm_closedir(struct FtpVfsNcmDir* f); -int ftp_vfs_ncm_isdir_open(struct FtpVfsNcmDir* f); - -int ftp_vfs_ncm_stat(const char* path, struct stat* st); -int ftp_vfs_ncm_lstat(const char* path, struct stat* st); -int ftp_vfs_ncm_mkdir(const char* path); -int ftp_vfs_ncm_unlink(const char* path); -int ftp_vfs_ncm_rmdir(const char* path); -int ftp_vfs_ncm_rename(const char* src, const char* dst); - -void ftp_vfs_ncm_init(void); -void ftp_vfs_ncm_exit(void); - -#ifdef __cplusplus -} -#endif diff --git a/src/platform/nx/vfs/vfs_nx_root.c b/src/platform/nx/vfs/vfs_nx_root.c index 19dbc8e..b8ab027 100644 --- a/src/platform/nx/vfs/vfs_nx_root.c +++ b/src/platform/nx/vfs/vfs_nx_root.c @@ -8,107 +8,124 @@ #include #include -static const char* DEVICES[] = { - "sdmc:", - "image_nand:", - "image_sd:", - "switch:", - "contents:", - - // "ns:", - "firmware:", - // "gc:", - "save:", -}; +static const struct VfsDeviceEntry* g_entries; +static const u32* g_count; -int ftp_vfs_root_open(struct FtpVfsRootFile* f, const char* path, enum FtpVfsOpenMode mode) { +static int vfs_root_open(void* user, const char* path, enum FtpVfsOpenMode mode) { return -1; } -int ftp_vfs_root_read(struct FtpVfsRootFile* f, void* buf, size_t size) { +static int vfs_root_read(void* user, void* buf, size_t size) { return -1; } -int ftp_vfs_root_write(struct FtpVfsRootFile* f, const void* buf, size_t size) { +static int vfs_root_write(void* user, const void* buf, size_t size) { return -1; } -int ftp_vfs_root_seek(struct FtpVfsRootFile* f, size_t off) { +static int vfs_root_seek(void* user, size_t off) { return -1; } -int ftp_vfs_root_fstat(struct FtpVfsRootFile* f, const char* path, struct stat* st) { +static int vfs_root_fstat(void* user, const char* path, struct stat* st) { return -1; } -int ftp_vfs_root_close(struct FtpVfsRootFile* f) { +static int vfs_root_isfile_open(void* user) { return -1; } -int ftp_vfs_root_isfile_open(struct FtpVfsRootFile* f) { +static int vfs_root_close(void* user) { return -1; } -int ftp_vfs_root_opendir(struct FtpVfsRootDir* f, const char* path) { +static int vfs_root_opendir(void* user, const char* path) { + struct VfsRootDir* f = user; f->index = 0; f->is_valid = 1; return 0; } -const char* ftp_vfs_root_readdir(struct FtpVfsRootDir* f, struct FtpVfsRootDirEntry* entry) { - if (f->index < sizeof(DEVICES) / sizeof(DEVICES[0])) { - return DEVICES[f->index++]; +static const char* vfs_root_readdir(void* user, void* user_entry) { + struct VfsRootDir* f = user; + if (f->index < *g_count) { + return g_entries[f->index++].name; } else { return NULL; } } -int ftp_vfs_root_dirstat(struct FtpVfsRootDir* f, const struct FtpVfsRootDirEntry* entry, const char* path, struct stat* st) { +static int vfs_root_dirstat(void* user, const void* user_entry, const char* path, struct stat* st) { memset(st, 0, sizeof(*st)); st->st_nlink = 1; st->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; return 0; } -int ftp_vfs_root_dirlstat(struct FtpVfsRootDir* f, const struct FtpVfsRootDirEntry* entry, const char* path, struct stat* st) { - return ftp_vfs_root_dirstat(f, entry, path, st); +static int vfs_root_isdir_open(void* user) { + struct VfsRootDir* f = user; + return f->is_valid; } -int ftp_vfs_root_closedir(struct FtpVfsRootDir* f) { - if (!ftp_vfs_root_isdir_open(f)) { +static int vfs_root_closedir(void* user) { + struct VfsRootDir* f = user; + if (!vfs_root_isdir_open(f)) { return -1; } memset(f, 0, sizeof(*f)); return 0; } -int ftp_vfs_root_isdir_open(struct FtpVfsRootDir* f) { - return f->is_valid; -} - -int ftp_vfs_root_stat(const char* path, struct stat* st) { +static int vfs_root_stat(const char* path, struct stat* st) { memset(st, 0, sizeof(*st)); st->st_nlink = 1; st->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; return 0; } -int ftp_vfs_root_lstat(const char* path, struct stat* st) { - return ftp_vfs_root_stat(path, st); +static int vfs_root_mkdir(const char* path) { + return -1; } -int ftp_vfs_root_mkdir(const char* path) { +static int vfs_root_unlink(const char* path) { return -1; } -int ftp_vfs_root_unlink(const char* path) { +static int vfs_root_rmdir(const char* path) { return -1; } -int ftp_vfs_root_rmdir(const char* path) { +static int vfs_root_rename(const char* src, const char* dst) { return -1; } -int ftp_vfs_root_rename(const char* src, const char* dst) { - return -1; +void vfs_root_init(const struct VfsDeviceEntry* entries, const u32* count) { + g_entries = entries; + g_count = count; +} + +void vfs_root_exit(void) { + } + +const FtpVfs g_vfs_root = { + .open = vfs_root_open, + .read = vfs_root_read, + .write = vfs_root_write, + .seek = vfs_root_seek, + .fstat = vfs_root_fstat, + .close = vfs_root_close, + .isfile_open = vfs_root_isfile_open, + .opendir = vfs_root_opendir, + .readdir = vfs_root_readdir, + .dirstat = vfs_root_dirstat, + .dirlstat = vfs_root_dirstat, + .closedir = vfs_root_closedir, + .isdir_open = vfs_root_isdir_open, + .stat = vfs_root_stat, + .lstat = vfs_root_stat, + .mkdir = vfs_root_mkdir, + .unlink = vfs_root_unlink, + .rmdir = vfs_root_rmdir, + .rename = vfs_root_rename, +}; diff --git a/src/platform/nx/vfs/vfs_nx_root.h b/src/platform/nx/vfs/vfs_nx_root.h index 33034c8..f294255 100644 --- a/src/platform/nx/vfs/vfs_nx_root.h +++ b/src/platform/nx/vfs/vfs_nx_root.h @@ -7,43 +7,30 @@ extern "C" { #endif #include -#include -#include +#include -struct FtpVfsRootFile { +struct VfsDeviceEntry { + char name[32]; +}; + +struct VfsRootFile { bool padding; }; -struct FtpVfsRootDir { +struct VfsRootDir { size_t index; bool is_valid; }; -struct FtpVfsRootDirEntry { +struct VfsRootDirEntry { char buf[64]; }; -int ftp_vfs_root_open(struct FtpVfsRootFile* f, const char* path, enum FtpVfsOpenMode mode); -int ftp_vfs_root_read(struct FtpVfsRootFile* f, void* buf, size_t size); -int ftp_vfs_root_write(struct FtpVfsRootFile* f, const void* buf, size_t size); -int ftp_vfs_root_seek(struct FtpVfsRootFile* f, size_t off); -int ftp_vfs_root_fstat(struct FtpVfsRootFile* f, const char* path, struct stat* st); -int ftp_vfs_root_close(struct FtpVfsRootFile* f); -int ftp_vfs_root_isfile_open(struct FtpVfsRootFile* f); - -int ftp_vfs_root_opendir(struct FtpVfsRootDir* f, const char* path); -const char* ftp_vfs_root_readdir(struct FtpVfsRootDir* f, struct FtpVfsRootDirEntry* entry); -int ftp_vfs_root_dirstat(struct FtpVfsRootDir* f, const struct FtpVfsRootDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_root_dirlstat(struct FtpVfsRootDir* f, const struct FtpVfsRootDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_root_closedir(struct FtpVfsRootDir* f); -int ftp_vfs_root_isdir_open(struct FtpVfsRootDir* f); - -int ftp_vfs_root_stat(const char* path, struct stat* st); -int ftp_vfs_root_lstat(const char* path, struct stat* st); -int ftp_vfs_root_mkdir(const char* path); -int ftp_vfs_root_unlink(const char* path); -int ftp_vfs_root_rmdir(const char* path); -int ftp_vfs_root_rename(const char* src, const char* dst); +struct FtpVfs; +const extern struct FtpVfs g_vfs_root; + +void vfs_root_init(const struct VfsDeviceEntry* entries, const u32* count); +void vfs_root_exit(void); #ifdef __cplusplus } diff --git a/src/platform/nx/vfs/vfs_nx_save.c b/src/platform/nx/vfs/vfs_nx_save.c index 1021bd1..8c798c5 100644 --- a/src/platform/nx/vfs/vfs_nx_save.c +++ b/src/platform/nx/vfs/vfs_nx_save.c @@ -5,6 +5,7 @@ #include "ftpsrv_vfs.h" #include "../utils.h" +#include "log/log.h" #include #include #include @@ -26,7 +27,7 @@ struct SaveCacheEntry { }; static struct SaveCacheEntry g_save_cache[16]; -static struct SaveAcc g_acc_profile[10]; +static struct SaveAcc g_acc_profile[12]; static s32 g_acc_count; static bool g_writable; @@ -44,25 +45,31 @@ static FsFileSystem* mount_save_fs(const struct SavePathData* d) { struct SaveCacheEntry* entry = &g_save_cache[i]; if (!entry->ref_count) { FsSaveDataAttribute attr = {0}; - attr.application_id = d->app_id; - attr.uid = d->uid; attr.save_data_type = d->data_type; - Result rc; - if (g_writable) { - rc = fsOpenSaveDataFileSystem(&entry->fs, FsSaveDataSpaceId_User, &attr); + + if (d->data_type == FsSaveDataType_System) { + attr.system_save_data_id = d->app_id; + rc = fsOpenSaveDataFileSystemBySystemSaveDataId(&entry->fs, d->space_id, &attr); } else { - rc = fsOpenReadOnlySaveDataFileSystem(&entry->fs, FsSaveDataSpaceId_User, &attr); + attr.application_id = d->app_id; + attr.uid = d->uid; + if (g_writable) { + rc = fsOpenSaveDataFileSystem(&entry->fs, d->space_id, &attr); + } else { + rc = fsOpenReadOnlySaveDataFileSystem(&entry->fs, d->space_id, &attr); + } } if (R_FAILED(rc)) { - // printf("\tfailed to open save: 0x%X id: %016lX\n", rc, d->app_id); + vfs_fs_set_errno(rc); + log_file_fwrite("failed: fsOpenReadOnlySaveDataFileSystem(%016lX) 0x%X\n", d->app_id, rc); return NULL; } - entry->uid = attr.uid; - entry->app_id = attr.application_id; - entry->type = attr.save_data_type; + entry->uid = d->uid; + entry->app_id = d->app_id; + entry->type = d->data_type; entry->ref_count++; return &entry->fs; } @@ -88,16 +95,26 @@ static void unmount_save_fs(const struct SavePathData* d) { static struct SavePathData get_type(const char* path) { struct SavePathData data = {0}; - if (!strcmp(path, "save:")) { data.type = SaveDirType_Root; } else { const char* dilem = strchr(path, '['); + data.space_id = FsSaveDataSpaceId_User; if (!strncmp(path, "save:/bcat", strlen("save:/bcat"))) { data.data_type = FsSaveDataType_Bcat; + data.space_id = FsSaveDataSpaceId_User; data.type = SaveDirType_User; } else if (!strncmp(path, "save:/cache", strlen("save:/cache"))) { data.data_type = FsSaveDataType_Cache; + data.space_id = FsSaveDataSpaceId_SdUser; + data.type = SaveDirType_User; + } else if (!strncmp(path, "save:/device", strlen("save:/device"))) { + data.data_type = FsSaveDataType_Device; + data.space_id = FsSaveDataSpaceId_User; + data.type = SaveDirType_User; + } else if (!strncmp(path, "save:/system", strlen("save:/system"))) { + data.data_type = FsSaveDataType_System; + data.space_id = FsSaveDataSpaceId_System; data.type = SaveDirType_User; } else if (dilem && strlen(dilem) >= 33) { dilem++; @@ -109,6 +126,7 @@ static struct SavePathData get_type(const char* path) { data.uid.uid[1] = strtoull(uid_buf[1], NULL, 0x10); data.data_type = FsSaveDataType_Account; + data.space_id = FsSaveDataSpaceId_User; data.type = SaveDirType_User; dilem = strchr(dilem, '['); } @@ -133,7 +151,13 @@ static void build_native_path(char out[static FS_MAX_PATH], const char* path, co } } -int ftp_vfs_save_open(struct FtpVfsSaveFile* f, const char* path, enum FtpVfsOpenMode mode) { +static int vfs_save_open(void* user, const char* path, enum FtpVfsOpenMode mode) { + if (mode != FtpVfsOpenMode_READ && !g_writable) { + errno = EROFS; + return -1; + } + + struct VfsSaveFile* f = user; f->data = get_type(path); if (f->data.type != SaveDirType_App) { return -1; @@ -156,26 +180,41 @@ int ftp_vfs_save_open(struct FtpVfsSaveFile* f, const char* path, enum FtpVfsOpe return 0; } -int ftp_vfs_save_read(struct FtpVfsSaveFile* f, void* buf, size_t size) { +static int vfs_save_read(void* user, void* buf, size_t size) { + struct VfsSaveFile* f = user; return vfs_fs_internal_read(&f->fs_file, buf, size); } -int ftp_vfs_save_write(struct FtpVfsSaveFile* f, const void* buf, size_t size) { +static int vfs_save_write(void* user, const void* buf, size_t size) { + if (!g_writable) { + errno = EROFS; + return -1; + } + + struct VfsSaveFile* f = user; return vfs_fs_internal_write(&f->fs_file, buf, size); } -int ftp_vfs_save_seek(struct FtpVfsSaveFile* f, size_t off) { +static int vfs_save_seek(void* user, size_t off) { + struct VfsSaveFile* f = user; return vfs_fs_internal_seek(&f->fs_file, off); } -int ftp_vfs_save_fstat(struct FtpVfsSaveFile* f, const char* path, struct stat* st) { +static int vfs_save_fstat(void* user, const char* path, struct stat* st) { + struct VfsSaveFile* f = user; char nxpath[FS_MAX_PATH]; build_native_path(nxpath, path, &f->data); return vfs_fs_internal_fstat(&f->fs, &f->fs_file, nxpath, st); } -int ftp_vfs_save_close(struct FtpVfsSaveFile* f) { - if (!ftp_vfs_save_isfile_open(f)) { +static int vfs_save_isfile_open(void* user) { + struct VfsSaveFile* f = user; + return f->is_valid; +} + +static int vfs_save_close(void* user) { + struct VfsSaveFile* f = user; + if (!vfs_save_isfile_open(f)) { return -1; } vfs_fs_internal_close(&f->fs_file); @@ -184,12 +223,10 @@ int ftp_vfs_save_close(struct FtpVfsSaveFile* f) { return 0; } -int ftp_vfs_save_isfile_open(struct FtpVfsSaveFile* f) { - return f->is_valid; -} - -int ftp_vfs_save_opendir(struct FtpVfsSaveDir* f, const char* path) { +static int vfs_save_opendir(void* user, const char* path) { + struct VfsSaveDir* f = user; f->data = get_type(path); + if (f->data.type == SaveDirType_Invalid) { return -1; } else if (f->data.type == SaveDirType_User) { @@ -203,8 +240,8 @@ int ftp_vfs_save_opendir(struct FtpVfsSaveDir* f, const char* path) { } Result rc; - if (R_FAILED(rc = fsOpenSaveDataInfoReaderWithFilter(&f->r, FsSaveDataSpaceId_User, &filter))) { - // printf("\tfailed to open filter: 0x%X %016lX%016lX vs %016lX%016lX\n", rc, p->uid.uid[0], p->uid.uid[1], f->data.uid.uid[0], f->data.uid.uid[1]); + if (R_FAILED(rc = fsOpenSaveDataInfoReaderWithFilter(&f->r, f->data.space_id, &filter))) { + log_file_fwrite("failed: fsOpenSaveDataInfoReaderWithFilter() 0x%X\n", rc); return -1; } } else if (f->data.type == SaveDirType_App) { @@ -227,7 +264,10 @@ int ftp_vfs_save_opendir(struct FtpVfsSaveDir* f, const char* path) { return 0; } -const char* ftp_vfs_save_readdir(struct FtpVfsSaveDir* f, struct FtpVfsSaveDirEntry* entry) { +static const char* vfs_save_readdir(void* user, void* user_entry) { + struct VfsSaveDir* f = user; + struct VfsSaveDirEntry* entry = user_entry; + Result rc; switch (f->data.type) { default: case SaveDirType_Invalid: @@ -250,21 +290,26 @@ const char* ftp_vfs_save_readdir(struct FtpVfsSaveDir* f, struct FtpVfsSaveDirEn case SaveDirType_User: { s64 total; if (R_FAILED(rc = fsSaveDataInfoReaderRead(&f->r, &entry->info, 1, &total))) { + log_file_fwrite("failed: fsSaveDataInfoReaderRead() 0x%X\n", rc); return NULL; } if (total <= 0) { + log_file_fwrite("fsSaveDataInfoReaderRead() no more entries %zd\n", total); return NULL; } // this can fail if the game is no longer installed. NcmContentId id; struct AppName name; - if (R_FAILED(rc = get_app_name(entry->info.application_id, &id, &name))) { + if (f->data.data_type == FsSaveDataType_System) { + snprintf(entry->name, sizeof(entry->name), "[%016lX]", entry->info.system_save_data_id); + } else if (R_FAILED(rc = get_app_name(entry->info.application_id, &id, &name))) { snprintf(entry->name, sizeof(entry->name), "[%016lX]", entry->info.application_id); } else { snprintf(entry->name, sizeof(entry->name), "%s [%016lX]", name.str, entry->info.application_id); } + return entry->name; } @@ -274,7 +319,10 @@ const char* ftp_vfs_save_readdir(struct FtpVfsSaveDir* f, struct FtpVfsSaveDirEn } } -int ftp_vfs_save_dirstat(struct FtpVfsSaveDir* f, const struct FtpVfsSaveDirEntry* entry, const char* path, struct stat* st) { +static int vfs_save_dirstat(void* user, const void* user_entry, const char* path, struct stat* st) { + struct VfsSaveDir* f = user; + const struct VfsSaveDirEntry* entry = user_entry; + if (f->data.type == SaveDirType_App) { char nxpath[FS_MAX_PATH]; build_native_path(nxpath, path, &f->data); @@ -287,12 +335,14 @@ int ftp_vfs_save_dirstat(struct FtpVfsSaveDir* f, const struct FtpVfsSaveDirEntr return 0; } -int ftp_vfs_save_dirlstat(struct FtpVfsSaveDir* f, const struct FtpVfsSaveDirEntry* entry, const char* path, struct stat* st) { - return ftp_vfs_save_dirstat(f, entry, path, st); +static int vfs_save_isdir_open(void* user) { + struct VfsSaveDir* f = user; + return f->is_valid; } -int ftp_vfs_save_closedir(struct FtpVfsSaveDir* f) { - if (!ftp_vfs_save_isdir_open(f)) { +static int vfs_save_closedir(void* user) { + struct VfsSaveDir* f = user; + if (!vfs_save_isdir_open(f)) { return -1; } @@ -307,11 +357,7 @@ int ftp_vfs_save_closedir(struct FtpVfsSaveDir* f) { return 0; } -int ftp_vfs_save_isdir_open(struct FtpVfsSaveDir* f) { - return f->is_valid; -} - -int ftp_vfs_save_stat(const char* path, struct stat* st) { +static int vfs_save_stat(const char* path, struct stat* st) { memset(st, 0, sizeof(*st)); st->st_nlink = 1; @@ -336,11 +382,12 @@ int ftp_vfs_save_stat(const char* path, struct stat* st) { return 0; } -int ftp_vfs_save_lstat(const char* path, struct stat* st) { - return ftp_vfs_save_stat(path, st); -} +static int vfs_save_mkdir(const char* path) { + if (!g_writable) { + errno = EROFS; + return -1; + } -int ftp_vfs_save_mkdir(const char* path) { const struct SavePathData data = get_type(path); if (data.type != SaveDirType_App) { return -1; @@ -358,7 +405,12 @@ int ftp_vfs_save_mkdir(const char* path) { return rc; } -int ftp_vfs_save_unlink(const char* path) { +static int vfs_save_unlink(const char* path) { + if (!g_writable) { + errno = EROFS; + return -1; + } + const struct SavePathData data = get_type(path); if (data.type != SaveDirType_App) { return -1; @@ -376,7 +428,12 @@ int ftp_vfs_save_unlink(const char* path) { return rc; } -int ftp_vfs_save_rmdir(const char* path) { +static int vfs_save_rmdir(const char* path) { + if (!g_writable) { + errno = EROFS; + return -1; + } + const struct SavePathData data = get_type(path); if (data.type != SaveDirType_App) { return -1; @@ -394,7 +451,12 @@ int ftp_vfs_save_rmdir(const char* path) { return rc; } -int ftp_vfs_save_rename(const char* src, const char* dst) { +static int vfs_save_rename(const char* src, const char* dst) { + if (!g_writable) { + errno = EROFS; + return -1; + } + const struct SavePathData data_src = get_type(src); const struct SavePathData data_dst = get_type(dst); if (data_src.type != SaveDirType_App) { @@ -419,17 +481,24 @@ int ftp_vfs_save_rename(const char* src, const char* dst) { return rc; } -void ftp_vfs_save_init(bool save_writable) { +void vfs_save_init(bool save_writable) { g_writable = save_writable; AccountUid uids[8]; s32 count; - if (R_SUCCEEDED(accountListAllUsers(uids, 8, &count))) { + Result rc; + if (R_FAILED(rc = accountListAllUsers(uids, 8, &count))) { + log_file_fwrite("failed: accountListAllUsers() 0x%X\n", rc); + } else { for (int i = 0; i < count; i++) { AccountProfile profile; - if (R_SUCCEEDED(accountGetProfile(&profile, uids[i]))) { + if (R_FAILED(rc = accountGetProfile(&profile, uids[i]))) { + log_file_fwrite("failed: accountGetProfile() 0x%X\n", rc); + } else { AccountProfileBase base; - if (R_SUCCEEDED(accountProfileGet(&profile, NULL, &base))) { + if (R_FAILED(rc = accountProfileGet(&profile, NULL, &base))) { + log_file_fwrite("failed: accountProfileGet() 0x%X\n", rc); + } else { strcpy(g_acc_profile[g_acc_count].name, base.nickname); g_acc_profile[g_acc_count].uid = base.uid; g_acc_count++; @@ -437,14 +506,15 @@ void ftp_vfs_save_init(bool save_writable) { accountProfileClose(&profile); } } - - strcpy(g_acc_profile[g_acc_count++].name, "bcat"); - // doesn't work? - // strcpy(g_acc_profile[g_acc_count++].name, "cache"); } + + strcpy(g_acc_profile[g_acc_count++].name, "bcat"); + strcpy(g_acc_profile[g_acc_count++].name, "cache"); + strcpy(g_acc_profile[g_acc_count++].name, "device"); + strcpy(g_acc_profile[g_acc_count++].name, "system"); } -void ftp_vfs_save_exit(void) { +void vfs_save_exit(void) { for (int i = 0; i < 16; i++) { struct SaveCacheEntry* entry = &g_save_cache[i]; if (entry->ref_count) { @@ -455,3 +525,25 @@ void ftp_vfs_save_exit(void) { } } } + +const FtpVfs g_vfs_save = { + .open = vfs_save_open, + .read = vfs_save_read, + .write = vfs_save_write, + .seek = vfs_save_seek, + .fstat = vfs_save_fstat, + .close = vfs_save_close, + .isfile_open = vfs_save_isfile_open, + .opendir = vfs_save_opendir, + .readdir = vfs_save_readdir, + .dirstat = vfs_save_dirstat, + .dirlstat = vfs_save_dirstat, + .closedir = vfs_save_closedir, + .isdir_open = vfs_save_isdir_open, + .stat = vfs_save_stat, + .lstat = vfs_save_stat, + .mkdir = vfs_save_mkdir, + .unlink = vfs_save_unlink, + .rmdir = vfs_save_rmdir, + .rename = vfs_save_rename, +}; diff --git a/src/platform/nx/vfs/vfs_nx_save.h b/src/platform/nx/vfs/vfs_nx_save.h index 51c9893..62a1163 100644 --- a/src/platform/nx/vfs/vfs_nx_save.h +++ b/src/platform/nx/vfs/vfs_nx_save.h @@ -7,7 +7,6 @@ extern "C" { #endif #include -#include #include #include "vfs_nx_fs.h" @@ -22,60 +21,42 @@ struct SavePathData { enum SaveDirType type; AccountUid uid; FsSaveDataType data_type; + FsSaveDataSpaceId space_id; u64 app_id; size_t path_off; }; -struct FtpVfsSaveFile { +struct VfsSaveFile { struct SavePathData data; - struct FtpVfsFsFile fs_file; + struct VfsFsFile fs_file; FsFileSystem fs; bool is_valid; }; -struct FtpVfsSaveDir { +struct VfsSaveDir { struct SavePathData data; FsSaveDataInfoReader r; FsFileSystem fs; - struct FtpVfsFsDir fs_dir; + struct VfsFsDir fs_dir; s32 index; bool is_valid; }; -struct FtpVfsSaveDirEntry { +struct VfsSaveDirEntry { union { struct { FsSaveDataInfo info; char name[512 + 128]; }; - struct FtpVfsFsDirEntry fs_buf; + struct VfsFsDirEntry fs_buf; }; }; -int ftp_vfs_save_open(struct FtpVfsSaveFile* f, const char* path, enum FtpVfsOpenMode mode); -int ftp_vfs_save_read(struct FtpVfsSaveFile* f, void* buf, size_t size); -int ftp_vfs_save_write(struct FtpVfsSaveFile* f, const void* buf, size_t size); -int ftp_vfs_save_seek(struct FtpVfsSaveFile* f, size_t off); -int ftp_vfs_save_fstat(struct FtpVfsSaveFile* f, const char* path, struct stat* st); -int ftp_vfs_save_close(struct FtpVfsSaveFile* f); -int ftp_vfs_save_isfile_open(struct FtpVfsSaveFile* f); +void vfs_save_init(bool save_writable); +void vfs_save_exit(void); -int ftp_vfs_save_opendir(struct FtpVfsSaveDir* f, const char* path); -const char* ftp_vfs_save_readdir(struct FtpVfsSaveDir* f, struct FtpVfsSaveDirEntry* entry); -int ftp_vfs_save_dirstat(struct FtpVfsSaveDir* f, const struct FtpVfsSaveDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_save_dirlstat(struct FtpVfsSaveDir* f, const struct FtpVfsSaveDirEntry* entry, const char* path, struct stat* st); -int ftp_vfs_save_closedir(struct FtpVfsSaveDir* f); -int ftp_vfs_save_isdir_open(struct FtpVfsSaveDir* f); - -int ftp_vfs_save_stat(const char* path, struct stat* st); -int ftp_vfs_save_lstat(const char* path, struct stat* st); -int ftp_vfs_save_mkdir(const char* path); -int ftp_vfs_save_unlink(const char* path); -int ftp_vfs_save_rmdir(const char* path); -int ftp_vfs_save_rename(const char* src, const char* dst); - -void ftp_vfs_save_init(bool save_writable); -void ftp_vfs_save_exit(void); +struct FtpVfs; +const extern struct FtpVfs g_vfs_save; #ifdef __cplusplus } diff --git a/src/platform/nx/vfs_nx.c b/src/platform/nx/vfs_nx.c index 6fcb84c..de439d2 100644 --- a/src/platform/nx/vfs_nx.c +++ b/src/platform/nx/vfs_nx.c @@ -4,14 +4,126 @@ */ #include "ftpsrv_vfs.h" +#include "log/log.h" #include "utils.h" #include #include #include +#define NCM_SIZE 2 +#define DEVICE_NUM 32 + static bool g_enabled_devices = false; -static NcmContentStorage g_cs[2]; -static NcmContentMetaDatabase g_db[2]; +static NcmContentStorage g_cs[NCM_SIZE]; +static NcmContentMetaDatabase g_db[NCM_SIZE]; +static struct VfsDeviceEntry g_device[DEVICE_NUM]; +static enum VFS_TYPE g_device_type[DEVICE_NUM]; +static u32 g_device_count; + +static int set_errno_and_return_minus1(void) { + errno = ENOENT; + return -1; +} + +static int vfs_none_open(void* user, const char* path, enum FtpVfsOpenMode mode) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_read(void* user, void* buf, size_t size) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_write(void* user, const void* buf, size_t size) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_seek(void* user, size_t off) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_fstat(void* user, const char* path, struct stat* st) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_isfile_open(void* user) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_close(void* user) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_opendir(void* user, const char* path) { + return set_errno_and_return_minus1(); +} + +static const char* vfs_none_readdir(void* user, void* user_entry) { + return NULL; +} + +static int vfs_none_dirstat(void* user, const void* user_entry, const char* path, struct stat* st) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_isdir_open(void* user) { + return 0; +} + +static int vfs_none_closedir(void* user) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_stat(const char* path, struct stat* st) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_mkdir(const char* path) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_unlink(const char* path) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_rmdir(const char* path) { + return set_errno_and_return_minus1(); +} + +static int vfs_none_rename(const char* src, const char* dst) { + return set_errno_and_return_minus1(); +} + +static const FtpVfs g_vfs_none = { + .open = vfs_none_open, + .read = vfs_none_read, + .write = vfs_none_write, + .seek = vfs_none_seek, + .fstat = vfs_none_fstat, + .close = vfs_none_close, + .isfile_open = vfs_none_isfile_open, + .opendir = vfs_none_opendir, + .readdir = vfs_none_readdir, + .dirstat = vfs_none_dirstat, + .dirlstat = vfs_none_dirstat, + .closedir = vfs_none_closedir, + .isdir_open = vfs_none_isdir_open, + .stat = vfs_none_stat, + .lstat = vfs_none_stat, + .mkdir = vfs_none_mkdir, + .unlink = vfs_none_unlink, + .rmdir = vfs_none_rmdir, + .rename = vfs_none_rename, +}; + +static const FtpVfs* g_vfs[] = { + [VFS_TYPE_NONE] = &g_vfs_none, + [VFS_TYPE_ROOT] = &g_vfs_root, + [VFS_TYPE_FS] = &g_vfs_fs, + [VFS_TYPE_SAVE] = &g_vfs_save, +#if USE_USBHSFS + [VFS_TYPE_HDD] = &g_vfs_hdd, +#endif +}; static bool is_path(const char* path, const char* name) { if (path[0] == '/') { @@ -28,12 +140,10 @@ static enum VFS_TYPE get_type(const char* path) { if (!path || !strcmp(path, "/")) { return VFS_TYPE_ROOT; } else if (strchr(path, ':')) { - if (is_path(path, "firmware:")) { - return VFS_TYPE_NCM; - } else if (is_path(path, "save:")) { - return VFS_TYPE_SAVE; - } else { - return VFS_TYPE_FS; + for (u32 i = 0; i < g_device_count; i++) { + if (is_path(path, g_device[i].name)) { + return g_device_type[i]; + } } } @@ -53,111 +163,48 @@ static const char* fix_path(const char* path, enum VFS_TYPE type) { } } -static int set_errno_and_return_minus1(void) { - errno = ENOENT; - return -1; -} - int ftp_vfs_open(struct FtpVfsFile* f, const char* path, enum FtpVfsOpenMode mode) { f->type = get_type(path); - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_open(&f->root, fix_path(path, f->type), mode); - case VFS_TYPE_FS: return ftp_vfs_fs_open(&f->fs, fix_path(path, f->type), mode); - case VFS_TYPE_NCM: return ftp_vfs_ncm_open(&f->ncm, fix_path(path, f->type), mode); - case VFS_TYPE_SAVE: return ftp_vfs_save_open(&f->save, fix_path(path, f->type), mode); - } + return g_vfs[f->type]->open(&f->root, fix_path(path, f->type), mode); } int ftp_vfs_read(struct FtpVfsFile* f, void* buf, size_t size) { - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_read(&f->root, buf, size); - case VFS_TYPE_FS: return ftp_vfs_fs_read(&f->fs, buf, size); - case VFS_TYPE_NCM: return ftp_vfs_ncm_read(&f->ncm, buf, size); - case VFS_TYPE_SAVE: return ftp_vfs_save_read(&f->save, buf, size); - } + return g_vfs[f->type]->read(&f->root, buf, size); } int ftp_vfs_write(struct FtpVfsFile* f, const void* buf, size_t size) { - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_write(&f->root, buf, size); - case VFS_TYPE_FS: return ftp_vfs_fs_write(&f->fs, buf, size); - case VFS_TYPE_NCM: return ftp_vfs_ncm_write(&f->ncm, buf, size); - case VFS_TYPE_SAVE: return ftp_vfs_save_write(&f->save, buf, size); - } + return g_vfs[f->type]->write(&f->root, buf, size); } int ftp_vfs_seek(struct FtpVfsFile* f, size_t off) { - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_seek(&f->root, off); - case VFS_TYPE_FS: return ftp_vfs_fs_seek(&f->fs, off); - case VFS_TYPE_NCM: return ftp_vfs_ncm_seek(&f->ncm, off); - case VFS_TYPE_SAVE: return ftp_vfs_save_seek(&f->save, off); - } + return g_vfs[f->type]->seek(&f->root, off); } int ftp_vfs_fstat(struct FtpVfsFile* f, const char* path, struct stat* st) { - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_fstat(&f->root, fix_path(path, f->type), st); - case VFS_TYPE_FS: return ftp_vfs_fs_fstat(&f->fs, fix_path(path, f->type), st); - case VFS_TYPE_NCM: return ftp_vfs_ncm_fstat(&f->ncm, fix_path(path, f->type), st); - case VFS_TYPE_SAVE: return ftp_vfs_save_fstat(&f->save, fix_path(path, f->type), st); - } + return g_vfs[f->type]->fstat(&f->root, fix_path(path, f->type), st); } int ftp_vfs_close(struct FtpVfsFile* f) { - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_close(&f->root); - case VFS_TYPE_FS: return ftp_vfs_fs_close(&f->fs); - case VFS_TYPE_NCM: return ftp_vfs_ncm_close(&f->ncm); - case VFS_TYPE_SAVE: return ftp_vfs_save_close(&f->save); - } + const enum VFS_TYPE type = f->type; + f->type = VFS_TYPE_NONE; + return g_vfs[type]->close(&f->root); } int ftp_vfs_isfile_open(struct FtpVfsFile* f) { - switch (f->type) { - default: case VFS_TYPE_NONE: return 0; - case VFS_TYPE_ROOT: return ftp_vfs_root_isfile_open(&f->root); - case VFS_TYPE_FS: return ftp_vfs_fs_isfile_open(&f->fs); - case VFS_TYPE_NCM: return ftp_vfs_ncm_isfile_open(&f->ncm); - case VFS_TYPE_SAVE: return ftp_vfs_save_isfile_open(&f->save); - } + return g_vfs[f->type]->isfile_open(&f->root); } int ftp_vfs_opendir(struct FtpVfsDir* f, const char* path) { f->type = get_type(path); - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_opendir(&f->root, fix_path(path, f->type)); - case VFS_TYPE_FS: return ftp_vfs_fs_opendir(&f->fs, fix_path(path, f->type)); - case VFS_TYPE_NCM: return ftp_vfs_ncm_opendir(&f->ncm, fix_path(path, f->type)); - case VFS_TYPE_SAVE: return ftp_vfs_save_opendir(&f->save, fix_path(path, f->type)); - } + return g_vfs[f->type]->opendir(&f->root, fix_path(path, f->type)); } const char* ftp_vfs_readdir(struct FtpVfsDir* f, struct FtpVfsDirEntry* entry) { - switch (f->type) { - default: case VFS_TYPE_NONE: return NULL; - case VFS_TYPE_ROOT: return ftp_vfs_root_readdir(&f->root, &entry->root); - case VFS_TYPE_FS: return ftp_vfs_fs_readdir(&f->fs, &entry->fs); - case VFS_TYPE_NCM: return ftp_vfs_ncm_readdir(&f->ncm, &entry->ncm); - case VFS_TYPE_SAVE: return ftp_vfs_save_readdir(&f->save, &entry->save); - } + return g_vfs[f->type]->readdir(&f->root, &entry->root); } int ftp_vfs_dirstat(struct FtpVfsDir* f, const struct FtpVfsDirEntry* entry, const char* path, struct stat* st) { - switch (f->type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_dirstat(&f->root, &entry->root, fix_path(path, f->type), st); - case VFS_TYPE_FS: return ftp_vfs_fs_dirstat(&f->fs, &entry->fs, fix_path(path, f->type), st); - case VFS_TYPE_NCM: return ftp_vfs_ncm_dirstat(&f->ncm, &entry->ncm, fix_path(path, f->type), st); - case VFS_TYPE_SAVE: return ftp_vfs_save_dirstat(&f->save, &entry->save, fix_path(path, f->type), st); - } + return g_vfs[f->type]->dirstat(&f->root, &entry->root, fix_path(path, f->type), st); } int ftp_vfs_dirlstat(struct FtpVfsDir* f, const struct FtpVfsDirEntry* entry, const char* path, struct stat* st) { @@ -167,24 +214,11 @@ int ftp_vfs_dirlstat(struct FtpVfsDir* f, const struct FtpVfsDirEntry* entry, co int ftp_vfs_closedir(struct FtpVfsDir* f) { const enum VFS_TYPE type = f->type; f->type = VFS_TYPE_NONE; - - switch (type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_closedir(&f->root); - case VFS_TYPE_FS: return ftp_vfs_fs_closedir(&f->fs); - case VFS_TYPE_NCM: return ftp_vfs_ncm_closedir(&f->ncm); - case VFS_TYPE_SAVE: return ftp_vfs_save_closedir(&f->save); - } + return g_vfs[type]->closedir(&f->root); } int ftp_vfs_isdir_open(struct FtpVfsDir* f) { - switch (f->type) { - default: case VFS_TYPE_NONE: return 0; - case VFS_TYPE_ROOT: return ftp_vfs_root_isdir_open(&f->root); - case VFS_TYPE_FS: return ftp_vfs_fs_isdir_open(&f->fs); - case VFS_TYPE_NCM: return ftp_vfs_ncm_isdir_open(&f->ncm); - case VFS_TYPE_SAVE: return ftp_vfs_save_isdir_open(&f->save); - } + return g_vfs[f->type]->isdir_open(&f->root); } int ftp_vfs_stat(const char* path, struct stat* st) { @@ -192,16 +226,10 @@ int ftp_vfs_stat(const char* path, struct stat* st) { const char* dilem = strchr(path, ':'); if (type != VFS_TYPE_NONE && dilem && (!strcmp(dilem, ":") || !strcmp(dilem, ":/"))) { - return ftp_vfs_root_stat(path, st); + return g_vfs[VFS_TYPE_ROOT]->stat(fix_path(path, type), st); } - switch (type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_stat(fix_path(path, type), st); - case VFS_TYPE_FS: return ftp_vfs_fs_stat(fix_path(path, type), st); - case VFS_TYPE_NCM: return ftp_vfs_ncm_stat(fix_path(path, type), st); - case VFS_TYPE_SAVE: return ftp_vfs_save_stat(fix_path(path, type), st); - } + return g_vfs[type]->stat(fix_path(path, type), st); } int ftp_vfs_lstat(const char* path, struct stat* st) { @@ -210,35 +238,17 @@ int ftp_vfs_lstat(const char* path, struct stat* st) { int ftp_vfs_mkdir(const char* path) { const enum VFS_TYPE type = get_type(path); - switch (type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_mkdir(fix_path(path, type)); - case VFS_TYPE_FS: return ftp_vfs_fs_mkdir(fix_path(path, type)); - case VFS_TYPE_NCM: return ftp_vfs_ncm_mkdir(fix_path(path, type)); - case VFS_TYPE_SAVE: return ftp_vfs_save_mkdir(fix_path(path, type)); - } + return g_vfs[type]->mkdir(fix_path(path, type)); } int ftp_vfs_unlink(const char* path) { const enum VFS_TYPE type = get_type(path); - switch (type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_unlink(fix_path(path, type)); - case VFS_TYPE_FS: return ftp_vfs_fs_unlink(fix_path(path, type)); - case VFS_TYPE_NCM: return ftp_vfs_ncm_unlink(fix_path(path, type)); - case VFS_TYPE_SAVE: return ftp_vfs_save_unlink(fix_path(path, type)); - } + return g_vfs[type]->unlink(fix_path(path, type)); } int ftp_vfs_rmdir(const char* path) { const enum VFS_TYPE type = get_type(path); - switch (type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_rmdir(fix_path(path, type)); - case VFS_TYPE_FS: return ftp_vfs_fs_rmdir(fix_path(path, type)); - case VFS_TYPE_NCM: return ftp_vfs_ncm_rmdir(fix_path(path, type)); - case VFS_TYPE_SAVE: return ftp_vfs_save_rmdir(fix_path(path, type)); - } + return g_vfs[type]->rmdir(fix_path(path, type)); } int ftp_vfs_rename(const char* src, const char* dst) { @@ -249,13 +259,7 @@ int ftp_vfs_rename(const char* src, const char* dst) { return -1; } - switch (src_type) { - default: case VFS_TYPE_NONE: return set_errno_and_return_minus1(); - case VFS_TYPE_ROOT: return ftp_vfs_root_rename(fix_path(src, src_type), fix_path(dst, dst_type)); - case VFS_TYPE_FS: return ftp_vfs_fs_rename(fix_path(src, src_type), fix_path(dst, dst_type)); - case VFS_TYPE_NCM: return ftp_vfs_ncm_rename(fix_path(src, src_type), fix_path(dst, dst_type)); - case VFS_TYPE_SAVE: return ftp_vfs_save_rename(fix_path(src, src_type), fix_path(dst, dst_type)); - } + return g_vfs[src_type]->rename(fix_path(src, src_type), fix_path(dst, dst_type)); } int ftp_vfs_readlink(const char* path, char* buf, size_t buflen) { @@ -270,50 +274,75 @@ const char* ftp_vfs_getgrgid(const struct stat* st) { return "unknown"; } +static const u32 g_nacpLanguageTable[15] = { + [SetLanguage_JA] = 2, + [SetLanguage_ENUS] = 0, + [SetLanguage_ENGB] = 1, + [SetLanguage_FR] = 3, + [SetLanguage_DE] = 4, + [SetLanguage_ES419] = 5, + [SetLanguage_ES] = 6, + [SetLanguage_IT] = 7, + [SetLanguage_NL] = 8, + [SetLanguage_FRCA] = 9, + [SetLanguage_PT] = 10, + [SetLanguage_RU] = 11, + [SetLanguage_KO] = 12, + [SetLanguage_ZHTW] = 13, + [SetLanguage_ZHCN] = 14, +}; + +static u8 g_lang_index; + Result get_app_name(u64 app_id, NcmContentId* id, struct AppName* name) { Result rc; - for (int i = 0; i < 2; i++) { + for (int i = 0; i < NCM_SIZE; i++) { NcmContentMetaKey key; s32 entries_total; s32 entries_written; - if (R_FAILED(rc = ncmContentMetaDatabaseList(&g_db[i], &entries_total, &entries_written, &key, 1, NcmContentMetaType_Application, app_id, app_id, app_id, NcmContentInstallType_Full))) { - // printf("failed to list ncm\n"); + if (R_FAILED(rc = ncmContentMetaDatabaseList(&g_db[i], &entries_total, &entries_written, &key, 1, NcmContentMetaType_Application, app_id, 0, UINT64_MAX, NcmContentInstallType_Full))) { continue; } if (R_FAILED(rc = ncmContentMetaDatabaseGetContentIdByType(&g_db[i], id, &key, NcmContentType_Control))) { - // printf("failed to list id\n"); continue; } char nxpath[FS_MAX_PATH] = {0}; if (R_FAILED(rc = ncmContentStorageGetPath(&g_cs[i], nxpath, sizeof(nxpath), id))) { - // printf("failed to get path: %s \n", nxpath); continue; } FsFileSystem fs; - if (R_FAILED(rc = fsOpenFileSystemWithId(&fs, key.id, FsFileSystemType_ContentControl, nxpath, FsContentAttributes_None))) { - // printf("failed to open fs: %s \n", nxpath); + if (R_FAILED(rc = fsOpenFileSystemWithId(&fs, key.id, FsFileSystemType_ContentControl, nxpath, FsContentAttributes_All))) { continue; } strcpy(nxpath, "/control.nacp"); FsFile file; if (R_FAILED(rc = fsFsOpenFile(&fs, nxpath, FsOpenMode_Read, &file))) { - // printf("failed to open file: %s \n", nxpath); fsFsClose(&fs); continue; } + name->str[0] = '\0'; + s64 off = g_lang_index * sizeof(NacpLanguageEntry); u64 bytes_read; - rc = fsFileRead(&file, 0, name->str, sizeof(name->str), 0, &bytes_read); + rc = fsFileRead(&file, off, name->str, sizeof(name->str), 0, &bytes_read); + if (name->str[0] == '\0') { + for (int i = 0; i < 16; i++) { + off = i * sizeof(NacpLanguageEntry); + rc = fsFileRead(&file, off, name->str, sizeof(name->str), 0, &bytes_read); + if (name->str[0] != '\0') { + break; + } + } + } fsFileClose(&file); fsFsClose(&fs); if (R_FAILED(rc) || bytes_read != sizeof(name->str)) { - // printf("failed to read file: %s \n", nxpath); continue; } @@ -323,29 +352,89 @@ Result get_app_name(u64 app_id, NcmContentId* id, struct AppName* name) { return rc; } -void vfs_nx_init(bool enable_devices, bool save_writable) { +void vfs_nx_init(bool enable_devices, bool save_writable, bool mount_bis) { g_enabled_devices = enable_devices; if (g_enabled_devices) { - for (int i = 0; i < 2; i++) { - ncmOpenContentStorage(&g_cs[i], NcmStorageId_SdCard - i); - ncmOpenContentMetaDatabase(&g_db[i], NcmStorageId_SdCard - i); + + // sorted based on most common + const NcmStorageId ids[NCM_SIZE] = { + NcmStorageId_SdCard, + NcmStorageId_BuiltInUser, + }; + + for (int i = 0; i < NCM_SIZE; i++) { + Result rc; + if (R_FAILED(rc = ncmOpenContentStorage(&g_cs[i], ids[i]))) { + log_file_fwrite("failed: ncmOpenContentStorage() 0x%X\n", rc); + } + if (R_FAILED(rc = ncmOpenContentMetaDatabase(&g_db[i], ids[i]))) { + log_file_fwrite("failed: ncmOpenContentMetaDatabase() 0x%X\n", rc); + } } - // ftp_vfs_ns_init(); - ftp_vfs_ncm_init(); - // ftp_vfs_gc_init(); - ftp_vfs_save_init(save_writable); + vfs_nx_add_device("sdmc", VFS_TYPE_FS); + + if (!fsdev_wrapMountImage("image_nand", FsImageDirectoryId_Nand)) { + vfs_nx_add_device("image_nand", VFS_TYPE_FS); + } + if (!fsdev_wrapMountImage("image_sd", FsImageDirectoryId_Sd)) { + vfs_nx_add_device("image_sd", VFS_TYPE_FS); + } + + if (mount_bis) { + if (!fsdev_wrapMountBis("bis_system", FsBisPartitionId_System)) { + vfs_nx_add_device("bis_system", VFS_TYPE_FS); + } + if (!fsdev_wrapMountBis("bis_safe", FsBisPartitionId_SafeMode)) { + vfs_nx_add_device("bis_safe", VFS_TYPE_FS); + } + if (!fsdev_wrapMountBis("bis_user", FsBisPartitionId_User)) { + vfs_nx_add_device("bis_user", VFS_TYPE_FS); + } + } + + // add some shortcuts. + FsFileSystem* sdmc = fsdev_wrapGetDeviceFileSystem("sdmc"); + if (sdmc) { + if (!fsdev_wrapMountDevice("switch", "/switch", *sdmc, false)) { + vfs_nx_add_device("switch", VFS_TYPE_FS); + } + if (!fsdev_wrapMountDevice("contents", "/atmosphere/contents", *sdmc, false)) { + vfs_nx_add_device("contents", VFS_TYPE_FS); + } + } + + vfs_save_init(save_writable); + vfs_nx_add_device("save", VFS_TYPE_SAVE); +#if USE_USBHSFS + vfs_hdd_init(); + vfs_nx_add_device("hdd", VFS_TYPE_HDD); +#endif + vfs_root_init(g_device, &g_device_count); + + u64 LanguageCode; + SetLanguage Language; + if (R_SUCCEEDED(setGetSystemLanguage(&LanguageCode))) { + setMakeLanguage(LanguageCode, &Language); + } + + if (Language < 0 || Language >= 15) { + Language = SetLanguage_ENUS; + } + + g_lang_index = g_nacpLanguageTable[Language]; } } void vfs_nx_exit(void) { if (g_enabled_devices) { - // ftp_vfs_ns_exit(); - ftp_vfs_ncm_exit(); - // ftp_vfs_gc_exit(); - ftp_vfs_save_exit(); + vfs_save_exit(); +#if USE_USBHSFS + vfs_hdd_exit(); +#endif + vfs_root_exit(); - for (int i = 0; i < 2; i++) { + for (int i = 0; i < NCM_SIZE; i++) { ncmContentStorageClose(&g_cs[i]); ncmContentMetaDatabaseClose(&g_db[i]); } @@ -353,3 +442,17 @@ void vfs_nx_exit(void) { g_enabled_devices = false; } } + +void vfs_nx_add_device(const char* name, enum VFS_TYPE type) { + if (g_device_count >= 32) { + return; + } + + if (strlen(name) >= sizeof(g_device[0].name) + 2) { + return; + } + + snprintf(g_device[g_device_count].name, sizeof(g_device[g_device_count].name), "%s:", name); + g_device_type[g_device_count] = type; + g_device_count++; +} diff --git a/src/platform/nx/vfs_nx.h b/src/platform/nx/vfs_nx.h index 76142a7..d2edaa1 100644 --- a/src/platform/nx/vfs_nx.h +++ b/src/platform/nx/vfs_nx.h @@ -12,45 +12,54 @@ extern "C" { #include "vfs/vfs_nx_root.h" #include "vfs/vfs_nx_fs.h" -#include "vfs/vfs_nx_ncm.h" #include "vfs/vfs_nx_save.h" +#if USE_USBHSFS +#include "vfs/vfs_nx_hdd.h" +#endif enum VFS_TYPE { VFS_TYPE_NONE, VFS_TYPE_ROOT, // list root devices VFS_TYPE_FS, // list native fs devices - VFS_TYPE_NCM, // list nca's, uses ncm VFS_TYPE_SAVE, // list xci, uses ncm +#if USE_USBHSFS + VFS_TYPE_HDD, // list xci, uses ncm +#endif }; struct FtpVfsFile { enum VFS_TYPE type; union { - struct FtpVfsRootFile root; - struct FtpVfsFsFile fs; - struct FtpVfsNcmFile ncm; - struct FtpVfsSaveFile save; + struct VfsRootFile root; + struct VfsFsFile fs; + struct VfsSaveFile save; +#if USE_USBHSFS + struct VfsHddFile usbhsfs; +#endif }; }; - struct FtpVfsDir { enum VFS_TYPE type; union { - struct FtpVfsRootDir root; - struct FtpVfsFsDir fs; - struct FtpVfsNcmDir ncm; - struct FtpVfsSaveDir save; + struct VfsRootDir root; + struct VfsFsDir fs; + struct VfsSaveDir save; +#if USE_USBHSFS + struct VfsHddDir usbhsfs; +#endif }; }; struct FtpVfsDirEntry { enum VFS_TYPE type; union { - struct FtpVfsRootDirEntry root; - struct FtpVfsFsDirEntry fs; - struct FtpVfsNcmDirEntry ncm; - struct FtpVfsSaveDirEntry save; + struct VfsRootDirEntry root; + struct VfsFsDirEntry fs; + struct VfsSaveDirEntry save; +#if USE_USBHSFS + struct VfsHddDirEntry usbhsfs; +#endif }; }; @@ -58,8 +67,36 @@ struct AppName { char str[0x200]; }; -void vfs_nx_init(bool enable_devices, bool save_writable); +typedef struct FtpVfs { + // vfs_file + int (*open)(void* user, const char* path, enum FtpVfsOpenMode mode); + int (*read)(void* user, void* buf, size_t size); + int (*write)(void* user, const void* buf, size_t size); + int (*seek)(void* user, size_t off); + int (*fstat)(void* user, const char* path, struct stat* st); + int (*close)(void* user); + int (*isfile_open)(void* user); + + // vfs_dir + int (*opendir)(void* user, const char* path); + const char* (*readdir)(void* user, void* user_entry); + int (*dirstat)(void* user, const void* user_entry, const char* path, struct stat* st); + int (*dirlstat)(void* user, const void* user_entry, const char* path, struct stat* st); + int (*closedir)(void* user); + int (*isdir_open)(void* user); + + // vfs_sys + int (*stat)(const char* path, struct stat* st); + int (*lstat)(const char* path, struct stat* st); + int (*mkdir)(const char* path); + int (*unlink)(const char* path); + int (*rmdir)(const char* path); + int (*rename)(const char* src, const char* dst); +} FtpVfs; + +void vfs_nx_init(bool enable_devices, bool save_writable, bool mount_bis); void vfs_nx_exit(void); +void vfs_nx_add_device(const char* name, enum VFS_TYPE type); Result get_app_name(u64 app_id, NcmContentId* id, struct AppName* name); diff --git a/src/platform/unistd/main.c b/src/platform/unistd/main.c index 8bfb4e7..ee70f4d 100644 --- a/src/platform/unistd/main.c +++ b/src/platform/unistd/main.c @@ -88,10 +88,10 @@ int main(int argc, char** argv) { ftpsrv_config.port = arg_data.value.i; break; case ArgsId_user: - strncpy(ftpsrv_config.user, arg_data.value.s, sizeof(ftpsrv_config.user)); + snprintf(ftpsrv_config.user, sizeof(ftpsrv_config.user), arg_data.value.s); break; case ArgsId_pass: - strncpy(ftpsrv_config.pass, arg_data.value.s, sizeof(ftpsrv_config.pass)); + snprintf(ftpsrv_config.pass, sizeof(ftpsrv_config.pass), arg_data.value.s); break; case ArgsId_anon: ftpsrv_config.anon = true;