devoptab: add SFTP. fs: disable stdio buffering. cmake: add options to disable components of sphaira, add new "lite" build with minimal features.
This commit is contained in:
@@ -21,6 +21,35 @@
|
||||
"LTO": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Lite",
|
||||
"displayName": "Lite",
|
||||
"inherits":["core"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "MinSizeRel",
|
||||
"LTO": true,
|
||||
|
||||
"ENABLE_NVJPG": false,
|
||||
"ENABLE_NSZ": false,
|
||||
|
||||
"ENABLE_LIBUSBHSFS": false,
|
||||
"ENABLE_LIBUSBDVD": false,
|
||||
"ENABLE_FTPSRV": false,
|
||||
"ENABLE_LIBHAZE": false,
|
||||
|
||||
"ENABLE_AUDIO_MP3": false,
|
||||
"ENABLE_AUDIO_OGG": false,
|
||||
"ENABLE_AUDIO_WAV": false,
|
||||
"ENABLE_AUDIO_FLAC": false,
|
||||
|
||||
"ENABLE_DEVOPTAB_HTTP": false,
|
||||
"ENABLE_DEVOPTAB_NFS": false,
|
||||
"ENABLE_DEVOPTAB_SMB2": false,
|
||||
"ENABLE_DEVOPTAB_FTP": false,
|
||||
"ENABLE_DEVOPTAB_SFTP": false,
|
||||
"ENABLE_DEVOPTAB_WEBDAV": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Dev",
|
||||
"displayName": "Dev",
|
||||
@@ -38,6 +67,11 @@
|
||||
"configurePreset": "Release",
|
||||
"jobs": 16
|
||||
},
|
||||
{
|
||||
"name": "Lite",
|
||||
"configurePreset": "Lite",
|
||||
"jobs": 16
|
||||
},
|
||||
{
|
||||
"name": "Dev",
|
||||
"configurePreset": "Dev",
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
# generic options.
|
||||
option(ENABLE_NVJPG "" OFF)
|
||||
option(ENABLE_NSZ "enables exporting to nsz" ON)
|
||||
|
||||
# lib options.
|
||||
option(ENABLE_LIBUSBHSFS "enables FAT/exFAT hdd mounting" ON)
|
||||
option(ENABLE_LIBUSBDVD "enables cd/dvd/iso/cue mounting" ON)
|
||||
option(ENABLE_FTPSRV "enables MTP server support" ON)
|
||||
option(ENABLE_LIBHAZE "enables MTP server support" ON)
|
||||
|
||||
# audio options.
|
||||
option(ENABLE_AUDIO_MP3 "" ON)
|
||||
option(ENABLE_AUDIO_OGG "" ON)
|
||||
option(ENABLE_AUDIO_WAV "" ON)
|
||||
option(ENABLE_AUDIO_FLAC "" ON)
|
||||
|
||||
# devoptab options.
|
||||
option(ENABLE_DEVOPTAB_HTTP "" ON)
|
||||
option(ENABLE_DEVOPTAB_NFS "" ON)
|
||||
option(ENABLE_DEVOPTAB_SMB2 "" ON)
|
||||
option(ENABLE_DEVOPTAB_FTP "" ON)
|
||||
option(ENABLE_DEVOPTAB_WEBDAV "" ON)
|
||||
# disable by default because we are CPU bound for upload/download.
|
||||
# max speed is 8MiB/s, which is fine for wifi, but awful for ethernet.
|
||||
# other clients get 36-40MiB/s.
|
||||
# it also adds 230k to binary size, and i don't think anyone will use it.
|
||||
option(ENABLE_DEVOPTAB_SFTP "" OFF)
|
||||
|
||||
set(sphaira_VERSION 0.13.3)
|
||||
|
||||
project(sphaira
|
||||
@@ -46,8 +74,6 @@ add_executable(sphaira
|
||||
source/ui/menus/themezer.cpp
|
||||
source/ui/menus/ghdl.cpp
|
||||
source/ui/menus/usb_menu.cpp
|
||||
source/ui/menus/ftp_menu.cpp
|
||||
source/ui/menus/mtp_menu.cpp
|
||||
source/ui/menus/gc_menu.cpp
|
||||
source/ui/menus/game_menu.cpp
|
||||
source/ui/menus/game_meta_menu.cpp
|
||||
@@ -85,16 +111,12 @@ add_executable(sphaira
|
||||
source/web.cpp
|
||||
source/hasher.cpp
|
||||
source/i18n.cpp
|
||||
source/ftpsrv_helper.cpp
|
||||
source/haze_helper.cpp
|
||||
source/threaded_file_transfer.cpp
|
||||
source/title_info.cpp
|
||||
source/minizip_helper.cpp
|
||||
source/usbdvd.cpp
|
||||
|
||||
source/utils/utils.cpp
|
||||
source/utils/audio.cpp
|
||||
source/utils/nsz_dumper.cpp
|
||||
source/utils/devoptab_common.cpp
|
||||
source/utils/devoptab_romfs.cpp
|
||||
source/utils/devoptab_save.cpp
|
||||
@@ -104,11 +126,6 @@ add_executable(sphaira
|
||||
source/utils/devoptab_xci.cpp
|
||||
source/utils/devoptab_zip.cpp
|
||||
source/utils/devoptab_bfsar.cpp
|
||||
source/utils/devoptab_http.cpp
|
||||
source/utils/devoptab_nfs.cpp
|
||||
source/utils/devoptab_smb2.cpp
|
||||
source/utils/devoptab_ftp.cpp
|
||||
source/utils/devoptab_webdav.cpp
|
||||
source/utils/devoptab_vfs.cpp
|
||||
source/utils/devoptab_fatfs.cpp
|
||||
|
||||
@@ -188,17 +205,6 @@ target_compile_options(sphaira PRIVATE
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_QUIET FALSE)
|
||||
|
||||
FetchContent_Declare(ftpsrv
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/ftpsrv.git
|
||||
GIT_TAG 85b3cf0
|
||||
SOURCE_SUBDIR NONE
|
||||
)
|
||||
|
||||
FetchContent_Declare(libhaze
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/libhaze.git
|
||||
GIT_TAG f0b2a14
|
||||
)
|
||||
|
||||
FetchContent_Declare(libpulsar
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/switch-libpulsar.git
|
||||
GIT_TAG ac7bc97
|
||||
@@ -230,11 +236,6 @@ FetchContent_Declare(zstd
|
||||
SOURCE_SUBDIR build/cmake
|
||||
)
|
||||
|
||||
FetchContent_Declare(libusbhsfs
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/libusbhsfs.git
|
||||
GIT_TAG 625269b
|
||||
)
|
||||
|
||||
FetchContent_Declare(libnxtc
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/libnxtc.git
|
||||
GIT_TAG 88ce3d8
|
||||
@@ -251,54 +252,286 @@ FetchContent_Declare(dr_libs
|
||||
SOURCE_SUBDIR NONE
|
||||
)
|
||||
|
||||
FetchContent_Declare(id3v2lib
|
||||
GIT_REPOSITORY https://github.com/larsbs/id3v2lib.git
|
||||
GIT_TAG 141ffb8
|
||||
)
|
||||
if (ENABLE_NVJPG)
|
||||
FetchContent_Declare(nvjpg
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/oss-nvjpg.git
|
||||
GIT_TAG 45680e7
|
||||
)
|
||||
|
||||
FetchContent_Declare(libusbdvd
|
||||
FetchContent_MakeAvailable(nvjpg)
|
||||
|
||||
add_library(nvjpg
|
||||
${nvjpg_SOURCE_DIR}/lib/decoder.cpp
|
||||
${nvjpg_SOURCE_DIR}/lib/image.cpp
|
||||
${nvjpg_SOURCE_DIR}/lib/surface.cpp
|
||||
)
|
||||
|
||||
target_include_directories(nvjpg PUBLIC ${nvjpg_SOURCE_DIR}/include)
|
||||
set_target_properties(nvjpg PROPERTIES CXX_STANDARD 26)
|
||||
|
||||
target_link_libraries(nvjpg PRIVATE nvjpg)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_NVJPG)
|
||||
endif()
|
||||
|
||||
if (ENABLE_NSZ)
|
||||
target_sources(sphaira PRIVATE source/utils/nsz_dumper.cpp)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_NSZ)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBUSBHSFS)
|
||||
# enable this if you want ntfs and ext4 support, at the cost of a huge final binary size.
|
||||
set(USBHSFS_GPL OFF)
|
||||
set(USBHSFS_SXOS_DISABLE ON)
|
||||
|
||||
FetchContent_Declare(libusbhsfs
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/libusbhsfs.git
|
||||
GIT_TAG 625269b
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(libusbhsfs)
|
||||
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_LIBUSBHSFS)
|
||||
target_link_libraries(sphaira PRIVATE libusbhsfs)
|
||||
else()
|
||||
target_sources(sphaira PRIVATE source/ff16/ffunicode.c)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBUSBDVD)
|
||||
FetchContent_Declare(libusbdvd
|
||||
GIT_REPOSITORY https://github.com/proconsule/libusbdvd.git
|
||||
GIT_TAG 3cb0613
|
||||
)
|
||||
)
|
||||
|
||||
FetchContent_Declare(libnfs
|
||||
FetchContent_MakeAvailable(libusbdvd)
|
||||
|
||||
add_library(libusbdvd
|
||||
${libusbdvd_SOURCE_DIR}/source/usbdvd.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/usbdvd_scsi.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/usbdvd_utils.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/usbdvd_datadisc.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/audiocdfs/audiocdfs.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/audiocdfs/cdaudio_devoptab.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/iso9660/usbdvd_iso9660.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/iso9660/iso9660_devoptab.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/udf/usbdvd_udf.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/udf/udf_devoptab.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/os/switch/switch_usb.cpp
|
||||
|
||||
)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/os/switch)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs/audiocdfs)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs/iso9660)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs/udf)
|
||||
target_include_directories(libusbdvd PUBLIC ${libusbdvd_SOURCE_DIR}/include)
|
||||
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_LIBUSBDVD)
|
||||
target_link_libraries(sphaira PRIVATE libusbdvd)
|
||||
target_sources(sphaira PRIVATE source/usbdvd.cpp)
|
||||
endif()
|
||||
|
||||
if (ENABLE_FTPSRV)
|
||||
FetchContent_Declare(ftpsrv
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/ftpsrv.git
|
||||
GIT_TAG 85b3cf0
|
||||
SOURCE_SUBDIR NONE
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(ftpsrv)
|
||||
|
||||
set(FTPSRV_LIB_BUILD TRUE)
|
||||
set(FTPSRV_LIB_VFS_CUSTOM ${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs_nx.h)
|
||||
set(FTPSRV_LIB_PATH_SIZE 0x301)
|
||||
set(FTPSRV_LIB_SESSIONS 16)
|
||||
set(FTPSRV_LIB_BUF_SIZE 1024*64)
|
||||
|
||||
set(FTPSRV_LIB_CUSTOM_DEFINES
|
||||
USE_VFS_SAVE=$<BOOL:FALSE>
|
||||
USE_VFS_STORAGE=$<BOOL:TRUE>
|
||||
# disabled as it may conflict with the gamecard menu.
|
||||
USE_VFS_GC=$<BOOL:FALSE>
|
||||
USE_VFS_USBHSFS=$<BOOL:${ENABLE_LIBUSBHSFS}>
|
||||
VFS_NX_BUFFER_IO=$<BOOL:TRUE>
|
||||
# let sphaira handle init / closing of the hdd.
|
||||
USE_VFS_USBHSFS_INIT=$<BOOL:FALSE>
|
||||
# disable romfs mounting as otherwise we cannot write / modify sphaira.nro
|
||||
USE_VFS_ROMFS=$<BOOL:FALSE>
|
||||
FTP_SOCKET_HEADER="${ftpsrv_SOURCE_DIR}/src/platform/nx/socket_nx.h"
|
||||
)
|
||||
|
||||
add_subdirectory(${ftpsrv_SOURCE_DIR} binary_dir)
|
||||
|
||||
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_storage.c
|
||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/utils.c
|
||||
)
|
||||
|
||||
if (ENABLE_LIBUSBHSFS)
|
||||
target_sources(ftpsrv_helper PRIVATE
|
||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_stdio.c
|
||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_hdd.c
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(ftpsrv_helper PUBLIC ftpsrv libusbhsfs)
|
||||
target_include_directories(ftpsrv_helper PUBLIC ${ftpsrv_SOURCE_DIR}/src/platform)
|
||||
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_FTPSRV)
|
||||
target_link_libraries(sphaira PRIVATE ftpsrv_helper)
|
||||
|
||||
target_sources(sphaira PRIVATE
|
||||
source/ftpsrv_helper.cpp
|
||||
source/ui/menus/ftp_menu.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBHAZE)
|
||||
FetchContent_Declare(libhaze
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/libhaze.git
|
||||
GIT_TAG f0b2a14
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(libhaze)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_LIBHAZE)
|
||||
target_link_libraries(sphaira PRIVATE libhaze)
|
||||
|
||||
target_sources(sphaira PRIVATE
|
||||
source/haze_helper.cpp
|
||||
source/ui/menus/mtp_menu.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_DEVOPTAB_HTTP)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_DEVOPTAB_HTTP)
|
||||
target_sources(sphaira PRIVATE source/utils/devoptab_http.cpp)
|
||||
endif()
|
||||
|
||||
if (ENABLE_DEVOPTAB_NFS)
|
||||
FetchContent_Declare(libnfs
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/libnfs.git
|
||||
GIT_TAG 65f3e11
|
||||
)
|
||||
)
|
||||
|
||||
FetchContent_Declare(libsmb2
|
||||
FetchContent_MakeAvailable(libnfs)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_DEVOPTAB_NFS)
|
||||
target_link_libraries(sphaira PRIVATE nfs)
|
||||
target_sources(sphaira PRIVATE source/utils/devoptab_nfs.cpp)
|
||||
|
||||
# todo: fix this upstream as nfs should export these folders.
|
||||
target_include_directories(sphaira PRIVATE
|
||||
${libnfs_SOURCE_DIR}/include
|
||||
${libnfs_SOURCE_DIR}/include/nfsc
|
||||
${libnfs_SOURCE_DIR}/nfs
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_DEVOPTAB_SMB2)
|
||||
FetchContent_Declare(libsmb2
|
||||
GIT_REPOSITORY https://github.com/ITotalJustice/libsmb2.git
|
||||
GIT_TAG 867beea
|
||||
)
|
||||
)
|
||||
|
||||
FetchContent_Declare(pugixml
|
||||
FetchContent_MakeAvailable(libsmb2)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_DEVOPTAB_SMB2)
|
||||
target_link_libraries(sphaira PRIVATE smb2)
|
||||
target_sources(sphaira PRIVATE source/utils/devoptab_smb2.cpp)
|
||||
endif()
|
||||
|
||||
if (ENABLE_DEVOPTAB_FTP)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_DEVOPTAB_FTP)
|
||||
target_sources(sphaira PRIVATE source/utils/devoptab_ftp.cpp)
|
||||
endif()
|
||||
|
||||
if (ENABLE_DEVOPTAB_SFTP)
|
||||
# set to build from source, otherwise it will link against the older dkp libssh2.
|
||||
if (1)
|
||||
set(CRYPTO_BACKEND mbedTLS)
|
||||
set(ENABLE_ZLIB_COMPRESSION ON)
|
||||
set(ENABLE_DEBUG_LOGGING OFF)
|
||||
set(BUILD_EXAMPLES OFF)
|
||||
set(BUILD_TESTING OFF)
|
||||
set(LINT OFF)
|
||||
|
||||
FetchContent_Declare(libssh2
|
||||
GIT_REPOSITORY https://github.com/libssh2/libssh2.git
|
||||
# GIT_TAG a0dafb3 # latest commit, works fine, but i'll stick to main release.
|
||||
GIT_TAG libssh2-1.11.1
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(libssh2)
|
||||
target_link_libraries(sphaira PRIVATE libssh2::libssh2)
|
||||
else()
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(LIBSSH2 libssh2 REQUIRED)
|
||||
target_include_directories(sphaira PRIVATE ${LIBSSH2_INCLUDE_DIRS})
|
||||
target_link_libraries(sphaira PRIVATE ${LIBSSH2_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_DEVOPTAB_SFTP)
|
||||
target_sources(sphaira PRIVATE source/utils/devoptab_sftp.cpp)
|
||||
endif()
|
||||
|
||||
if (ENABLE_DEVOPTAB_WEBDAV)
|
||||
set(PUGIXML_NO_EXCEPTIONS ON)
|
||||
set(PUGIXML_WCHAR_MODE OFF)
|
||||
|
||||
FetchContent_Declare(pugixml
|
||||
GIT_REPOSITORY https://github.com/zeux/pugixml.git
|
||||
GIT_TAG v1.15
|
||||
)
|
||||
)
|
||||
|
||||
set(PUGIXML_NO_EXCEPTIONS ON)
|
||||
# set(PUGIXML_NO_XPATH ON)
|
||||
set(PUGIXML_WCHAR_MODE OFF)
|
||||
FetchContent_MakeAvailable(pugixml)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_DEVOPTAB_WEBDAV)
|
||||
target_link_libraries(sphaira PRIVATE pugixml)
|
||||
target_sources(sphaira PRIVATE source/utils/devoptab_webdav.cpp)
|
||||
endif()
|
||||
|
||||
set(USE_NEW_ZSTD ON)
|
||||
# has issues with some homebrew and game icons (oxenfree, overwatch2).
|
||||
set(USE_NVJPG OFF)
|
||||
if (ENABLE_AUDIO_MP3)
|
||||
FetchContent_Declare(id3v2lib
|
||||
GIT_REPOSITORY https://github.com/larsbs/id3v2lib.git
|
||||
GIT_TAG 141ffb8
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(id3v2lib)
|
||||
target_link_libraries(sphaira PRIVATE id3v2lib)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_AUDIO_MP3)
|
||||
endif()
|
||||
|
||||
if (ENABLE_AUDIO_OGG)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_AUDIO_OGG)
|
||||
endif()
|
||||
|
||||
if (ENABLE_AUDIO_WAV)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_AUDIO_WAV)
|
||||
endif()
|
||||
|
||||
if (ENABLE_AUDIO_FLAC)
|
||||
target_compile_definitions(sphaira PRIVATE ENABLE_AUDIO_FLAC)
|
||||
endif()
|
||||
|
||||
# ztsd
|
||||
set(ZSTD_BUILD_STATIC ON)
|
||||
set(ZSTD_BUILD_SHARED OFF)
|
||||
set(ZSTD_BUILD_COMPRESSION ON)
|
||||
set(ZSTD_MULTITHREAD_SUPPORT ON)
|
||||
set(ZSTD_BUILD_COMPRESSION ${ENABLE_NSZ})
|
||||
set(ZSTD_MULTITHREAD_SUPPORT ${ENABLE_NSZ})
|
||||
set(ZSTD_BUILD_DECOMPRESSION ON)
|
||||
set(ZSTD_BUILD_DICTBUILDER OFF)
|
||||
set(ZSTD_LEGACY_SUPPORT OFF)
|
||||
set(ZSTD_BUILD_PROGRAMS OFF)
|
||||
set(ZSTD_BUILD_TESTS OFF)
|
||||
|
||||
# minini
|
||||
set(MININI_LIB_NAME minIni)
|
||||
set(MININI_USE_STDIO ON)
|
||||
set(MININI_USE_NX OFF)
|
||||
set(MININI_USE_FLOAT ON)
|
||||
|
||||
# nanovg
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
set(NANOVG_DEBUG ON)
|
||||
endif()
|
||||
@@ -312,6 +545,7 @@ set(NANOVG_NO_HDR ON)
|
||||
set(NANOVG_NO_PIC ON)
|
||||
set(NANOVG_NO_PNM ON)
|
||||
|
||||
# yyjson
|
||||
set(YYJSON_INSTALL OFF)
|
||||
set(YYJSON_DISABLE_READER OFF)
|
||||
set(YYJSON_DISABLE_WRITER OFF)
|
||||
@@ -321,66 +555,17 @@ set(YYJSON_DISABLE_NON_STANDARD ON)
|
||||
set(YYJSON_DISABLE_UTF8_VALIDATION ON)
|
||||
set(YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS OFF)
|
||||
|
||||
# enable this if you want ntfs and ext4 support, at the cost of a huge final binary size.
|
||||
set(USBHSFS_GPL OFF)
|
||||
set(USBHSFS_SXOS_DISABLE ON)
|
||||
|
||||
FetchContent_MakeAvailable(
|
||||
ftpsrv
|
||||
libhaze
|
||||
libpulsar
|
||||
nanovg
|
||||
stb
|
||||
minIni
|
||||
yyjson
|
||||
zstd
|
||||
libusbhsfs
|
||||
libnxtc
|
||||
nvjpg
|
||||
dr_libs
|
||||
id3v2lib
|
||||
libusbdvd
|
||||
libnfs
|
||||
libsmb2
|
||||
pugixml
|
||||
)
|
||||
|
||||
set(FTPSRV_LIB_BUILD TRUE)
|
||||
set(FTPSRV_LIB_VFS_CUSTOM ${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs_nx.h)
|
||||
set(FTPSRV_LIB_PATH_SIZE 0x301)
|
||||
set(FTPSRV_LIB_SESSIONS 16)
|
||||
set(FTPSRV_LIB_BUF_SIZE 1024*64)
|
||||
|
||||
set(FTPSRV_LIB_CUSTOM_DEFINES
|
||||
USE_VFS_SAVE=$<BOOL:FALSE>
|
||||
USE_VFS_STORAGE=$<BOOL:TRUE>
|
||||
# disabled as it may conflict with the gamecard menu.
|
||||
USE_VFS_GC=$<BOOL:FALSE>
|
||||
USE_VFS_USBHSFS=$<BOOL:TRUE>
|
||||
VFS_NX_BUFFER_IO=$<BOOL:TRUE>
|
||||
# let sphaira handle init / closing of the hdd.
|
||||
USE_VFS_USBHSFS_INIT=$<BOOL:FALSE>
|
||||
# disable romfs mounting as otherwise we cannot write / modify sphaira.nro
|
||||
USE_VFS_ROMFS=$<BOOL:FALSE>
|
||||
FTP_SOCKET_HEADER="${ftpsrv_SOURCE_DIR}/src/platform/nx/socket_nx.h"
|
||||
)
|
||||
|
||||
add_subdirectory(${ftpsrv_SOURCE_DIR} binary_dir)
|
||||
|
||||
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_storage.c
|
||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_stdio.c
|
||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/vfs/vfs_nx_hdd.c
|
||||
${ftpsrv_SOURCE_DIR}/src/platform/nx/utils.c
|
||||
)
|
||||
|
||||
target_link_libraries(ftpsrv_helper PUBLIC ftpsrv libusbhsfs)
|
||||
target_include_directories(ftpsrv_helper PUBLIC ${ftpsrv_SOURCE_DIR}/src/platform)
|
||||
|
||||
add_library(stb INTERFACE)
|
||||
target_include_directories(stb INTERFACE ${stb_SOURCE_DIR})
|
||||
|
||||
@@ -394,38 +579,6 @@ add_library(libnxtc
|
||||
)
|
||||
target_include_directories(libnxtc PUBLIC ${libnxtc_SOURCE_DIR}/include)
|
||||
|
||||
add_library(libusbdvd
|
||||
${libusbdvd_SOURCE_DIR}/source/usbdvd.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/usbdvd_scsi.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/usbdvd_utils.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/usbdvd_datadisc.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/audiocdfs/audiocdfs.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/audiocdfs/cdaudio_devoptab.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/iso9660/usbdvd_iso9660.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/iso9660/iso9660_devoptab.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/udf/usbdvd_udf.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/fs/udf/udf_devoptab.cpp
|
||||
${libusbdvd_SOURCE_DIR}/source/os/switch/switch_usb.cpp
|
||||
|
||||
)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/os/switch)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs/audiocdfs)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs/iso9660)
|
||||
target_include_directories(libusbdvd PRIVATE ${libusbdvd_SOURCE_DIR}/source/fs/udf)
|
||||
target_include_directories(libusbdvd PUBLIC ${libusbdvd_SOURCE_DIR}/include)
|
||||
|
||||
if (USE_NVJPG)
|
||||
add_library(nvjpg
|
||||
${nvjpg_SOURCE_DIR}/lib/decoder.cpp
|
||||
${nvjpg_SOURCE_DIR}/lib/image.cpp
|
||||
${nvjpg_SOURCE_DIR}/lib/surface.cpp
|
||||
)
|
||||
target_include_directories(nvjpg PUBLIC ${nvjpg_SOURCE_DIR}/include)
|
||||
set_target_properties(nvjpg PROPERTIES CXX_STANDARD 26)
|
||||
endif()
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_library(minizip_lib minizip REQUIRED)
|
||||
find_path(minizip_inc minizip REQUIRED)
|
||||
@@ -434,11 +587,6 @@ find_package(CURL REQUIRED)
|
||||
find_path(mbedtls_inc mbedtls REQUIRED)
|
||||
find_library(mbedcrypto_lib mbedcrypto REQUIRED)
|
||||
|
||||
if (NOT USE_NEW_ZSTD)
|
||||
find_path(zstd_inc zstd.h REQUIRED)
|
||||
find_library(zstd_lib zstd REQUIRED)
|
||||
endif()
|
||||
|
||||
add_library(fatfs
|
||||
source/ff16/diskio.c
|
||||
source/ff16/ff.c
|
||||
@@ -453,30 +601,16 @@ set_target_properties(sphaira PROPERTIES
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
|
||||
# todo: fix this upstream as nfs should export these folders.
|
||||
target_include_directories(sphaira PRIVATE
|
||||
${libnfs_SOURCE_DIR}/include
|
||||
${libnfs_SOURCE_DIR}/include/nfsc
|
||||
${libnfs_SOURCE_DIR}/nfs
|
||||
)
|
||||
|
||||
target_link_libraries(sphaira PRIVATE
|
||||
ftpsrv_helper
|
||||
libhaze
|
||||
libpulsar
|
||||
minIni
|
||||
nanovg
|
||||
stb
|
||||
yyjson
|
||||
# libusbhsfs
|
||||
libnxtc
|
||||
fatfs
|
||||
dr_libs
|
||||
id3v2lib
|
||||
libusbdvd
|
||||
nfs
|
||||
smb2
|
||||
pugixml
|
||||
libzstd_static
|
||||
|
||||
${minizip_lib}
|
||||
ZLIB::ZLIB
|
||||
@@ -484,20 +618,6 @@ target_link_libraries(sphaira PRIVATE
|
||||
${mbedcrypto_lib}
|
||||
)
|
||||
|
||||
if (USE_NEW_ZSTD)
|
||||
message(STATUS "USING UPSTREAM ZSTD")
|
||||
target_link_libraries(sphaira PRIVATE libzstd_static)
|
||||
else()
|
||||
message(STATUS "USING LOCAL ZSTD")
|
||||
target_link_libraries(sphaira PRIVATE ${zstd_lib})
|
||||
target_include_directories(sphaira PRIVATE ${zstd_inc})
|
||||
endif()
|
||||
|
||||
if (USE_NVJPG)
|
||||
target_link_libraries(sphaira PRIVATE nvjpg)
|
||||
target_compile_definitions(sphaira PRIVATE USE_NVJPG)
|
||||
endif()
|
||||
|
||||
target_include_directories(sphaira PRIVATE
|
||||
include
|
||||
${minizip_inc}
|
||||
|
||||
@@ -12,6 +12,18 @@
|
||||
|
||||
namespace fs {
|
||||
|
||||
enum OpenMode : u32 {
|
||||
OpenMode_Read = FsOpenMode_Read,
|
||||
OpenMode_Write = FsOpenMode_Write,
|
||||
OpenMode_Append = FsOpenMode_Append,
|
||||
|
||||
// enables buffering for stdio based files.
|
||||
OpenMode_EnableBuffer = 1 << 16,
|
||||
OpenMode_ReadBuffered = OpenMode_Read | OpenMode_EnableBuffer,
|
||||
OpenMode_WriteBuffered = OpenMode_Write | OpenMode_EnableBuffer,
|
||||
OpenMode_AppendBuffered = OpenMode_Append | OpenMode_EnableBuffer,
|
||||
};
|
||||
|
||||
struct FsPath {
|
||||
FsPath() = default;
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@ enum class Type {
|
||||
Sha1,
|
||||
Sha256,
|
||||
Null,
|
||||
Deflate,
|
||||
Zstd,
|
||||
};
|
||||
|
||||
struct BaseSource {
|
||||
|
||||
@@ -23,6 +23,7 @@ Result MountVfsAll();
|
||||
Result MountWebdavAll();
|
||||
Result MountHttpAll();
|
||||
Result MountFtpAll();
|
||||
Result MountSftpAll();
|
||||
Result MountNfsAll();
|
||||
Result MountSmb2All();
|
||||
Result MountFatfsAll();
|
||||
|
||||
@@ -130,7 +130,7 @@ struct MountConfig {
|
||||
std::string pass{};
|
||||
std::string dump_path{};
|
||||
std::optional<long> port{};
|
||||
int timeout{3000}; // 3 seconds.
|
||||
int timeout{5000}; // 5 seconds.
|
||||
bool read_only{};
|
||||
bool no_stat_file{true};
|
||||
bool no_stat_dir{true};
|
||||
|
||||
@@ -37,7 +37,10 @@
|
||||
#include <ctime>
|
||||
#include <span>
|
||||
#include <dirent.h>
|
||||
#include <usbhsfs.h>
|
||||
|
||||
#ifdef ENABLE_LIBUSBHSFS
|
||||
#include <usbhsfs.h>
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
|
||||
extern "C" {
|
||||
u32 __nx_applet_exit_mode = 0;
|
||||
@@ -748,6 +751,7 @@ void App::SetNxlinkEnable(bool enable) {
|
||||
void App::SetHddEnable(bool enable) {
|
||||
if (App::GetHddEnable() != enable) {
|
||||
g_app->m_hdd_enabled.Set(enable);
|
||||
#ifdef ENABLE_LIBUSBHSFS
|
||||
if (enable) {
|
||||
if (App::GetWriteProtect()) {
|
||||
usbHsFsSetFileSystemMountFlags(UsbHsFsMountFlags_ReadOnly);
|
||||
@@ -756,6 +760,7 @@ void App::SetHddEnable(bool enable) {
|
||||
} else {
|
||||
usbHsFsExit();
|
||||
}
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,11 +768,13 @@ void App::SetWriteProtect(bool enable) {
|
||||
if (App::GetWriteProtect() != enable) {
|
||||
g_app->m_hdd_write_protect.Set(enable);
|
||||
|
||||
#ifdef ENABLE_LIBUSBHSFS
|
||||
if (enable) {
|
||||
usbHsFsSetFileSystemMountFlags(UsbHsFsMountFlags_ReadOnly);
|
||||
} else {
|
||||
usbHsFsSetFileSystemMountFlags(0);
|
||||
}
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,22 +918,28 @@ void App::Set12HourTimeEnable(bool enable) {
|
||||
void App::SetMtpEnable(bool enable) {
|
||||
if (App::GetMtpEnable() != enable) {
|
||||
g_app->m_mtp_enabled.Set(enable);
|
||||
|
||||
#ifdef ENABLE_LIBHAZE
|
||||
if (enable) {
|
||||
haze::Init();
|
||||
} else {
|
||||
haze::Exit();
|
||||
}
|
||||
#endif // ENABLE_LIBHAZE
|
||||
}
|
||||
}
|
||||
|
||||
void App::SetFtpEnable(bool enable) {
|
||||
if (App::GetFtpEnable() != enable) {
|
||||
g_app->m_ftp_enabled.Set(enable);
|
||||
|
||||
#ifdef ENABLE_FTPSRV
|
||||
if (enable) {
|
||||
ftpsrv::Init();
|
||||
} else {
|
||||
ftpsrv::Exit();
|
||||
}
|
||||
#endif // ENABLE_FTPSRV
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1554,21 +1567,26 @@ App::App(const char* argv0) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LIBHAZE
|
||||
if (App::GetMtpEnable()) {
|
||||
SCOPED_TIMESTAMP("mtp init");
|
||||
haze::Init();
|
||||
}
|
||||
#endif // ENABLE_LIBHAZE
|
||||
|
||||
#ifdef ENABLE_FTPSRV
|
||||
if (App::GetFtpEnable()) {
|
||||
SCOPED_TIMESTAMP("ftp init");
|
||||
ftpsrv::Init();
|
||||
}
|
||||
#endif // ENABLE_FTPSRV
|
||||
|
||||
if (App::GetNxlinkEnable()) {
|
||||
SCOPED_TIMESTAMP("nxlink init");
|
||||
nxlinkInitialize(nxlink_callback);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LIBUSBHSFS
|
||||
if (App::GetHddEnable()) {
|
||||
SCOPED_TIMESTAMP("hdd init");
|
||||
if (App::GetWriteProtect()) {
|
||||
@@ -1577,13 +1595,16 @@ App::App(const char* argv0) {
|
||||
|
||||
usbHsFsInitialize(1);
|
||||
}
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
|
||||
#ifdef ENABLE_LIBUSBDVD
|
||||
{
|
||||
SCOPED_TIMESTAMP("usbdvd init");
|
||||
if (R_FAILED(usbdvd::MountAll())) {
|
||||
log_write("[USBDVD] failed to mount\n");
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_LIBUSBDVD
|
||||
|
||||
{
|
||||
SCOPED_TIMESTAMP("curl init");
|
||||
@@ -1596,30 +1617,47 @@ App::App(const char* argv0) {
|
||||
devoptab::MountVfsAll();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEVOPTAB_HTTP
|
||||
{
|
||||
SCOPED_TIMESTAMP("http init");
|
||||
devoptab::MountHttpAll();
|
||||
}
|
||||
#endif // ENABLE_DEVOPTAB_HTTP
|
||||
|
||||
#ifdef ENABLE_DEVOPTAB_WEBDAV
|
||||
{
|
||||
SCOPED_TIMESTAMP("webdav init");
|
||||
devoptab::MountWebdavAll();
|
||||
}
|
||||
#endif // ENABLE_DEVOPTAB_WEBDAV
|
||||
|
||||
#ifdef ENABLE_DEVOPTAB_FTP
|
||||
{
|
||||
SCOPED_TIMESTAMP("ftp init");
|
||||
devoptab::MountFtpAll();
|
||||
}
|
||||
#endif // ENABLE_DEVOPTAB_FTP
|
||||
|
||||
#ifdef ENABLE_DEVOPTAB_SFTP
|
||||
{
|
||||
SCOPED_TIMESTAMP("sftp init");
|
||||
devoptab::MountSftpAll();
|
||||
}
|
||||
#endif // ENABLE_DEVOPTAB_SFTP
|
||||
|
||||
#ifdef ENABLE_DEVOPTAB_NFS
|
||||
{
|
||||
SCOPED_TIMESTAMP("nfs init");
|
||||
devoptab::MountNfsAll();
|
||||
}
|
||||
#endif // ENABLE_DEVOPTAB_NFS
|
||||
|
||||
#ifdef ENABLE_DEVOPTAB_SMB2
|
||||
{
|
||||
SCOPED_TIMESTAMP("smb init");
|
||||
devoptab::MountSmb2All();
|
||||
}
|
||||
#endif // ENABLE_DEVOPTAB_SMB2
|
||||
|
||||
{
|
||||
SCOPED_TIMESTAMP("fatfs init");
|
||||
@@ -2186,8 +2224,10 @@ App::~App() {
|
||||
// async exit as these threads sleep every 100ms.
|
||||
{
|
||||
SCOPED_TIMESTAMP("async signal");
|
||||
nxlinkSignalExit();
|
||||
#ifdef ENABLE_FTPSRV
|
||||
ftpsrv::ExitSignal();
|
||||
#endif // ENABLE_FTPSRV
|
||||
nxlinkSignalExit();
|
||||
audio::ExitSignal();
|
||||
curl::ExitSignal();
|
||||
}
|
||||
@@ -2203,25 +2243,31 @@ App::~App() {
|
||||
}
|
||||
|
||||
utils::Async async_exit([this](){
|
||||
{
|
||||
SCOPED_TIMESTAMP("usbdvd_exit");
|
||||
usbdvd::UnmountAll();
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_TIMESTAMP("i18n_exit");
|
||||
i18n::exit();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LIBUSBDVD
|
||||
{
|
||||
SCOPED_TIMESTAMP("usbdvd_exit");
|
||||
usbdvd::UnmountAll();
|
||||
}
|
||||
#endif // ENABLE_LIBUSBDVD
|
||||
|
||||
#ifdef ENABLE_LIBHAZE
|
||||
{
|
||||
SCOPED_TIMESTAMP("mtp exit");
|
||||
haze::Exit();
|
||||
}
|
||||
#endif // ENABLE_LIBHAZE
|
||||
|
||||
#ifdef ENABLE_LIBUSBHSFS
|
||||
{
|
||||
SCOPED_TIMESTAMP("hdd exit");
|
||||
usbHsFsExit();
|
||||
}
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
|
||||
// this has to come before curl exit as it uses curl global.
|
||||
{
|
||||
@@ -2236,10 +2282,12 @@ App::~App() {
|
||||
audio::Exit();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FTPSRV
|
||||
{
|
||||
SCOPED_TIMESTAMP("ftp exit");
|
||||
ftpsrv::Exit();
|
||||
}
|
||||
#endif // ENABLE_FTPSRV
|
||||
|
||||
{
|
||||
SCOPED_TIMESTAMP("nxlink exit");
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "i18n.hpp"
|
||||
#include "location.hpp"
|
||||
#include "threaded_file_transfer.hpp"
|
||||
#include "haze_helper.hpp"
|
||||
|
||||
#include "ui/sidebar.hpp"
|
||||
#include "ui/error_box.hpp"
|
||||
@@ -133,9 +132,9 @@ struct WriteNullSource final : WriteSource {
|
||||
struct WriteUsbSource final : WriteSource {
|
||||
WriteUsbSource(u64 transfer_timeout) {
|
||||
// disable mtp if enabled.
|
||||
m_was_mtp_enabled = haze::IsInit();
|
||||
m_was_mtp_enabled = App::GetMtpEnable();
|
||||
if (m_was_mtp_enabled) {
|
||||
haze::Exit();
|
||||
App::SetMtpEnable(false);
|
||||
}
|
||||
|
||||
m_usb = std::make_unique<usb::dump::Usb>(transfer_timeout);
|
||||
@@ -145,7 +144,7 @@ struct WriteUsbSource final : WriteSource {
|
||||
m_usb.reset();
|
||||
|
||||
if (m_was_mtp_enabled) {
|
||||
haze::Init();
|
||||
App::SetMtpEnable(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10908
sphaira/source/ff16/ffunicode.c
Normal file
10908
sphaira/source/ff16/ffunicode.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -468,6 +468,10 @@ bool DirExists(const FsPath& path) {
|
||||
}
|
||||
|
||||
Result OpenFile(fs::Fs* fs, const FsPathReal& path, u32 mode, File* f) {
|
||||
const auto should_buffer = (mode & OpenMode_EnableBuffer);
|
||||
// remove the invalid flag so that native fs doesn't error.
|
||||
mode &= ~OpenMode_EnableBuffer;
|
||||
|
||||
f->m_fs = fs;
|
||||
f->m_mode = mode;
|
||||
|
||||
@@ -486,6 +490,13 @@ Result OpenFile(fs::Fs* fs, const FsPathReal& path, u32 mode, File* f) {
|
||||
}
|
||||
|
||||
R_UNLESS(f->m_stdio, Result_FsUnknownStdioError);
|
||||
|
||||
// disable buffering to match native fs behavior.
|
||||
// this also causes problems with network io as it will do double reads.
|
||||
// which kills performance (see sftp).
|
||||
if (!should_buffer) {
|
||||
std::setvbuf(f->m_stdio, nullptr, _IONBF, 0);
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include <mbedtls/md5.h>
|
||||
#include <utility>
|
||||
|
||||
#include <zlib.h>
|
||||
#include <zstd.h>
|
||||
|
||||
namespace sphaira::hash {
|
||||
namespace {
|
||||
|
||||
@@ -81,131 +78,6 @@ private:
|
||||
size_t m_in_size{};
|
||||
};
|
||||
|
||||
// this currently crashes when freeing the pool :/
|
||||
#define USE_THREAD_POOL 0
|
||||
struct HashZstd final : HashSource {
|
||||
HashZstd() {
|
||||
const auto num_threads = 3;
|
||||
const auto level = ZSTD_CLEVEL_DEFAULT;
|
||||
|
||||
m_ctx = ZSTD_createCCtx();
|
||||
if (!m_ctx) {
|
||||
log_write("[ZSTD] failed to create ctx\n");
|
||||
}
|
||||
|
||||
|
||||
#if USE_THREAD_POOL
|
||||
m_pool = ZSTD_createThreadPool(num_threads);
|
||||
if (!m_pool) {
|
||||
log_write("[ZSTD] failed to create pool\n");
|
||||
}
|
||||
|
||||
if (ZSTD_isError(ZSTD_CCtx_refThreadPool(m_ctx, m_pool))) {
|
||||
log_write("[ZSTD] failed ZSTD_CCtx_refThreadPool(m_pool)\n");
|
||||
}
|
||||
#endif
|
||||
if (ZSTD_isError(ZSTD_CCtx_setParameter(m_ctx, ZSTD_c_compressionLevel, level))) {
|
||||
log_write("[ZSTD] failed ZSTD_CCtx_setParameter(ZSTD_c_compressionLevel)\n");
|
||||
}
|
||||
if (ZSTD_isError(ZSTD_CCtx_setParameter(m_ctx, ZSTD_c_nbWorkers, num_threads))) {
|
||||
log_write("[ZSTD] failed ZSTD_CCtx_setParameter(ZSTD_c_nbWorkers)\n");
|
||||
}
|
||||
|
||||
m_out_buf.resize(ZSTD_CStreamOutSize());
|
||||
}
|
||||
|
||||
~HashZstd() {
|
||||
ZSTD_freeCCtx(m_ctx);
|
||||
#if USE_THREAD_POOL
|
||||
// crashes here during ZSTD_pthread_join()
|
||||
// ZSTD_freeThreadPool(m_pool);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Update(const void* buf, s64 size, s64 file_size) override {
|
||||
ZSTD_inBuffer input = { buf, (u64)size, 0 };
|
||||
|
||||
const auto last_chunk = m_in_size + size >= file_size;
|
||||
const auto mode = last_chunk ? ZSTD_e_end : ZSTD_e_continue;
|
||||
|
||||
while (input.pos < input.size) {
|
||||
ZSTD_outBuffer output = { m_out_buf.data(), m_out_buf.size(), 0 };
|
||||
const size_t remaining = ZSTD_compressStream2(m_ctx, &output , &input, mode);
|
||||
|
||||
if (ZSTD_isError(remaining)) {
|
||||
log_write("[ZSTD] error: %zu\n", remaining);
|
||||
break;
|
||||
}
|
||||
|
||||
m_out_size += output.pos;
|
||||
};
|
||||
|
||||
m_in_size += size;
|
||||
}
|
||||
|
||||
void Get(std::string& out) override {
|
||||
log_write("getting size: %zu vs %zu\n", m_out_size, m_in_size);
|
||||
char str[64];
|
||||
const u32 percentage = ((double)m_out_size / (double)m_in_size) * 100.0;
|
||||
std::snprintf(str, sizeof(str), "%u%%", percentage);
|
||||
out = str;
|
||||
log_write("got size: %zu vs %zu\n", m_out_size, m_in_size);
|
||||
}
|
||||
|
||||
private:
|
||||
ZSTD_CCtx* m_ctx{};
|
||||
ZSTD_threadPool* m_pool{};
|
||||
std::vector<u8> m_out_buf{};
|
||||
size_t m_in_size{};
|
||||
size_t m_out_size{};
|
||||
};
|
||||
|
||||
struct HashDeflate final : HashSource {
|
||||
HashDeflate() {
|
||||
deflateInit(&m_ctx, Z_DEFAULT_COMPRESSION);
|
||||
m_out_buf.resize(deflateBound(&m_ctx, 1024*1024*16)); // max chunk size.
|
||||
}
|
||||
|
||||
~HashDeflate() {
|
||||
deflateEnd(&m_ctx);
|
||||
}
|
||||
|
||||
void Update(const void* buf, s64 size, s64 file_size) override {
|
||||
m_ctx.avail_in = size;
|
||||
m_ctx.next_in = const_cast<Bytef*>((const Bytef*)buf);
|
||||
|
||||
const auto last_chunk = m_in_size + size >= file_size;
|
||||
const auto mode = last_chunk ? Z_FINISH : Z_NO_FLUSH;
|
||||
|
||||
while (m_ctx.avail_in != 0) {
|
||||
m_ctx.next_out = m_out_buf.data();
|
||||
m_ctx.avail_out = m_out_buf.size();
|
||||
|
||||
const auto rc = deflate(&m_ctx, mode);
|
||||
if (Z_OK != rc) {
|
||||
if (Z_STREAM_END != rc) {
|
||||
log_write("[ZLIB] deflate error: %d\n", rc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_in_size += size;
|
||||
}
|
||||
|
||||
void Get(std::string& out) override {
|
||||
char str[64];
|
||||
const u32 percentage = ((double)m_ctx.total_out / (double)m_in_size) * 100.0;
|
||||
std::snprintf(str, sizeof(str), "%u%%", percentage);
|
||||
out = str;
|
||||
}
|
||||
|
||||
private:
|
||||
z_stream m_ctx{};
|
||||
std::vector<u8> m_out_buf{};
|
||||
size_t m_in_size{};
|
||||
};
|
||||
|
||||
struct HashCrc32 final : HashSource {
|
||||
void Update(const void* buf, s64 size, s64 file_size) override {
|
||||
m_seed = crc32CalculateWithSeed(m_seed, buf, size);
|
||||
@@ -328,8 +200,6 @@ auto GetTypeStr(Type type) -> const char* {
|
||||
case Type::Sha1: return "SHA1";
|
||||
case Type::Sha256: return "SHA256";
|
||||
case Type::Null: return "/dev/null (Speed Test)";
|
||||
case Type::Deflate: return "Deflate (Speed Test)";
|
||||
case Type::Zstd: return "ZSTD (Speed Test)";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -341,8 +211,6 @@ Result Hash(ui::ProgressBox* pbox, Type type, BaseSource* source, std::string& o
|
||||
case Type::Sha1: return Hash(pbox, std::make_unique<HashSha1>(), source, out);
|
||||
case Type::Sha256: return Hash(pbox, std::make_unique<HashSha256>(), source, out);
|
||||
case Type::Null: return Hash(pbox, std::make_unique<HashNull>(), source, out);
|
||||
case Type::Deflate: return Hash(pbox, std::make_unique<HashDeflate>(), source, out);
|
||||
case Type::Zstd: return Hash(pbox, std::make_unique<HashZstd>(), source, out);
|
||||
}
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#include "location.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "app.hpp"
|
||||
#include "usbdvd.hpp"
|
||||
#include "utils/devoptab.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <usbhsfs.h>
|
||||
|
||||
#ifdef ENABLE_LIBUSBDVD
|
||||
#include "usbdvd.hpp"
|
||||
#endif // ENABLE_LIBUSBDVD
|
||||
|
||||
#ifdef ENABLE_LIBUSBHSFS
|
||||
#include <usbhsfs.h>
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
|
||||
namespace sphaira::location {
|
||||
namespace {
|
||||
@@ -38,6 +44,7 @@ auto GetStdio(bool write) -> StdioEntries {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LIBUSBDVD
|
||||
// try and load usbdvd entry.
|
||||
// todo: check if more than 1 entry is supported.
|
||||
// todo: only call if usbdvd is init.
|
||||
@@ -47,7 +54,9 @@ auto GetStdio(bool write) -> StdioEntries {
|
||||
out.emplace_back(entry);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_LIBUSBDVD
|
||||
|
||||
#ifdef ENABLE_LIBUSBHSFS
|
||||
// bail out early if usbhdd is disabled.
|
||||
if (!App::GetHddEnable()) {
|
||||
log_write("[USBHSFS] not enabled\n");
|
||||
@@ -78,6 +87,7 @@ auto GetStdio(bool write) -> StdioEntries {
|
||||
out.emplace_back(e.name, display_name, flags);
|
||||
log_write("\t[USBHSFS] %s name: %s serial: %s man: %s\n", e.name, e.product_name, e.serial_number, e.manufacturer);
|
||||
}
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ void FileFuncNative(zlib_filefunc64_def* funcs) {
|
||||
|
||||
Result PeekFirstFileName(fs::Fs* fs, const fs::FsPath& path, fs::FsPath& name) {
|
||||
fs::File file;
|
||||
R_TRY(fs->OpenFile(path, FsOpenMode_Read, &file));
|
||||
R_TRY(fs->OpenFile(path, fs::OpenMode_ReadBuffered, &file));
|
||||
|
||||
mmz_LocalHeader local_hdr;
|
||||
u64 bytes_read;
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "yati/yati.hpp"
|
||||
#include "yati/source/file.hpp"
|
||||
|
||||
#include <usbdvd.h>
|
||||
#include <minIni.h>
|
||||
#include <minizip/zip.h>
|
||||
#include <minizip/unzip.h>
|
||||
@@ -45,6 +44,10 @@
|
||||
#include <utility>
|
||||
#include <ranges>
|
||||
|
||||
#ifdef ENABLE_LIBUSBDVD
|
||||
#include <usbdvd.h>
|
||||
#endif // ENABLE_LIBUSBDVD
|
||||
|
||||
namespace sphaira::ui::menu::filebrowser {
|
||||
namespace {
|
||||
|
||||
@@ -724,7 +727,9 @@ void FsView::OnClick() {
|
||||
App::Push<music::Menu>(GetFs(), GetNewPathCurrent());
|
||||
} else if (IsExtension(entry.GetExtension(), IMAGE_EXTENSIONS)) {
|
||||
App::Push<imageview::Menu>(GetFs(), GetNewPathCurrent());
|
||||
} else if (IsExtension(entry.GetExtension(), CDDVD_EXTENSIONS)) {
|
||||
}
|
||||
#ifdef ENABLE_LIBUSBDVD
|
||||
else if (IsExtension(entry.GetExtension(), CDDVD_EXTENSIONS)) {
|
||||
std::shared_ptr<CUSBDVD> usbdvd;
|
||||
|
||||
if (entry.GetExtension() == "cue") {
|
||||
@@ -748,7 +753,9 @@ void FsView::OnClick() {
|
||||
} else {
|
||||
log_write("[USBDVD] failed to mount\n");
|
||||
}
|
||||
} else if (IsExtension(entry.GetExtension(), INSTALL_EXTENSIONS)) {
|
||||
}
|
||||
#endif // ENABLE_LIBUSBDVD
|
||||
else if (IsExtension(entry.GetExtension(), INSTALL_EXTENSIONS)) {
|
||||
InstallFiles();
|
||||
} else if (IsSd()) {
|
||||
const auto assoc_list = m_menu->FindFileAssocFor();
|
||||
@@ -1895,12 +1902,6 @@ void FsView::DisplayAdvancedOptions() {
|
||||
options->Add<SidebarEntryCallback>("/dev/null (Speed Test)"_i18n, [this](){
|
||||
DisplayHash(hash::Type::Null);
|
||||
});
|
||||
options->Add<SidebarEntryCallback>("Deflate (Speed Test)"_i18n, [this](){
|
||||
DisplayHash(hash::Type::Deflate);
|
||||
});
|
||||
options->Add<SidebarEntryCallback>("ZSTD (Speed Test)"_i18n, [this](){
|
||||
DisplayHash(hash::Type::Zstd);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ private:
|
||||
bool m_is_file_based_emummc{};
|
||||
};
|
||||
|
||||
#ifdef ENABLE_NSZ
|
||||
Result NszExport(ProgressBox* pbox, const keys::Keys& keys, dump::BaseSource* _source, dump::WriteSource* writer, const fs::FsPath& path) {
|
||||
auto source = (NspSource*)_source;
|
||||
|
||||
@@ -145,6 +146,7 @@ Result NszExport(ProgressBox* pbox, const keys::Keys& keys, dump::BaseSource* _s
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif // ENABLE_NSZ
|
||||
|
||||
Result Notify(Result rc, const std::string& error_message) {
|
||||
if (R_FAILED(rc)) {
|
||||
@@ -979,6 +981,7 @@ void DumpNsp(const std::vector<NspEntry>& entries, bool to_nsz) {
|
||||
auto source = std::make_shared<NspSource>(entries);
|
||||
|
||||
if (to_nsz) {
|
||||
#ifdef ENABLE_NSZ
|
||||
// todo: log keys error.
|
||||
keys::Keys keys;
|
||||
keys::parse_keys(keys, true);
|
||||
@@ -986,6 +989,7 @@ void DumpNsp(const std::vector<NspEntry>& entries, bool to_nsz) {
|
||||
dump::Dump(source, paths, [keys](ProgressBox* pbox, dump::BaseSource* source, dump::WriteSource* writer, const fs::FsPath& path) {
|
||||
return NszExport(pbox, keys, source, writer, path);
|
||||
});
|
||||
#endif // ENABLE_NSZ
|
||||
} else {
|
||||
dump::Dump(source, paths);
|
||||
}
|
||||
|
||||
@@ -323,6 +323,7 @@ private:
|
||||
const s64 m_offset;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_NSZ
|
||||
Result NszExport(ProgressBox* pbox, const keys::Keys& keys, dump::BaseSource* _source, dump::WriteSource* writer, const fs::FsPath& path) {
|
||||
auto source = (XciSource*)_source;
|
||||
|
||||
@@ -464,6 +465,7 @@ Result NszExport(ProgressBox* pbox, const keys::Keys& keys, dump::BaseSource* _s
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif // ENABLE_NSZ
|
||||
|
||||
struct GcSource final : yati::source::Base {
|
||||
GcSource(const ApplicationEntry& entry, fs::FsNativeGameCard* fs);
|
||||
@@ -617,7 +619,9 @@ Menu::Menu(u32 flags) : MenuBase{"GameCard"_i18n, flags} {
|
||||
add("Export Certificate"_i18n, DumpFileFlag_Cert);
|
||||
add("Export Initial Data"_i18n, DumpFileFlag_Initial);
|
||||
} else if (m_option_index == 2) {
|
||||
#ifdef ENABLE_NSZ
|
||||
DumpXcz(0);
|
||||
#endif // ENABLE_NSZ
|
||||
} else if (m_option_index == 3) {
|
||||
const auto rc = MountGcFs();
|
||||
App::PushErrorBox(rc, "Failed to mount GameCard filesystem"_i18n);
|
||||
@@ -729,6 +733,11 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
|
||||
if (!m_mounted) {
|
||||
colour = ThemeEntryID_TEXT_INFO;
|
||||
}
|
||||
if (i == 2) {
|
||||
#ifndef ENABLE_NSZ
|
||||
colour = ThemeEntryID_TEXT_INFO;
|
||||
#endif // ENABLE_NSZ
|
||||
}
|
||||
|
||||
gfx::drawTextArgs(vg, x + 15, y + (h / 2.f), 23.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(colour), "%s", i18n::get(g_option_list[i]).c_str());
|
||||
});
|
||||
@@ -1099,6 +1108,7 @@ void Menu::OnChangeIndex(s64 new_index) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NSZ
|
||||
Result Menu::DumpXcz(u32 flags) {
|
||||
R_TRY(GcMountStorage());
|
||||
|
||||
@@ -1122,6 +1132,7 @@ Result Menu::DumpXcz(u32 flags) {
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
#endif // ENABLE_NSZ
|
||||
|
||||
Result Menu::DumpGames(u32 flags) {
|
||||
// first, try and mount the storage.
|
||||
@@ -1183,18 +1194,8 @@ Result Menu::DumpGames(u32 flags) {
|
||||
paths.emplace_back(BuildFullDumpPath(DumpFileType_Initial, m_entries));
|
||||
}
|
||||
|
||||
if (0) {
|
||||
// todo: log keys error.
|
||||
keys::Keys keys;
|
||||
keys::parse_keys(keys, true);
|
||||
|
||||
dump::Dump(source, paths, [keys](ProgressBox* pbox, dump::BaseSource* source, dump::WriteSource* writer, const fs::FsPath& path) {
|
||||
return NszExport(pbox, keys, source, writer, path);
|
||||
});
|
||||
} else {
|
||||
dump::Dump(source, paths, nullptr, location_flags);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
|
||||
@@ -78,15 +78,19 @@ const MiscMenuEntry MISC_MENU_ENTRIES[] = {
|
||||
"Download releases directly from GitHub. "\
|
||||
"Custom entries can be added to /config/sphaira/github" },
|
||||
|
||||
#ifdef ENABLE_FTPSRV
|
||||
{ .name = "FTP", .title = "FTP Install", .func = MiscMenuFuncGenerator<ui::menu::ftp::Menu>, .flag = MiscMenuFlag_Install, .info =
|
||||
"Install apps via FTP.\n\n"\
|
||||
"NOTE: This feature does not always work, use at your own risk. "\
|
||||
"If you encounter an issue, do not open an issue, it will not be fixed." },
|
||||
#endif // ENABLE_FTPSRV
|
||||
|
||||
#ifdef ENABLE_LIBHAZE
|
||||
{ .name = "MTP", .title = "MTP Install", .func = MiscMenuFuncGenerator<ui::menu::mtp::Menu>, .flag = MiscMenuFlag_Install, .info =
|
||||
"Install apps via MTP.\n\n"\
|
||||
"NOTE: This feature does not always work, use at your own risk. "\
|
||||
"If you encounter an issue, do not open an issue, it will not be fixed." },
|
||||
#endif // ENABLE_LIBHAZE
|
||||
|
||||
{ .name = "USB", .title = "USB Install", .func = MiscMenuFuncGenerator<ui::menu::usb::Menu>, .flag = MiscMenuFlag_Install, .info =
|
||||
"Install apps via USB.\n\n"\
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "log.hpp"
|
||||
#include "ui/nvg_util.hpp"
|
||||
#include "i18n.hpp"
|
||||
#include "haze_helper.hpp"
|
||||
|
||||
#include "utils/thread.hpp"
|
||||
|
||||
@@ -35,10 +34,10 @@ Menu::Menu(u32 flags) : MenuBase{"USB"_i18n, flags} {
|
||||
}});
|
||||
|
||||
// if mtp is enabled, disable it for now.
|
||||
m_was_mtp_enabled = haze::IsInit();
|
||||
m_was_mtp_enabled = App::GetMtpEnable();
|
||||
if (m_was_mtp_enabled) {
|
||||
App::Notify("Disable MTP for usb install"_i18n);
|
||||
haze::Exit();
|
||||
App::SetMtpEnable(false);
|
||||
}
|
||||
|
||||
// 3 second timeout for transfers.
|
||||
@@ -70,7 +69,7 @@ Menu::~Menu() {
|
||||
|
||||
if (m_was_mtp_enabled) {
|
||||
App::Notify("Re-enabled MTP"_i18n);
|
||||
haze::Init();
|
||||
App::SetMtpEnable(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,52 +21,55 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#if 1
|
||||
#define DR_FLAC_IMPLEMENTATION
|
||||
#define DR_FLAC_NO_OGG
|
||||
#define DR_FLAC_NO_STDIO
|
||||
#define DRFLAC_API static
|
||||
#define DRFLAC_PRIVATE static
|
||||
#include <dr_flac.h>
|
||||
#endif
|
||||
|
||||
#define DR_WAV_IMPLEMENTATION
|
||||
#define DR_WAV_NO_STDIO
|
||||
#define DRWAV_API static
|
||||
#define DRWAV_PRIVATE static
|
||||
#include <dr_wav.h>
|
||||
|
||||
#define DR_MP3_IMPLEMENTATION
|
||||
#define DR_MP3_NO_STDIO
|
||||
#define DRMP3_API static
|
||||
#define DRMP3_PRIVATE static
|
||||
// improves load / seek times.
|
||||
// hopefully drmp3 will have binary seek rather than linear.
|
||||
// this also improves
|
||||
#define DRMP3_DATA_CHUNK_SIZE (1024*64)
|
||||
#include <dr_mp3.h>
|
||||
|
||||
#if 0
|
||||
#define DR_VORBIS_IMPLEMENTATION
|
||||
#define DR_VORBIS_NO_STDIO
|
||||
#define DR_VORBIS_API static
|
||||
#include "dr_vorbis.h"
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#pragma GCC diagnostic ignored "-Walloca"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#define STB_VORBIS_NO_PUSHDATA_API
|
||||
#define STB_VORBIS_NO_STDIO
|
||||
#define STB_VORBIS_NO_OPENMEM
|
||||
#include "stb_vorbis.h"
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#include <id3v2lib.h>
|
||||
#ifdef ENABLE_AUDIO_FLAC
|
||||
#define DR_FLAC_IMPLEMENTATION
|
||||
#define DR_FLAC_NO_OGG
|
||||
#define DR_FLAC_NO_STDIO
|
||||
#define DRFLAC_API static
|
||||
#define DRFLAC_PRIVATE static
|
||||
#include <dr_flac.h>
|
||||
#endif // ENABLE_AUDIO_FLAC
|
||||
|
||||
#ifdef ENABLE_AUDIO_WAV
|
||||
#define DR_WAV_IMPLEMENTATION
|
||||
#define DR_WAV_NO_STDIO
|
||||
#define DRWAV_API static
|
||||
#define DRWAV_PRIVATE static
|
||||
#include <dr_wav.h>
|
||||
#endif // ENABLE_AUDIO_WAV
|
||||
|
||||
#ifdef ENABLE_AUDIO_MP3
|
||||
#define DR_MP3_IMPLEMENTATION
|
||||
#define DR_MP3_NO_STDIO
|
||||
#define DRMP3_API static
|
||||
#define DRMP3_PRIVATE static
|
||||
// improves load / seek times.
|
||||
// hopefully drmp3 will have binary seek rather than linear.
|
||||
// this also improves
|
||||
#define DRMP3_DATA_CHUNK_SIZE (1024*64)
|
||||
#include <dr_mp3.h>
|
||||
#include <id3v2lib.h>
|
||||
#endif // ENABLE_AUDIO_MP3
|
||||
|
||||
#ifdef ENABLE_AUDIO_OGG
|
||||
#if 0
|
||||
#define DR_VORBIS_IMPLEMENTATION
|
||||
#define DR_VORBIS_NO_STDIO
|
||||
#define DR_VORBIS_API static
|
||||
#include "dr_vorbis.h"
|
||||
#endif
|
||||
#define STB_VORBIS_NO_PUSHDATA_API
|
||||
#define STB_VORBIS_NO_STDIO
|
||||
#define STB_VORBIS_NO_OPENMEM
|
||||
#include "stb_vorbis.h"
|
||||
#endif // ENABLE_AUDIO_OGG
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include <pulsar.h>
|
||||
@@ -130,6 +133,7 @@ private:
|
||||
s64 m_size{};
|
||||
};
|
||||
|
||||
#ifdef ENABLE_AUDIO_MP3
|
||||
// gta vice "encrypted" mp3's using xor 0x22, very cool.
|
||||
struct GTAViceCityFile final : File {
|
||||
size_t ReadFile(void* _buf, size_t read_size) override {
|
||||
@@ -164,6 +168,7 @@ auto convert_utf16(const ID3v2_TextFrameData* data) -> std::string{
|
||||
buf[sz] = 0;
|
||||
return buf;
|
||||
}
|
||||
#endif // ENABLE_AUDIO_MP3
|
||||
|
||||
struct Base {
|
||||
virtual ~Base() = default;
|
||||
@@ -458,6 +463,7 @@ struct PlsrBFWAV final : PlsrBase {
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef ENABLE_AUDIO_WAV
|
||||
struct DrWAV final : CustomBase {
|
||||
~DrWAV() {
|
||||
drwav_uninit(&m_wav);
|
||||
@@ -532,7 +538,9 @@ private:
|
||||
drwav m_wav{};
|
||||
File m_file{};
|
||||
};
|
||||
#endif // ENABLE_AUDIO_WAV
|
||||
|
||||
#ifdef ENABLE_AUDIO_MP3
|
||||
struct DrMP3 final : CustomBase {
|
||||
DrMP3(std::unique_ptr<File>&& file = std::make_unique<File>()) : m_file{std::forward<decltype(file)>(file)} {
|
||||
|
||||
@@ -668,8 +676,9 @@ private:
|
||||
std::vector<drmp3_seek_point> m_seek_points{};
|
||||
#endif
|
||||
};
|
||||
#endif // ENABLE_AUDIO_MP3
|
||||
|
||||
#if 1
|
||||
#ifdef ENABLE_AUDIO_FLAC
|
||||
struct DrFLAC final : CustomBase {
|
||||
~DrFLAC() {
|
||||
drflac_close(m_flac);
|
||||
@@ -718,8 +727,9 @@ private:
|
||||
drflac* m_flac{};
|
||||
File m_file{};
|
||||
};
|
||||
#endif
|
||||
#endif // ENABLE_AUDIO_FLAC
|
||||
|
||||
#ifdef ENABLE_AUDIO_OGG
|
||||
// api is not ready, leaving this here for when it is.
|
||||
#if 0
|
||||
struct DrOGG final : CustomBase {
|
||||
@@ -864,6 +874,7 @@ private:
|
||||
stb_vorbis* m_ogg{};
|
||||
File m_file{};
|
||||
};
|
||||
#endif // ENABLE_AUDIO_OGG
|
||||
|
||||
constexpr u32 MAX_SONGS = 4;
|
||||
|
||||
@@ -1072,24 +1083,32 @@ Result OpenSong(fs::Fs* fs, const fs::FsPath& path, u32 flags, SongID* id) {
|
||||
else if (path.ends_with(".bfwav")) {
|
||||
source = std::make_unique<PlsrBFWAV>();
|
||||
}
|
||||
#ifdef ENABLE_AUDIO_WAV
|
||||
else if (path.ends_with(".wav")) {
|
||||
source = std::make_unique<DrWAV>();
|
||||
}
|
||||
#endif // ENABLE_AUDIO_WAV
|
||||
#ifdef ENABLE_AUDIO_MP3
|
||||
else if (path.ends_with(".mp3") || path.ends_with(".mp2") || path.ends_with(".mp1")) {
|
||||
source = std::make_unique<DrMP3>();
|
||||
}
|
||||
else if (path.ends_with(".adf")) {
|
||||
source = std::make_unique<DrMP3>(std::make_unique<GTAViceCityFile>());
|
||||
}
|
||||
#endif // ENABLE_AUDIO_MP3
|
||||
#ifdef ENABLE_AUDIO_FLAC
|
||||
else if (path.ends_with(".flac")) {
|
||||
source = std::make_unique<DrFLAC>();
|
||||
}
|
||||
#endif // ENABLE_AUDIO_FLAC
|
||||
#ifdef ENABLE_AUDIO_OGG
|
||||
// else if (path.ends_with(".ogg")) {
|
||||
// source = std::make_unique<DrOGG>();
|
||||
// }
|
||||
else if (path.ends_with(".ogg")) {
|
||||
source = std::make_unique<stbOGG>();
|
||||
}
|
||||
#endif // ENABLE_AUDIO_OGG
|
||||
|
||||
R_UNLESS(source, 0x1);
|
||||
R_TRY(source->LoadFile(fs, path, flags));
|
||||
|
||||
@@ -1475,7 +1475,7 @@ void UmountAllNeworkDevices() {
|
||||
continue;
|
||||
}
|
||||
|
||||
log_write("[DEVOPTAB] Unmounting %s\n", entry->device.config.url.c_str());
|
||||
log_write("[DEVOPTAB] Unmounting %s URL: %s\n", entry->mount.s, entry->device.config.url.c_str());
|
||||
entry.reset();
|
||||
}
|
||||
}
|
||||
@@ -1488,7 +1488,7 @@ void UmountNeworkDevice(const fs::FsPath& mount) {
|
||||
});
|
||||
|
||||
if (it != g_entries.end()) {
|
||||
log_write("[DEVOPTAB] Unmounting %s\n", (*it)->device.config.url.c_str());
|
||||
log_write("[DEVOPTAB] Unmounting %s URL: %s\n", (*it)->mount.s, (*it)->device.config.url.c_str());
|
||||
it->reset();
|
||||
} else {
|
||||
log_write("[DEVOPTAB] No such mount %s\n", mount.s);
|
||||
|
||||
@@ -460,4 +460,15 @@ Result fatfs_read(u8 num, void* dst, u64 offset, u64 size) {
|
||||
return fat.buffered->Read2(dst, offset, size);
|
||||
}
|
||||
|
||||
// libusbhsfs also defines these, so only define if not using it.
|
||||
#ifndef ENABLE_LIBUSBHSFS
|
||||
void* ff_memalloc (UINT msize) {
|
||||
return std::malloc(msize);
|
||||
}
|
||||
|
||||
void ff_memfree (void* mblock) {
|
||||
std::free(mblock);
|
||||
}
|
||||
#endif // ENABLE_LIBUSBHSFS
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#ifdef ENABLE_DEVOPTAB_NFS
|
||||
|
||||
#include "utils/devoptab_common.hpp"
|
||||
#include "defines.hpp"
|
||||
#include "log.hpp"
|
||||
@@ -412,3 +414,17 @@ Result MountNfsAll() {
|
||||
}
|
||||
|
||||
} // namespace sphaira::devoptab
|
||||
|
||||
#else // ENABLE_DEVOPTAB_NFS
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
namespace sphaira::devoptab {
|
||||
|
||||
Result MountNfsAll() {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace sphaira::devoptab
|
||||
|
||||
#endif // ENABLE_DEVOPTAB_NFS
|
||||
|
||||
540
sphaira/source/utils/devoptab_sftp.cpp
Normal file
540
sphaira/source/utils/devoptab_sftp.cpp
Normal file
@@ -0,0 +1,540 @@
|
||||
// NOTE (09/09/2025): do not use as it is unusably slow, even on local network.
|
||||
// the issue isn't the ssh protocol (although it is slow). haven't looked into libssh2 yet
|
||||
// it could be how they handle blocking. CPU usage is 0%, so its not that.
|
||||
|
||||
// NOTE (09/09/2025): its just reads that as super slow, which is even more strange!
|
||||
// writes are very fast (for sftp), maxing switch wifi. what is going on???
|
||||
|
||||
// NOTE (09/09/2025): the issue was that fread was buffering, causing double reads.
|
||||
// it would read the first 4mb, then read another 1kb.
|
||||
// disabling buffering fixed the issue, and i have disabled buffering by default.
|
||||
// buffering is now enabled only when requested.
|
||||
#include "utils/devoptab_common.hpp"
|
||||
#include "utils/profile.hpp"
|
||||
#include "defines.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
namespace sphaira::devoptab {
|
||||
namespace {
|
||||
|
||||
struct Device final : common::MountDevice {
|
||||
using MountDevice::MountDevice;
|
||||
~Device();
|
||||
|
||||
private:
|
||||
bool Mount() override;
|
||||
int devoptab_open(void *fileStruct, const char *path, int flags, int mode) override;
|
||||
int devoptab_close(void *fd) override;
|
||||
ssize_t devoptab_read(void *fd, char *ptr, size_t len) override;
|
||||
ssize_t devoptab_write(void *fd, const char *ptr, size_t len) override;
|
||||
off_t devoptab_seek(void *fd, off_t pos, int dir) override;
|
||||
int devoptab_fstat(void *fd, struct stat *st) override;
|
||||
int devoptab_unlink(const char *path) override;
|
||||
int devoptab_rename(const char *oldName, const char *newName) override;
|
||||
int devoptab_mkdir(const char *path, int mode) override;
|
||||
int devoptab_rmdir(const char *path) override;
|
||||
int devoptab_diropen(void* fd, const char *path) override;
|
||||
int devoptab_dirreset(void* fd) override;
|
||||
int devoptab_dirnext(void* fd, char *filename, struct stat *filestat) override;
|
||||
int devoptab_dirclose(void* fd) override;
|
||||
int devoptab_lstat(const char *path, struct stat *st) override;
|
||||
int devoptab_ftruncate(void *fd, off_t len) override;
|
||||
int devoptab_statvfs(const char *path, struct statvfs *buf) override;
|
||||
int devoptab_fsync(void *fd) override;
|
||||
|
||||
private:
|
||||
LIBSSH2_SESSION* m_session{};
|
||||
LIBSSH2_SFTP* m_sftp_session{};
|
||||
int m_socket{};
|
||||
bool m_is_ssh2_init{}; // set if libssh2_init() was successful.
|
||||
bool m_is_handshake_done{}; // set if handshake was successful.
|
||||
bool m_is_auth_done{}; // set if auth was successful.
|
||||
bool mounted{};
|
||||
};
|
||||
|
||||
struct File {
|
||||
LIBSSH2_SFTP_HANDLE* fd{};
|
||||
};
|
||||
|
||||
struct Dir {
|
||||
LIBSSH2_SFTP_HANDLE* fd{};
|
||||
};
|
||||
|
||||
int convert_flags_to_sftp(int flags) {
|
||||
int sftp_flags = 0;
|
||||
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
sftp_flags |= LIBSSH2_FXF_READ;
|
||||
} else if ((flags & O_ACCMODE) == O_WRONLY) {
|
||||
sftp_flags |= LIBSSH2_FXF_WRITE;
|
||||
} else if ((flags & O_ACCMODE) == O_RDWR) {
|
||||
sftp_flags |= LIBSSH2_FXF_READ | LIBSSH2_FXF_WRITE;
|
||||
}
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
sftp_flags |= LIBSSH2_FXF_CREAT;
|
||||
}
|
||||
if (flags & O_TRUNC) {
|
||||
sftp_flags |= LIBSSH2_FXF_TRUNC;
|
||||
}
|
||||
if (flags & O_APPEND) {
|
||||
sftp_flags |= LIBSSH2_FXF_APPEND;
|
||||
}
|
||||
if (flags & O_EXCL) {
|
||||
sftp_flags |= LIBSSH2_FXF_EXCL;
|
||||
}
|
||||
|
||||
return sftp_flags;
|
||||
}
|
||||
|
||||
int convert_mode_to_sftp(int mode) {
|
||||
int sftp_mode = 0;
|
||||
|
||||
// permission bits.
|
||||
sftp_mode |= (mode & S_IRUSR) ? LIBSSH2_SFTP_S_IRUSR : 0;
|
||||
sftp_mode |= (mode & S_IWUSR) ? LIBSSH2_SFTP_S_IWUSR : 0;
|
||||
sftp_mode |= (mode & S_IXUSR) ? LIBSSH2_SFTP_S_IXUSR : 0;
|
||||
|
||||
sftp_mode |= (mode & S_IRGRP) ? LIBSSH2_SFTP_S_IRGRP : 0;
|
||||
sftp_mode |= (mode & S_IWGRP) ? LIBSSH2_SFTP_S_IWGRP : 0;
|
||||
sftp_mode |= (mode & S_IXGRP) ? LIBSSH2_SFTP_S_IXGRP : 0;
|
||||
|
||||
sftp_mode |= (mode & S_IROTH) ? LIBSSH2_SFTP_S_IROTH : 0;
|
||||
sftp_mode |= (mode & S_IWOTH) ? LIBSSH2_SFTP_S_IWOTH : 0;
|
||||
sftp_mode |= (mode & S_IXOTH) ? LIBSSH2_SFTP_S_IXOTH : 0;
|
||||
|
||||
// file type bits.
|
||||
if (S_ISREG(mode)) {
|
||||
sftp_mode |= LIBSSH2_SFTP_S_IFREG;
|
||||
} else if (S_ISDIR(mode)) {
|
||||
sftp_mode |= LIBSSH2_SFTP_S_IFDIR;
|
||||
} else if (S_ISCHR(mode)) {
|
||||
sftp_mode |= LIBSSH2_SFTP_S_IFCHR;
|
||||
} else if (S_ISBLK(mode)) {
|
||||
sftp_mode |= LIBSSH2_SFTP_S_IFBLK;
|
||||
} else if (S_ISFIFO(mode)) {
|
||||
sftp_mode |= LIBSSH2_SFTP_S_IFIFO;
|
||||
} else if (S_ISLNK(mode)) {
|
||||
sftp_mode |= LIBSSH2_SFTP_S_IFLNK;
|
||||
} else if (S_ISSOCK(mode)) {
|
||||
sftp_mode |= LIBSSH2_SFTP_S_IFSOCK;
|
||||
}
|
||||
|
||||
return sftp_mode;
|
||||
}
|
||||
|
||||
void fill_stat(struct stat* st, const LIBSSH2_SFTP_ATTRIBUTES* attrs) {
|
||||
if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
|
||||
st->st_mode = attrs->permissions;
|
||||
}
|
||||
|
||||
if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
|
||||
st->st_size = attrs->filesize;
|
||||
}
|
||||
|
||||
if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
|
||||
st->st_uid = attrs->uid;
|
||||
st->st_gid = attrs->gid;
|
||||
}
|
||||
|
||||
if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
|
||||
st->st_atime = attrs->atime;
|
||||
st->st_mtime = attrs->mtime;
|
||||
st->st_ctime = attrs->mtime; // no ctime available, use mtime.
|
||||
}
|
||||
|
||||
st->st_nlink = 1;
|
||||
}
|
||||
|
||||
Device::~Device() {
|
||||
if (m_sftp_session) {
|
||||
libssh2_sftp_shutdown(m_sftp_session);
|
||||
}
|
||||
|
||||
if (m_session) {
|
||||
libssh2_session_disconnect(m_session, "Normal Shutdown");
|
||||
libssh2_session_free(m_session);
|
||||
}
|
||||
|
||||
if (m_socket > 0) {
|
||||
shutdown(m_socket, SHUT_RDWR);
|
||||
close(m_socket);
|
||||
}
|
||||
|
||||
if (m_is_ssh2_init) {
|
||||
libssh2_exit();
|
||||
}
|
||||
}
|
||||
|
||||
bool Device::Mount() {
|
||||
if (mounted) {
|
||||
return true;
|
||||
}
|
||||
|
||||
log_write("[SFTP] Mounting %s version: %s\n", this->config.url.c_str(), LIBSSH2_VERSION);
|
||||
|
||||
if (!m_socket) {
|
||||
// connect the socket.
|
||||
addrinfo hints{};
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
addrinfo* res{};
|
||||
const auto port = this->config.port.value_or(22);
|
||||
const auto port_str = std::to_string(port);
|
||||
auto ret = getaddrinfo(this->config.url.c_str(), port_str.c_str(), &hints, &res);
|
||||
if (ret != 0) {
|
||||
log_write("[SFTP] getaddrinfo() failed: %s\n", gai_strerror(ret));
|
||||
return false;
|
||||
}
|
||||
ON_SCOPE_EXIT(freeaddrinfo(res));
|
||||
|
||||
for (auto addr = res; addr != nullptr; addr = addr->ai_next) {
|
||||
m_socket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (m_socket < 0) {
|
||||
log_write("[SFTP] socket() failed: %s\n", std::strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = connect(m_socket, addr->ai_addr, addr->ai_addrlen);
|
||||
if (ret < 0) {
|
||||
log_write("[SFTP] connect() failed: %s\n", std::strerror(errno));
|
||||
close(m_socket);
|
||||
m_socket = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_socket < 0) {
|
||||
log_write("[SFTP] Failed to connect to %s:%ld\n", this->config.url.c_str(), port);
|
||||
return false;
|
||||
}
|
||||
|
||||
log_write("[SFTP] Connected to %s:%ld\n", this->config.url.c_str(), port);
|
||||
}
|
||||
|
||||
if (!m_is_ssh2_init) {
|
||||
auto ret = libssh2_init(0);
|
||||
if (ret != 0) {
|
||||
log_write("[SFTP] libssh2_init() failed: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_is_ssh2_init = true;
|
||||
}
|
||||
|
||||
if (!m_session) {
|
||||
m_session = libssh2_session_init();
|
||||
if (!m_session) {
|
||||
log_write("[SFTP] libssh2_session_init() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
libssh2_session_set_blocking(m_session, 1);
|
||||
libssh2_session_flag(m_session, LIBSSH2_FLAG_COMPRESS, 1);
|
||||
libssh2_session_set_timeout(m_session, this->config.timeout);
|
||||
// dkp libssh2 is too old for this.
|
||||
#if LIBSSH2_VERSION_NUM >= 0x010B00
|
||||
libssh2_session_set_read_timeout(m_session, this->config.timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (this->config.user.empty() || this->config.pass.empty()) {
|
||||
log_write("[SFTP] Missing username or password\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_is_handshake_done) {
|
||||
const auto ret = libssh2_session_handshake(m_session, m_socket);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_session_handshake() failed: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_is_handshake_done = true;
|
||||
}
|
||||
|
||||
if (!m_is_auth_done) {
|
||||
const auto userauthlist = libssh2_userauth_list(m_session, this->config.user.c_str(), this->config.user.length());
|
||||
if (!userauthlist) {
|
||||
log_write("[SFTP] libssh2_userauth_list() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// just handle user/pass auth for now, pub/priv key is a bit overkill.
|
||||
if (std::strstr(userauthlist, "password")) {
|
||||
auto ret = libssh2_userauth_password(m_session, this->config.user.c_str(), this->config.pass.c_str());
|
||||
if (ret) {
|
||||
log_write("[SFTP] Password auth failed: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
log_write("[SFTP] No supported auth methods found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_is_auth_done = true;
|
||||
}
|
||||
|
||||
if (!m_sftp_session) {
|
||||
m_sftp_session = libssh2_sftp_init(m_session);
|
||||
if (!m_sftp_session) {
|
||||
log_write("[SFTP] libssh2_sftp_init() failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
log_write("[SFTP] Mounted %s\n", this->config.url.c_str());
|
||||
return mounted = true;
|
||||
}
|
||||
|
||||
int Device::devoptab_open(void *fileStruct, const char *path, int flags, int mode) {
|
||||
auto file = static_cast<File*>(fileStruct);
|
||||
|
||||
file->fd = libssh2_sftp_open(m_sftp_session, path, convert_flags_to_sftp(flags), convert_mode_to_sftp(mode));
|
||||
if (!file->fd) {
|
||||
log_write("[SFTP] libssh2_sftp_open() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_close(void *fd) {
|
||||
auto file = static_cast<File*>(fd);
|
||||
|
||||
libssh2_sftp_close(file->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t Device::devoptab_read(void *fd, char *ptr, size_t len) {
|
||||
auto file = static_cast<File*>(fd);
|
||||
|
||||
// enable if sftp read is slow again.
|
||||
#if 0
|
||||
char name[256]{};
|
||||
std::snprintf(name, sizeof(name), "SFTP read %zu bytes", len);
|
||||
SCOPED_TIMESTAMP(name);
|
||||
#endif
|
||||
|
||||
const auto ret = libssh2_sftp_read(file->fd, ptr, len);
|
||||
if (ret < 0) {
|
||||
log_write("[SFTP] libssh2_sftp_read() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t Device::devoptab_write(void *fd, const char *ptr, size_t len) {
|
||||
auto file = static_cast<File*>(fd);
|
||||
|
||||
const auto ret = libssh2_sftp_write(file->fd, ptr, len);
|
||||
if (ret < 0) {
|
||||
log_write("[SFTP] libssh2_sftp_write() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
off_t Device::devoptab_seek(void *fd, off_t pos, int dir) {
|
||||
auto file = static_cast<File*>(fd);
|
||||
const auto current_pos = libssh2_sftp_tell64(file->fd);
|
||||
|
||||
if (dir == SEEK_CUR) {
|
||||
pos += current_pos;
|
||||
} else if (dir == SEEK_END) {
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs{};
|
||||
auto ret = libssh2_sftp_fstat(file->fd, &attrs);
|
||||
if (ret || !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE)) {
|
||||
log_write("[SFTP] libssh2_sftp_fstat() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
} else {
|
||||
pos = attrs.filesize;
|
||||
}
|
||||
}
|
||||
|
||||
// libssh2 already does this internally, but handle just in case this changes.
|
||||
if (pos == current_pos) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
log_write("[SFTP] Seeking to %ld dir: %d old: %llu\n", pos, dir, current_pos);
|
||||
libssh2_sftp_seek64(file->fd, pos);
|
||||
return libssh2_sftp_tell64(file->fd);
|
||||
}
|
||||
|
||||
int Device::devoptab_fstat(void *fd, struct stat *st) {
|
||||
auto file = static_cast<File*>(fd);
|
||||
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs{};
|
||||
const auto ret = libssh2_sftp_fstat(file->fd, &attrs);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_fstat() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fill_stat(st, &attrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_unlink(const char *path) {
|
||||
const auto ret = libssh2_sftp_unlink(m_sftp_session, path);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_unlink() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_rename(const char *oldName, const char *newName) {
|
||||
const auto ret = libssh2_sftp_rename(m_sftp_session, oldName, newName);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_rename() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_mkdir(const char *path, int mode) {
|
||||
const auto ret = libssh2_sftp_mkdir(m_sftp_session, path, mode);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_mkdir() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_rmdir(const char *path) {
|
||||
const auto ret = libssh2_sftp_rmdir(m_sftp_session, path);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_rmdir() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_diropen(void* fd, const char *path) {
|
||||
auto dir = static_cast<Dir*>(fd);
|
||||
|
||||
dir->fd = libssh2_sftp_opendir(m_sftp_session, path);
|
||||
if (!dir->fd) {
|
||||
log_write("[SFTP] libssh2_sftp_opendir() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_dirreset(void* fd) {
|
||||
auto dir = static_cast<Dir*>(fd);
|
||||
|
||||
libssh2_sftp_rewind(dir->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_dirnext(void* fd, char *filename, struct stat *filestat) {
|
||||
auto dir = static_cast<Dir*>(fd);
|
||||
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs{};
|
||||
const auto ret = libssh2_sftp_readdir(dir->fd, filename, NAME_MAX, &attrs);
|
||||
if (ret <= 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
fill_stat(filestat, &attrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_dirclose(void* fd) {
|
||||
auto dir = static_cast<Dir*>(fd);
|
||||
|
||||
libssh2_sftp_closedir(dir->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_lstat(const char *path, struct stat *st) {
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs{};
|
||||
const auto ret = libssh2_sftp_stat(m_sftp_session, path, &attrs);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_stat() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fill_stat(st, &attrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 1
|
||||
int Device::devoptab_ftruncate(void *fd, off_t len) {
|
||||
// stubbed.
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int Device::devoptab_statvfs(const char *path, struct statvfs *buf) {
|
||||
LIBSSH2_SFTP_STATVFS sftp_st{};
|
||||
const auto ret = libssh2_sftp_statvfs(m_sftp_session, path, std::strlen(path), &sftp_st);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_statvfs() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
buf->f_bsize = sftp_st.f_bsize;
|
||||
buf->f_frsize = sftp_st.f_frsize;
|
||||
buf->f_blocks = sftp_st.f_blocks;
|
||||
buf->f_bfree = sftp_st.f_bfree;
|
||||
buf->f_bavail = sftp_st.f_bavail;
|
||||
buf->f_files = sftp_st.f_files;
|
||||
buf->f_ffree = sftp_st.f_ffree;
|
||||
buf->f_favail = sftp_st.f_favail;
|
||||
buf->f_fsid = sftp_st.f_fsid;
|
||||
buf->f_flag = sftp_st.f_flag;
|
||||
buf->f_namemax = sftp_st.f_namemax;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::devoptab_fsync(void *fd) {
|
||||
auto file = static_cast<File*>(fd);
|
||||
|
||||
const auto ret = libssh2_sftp_fsync(file->fd);
|
||||
if (ret) {
|
||||
log_write("[SFTP] libssh2_sftp_fsync() failed: %ld\n", libssh2_sftp_last_error(m_sftp_session));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result MountSftpAll() {
|
||||
return common::MountNetworkDevice([](const common::MountConfig& cfg) {
|
||||
return std::make_unique<Device>(cfg);
|
||||
},
|
||||
sizeof(File), sizeof(Dir),
|
||||
"SFTP"
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace sphaira::devoptab
|
||||
Reference in New Issue
Block a user