Skip to content

Commit

Permalink
fix many nx bugs.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ITotalJustice committed Nov 28, 2024
1 parent c412ad9 commit 36a0600
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 65 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down
22 changes: 15 additions & 7 deletions src/ftpsrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -1180,7 +1188,7 @@ static void ftp_cmd_STAT(struct FtpSession* session, const char* data) {

// HELP <CRLF> | 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 <CRLF> | 200, 500, 421
Expand Down
2 changes: 1 addition & 1 deletion src/platform/3ds/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/platform/nds/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
21 changes: 12 additions & 9 deletions src/platform/nx/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
#include <switch.h>
#include <minIni.h>

#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;
Expand All @@ -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;
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}
4 changes: 2 additions & 2 deletions src/platform/nx/main_sysmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/platform/nx/sysftp.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
103 changes: 64 additions & 39 deletions src/platform/nx/utils.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#include "utils.h"
#include <string.h>
#include <stdio.h>

#define FsDevWrap_DEVICES_MAX 32
#include <errno.h>

#define FsDevWrap_Module 0x505

Expand All @@ -12,14 +11,25 @@ enum FsDevWrap_Error {

struct FsDevWrapEntry {
FsFileSystem fs;
char path[32];
char path[FsDevWrap_PATH_MAX];
const char* shortcut;
bool active;
bool own;
};

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);
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/platform/nx/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ extern "C" {

#include <switch.h>

#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);
Expand Down
9 changes: 8 additions & 1 deletion src/platform/nx/vfs_nx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/platform/unistd/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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\
Expand Down
2 changes: 1 addition & 1 deletion src/platform/wii/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading

0 comments on commit 36a0600

Please sign in to comment.