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;