From 36a06005b42804fda29301596781f083418d0fb1 Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Thu, 28 Nov 2024 02:49:07 +0000 Subject: [PATCH] fix many nx bugs. 1. i made multiple changes to utils.c and vfs_nx.c without testing before making a release, all because i thought doing so at 2am would be a great idea. 2. i then decided, 10 minutes before leaving for work, to try and fix a reported bug and make a new release and label it "fixed" lol. actual fixes: - [NX] check that the src/dst fs is the same before attempting a rename. - [NX] correctly translate device path to fs path. - fix path building when listing a directory if cwd is root '/'. - [NX] block sleep mode when using application build. - [NX] fail on cross fs rename. --- CMakeLists.txt | 2 +- src/ftpsrv.c | 22 +++++--- src/platform/3ds/main.c | 2 +- src/platform/nds/main.c | 2 +- src/platform/nx/main.c | 21 ++++--- src/platform/nx/main_sysmod.c | 4 +- src/platform/nx/sysftp.json | 2 +- src/platform/nx/utils.c | 103 +++++++++++++++++++++------------- src/platform/nx/utils.h | 3 + src/platform/nx/vfs_nx.c | 9 ++- src/platform/unistd/main.c | 2 +- src/platform/wii/main.c | 2 +- src/platform/wii/meta.xml | 2 +- 13 files changed, 111 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4edf3b..eaffc73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(ftpsrv LANGUAGES C - VERSION 0.1.1 + VERSION 0.1.2 DESCRIPTION "small and fast ftp server" ) diff --git a/src/ftpsrv.c b/src/ftpsrv.c index 1779991..48c74c3 100644 --- a/src/ftpsrv.c +++ b/src/ftpsrv.c @@ -293,7 +293,8 @@ static int build_fullpath(const struct FtpSession* session, struct Pathname* out } // return an error if the output was truncated or it failed. - if (rc < 0 || rc > sizeof(*out)) { + if (rc < 0 || rc >= sizeof(*out)) { + errno = ENAMETOOLONG; rc = -1; } else { rc = 0; @@ -323,7 +324,6 @@ static inline struct Pathname fix_path_for_device(const struct Pathname* path) { static int ftp_build_list_entry(struct FtpSession* session, const time_t cur_time, const struct Pathname* fullpath, const char* name, const struct stat* st, int nlist) { int rc; struct FtpTransfer* transfer = &session->transfer; - // char buf[1024 * 4] = {0}; if (nlist) { rc = snprintf(transfer->list_buf, sizeof(transfer->list_buf), "%s" TELNET_EOL, name); @@ -393,6 +393,7 @@ static int ftp_build_list_entry(struct FtpSession* session, const time_t cur_tim if (rc <= 0 || rc > sizeof(transfer->list_buf)) { // don't send anything on error or truncated + errno = ENAMETOOLONG; rc = -1; } else { transfer->size = rc; @@ -490,6 +491,7 @@ static void ftp_dir_data_transfer_progress(struct FtpSession* session) { const time_t cur_time = time(NULL); const bool nlist = session->transfer.mode == FTP_TRANSFER_MODE_NLST; const bool device_list = g_ftp.cfg.devices && g_ftp.cfg.devices_count && !strcmp("/", session->temp_path.s); + const bool is_root = !strcmp("/", session->temp_path.s); struct FtpTransfer* transfer = &session->transfer; // send as much data as possible. @@ -543,8 +545,14 @@ static void ftp_dir_data_transfer_progress(struct FtpSession* session) { continue; } - static struct Pathname filepath; - int rc = snprintf(filepath.s, sizeof(filepath), "%s/%s", session->temp_path.s, name); + int rc; + struct Pathname filepath; + if (is_root) { + rc = snprintf(filepath.s, sizeof(filepath), "%s%s", session->temp_path.s, name); + } else { + rc = snprintf(filepath.s, sizeof(filepath), "%s/%s", session->temp_path.s, name); + } + if (rc <= 0 || rc > sizeof(filepath)) { continue; } @@ -1115,7 +1123,7 @@ static void ftp_list_directory(struct FtpSession* session, const char* data, int struct stat st = {0}; rc = ftp_vfs_lstat(session->temp_path.s, &st); if (rc < 0) { - ftp_client_msg(session, "450 Requested file action not taken. %s %s", strerror(errno), session->temp_path.s); + ftp_client_msg(session, "450 Requested file action not taken. %s", strerror(errno)); } else { if (S_ISDIR(st.st_mode)) { rc = ftp_vfs_opendir(&session->transfer.dir_vfs, session->temp_path.s); @@ -1124,7 +1132,7 @@ static void ftp_list_directory(struct FtpSession* session, const char* data, int } else { rc = ftp_data_open(session); if (rc < 0) { - ftp_client_msg(session, "425 Can't open data connection. %s rc: %d", strerror(errno), errno); + ftp_client_msg(session, "425 Can't open data connection. %s", strerror(errno)); } else { session->transfer.mode = mode; return; @@ -1180,7 +1188,7 @@ static void ftp_cmd_STAT(struct FtpSession* session, const char* data) { // HELP | 211, 214, 500, 501, 502, 421 static void ftp_cmd_HELP(struct FtpSession* session, const char* data) { - ftp_client_msg(session, "214 ftpsrv 0.1.1 By TotalJustice."); + ftp_client_msg(session, "214 ftpsrv 0.1.2 By TotalJustice."); } // NOOP | 200, 500, 421 diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index dbfef8c..643f419 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -126,7 +126,7 @@ int main(void) { gfxInitDefault(); consoleInit(GFX_TOP, &topScreen); consoleInit(GFX_BOTTOM, &bottomScreen); - consolePrint("\n[ftpsrv 0.1.1 By TotalJustice]\n\n"); + consolePrint("\n[ftpsrv 0.1.2 By TotalJustice]\n\n"); g_ftpsrv_config.log_callback = ftp_log_callback; g_ftpsrv_config.anon = ini_getl("Login", "anon", 0, INI_PATH); diff --git a/src/platform/nds/main.c b/src/platform/nds/main.c index 39ab403..fea1d93 100644 --- a/src/platform/nds/main.c +++ b/src/platform/nds/main.c @@ -101,7 +101,7 @@ int main(void) { consoleInit(&topScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true); consoleInit(&bottomScreen, 3,BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true); - consolePrint("\n[ftpsrv 0.1.1 By TotalJustice]\n\n"); + consolePrint("\n[ftpsrv 0.1.2 By TotalJustice]\n\n"); // init sd card. if (!fatInitDefault()) { diff --git a/src/platform/nx/main.c b/src/platform/nx/main.c index 57b7faf..4423380 100644 --- a/src/platform/nx/main.c +++ b/src/platform/nx/main.c @@ -15,11 +15,11 @@ #include #include -#define TEXT_NORMAL "\033[0m" -#define TEXT_RED "\033[0;31m" -#define TEXT_GREEN "\033[0;32m" -#define TEXT_YELLOW "\033[0;33m" -#define TEXT_BLUE "\033[0;34m" +#define TEXT_NORMAL "\033[37;1m" +#define TEXT_RED "\033[31;1m" +#define TEXT_GREEN "\033[32;1m" +#define TEXT_YELLOW "\033[33;1m" +#define TEXT_BLUE "\033[34;1m" struct CallbackData { enum FTP_API_LOG_TYPE type; @@ -28,7 +28,7 @@ struct CallbackData { static const char INI_PATH[FS_MAX_PATH] = {"/config/ftpsrv/config.ini"}; static struct FtpSrvConfig g_ftpsrv_config = {0}; -static struct FtpSrvDevice g_devices[32] = {0}; +static struct FtpSrvDevice g_devices[FsDevWrap_DEVICES_MAX] = {0}; static int g_devices_count; static PadState g_pad; @@ -43,7 +43,7 @@ static bool IsApplication(void) { } static void add_device(const char* path) { - if (g_devices_count < 32) { + if (g_devices_count < FsDevWrap_DEVICES_MAX) { sprintf(g_devices[g_devices_count++].mount, "%s:", path); } } @@ -121,7 +121,7 @@ static int error_loop(const char* msg) { } int main(int argc, char** argv) { - consolePrint("\n[ftpsrv 0.1.1 By TotalJustice]\n\n"); + consolePrint("\n[ftpsrv 0.1.2 By TotalJustice]\n\n"); padConfigureInput(8, HidNpadStyleSet_NpadStandard); padInitializeDefault(&g_pad); @@ -199,6 +199,7 @@ int main(int argc, char** argv) { printf(TEXT_YELLOW "user: %s" TEXT_NORMAL "\n", g_ftpsrv_config.user); printf(TEXT_YELLOW "pass: %s" TEXT_NORMAL "\n", g_ftpsrv_config.pass); } + printf(TEXT_YELLOW "mount_devices: %d" TEXT_NORMAL "\n", mount_devices); printf(TEXT_YELLOW "\nconfig: %s" TEXT_NORMAL "\n", INI_PATH); printf("\n"); consoleUpdate(NULL); @@ -318,16 +319,18 @@ void userAppInit(void) { if (R_FAILED(rc = fsdev_wrapMountSdmc())) diagAbortWithResult(rc); + appletRequestToAcquireSleepLock(); add_device("sdmc"); consoleInit(NULL); } void userAppExit(void) { + consoleExit(NULL); accountExit(); socketExit(); bsdExit(); nifmExit(); - consoleExit(NULL); fsdev_wrapUnmountAll(); + appletReleaseSleepLock(); appletUnlockExit(); } diff --git a/src/platform/nx/main_sysmod.c b/src/platform/nx/main_sysmod.c index ac4f00e..066f7e6 100644 --- a/src/platform/nx/main_sysmod.c +++ b/src/platform/nx/main_sysmod.c @@ -8,11 +8,11 @@ static const char* INI_PATH = "/config/ftpsrv/config.ini"; static struct FtpSrvConfig g_ftpsrv_config = {0}; -static struct FtpSrvDevice g_devices[32] = {0}; +static struct FtpSrvDevice g_devices[FsDevWrap_DEVICES_MAX] = {0}; static int g_devices_count = 0; static void add_device(const char* path) { - if (g_devices_count < 32) { + if (g_devices_count < FsDevWrap_DEVICES_MAX) { sprintf(g_devices[g_devices_count++].mount, "%s:", path); } } diff --git a/src/platform/nx/sysftp.json b/src/platform/nx/sysftp.json index d8bd68f..a932c0a 100644 --- a/src/platform/nx/sysftp.json +++ b/src/platform/nx/sysftp.json @@ -1,6 +1,6 @@ { "name": "sys-ftp", - "version": "0.1.1", + "version": "0.1.2", "program_id": "0x420000000000011B", "program_id_range_min": "0x420000000000011B", "program_id_range_max": "0x420000000000011B", diff --git a/src/platform/nx/utils.c b/src/platform/nx/utils.c index 4152a1e..d3a33a3 100644 --- a/src/platform/nx/utils.c +++ b/src/platform/nx/utils.c @@ -1,8 +1,7 @@ #include "utils.h" #include #include - -#define FsDevWrap_DEVICES_MAX 32 +#include #define FsDevWrap_Module 0x505 @@ -12,7 +11,7 @@ enum FsDevWrap_Error { struct FsDevWrapEntry { FsFileSystem fs; - char path[32]; + char path[FsDevWrap_PATH_MAX]; const char* shortcut; bool active; bool own; @@ -20,6 +19,17 @@ struct FsDevWrapEntry { static struct FsDevWrapEntry g_fsdev_entries[FsDevWrap_DEVICES_MAX] = {0}; +static struct FsDevWrapEntry* find_entry(const char* path) { + for (int i = 0; i < FsDevWrap_DEVICES_MAX; i++) { + const size_t dev_len = strlen(g_fsdev_entries[i].path); + if (g_fsdev_entries[i].active && !strncmp(g_fsdev_entries[i].path, path, dev_len) && (path[dev_len] == '\0' || path[dev_len] == ':')) { + return &g_fsdev_entries[i]; + } + } + + return NULL; +} + static Result mount_helper(const char* path, FsFileSystem fs) { if (fsdev_wrapMountDevice(path, NULL, fs, true)) { fsFsClose(&fs); @@ -83,65 +93,80 @@ Result fsdev_wrapMountSaveBcat(const char* path, u64 id) { } FsFileSystem* fsdev_wrapGetDeviceFileSystem(const char* name) { - size_t len = strlen(name); - if (!len) { + struct FsDevWrapEntry* entry = find_entry(name); + if (!entry) { + errno = ENODEV; return NULL; } - - const char* sdmc_path = "sdmc"; - if (name[0] == '/') { - name = sdmc_path; - } - - for (int i = 0; i < FsDevWrap_DEVICES_MAX; i++) { - if (g_fsdev_entries[i].active && !strncmp(name, g_fsdev_entries[i].path, strlen(name))) { - return &g_fsdev_entries[i].fs; - } - } - return NULL; + return &entry->fs; } int fsdev_wrapTranslatePath(const char *path, FsFileSystem** device, char *outpath) { - size_t len = strlen(path); - if (!len) { + int rc = 0; + char nxpath[FS_MAX_PATH]; + + if (!path) { + errno = ENODEV; return -1; } - const char* sdmc_path = "sdmc:/"; if (path[0] == '/') { - path = sdmc_path; + if (strchr(path, ':')) { + strcpy(nxpath, path + 1); + } else { + rc = snprintf(nxpath, sizeof(nxpath), "%s%s", "sdmc:", path); + if (rc <= 0 || rc >= sizeof(nxpath)) { + errno = ENAMETOOLONG; + return -1; + } + } + } else { + strcpy(nxpath, path); } - const char* colon = memchr(path, ':', len); - if (!colon || colon == path) { + const char* colon = strchr(nxpath, ':'); + if (!colon) { + errno = ENODEV; return -1; } - const size_t device_name_len = colon - path; + struct FsDevWrapEntry* entry = find_entry(nxpath); + if (!entry) { + errno = ENODEV; + return -1; + } - for (int i = 0; i < FsDevWrap_DEVICES_MAX; i++) { - if (g_fsdev_entries[i].active && !strncmp(path, g_fsdev_entries[i].path, device_name_len)) { - if (device) { - *device = &g_fsdev_entries[i].fs; - } - if (g_fsdev_entries[i].shortcut) { - sprintf(outpath, "/%s/%s", g_fsdev_entries[i].shortcut, colon + 1); - } else { - strcpy(outpath, colon + 1); - } + if (device) { + *device = &entry->fs; + } - if (outpath[0] == '\0') { - outpath[0] = '/'; - outpath[1] = '\0'; + if (outpath) { + if (entry->shortcut) { + rc = snprintf(outpath, FS_MAX_PATH, "/%s/%s", entry->shortcut, colon + 1); + if (rc <= 0 || rc >= FS_MAX_PATH) { + errno = ENAMETOOLONG; + return -1; } - return 0; + } else { + strcpy(outpath, colon + 1); + } + + if (outpath[0] == '\0') { + outpath[0] = '/'; + outpath[1] = '\0'; } } - return -1; + return 0; } int fsdev_wrapMountDevice(const char *name, const char* shortcut, FsFileSystem fs, bool own) { + const size_t name_len = strlen(name); + if (name_len <= 1 || name_len + 1 >= FsDevWrap_PATH_MAX) { + errno = ENAMETOOLONG; + return -1; + } + for (int i = 0; i < FsDevWrap_DEVICES_MAX; i++) { if (!g_fsdev_entries[i].active) { g_fsdev_entries[i].active = true; diff --git a/src/platform/nx/utils.h b/src/platform/nx/utils.h index ee34577..48e3e4a 100644 --- a/src/platform/nx/utils.h +++ b/src/platform/nx/utils.h @@ -8,6 +8,9 @@ extern "C" { #include +#define FsDevWrap_DEVICES_MAX 32 +#define FsDevWrap_PATH_MAX 32 + Result fsdev_wrapMountSdmc(void); Result fsdev_wrapMountImage(const char* path, FsImageDirectoryId id); Result fsdev_wrapMountContent(const char* path, FsContentStorageId id); diff --git a/src/platform/nx/vfs_nx.c b/src/platform/nx/vfs_nx.c index fa6e04d..5d328ac 100644 --- a/src/platform/nx/vfs_nx.c +++ b/src/platform/nx/vfs_nx.c @@ -674,9 +674,16 @@ int ftp_vfs_rmdir(const char* path) { int ftp_vfs_rename(const char* src, const char* dst) { FsFileSystem* fs = NULL; + FsFileSystem* fs_dst = NULL; char nxpath_src[FS_MAX_PATH]; char nxpath_dst[FS_MAX_PATH]; - if (fsdev_wrapTranslatePath(src, &fs, nxpath_src) || fsdev_wrapTranslatePath(dst, NULL, nxpath_dst)) { + if (fsdev_wrapTranslatePath(src, &fs, nxpath_src) || fsdev_wrapTranslatePath(dst, &fs_dst, nxpath_dst)) { + return -1; + } + + // cannot rename across different fs. + if (fs != fs_dst) { + errno = EXDEV; // this will do for the error. return -1; } diff --git a/src/platform/unistd/main.c b/src/platform/unistd/main.c index ea88284..3069bc4 100644 --- a/src/platform/unistd/main.c +++ b/src/platform/unistd/main.c @@ -55,7 +55,7 @@ static void ftp_log_callback(enum FTP_API_LOG_TYPE type, const char* msg) { static int print_usage(int code) { printf("\ -[ftpsrv 0.1.1 By TotalJustice] \n\n\ +[ftpsrv 0.1.2 By TotalJustice] \n\n\ Usage\n\n\ -h, --help = Display help.\n\ -v, --version = Display version.\n\ diff --git a/src/platform/wii/main.c b/src/platform/wii/main.c index 9dd3fc1..518ba03 100644 --- a/src/platform/wii/main.c +++ b/src/platform/wii/main.c @@ -157,7 +157,7 @@ int main(void) { VIDEO_WaitVSync(); if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); - consolePrint("\n[ftpsrv 0.1.1 By TotalJustice]\n\n"); + consolePrint("\n[ftpsrv 0.1.2 By TotalJustice]\n\n"); if (!fatInitDefault()) { return error_loop("failed to init fat device\n"); diff --git a/src/platform/wii/meta.xml b/src/platform/wii/meta.xml index 2820ea7..1353ed1 100644 --- a/src/platform/wii/meta.xml +++ b/src/platform/wii/meta.xml @@ -2,6 +2,6 @@ Ftpsrv TotalJustice - 0.1.1 + 0.1.2 FTP server