use ftpsrv config and mountpoints, improve ftp performance by using its vfs.
This commit is contained in:
2
.github/workflows/build_presets.yml
vendored
2
.github/workflows/build_presets.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
run: |
|
run: |
|
||||||
cmake --preset ${{ matrix.preset }}
|
cmake --preset ${{ matrix.preset }} -DUSE_VFS_GC=0
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build --preset ${{ matrix.preset }} --parallel 4
|
run: cmake --build --preset ${{ matrix.preset }} --parallel 4
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ please include:
|
|||||||
|
|
||||||
## ftp
|
## ftp
|
||||||
|
|
||||||
ftp can be enabled via the network menu and listens on port 5000, no username or password is required.
|
ftp can be enabled via the network menu. It uses the same config as ftpsrv `/config/ftpsrv/config.ini`. [See here for the full list
|
||||||
|
of all configs available](https://github.com/ITotalJustice/ftpsrv/blob/master/assets/config.ini.template).
|
||||||
|
|
||||||
## mtp
|
## mtp
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ set(FETCHCONTENT_QUIET FALSE)
|
|||||||
|
|
||||||
FetchContent_Declare(ftpsrv
|
FetchContent_Declare(ftpsrv
|
||||||
GIT_REPOSITORY https://github.com/ITotalJustice/ftpsrv.git
|
GIT_REPOSITORY https://github.com/ITotalJustice/ftpsrv.git
|
||||||
GIT_TAG 8d5a14e
|
GIT_TAG 1.2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_Declare(libhaze
|
FetchContent_Declare(libhaze
|
||||||
@@ -114,12 +114,12 @@ FetchContent_Declare(yyjson
|
|||||||
GIT_TAG 0.10.0
|
GIT_TAG 0.10.0
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_Declare(minIni-sphaira
|
FetchContent_Declare(minIni
|
||||||
GIT_REPOSITORY https://github.com/ITotalJustice/minIni-nx.git
|
GIT_REPOSITORY https://github.com/ITotalJustice/minIni-nx.git
|
||||||
GIT_TAG 63ec295
|
GIT_TAG 63ec295
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MININI_LIB_NAME minIni-sphaira)
|
set(MININI_LIB_NAME minIni)
|
||||||
set(MININI_USE_STDIO ON)
|
set(MININI_USE_STDIO ON)
|
||||||
set(MININI_USE_NX ON)
|
set(MININI_USE_NX ON)
|
||||||
set(MININI_USE_FLOAT OFF)
|
set(MININI_USE_FLOAT OFF)
|
||||||
@@ -149,18 +149,48 @@ set(YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS OFF)
|
|||||||
|
|
||||||
set(FTPSRV_LIB_BUILD TRUE)
|
set(FTPSRV_LIB_BUILD TRUE)
|
||||||
set(FTPSRV_LIB_SOCK_UNISTD TRUE)
|
set(FTPSRV_LIB_SOCK_UNISTD TRUE)
|
||||||
set(FTPSRV_LIB_VFS_CUSTOM ${CMAKE_CURRENT_SOURCE_DIR}/include/ftpsrv_helper.hpp)
|
set(FTPSRV_LIB_VFS_CUSTOM ${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs_nx.h)
|
||||||
set(FTPSRV_LIB_PATH_SIZE 0x301)
|
set(FTPSRV_LIB_PATH_SIZE 0x301)
|
||||||
set(FTPSRV_LIB_SESSIONS 32)
|
set(FTPSRV_LIB_SESSIONS 32)
|
||||||
set(FTPSRV_LIB_BUF_SIZE 1024*64)
|
set(FTPSRV_LIB_BUF_SIZE 1024*64)
|
||||||
|
|
||||||
|
add_library(ftpsrv_helper
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs_nx.c
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_none.c
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_root.c
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_fs.c
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_save.c
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_storage.c
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/utils.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# workaround until a64 container has latest libnx release.
|
||||||
|
if (NOT DEFINED USE_VFS_GC)
|
||||||
|
set(USE_VFS_GC TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (USE_VFS_GC)
|
||||||
|
target_sources(ftpsrv_helper PRIVATE
|
||||||
|
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_gc.c
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FTPSRV_LIB_CUSTOM_DEFINES
|
||||||
|
USE_VFS_SAVE=$<BOOL:TRUE>
|
||||||
|
USE_VFS_STORAGE=$<BOOL:TRUE>
|
||||||
|
USE_VFS_GC=$<BOOL:${USE_VFS_GC}>
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(ftpsrv_helper PUBLIC ftpsrv)
|
||||||
|
target_include_directories(ftpsrv_helper PUBLIC ${ftpsrv_SOURCE_DIR}/src/platform)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(
|
FetchContent_MakeAvailable(
|
||||||
ftpsrv
|
ftpsrv
|
||||||
libhaze
|
libhaze
|
||||||
libpulsar
|
libpulsar
|
||||||
nanovg
|
nanovg
|
||||||
stb
|
stb
|
||||||
minIni-sphaira
|
minIni
|
||||||
yyjson
|
yyjson
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -241,10 +271,10 @@ set_target_properties(sphaira PROPERTIES
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(sphaira PRIVATE
|
target_link_libraries(sphaira PRIVATE
|
||||||
ftpsrv
|
ftpsrv_helper
|
||||||
libhaze
|
libhaze
|
||||||
libpulsar
|
libpulsar
|
||||||
minIni-sphaira
|
minIni
|
||||||
nanovg
|
nanovg
|
||||||
stb
|
stb
|
||||||
yyjson
|
yyjson
|
||||||
|
|||||||
@@ -1,33 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <switch.h>
|
|
||||||
|
|
||||||
struct FtpVfsFile {
|
|
||||||
FsFile fd;
|
|
||||||
s64 off;
|
|
||||||
s64 buf_off;
|
|
||||||
s64 buf_size;
|
|
||||||
bool is_write;
|
|
||||||
bool is_valid;
|
|
||||||
u8 buf[1024 * 1024 * 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FtpVfsDir {
|
|
||||||
FsDir dir;
|
|
||||||
bool is_valid;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FtpVfsDirEntry {
|
|
||||||
FsDirectoryEntry buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
namespace sphaira::ftpsrv {
|
namespace sphaira::ftpsrv {
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
void Exit();
|
void Exit();
|
||||||
|
|
||||||
} // namespace sphaira::ftpsrv
|
} // namespace sphaira::ftpsrv
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|||||||
@@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
#define sphaira_USE_LOG 1
|
#define sphaira_USE_LOG 1
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
#if sphaira_USE_LOG
|
#if sphaira_USE_LOG
|
||||||
auto log_file_init() -> bool;
|
auto log_file_init() -> bool;
|
||||||
auto log_nxlink_init() -> bool;
|
auto log_nxlink_init() -> bool;
|
||||||
void log_file_exit();
|
void log_file_exit();
|
||||||
void log_nxlink_exit();
|
void log_nxlink_exit();
|
||||||
void log_write(const char* s, ...) __attribute__ ((format (printf, 1, 2)));
|
void log_write(const char* s, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
void log_write_arg(const char* s, std::va_list& v);
|
||||||
#else
|
#else
|
||||||
inline auto log_file_init() -> bool {
|
inline auto log_file_init() -> bool {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
#include "ftpsrv_helper.hpp"
|
#include "ftpsrv_helper.hpp"
|
||||||
#include <ftpsrv.h>
|
|
||||||
#include <ftpsrv_vfs.h>
|
|
||||||
#include "app.hpp"
|
#include "app.hpp"
|
||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <minIni.h>
|
||||||
|
#include <ftpsrv.h>
|
||||||
|
#include <ftpsrv_vfs.h>
|
||||||
|
#include <nx/vfs_nx.h>
|
||||||
|
#include <nx/utils.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const char* INI_PATH = "/config/ftpsrv/config.ini";
|
||||||
FtpSrvConfig g_ftpsrv_config = {0};
|
FtpSrvConfig g_ftpsrv_config = {0};
|
||||||
volatile bool g_should_exit = false;
|
volatile bool g_should_exit = false;
|
||||||
bool g_is_running{false};
|
bool g_is_running{false};
|
||||||
Thread g_thread;
|
Thread g_thread;
|
||||||
std::mutex g_mutex{};
|
std::mutex g_mutex{};
|
||||||
FsFileSystem* g_fs;
|
|
||||||
|
|
||||||
void ftp_log_callback(enum FTP_API_LOG_TYPE type, const char* msg) {
|
void ftp_log_callback(enum FTP_API_LOG_TYPE type, const char* msg) {
|
||||||
sphaira::App::NotifyFlashLed();
|
sphaira::App::NotifyFlashLed();
|
||||||
@@ -28,32 +29,6 @@ void ftp_progress_callback(void) {
|
|||||||
sphaira::App::NotifyFlashLed();
|
sphaira::App::NotifyFlashLed();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
case FsError_UsableSpaceNotEnoughMmcSafe: errno = ENOSPC; break;
|
|
||||||
case FsError_UsableSpaceNotEnoughMmcUser: errno = ENOSPC; break;
|
|
||||||
case FsError_UsableSpaceNotEnoughMmcSystem: errno = ENOSPC; break;
|
|
||||||
case FsError_UsableSpaceNotEnoughSdCard: errno = ENOSPC; break;
|
|
||||||
case FsError_OutOfRange: errno = ESPIPE; break;
|
|
||||||
case FsError_TooLongPath: errno = ENAMETOOLONG; break;
|
|
||||||
case FsError_UnsupportedWriteForReadOnlyFileSystem: errno = EROFS; break;
|
|
||||||
default: errno = EIO; break;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result flush_buffered_write(struct FtpVfsFile* 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);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(void* arg) {
|
void loop(void* arg) {
|
||||||
while (!g_should_exit) {
|
while (!g_should_exit) {
|
||||||
ftpsrv_init(&g_ftpsrv_config);
|
ftpsrv_init(&g_ftpsrv_config);
|
||||||
@@ -77,16 +52,51 @@ bool Init() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_fs = fsdevGetDeviceFileSystem("sdmc");
|
if (R_FAILED(fsdev_wrapMountSdmc())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
g_ftpsrv_config.log_callback = ftp_log_callback;
|
g_ftpsrv_config.log_callback = ftp_log_callback;
|
||||||
g_ftpsrv_config.progress_callback = ftp_progress_callback;
|
g_ftpsrv_config.progress_callback = ftp_progress_callback;
|
||||||
g_ftpsrv_config.anon = true;
|
g_ftpsrv_config.anon = ini_getbool("Login", "anon", 0, INI_PATH);
|
||||||
g_ftpsrv_config.timeout = 15;
|
int user_len = ini_gets("Login", "user", "", g_ftpsrv_config.user, sizeof(g_ftpsrv_config.user), INI_PATH);
|
||||||
g_ftpsrv_config.port = 5000;
|
int pass_len = ini_gets("Login", "pass", "", g_ftpsrv_config.pass, sizeof(g_ftpsrv_config.pass), INI_PATH);
|
||||||
|
g_ftpsrv_config.port = ini_getl("Network", "port", 5000, INI_PATH); // 5000 to keep compat with older sphaira
|
||||||
|
g_ftpsrv_config.timeout = ini_getl("Network", "timeout", 0, INI_PATH);
|
||||||
|
g_ftpsrv_config.use_localtime = ini_getbool("Misc", "use_localtime", 0, INI_PATH);
|
||||||
|
bool log_enabled = ini_getbool("Log", "log", 0, INI_PATH);
|
||||||
|
|
||||||
|
// get nx config
|
||||||
|
bool mount_devices = ini_getbool("Nx", "mount_devices", 1, INI_PATH);
|
||||||
|
bool mount_bis = ini_getbool("Nx", "mount_bis", 0, INI_PATH);
|
||||||
|
bool save_writable = ini_getbool("Nx", "save_writable", 0, INI_PATH);
|
||||||
|
g_ftpsrv_config.port = ini_getl("Nx", "app_port", g_ftpsrv_config.port, INI_PATH); // compat
|
||||||
|
|
||||||
|
// get Nx-App overrides
|
||||||
|
g_ftpsrv_config.anon = ini_getbool("Nx-App", "anon", g_ftpsrv_config.anon, INI_PATH);
|
||||||
|
user_len = ini_gets("Nx-App", "user", g_ftpsrv_config.user, g_ftpsrv_config.user, sizeof(g_ftpsrv_config.user), INI_PATH);
|
||||||
|
pass_len = ini_gets("Nx-App", "pass", g_ftpsrv_config.pass, g_ftpsrv_config.pass, sizeof(g_ftpsrv_config.pass), INI_PATH);
|
||||||
|
g_ftpsrv_config.port = ini_getl("Nx-App", "port", g_ftpsrv_config.port, INI_PATH);
|
||||||
|
g_ftpsrv_config.timeout = ini_getl("Nx-App", "timeout", g_ftpsrv_config.timeout, INI_PATH);
|
||||||
|
g_ftpsrv_config.use_localtime = ini_getbool("Nx-App", "use_localtime", g_ftpsrv_config.use_localtime, INI_PATH);
|
||||||
|
log_enabled = ini_getbool("Nx-App", "log", log_enabled, INI_PATH);
|
||||||
|
mount_devices = ini_getbool("Nx-App", "mount_devices", mount_devices, INI_PATH);
|
||||||
|
mount_bis = ini_getbool("Nx-App", "mount_bis", mount_bis, INI_PATH);
|
||||||
|
save_writable = ini_getbool("Nx-App", "save_writable", save_writable, INI_PATH);
|
||||||
|
|
||||||
|
if (!g_ftpsrv_config.port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep compat with older sphaira
|
||||||
|
if (!user_len && !pass_len) {
|
||||||
|
g_ftpsrv_config.anon = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_nx_init(mount_devices, save_writable, mount_bis);
|
||||||
|
|
||||||
Result rc;
|
Result rc;
|
||||||
if (R_FAILED(rc = threadCreate(&g_thread, loop, nullptr, nullptr, 1024*64, 0x2C, 2))) {
|
if (R_FAILED(rc = threadCreate(&g_thread, loop, nullptr, nullptr, 1024*16, 0x2C, 2))) {
|
||||||
log_write("failed to create nxlink thread: 0x%X\n", rc);
|
log_write("failed to create nxlink thread: 0x%X\n", rc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -108,232 +118,24 @@ void Exit() {
|
|||||||
g_should_exit = true;
|
g_should_exit = true;
|
||||||
threadWaitForExit(&g_thread);
|
threadWaitForExit(&g_thread);
|
||||||
threadClose(&g_thread);
|
threadClose(&g_thread);
|
||||||
|
|
||||||
|
vfs_nx_exit();
|
||||||
|
fsdev_wrapUnmountAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sphaira::ftpsrv
|
} // namespace sphaira::ftpsrv
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
#define VFS_NX_BUFFER_IO 1
|
void log_file_write(const char* msg) {
|
||||||
|
log_write("%s", msg);
|
||||||
int ftp_vfs_open(struct FtpVfsFile* f, const char* path, enum FtpVfsOpenMode mode) {
|
|
||||||
u32 open_mode;
|
|
||||||
if (mode == FtpVfsOpenMode_READ) {
|
|
||||||
open_mode = FsOpenMode_Read;
|
|
||||||
f->is_write = false;
|
|
||||||
} else {
|
|
||||||
fsFsCreateFile(g_fs, path, 0, 0);
|
|
||||||
open_mode = FsOpenMode_Write | FsOpenMode_Append;
|
|
||||||
#if !VFS_NX_BUFFER_IO
|
|
||||||
open_mode |= FsOpenMode_Append;
|
|
||||||
#endif
|
|
||||||
f->is_write = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result rc;
|
|
||||||
if (R_FAILED(rc = fsFsOpenFile(g_fs, path, open_mode, &f->fd))) {
|
|
||||||
return vfs_fs_set_errno(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
f->off = f->buf_off = f->buf_size = 0;
|
|
||||||
|
|
||||||
if (mode == FtpVfsOpenMode_WRITE) {
|
|
||||||
if (R_FAILED(rc = fsFileSetSize(&f->fd, 0))) {
|
|
||||||
goto fail_close;
|
|
||||||
}
|
|
||||||
} else if (mode == FtpVfsOpenMode_APPEND) {
|
|
||||||
if (R_FAILED(rc = fsFileGetSize(&f->fd, &f->off))) {
|
|
||||||
goto fail_close;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f->is_valid = true;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail_close:
|
|
||||||
fsFileClose(&f->fd);
|
|
||||||
return vfs_fs_set_errno(rc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ftp_vfs_read(struct FtpVfsFile* f, void* buf, size_t size) {
|
void log_file_fwrite(const char* fmt, ...) {
|
||||||
Result rc;
|
std::va_list v{};
|
||||||
|
va_start(v, fmt);
|
||||||
#if VFS_NX_BUFFER_IO
|
log_write_arg(fmt, v);
|
||||||
if (f->buf_off == f->buf_size) {
|
va_end(v);
|
||||||
u64 bytes_read;
|
|
||||||
if (R_FAILED(rc = fsFileRead(&f->fd, f->off, f->buf, sizeof(f->buf), FsReadOption_None, &bytes_read))) {
|
|
||||||
return vfs_fs_set_errno(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
f->buf_off = 0;
|
|
||||||
f->buf_size = bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!f->buf_size) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = size < f->buf_size - f->buf_off ? size : f->buf_size - f->buf_off;
|
|
||||||
memcpy(buf, f->buf + f->buf_off, size);
|
|
||||||
f->off += size;
|
|
||||||
f->buf_off += size;
|
|
||||||
return size;
|
|
||||||
#else
|
|
||||||
u64 bytes_read;
|
|
||||||
if (R_FAILED(rc = fsFileRead(&f->fd, f->off, buf, size, FsReadOption_None, &bytes_read))) {
|
|
||||||
return vfs_fs_set_errno(rc);
|
|
||||||
}
|
|
||||||
f->off += bytes_read;
|
|
||||||
return bytes_read;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_write(struct FtpVfsFile* f, const void* buf, size_t size) {
|
|
||||||
Result rc;
|
|
||||||
|
|
||||||
#if VFS_NX_BUFFER_IO
|
|
||||||
const size_t ret = size;
|
|
||||||
while (size) {
|
|
||||||
if (f->buf_off + size > sizeof(f->buf)) {
|
|
||||||
const u64 sz = sizeof(f->buf) - f->buf_off;
|
|
||||||
memcpy(f->buf + f->buf_off, buf, sz);
|
|
||||||
f->buf_off += sz;
|
|
||||||
|
|
||||||
if (R_FAILED(rc = flush_buffered_write(f))) {
|
|
||||||
return vfs_fs_set_errno(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
|
||||||
buf += sz;
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
size -= sz;
|
|
||||||
f->off += f->buf_off;
|
|
||||||
f->buf_off = 0;
|
|
||||||
} else {
|
|
||||||
memcpy(f->buf + f->buf_off, buf, size);
|
|
||||||
f->buf_off += size;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
if (R_FAILED(rc = fsFileWrite(&f->fd, f->off, buf, size, FsWriteOption_None))) {
|
|
||||||
return vfs_fs_set_errno(rc);
|
|
||||||
}
|
|
||||||
f->off += size;
|
|
||||||
return size;
|
|
||||||
const size_t ret = size;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// buf and size is the amount of data sent.
|
|
||||||
int ftp_vfs_seek(struct FtpVfsFile* f, const void* buf, size_t size, size_t off) {
|
|
||||||
#if VFS_NX_BUFFER_IO
|
|
||||||
if (!f->is_write) {
|
|
||||||
f->buf_off -= f->off - off;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
f->off = off;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_close(struct FtpVfsFile* f) {
|
|
||||||
if (!ftp_vfs_isfile_open(f)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->is_write && f->buf_off) {
|
|
||||||
flush_buffered_write(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
fsFileClose(&f->fd);
|
|
||||||
f->is_valid = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_isfile_open(struct FtpVfsFile* f) {
|
|
||||||
return f->is_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_opendir(struct FtpVfsDir* f, const char* path) {
|
|
||||||
Result rc;
|
|
||||||
if (R_FAILED(rc = fsFsOpenDirectory(g_fs, path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles | FsDirOpenMode_NoFileSize, &f->dir))) {
|
|
||||||
return vfs_fs_set_errno(rc);
|
|
||||||
}
|
|
||||||
f->is_valid = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ftp_vfs_readdir(struct FtpVfsDir* f, struct FtpVfsDirEntry* entry) {
|
|
||||||
Result rc;
|
|
||||||
s64 total_entries;
|
|
||||||
if (R_FAILED(rc = fsDirRead(&f->dir, &total_entries, 1, &entry->buf))) {
|
|
||||||
vfs_fs_set_errno(rc);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total_entries <= 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry->buf.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_dirlstat(struct FtpVfsDir* f, const struct FtpVfsDirEntry* entry, const char* path, struct stat* st) {
|
|
||||||
return lstat(path, st);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_closedir(struct FtpVfsDir* f) {
|
|
||||||
if (!ftp_vfs_isdir_open(f)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsDirClose(&f->dir);
|
|
||||||
f->is_valid = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_isdir_open(struct FtpVfsDir* f) {
|
|
||||||
return f->is_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_stat(const char* path, struct stat* st) {
|
|
||||||
return stat(path, st);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_lstat(const char* path, struct stat* st) {
|
|
||||||
return lstat(path, st);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_mkdir(const char* path) {
|
|
||||||
return mkdir(path, 0777);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_unlink(const char* path) {
|
|
||||||
return unlink(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_rmdir(const char* path) {
|
|
||||||
return rmdir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_rename(const char* src, const char* dst) {
|
|
||||||
return rename(src, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ftp_vfs_readlink(const char* path, char* buf, size_t buflen) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ftp_vfs_getpwuid(const struct stat* st) {
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ftp_vfs_getgrgid(const struct stat* st) {
|
|
||||||
return "unknown";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -14,6 +14,16 @@ std::FILE* file{};
|
|||||||
int nxlink_socket{};
|
int nxlink_socket{};
|
||||||
std::mutex mutex{};
|
std::mutex mutex{};
|
||||||
|
|
||||||
|
void log_write_arg_internal(const char* s, std::va_list& v) {
|
||||||
|
if (file) {
|
||||||
|
std::vfprintf(file, s, v);
|
||||||
|
std::fflush(file);
|
||||||
|
}
|
||||||
|
if (nxlink_socket) {
|
||||||
|
std::vprintf(s, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
auto log_file_init() -> bool {
|
auto log_file_init() -> bool {
|
||||||
@@ -60,13 +70,17 @@ void log_write(const char* s, ...) {
|
|||||||
|
|
||||||
std::va_list v{};
|
std::va_list v{};
|
||||||
va_start(v, s);
|
va_start(v, s);
|
||||||
if (file) {
|
log_write_arg_internal(s, v);
|
||||||
std::vfprintf(file, s, v);
|
|
||||||
std::fflush(file);
|
|
||||||
}
|
|
||||||
if (nxlink_socket) {
|
|
||||||
std::vprintf(s, v);
|
|
||||||
}
|
|
||||||
va_end(v);
|
va_end(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void log_write_arg(const char* s, std::va_list& v) {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
if (!file && !nxlink_socket) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_write_arg_internal(s, v);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ void userAppInit(void) {
|
|||||||
diagAbortWithResult(rc);
|
diagAbortWithResult(rc);
|
||||||
if (R_FAILED(rc = hidsysInitialize()))
|
if (R_FAILED(rc = hidsysInitialize()))
|
||||||
diagAbortWithResult(rc);
|
diagAbortWithResult(rc);
|
||||||
|
if (R_FAILED(rc = ncmInitialize()))
|
||||||
|
diagAbortWithResult(rc);
|
||||||
|
|
||||||
log_nxlink_init();
|
log_nxlink_init();
|
||||||
}
|
}
|
||||||
@@ -70,6 +72,7 @@ void userAppInit(void) {
|
|||||||
void userAppExit(void) {
|
void userAppExit(void) {
|
||||||
log_nxlink_exit();
|
log_nxlink_exit();
|
||||||
|
|
||||||
|
ncmExit();
|
||||||
hidsysExit();
|
hidsysExit();
|
||||||
setExit();
|
setExit();
|
||||||
accountExit();
|
accountExit();
|
||||||
|
|||||||
Reference in New Issue
Block a user