diff --git a/.gitignore b/.gitignore index 3a4297b..348bf56 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ switch/romfs/shaders/*.dksh build/ *.rpx *.wuhb +*.wps diff --git a/Dockerfile.wiiu b/Dockerfile.wiiu new file mode 100644 index 0000000..0b000a9 --- /dev/null +++ b/Dockerfile.wiiu @@ -0,0 +1,6 @@ +FROM ghcr.io/wiiu-env/devkitppc:20231112 + +COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20230719 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libmocha:20230621 /artifacts $DEVKITPRO + +WORKDIR project \ No newline at end of file diff --git a/Makefile.wiiu b/Makefile.wiiu index 5e787b1..1ce1e27 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -8,16 +8,10 @@ endif TOPDIR ?= $(CURDIR) -#------------------------------------------------------------------------------- -# APP_NAME sets the long name of the application -# APP_SHORTNAME sets the short name of the application -# APP_AUTHOR sets the author of the application -#------------------------------------------------------------------------------- -#APP_NAME := Application Name -#APP_SHORTNAME := App Name -#APP_AUTHOR := Built with devkitPPC & wut +include $(DEVKITPRO)/wups/share/wups_rules -include $(DEVKITPRO)/wut/share/wut_rules +WUT_ROOT := $(DEVKITPRO)/wut +WUPS_ROOT := $(DEVKITPRO)/wups #------------------------------------------------------------------------------- # TARGET is the name of the output @@ -25,42 +19,44 @@ include $(DEVKITPRO)/wut/share/wut_rules # SOURCES is a list of directories containing source code # DATA is a list of directories containing data files # INCLUDES is a list of directories containing header files -# CONTENT is the path to the bundled folder that will be mounted as /vol/content/ -# ICON is the game icon, leave blank to use default rule -# TV_SPLASH is the image displayed during bootup on the TV, leave blank to use default rule -# DRC_SPLASH is the image displayed during bootup on the DRC, leave blank to use default rule #------------------------------------------------------------------------------- -TARGET := $(notdir $(CURDIR)) +TARGET := ftpd BUILD := build SOURCES := source source/wiiu DATA := data -INCLUDES := include -CONTENT := -ICON := -TV_SPLASH := -DRC_SPLASH := +INCLUDES := source include #------------------------------------------------------------------------------- # options for code generation #------------------------------------------------------------------------------- -CFLAGS := -g -Wall -O0 -ffunction-sections \ +CFLAGS := -Wall -O2 -ffunction-sections \ $(MACHDEP) - -CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -DSTATUS_STRING="\"ftpd v$(VERSION)\"" \ + +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__ -DSTATUS_STRING="\"ftpd v$(VERSION)\"" \ -DNO_IPV6 -DCLASSIC -DNO_CONSOLE -DFTPDCONFIG="\"/config/ftpd/ftpd.cfg\"" -CXXFLAGS := $(CFLAGS) -std=c++20 +CXXFLAGS := $(CFLAGS) -std=gnu++20 ASFLAGS := -g $(ARCH) -LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) +LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS) -LIBS := -lwutd -lmocha +ifeq ($(DEBUG),1) +CXXFLAGS += -DDEBUG -g +CFLAGS += -DDEBUG -g +endif + +ifeq ($(DEBUG),VERBOSE) +CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g +CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g +endif + +LIBS := -lwups -lwutd -lmocha #------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level # containing include and lib #------------------------------------------------------------------------------- -LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr +LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT) $(WUT_ROOT)/usr #------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional @@ -107,34 +103,6 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -ifneq (,$(strip $(CONTENT))) - export APP_CONTENT := $(TOPDIR)/$(CONTENT) -endif - -ifneq (,$(strip $(ICON))) - export APP_ICON := $(TOPDIR)/$(ICON) -else ifneq (,$(wildcard $(TOPDIR)/$(TARGET).png)) - export APP_ICON := $(TOPDIR)/$(TARGET).png -else ifneq (,$(wildcard $(TOPDIR)/icon.png)) - export APP_ICON := $(TOPDIR)/icon.png -endif - -ifneq (,$(strip $(TV_SPLASH))) - export APP_TV_SPLASH := $(TOPDIR)/$(TV_SPLASH) -else ifneq (,$(wildcard $(TOPDIR)/tv-splash.png)) - export APP_TV_SPLASH := $(TOPDIR)/tv-splash.png -else ifneq (,$(wildcard $(TOPDIR)/splash.png)) - export APP_TV_SPLASH := $(TOPDIR)/splash.png -endif - -ifneq (,$(strip $(DRC_SPLASH))) - export APP_DRC_SPLASH := $(TOPDIR)/$(DRC_SPLASH) -else ifneq (,$(wildcard $(TOPDIR)/drc-splash.png)) - export APP_DRC_SPLASH := $(TOPDIR)/drc-splash.png -else ifneq (,$(wildcard $(TOPDIR)/splash.png)) - export APP_DRC_SPLASH := $(TOPDIR)/splash.png -endif - .PHONY: $(BUILD) clean all #------------------------------------------------------------------------------- @@ -147,7 +115,7 @@ $(BUILD): #------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(TARGET).wuhb $(TARGET).rpx $(TARGET).elf + @rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf #------------------------------------------------------------------------------- else @@ -158,10 +126,9 @@ DEPENDS := $(OFILES:.o=.d) #------------------------------------------------------------------------------- # main targets #------------------------------------------------------------------------------- -all : $(OUTPUT).wuhb +all : $(OUTPUT).wps -$(OUTPUT).wuhb : $(OUTPUT).rpx -$(OUTPUT).rpx : $(OUTPUT).elf +$(OUTPUT).wps : $(OUTPUT).elf $(OUTPUT).elf : $(OFILES) $(OFILES_SRC) : $(HFILES_BIN) diff --git a/source/IOAbstraction.h b/include/IOAbstraction.h similarity index 79% rename from source/IOAbstraction.h rename to include/IOAbstraction.h index 7ad9199..af961b2 100644 --- a/source/IOAbstraction.h +++ b/include/IOAbstraction.h @@ -20,7 +20,6 @@ public: static int closedir (DIR *dirp); - static DIR *opendir (const char *dirname); static struct dirent *readdir (DIR *dirp); @@ -29,6 +28,16 @@ public: static int lstat (const char *path, struct stat *buf); + static int mkdir (const char *path, mode_t mode); + + static int rmdir (const char *path); + + static int rename (const char *path, const char *path2); + + static int unlink (const char *path); + static void addVirtualPath (const std::string &virtualPath, const std::vector &subDirectories); + + static void clear (); }; diff --git a/include/ftpSession.h b/include/ftpSession.h index b3478a2..33829d2 100644 --- a/include/ftpSession.h +++ b/include/ftpSession.h @@ -60,13 +60,7 @@ private: /// \brief Command buffer size constexpr static auto COMMAND_BUFFERSIZE = 4096; -#ifdef __WIIU__ - /// \brief Response buffer size - constexpr static auto RESPONSE_BUFFERSIZE = 128 * 1024; - - /// \brief Transfer buffersize - constexpr static auto XFER_BUFFERSIZE = 128 * 1024; -#elif defined(NDS) +#ifdef NDS /// \brief Response buffer size constexpr static auto RESPONSE_BUFFERSIZE = 4096; @@ -74,10 +68,10 @@ private: constexpr static auto XFER_BUFFERSIZE = 8192; #else /// \brief Response buffer size - constexpr static auto RESPONSE_BUFFERSIZE = 32768; + constexpr static auto RESPONSE_BUFFERSIZE = 16 * 1024; /// \brief Transfer buffersize - constexpr static auto XFER_BUFFERSIZE = 65536; + constexpr static auto XFER_BUFFERSIZE = 32 * 1024; #endif /// \brief File buffersize diff --git a/source/IOAbstraction.cpp b/source/IOAbstraction.cpp index 93bde66..00c1f70 100644 --- a/source/IOAbstraction.cpp +++ b/source/IOAbstraction.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include class VirtualDirectory @@ -17,9 +18,9 @@ public: mCurIterator = mDirectories.begin (); } - [[nodiscard]] DIR *getAsDir () const + [[nodiscard]] const DIR *getAsDir () const { - return (DIR *)this; + return &mDirPtr; } struct dirent *readdir () @@ -31,10 +32,12 @@ public: mDir = {}; snprintf (mDir.d_name, sizeof (mDir.d_name), "%s", mCurIterator->c_str ()); mCurIterator++; + mDirPtr.position++; return &mDir; } private: + DIR mDirPtr = {}; std::vector mDirectories; struct dirent mDir = {}; std::vector::iterator mCurIterator{}; @@ -70,7 +73,7 @@ bool remove_locked_first_if (std::mutex &mutex, Container &container, Predicate return remove_first_if (container, pred); } -static DIR *getVirtualDir (const std::vector &subDirectories) +static const DIR *getVirtualDir (const std::vector &subDirectories) { auto virtDir = std::make_unique (subDirectories); auto *result = virtDir->getAsDir (); @@ -124,12 +127,16 @@ int IOAbstraction::closedir (DIR *dirp) DIR *IOAbstraction::opendir (const char *dirname) { auto convertedPath = convertPath (dirname); - if (sVirtualDirs.count (convertedPath) > 0) + auto * res = ::opendir (convertedPath.c_str ()); + if(res == nullptr) { - return getVirtualDir (sVirtualDirs[convertedPath]); - } + if (sVirtualDirs.count (convertedPath) > 0) + { + return (DIR*) getVirtualDir (sVirtualDirs[convertedPath]); + } - return ::opendir (convertedPath.c_str ()); + } + return res; } FILE *IOAbstraction::fopen (const char *_name, const char *_type) @@ -195,3 +202,30 @@ void IOAbstraction::addVirtualPath (const std::string &virtualPath, { sVirtualDirs.insert (std::make_pair (virtualPath, subDirectories)); } + +void IOAbstraction::clear () +{ + std::lock_guard lock (sOpenVirtualDirectoriesMutex); + sOpenVirtualDirectories.clear (); + sVirtualDirs.clear (); +} + +int IOAbstraction::mkdir (const char *path, mode_t mode) +{ + return ::mkdir (convertPath (path).c_str (), mode); +} + +int IOAbstraction::rmdir (const char *path) +{ + return ::rmdir (convertPath (path).c_str ()); +} + +int IOAbstraction::unlink (const char *path) +{ + return ::unlink (convertPath (path).c_str ()); +} + +int IOAbstraction::rename (const char *path, const char *path2) +{ + return ::rename (convertPath (path).c_str (), convertPath (path2).c_str ()); +} diff --git a/source/ftpSession.cpp b/source/ftpSession.cpp index 295cd34..aafb889 100644 --- a/source/ftpSession.cpp +++ b/source/ftpSession.cpp @@ -583,10 +583,20 @@ bool FtpSession::poll (std::vector const &sessions_) } else if (i.revents & (POLLIN | POLLOUT)) { - for (unsigned i = 0; i < 10; ++i) + auto start_time = std::chrono::high_resolution_clock::now (); + while (true) { if (!((*session).*(session->m_transfer)) ()) + { break; + } + + if (std::chrono::duration_cast ( + std::chrono::high_resolution_clock::now () - start_time) > + 5000ms) + { + break; + } } } break; @@ -1677,7 +1687,7 @@ bool FtpSession::listTransfer () { // build the path auto const fullPath = buildPath (m_lwd, dent->d_name); - struct stat st; + struct stat st = {}; #ifdef __3DS__ // the sdmc directory entry already has the type and size, so no need to do a slow stat @@ -1997,7 +2007,7 @@ void FtpSession::DELE (char const *args_) } // unlink the path - if (::unlink (path.c_str ()) != 0) + if (IOAbstraction::unlink (path.c_str ()) != 0) { sendResponse ("550 %s\r\n", std::strerror (errno)); return; @@ -2081,7 +2091,7 @@ void FtpSession::MKD (char const *args_) } // create the directory - if (::mkdir (path.c_str (), 0755) != 0) + if (IOAbstraction::mkdir (path.c_str (), 0755) != 0) { sendResponse ("550 %s\r\n", std::strerror (errno)); return; @@ -2498,7 +2508,7 @@ void FtpSession::RMD (char const *args_) } // remove the directory - if (::rmdir (path.c_str ()) != 0) + if (IOAbstraction::rmdir (path.c_str ()) != 0) { sendResponse ("550 %d %s\r\n", __LINE__, std::strerror (errno)); return; @@ -2566,7 +2576,7 @@ void FtpSession::RNTO (char const *args_) } // rename the file - if (::rename (m_rename.c_str (), path.c_str ()) != 0) + if (IOAbstraction::rename (m_rename.c_str (), path.c_str ()) != 0) { m_rename.clear (); sendResponse ("550 %s\r\n", std::strerror (errno)); diff --git a/source/wiiu/platform.cpp b/source/wiiu/platform.cpp index aa1911b..af63dd5 100644 --- a/source/wiiu/platform.cpp +++ b/source/wiiu/platform.cpp @@ -20,7 +20,8 @@ #include "platform.h" -#include "../IOAbstraction.h" +#include "IOAbstraction.h" +#include "ftpServer.h" #include "log.h" #include @@ -28,12 +29,29 @@ #include #include -#include #include +#include +#include +#include +#include +#include #ifndef CLASSIC #error "Wii U must be built in classic mode" #endif +#define VERSION_FULL "0.1" + +WUPS_PLUGIN_NAME ("ftpd"); +WUPS_PLUGIN_DESCRIPTION ("FTP Server"); +WUPS_PLUGIN_VERSION (VERSION_FULL); +WUPS_PLUGIN_AUTHOR ("mtheall, Maschell"); +WUPS_PLUGIN_LICENSE ("GPL"); + +WUPS_USE_WUT_DEVOPTAB (); +WUPS_USE_STORAGE ("ftpd"); // Unqiue id for the storage api + +#define FTPIIU_ENABLED_STRING "enabled" +#define SYSTEM_FILES_ALLOWED_STRING "systemFilesAllowed" bool platform::networkVisible () { @@ -68,71 +86,262 @@ MochaUtilsStatus MountWrapper (const char *mount, const char *dev, const char *m return res; } -bool platform::init () +UniqueFtpServer server = nullptr; +bool sSystemFilesAllowed = false; +bool sMochaPathsWereMounted = false; +bool sFTPServerEnabled = true; + +void start_server () { - nn::ac::Initialize (); - nn::ac::ConnectAsync (); - WHBProcInit (); + if (server != nullptr) + { + return; + } MochaUtilsStatus res; if ((res = Mocha_InitLibrary ()) == MOCHA_RESULT_SUCCESS) { std::vector virtualDirsInRoot; - if (MountWrapper ("slccmpt01", "/dev/slccmpt01", "/vol/storage_slccmpt01") == - MOCHA_RESULT_SUCCESS) + if (sSystemFilesAllowed) { - virtualDirsInRoot.push_back ("slccmpt01"); + if (MountWrapper ("slccmpt01", "/dev/slccmpt01", "/vol/storage_slccmpt01") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("slccmpt01"); + IOAbstraction::addVirtualPath ("slccmpt01:/", {}); + } + if (MountWrapper ("storage_odd_tickets", nullptr, "/vol/storage_odd01") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("storage_odd_tickets"); + IOAbstraction::addVirtualPath ("storage_odd_tickets:/", {}); + } + if (MountWrapper ("storage_odd_updates", nullptr, "/vol/storage_odd02") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("storage_odd_updates"); + IOAbstraction::addVirtualPath ("storage_odd_updates:/", {}); + } + if (MountWrapper ("storage_odd_content", nullptr, "/vol/storage_odd03") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("storage_odd_content"); + IOAbstraction::addVirtualPath ("storage_odd_content:/", {}); + } + if (MountWrapper ("storage_odd_content2", nullptr, "/vol/storage_odd04") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("storage_odd_content2"); + IOAbstraction::addVirtualPath ("storage_odd_content2:/", {}); + } + if (MountWrapper ("storage_slc", "/dev/slc01", "/vol/storage_slc01") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("storage_slc"); + IOAbstraction::addVirtualPath ("storage_slc:/", {}); + } + if (Mocha_MountFS ("storage_mlc", nullptr, "/vol/storage_mlc01") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("storage_mlc"); + IOAbstraction::addVirtualPath ("storage_mlc:/", {}); + } + if (Mocha_MountFS ("storage_usb", nullptr, "/vol/storage_usb01") == + MOCHA_RESULT_SUCCESS) + { + virtualDirsInRoot.emplace_back ("storage_usb"); + IOAbstraction::addVirtualPath ("storage_usb:/", {}); + } } - if (MountWrapper ("storage_odd_tickets", nullptr, "/vol/storage_odd01") == - MOCHA_RESULT_SUCCESS) - { - virtualDirsInRoot.push_back ("storage_odd_tickets"); - } - if (MountWrapper ("storage_odd_updates", nullptr, "/vol/storage_odd02") == - MOCHA_RESULT_SUCCESS) - { - virtualDirsInRoot.push_back ("storage_odd_updates"); - } - if (MountWrapper ("storage_odd_content", nullptr, "/vol/storage_odd03") == - MOCHA_RESULT_SUCCESS) - { - virtualDirsInRoot.push_back ("storage_odd_content"); - } - if (MountWrapper ("storage_odd_content2", nullptr, "/vol/storage_odd04") == - MOCHA_RESULT_SUCCESS) - { - virtualDirsInRoot.push_back ("storage_odd_content2"); - } - if (MountWrapper ("storage_slc", "/dev/slc01", "/vol/storage_slc01") == - MOCHA_RESULT_SUCCESS) - { - virtualDirsInRoot.push_back ("storage_slc"); - } - if (Mocha_MountFS ("storage_mlc", nullptr, "/vol/storage_mlc01") == MOCHA_RESULT_SUCCESS) - { - virtualDirsInRoot.push_back ("storage_mlc"); - } - if (Mocha_MountFS ("storage_usb", nullptr, "/vol/storage_usb01") == MOCHA_RESULT_SUCCESS) - { - virtualDirsInRoot.push_back ("storage_usb"); - } - virtualDirsInRoot.push_back ("fs"); + virtualDirsInRoot.emplace_back ("fs"); IOAbstraction::addVirtualPath (":/", virtualDirsInRoot); IOAbstraction::addVirtualPath ("fs:/", std::vector{"vol"}); - IOAbstraction::addVirtualPath ("fs:/vol", std::vector{"external01"}); - IOAbstraction::addVirtualPath ("storage_odd_tickets:/", {}); - IOAbstraction::addVirtualPath ("storage_odd_updates:/", {}); - IOAbstraction::addVirtualPath ("storage_odd_content:/", {}); - IOAbstraction::addVirtualPath ("storage_odd_content2:/", {}); - IOAbstraction::addVirtualPath ("storage_usb:/", {}); + IOAbstraction::addVirtualPath ( + "fs:/vol", std::vector{"external01", "content", "save"}); + + IOAbstraction::addVirtualPath ("fs:/vol/content", {}); + sMochaPathsWereMounted = true; } else { - error ("Failed to init libmocha: %s [%d]", Mocha_GetStatusStr (res), res); + OSReport ("Failed to init libmocha: %s [%d]\n", Mocha_GetStatusStr (res), res); } - ::chdir ("fs:/vol/external01"); + server = FtpServer::create (); +} +void stop_server () +{ + server.reset (); + if (sMochaPathsWereMounted) + { + Mocha_UnmountFS ("slccmpt01"); + Mocha_UnmountFS ("storage_odd_tickets"); + Mocha_UnmountFS ("storage_odd_updates"); + Mocha_UnmountFS ("storage_odd_content"); + Mocha_UnmountFS ("storage_odd_content2"); + Mocha_UnmountFS ("storage_slc"); + Mocha_UnmountFS ("storage_mlc"); + Mocha_UnmountFS ("storage_usb"); + sMochaPathsWereMounted = false; + } + + IOAbstraction::clear (); +} + +void gFTPServerRunningChanged (ConfigItemBoolean *item, bool newValue) +{ + sFTPServerEnabled = newValue; + if (!sFTPServerEnabled) + { + stop_server (); + } + else + { + start_server (); + } + // If the value has changed, we store it in the storage. + auto res = WUPSStorageAPI::Store (FTPIIU_ENABLED_STRING, sFTPServerEnabled); + if (res != WUPS_STORAGE_ERROR_SUCCESS) + { + OSReport ("Failed to store gFTPServerEnabled: %s (%d)\n", + WUPSStorageAPI::GetStatusStr (res).data (), + res); + } +} + +void gSystemFilesAllowedChanged (ConfigItemBoolean *item, bool newValue) +{ + // DEBUG_FUNCTION_LINE("New value in gFTPServerEnabled: %d", newValue); + if (server != nullptr) + { // If the server is already running we need to restart it. + stop_server (); + sSystemFilesAllowed = newValue; + start_server (); + } + else + { + sSystemFilesAllowed = newValue; + } + // If the value has changed, we store it in the storage. + auto res = WUPSStorageAPI::Store (SYSTEM_FILES_ALLOWED_STRING, sSystemFilesAllowed); + if (res != WUPS_STORAGE_ERROR_SUCCESS) + { + OSReport ("Failed to store gSystemFilesAllowed: %s (%d)\n", + WUPSStorageAPI::GetStatusStr (res).data (), + res); + } +} + +WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback (WUPSConfigCategoryHandle rootHandle) +{ + uint32_t hostIpAddress = 0; + nn::ac::GetAssignedAddress (&hostIpAddress); + try + { + WUPSConfigCategory root = WUPSConfigCategory (rootHandle); + root.add (WUPSConfigItemBoolean::Create (FTPIIU_ENABLED_STRING, + "Enable ftpd", + true, + sFTPServerEnabled, + &gFTPServerRunningChanged)); + + root.add (WUPSConfigItemBoolean::Create (SYSTEM_FILES_ALLOWED_STRING, + "Allow access to system files", + false, + sSystemFilesAllowed, + &gSystemFilesAllowedChanged)); + + root.add (WUPSConfigItemStub::Create ("===")); + + char ipSettings[50]; + if (hostIpAddress != 0) + { + snprintf (ipSettings, + 50, + "IP of your console is %u.%u.%u.%u. Port %i", + (hostIpAddress >> 24) & 0xFF, + (hostIpAddress >> 16) & 0xFF, + (hostIpAddress >> 8) & 0xFF, + (hostIpAddress >> 0) & 0xFF, + 5000); + } + else + { + snprintf ( + ipSettings, sizeof (ipSettings), "The console is not connected to a network."); + } + + root.add (WUPSConfigItemStub::Create (ipSettings)); + root.add (WUPSConfigItemStub::Create ("You can connect with empty credentials")); + } + catch (std::exception &e) + { + OSReport ("Exception T_T : %s\n", e.what ()); + return WUPSCONFIG_API_CALLBACK_RESULT_ERROR; + } + + return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS; +} + +void ConfigMenuClosedCallback () +{ + OSReport ("ConfigMenuClosedCallback\n"); + WUPSStorageAPI::SaveStorage (); +} + +INITIALIZE_PLUGIN () +{ + WUPSConfigAPIOptionsV1 configOptions = {.name = "ftpd"}; + if (WUPSConfigAPI_Init (configOptions, ConfigMenuOpenedCallback, ConfigMenuClosedCallback) != + WUPSCONFIG_API_RESULT_SUCCESS) + { + OSFatal ("Failed to init config api"); + } + + if (WUPSStorageAPI::GetOrStoreDefault (FTPIIU_ENABLED_STRING, sFTPServerEnabled, true) != + WUPS_STORAGE_ERROR_SUCCESS) + { + OSReport ("Failed\n"); + } + if (WUPSStorageAPI::GetOrStoreDefault ( + SYSTEM_FILES_ALLOWED_STRING, sSystemFilesAllowed, false) != WUPS_STORAGE_ERROR_SUCCESS) + { + OSReport ("Failed\n"); + } + if (WUPSStorageAPI::SaveStorage () != WUPS_STORAGE_ERROR_SUCCESS) + { + OSReport ("Failed\n"); + } +} + +void wiiu_init () +{ + nn::ac::Initialize (); + nn::ac::ConnectAsync (); + if (sFTPServerEnabled) + { + start_server (); + } +} + +ON_APPLICATION_START () +{ + nn::ac::Initialize (); + nn::ac::ConnectAsync (); + + wiiu_init (); +} + +ON_APPLICATION_ENDS () +{ + stop_server (); +} + +bool platform::init () +{ + WHBProcInit (); + wiiu_init (); return true; } @@ -147,6 +356,7 @@ void platform::render () void platform::exit () { + IOAbstraction::clear (); WHBProcShutdown (); } @@ -162,11 +372,15 @@ public: explicit privateData_t (std::function &&func_) : thread (std::move (func_)) { auto nativeHandle = (OSThread *)thread.native_handle (); - OSSetThreadName (nativeHandle, "ftpd_server"); + OSSetThreadName (nativeHandle, "ftpd"); while (!OSSetThreadAffinity (nativeHandle, OS_THREAD_ATTRIB_AFFINITY_CPU2)) { OSSleepTicks (OSMillisecondsToTicks (16)); } + while (!OSSetThreadPriority (nativeHandle, 16)) + { + OSSleepTicks (OSMillisecondsToTicks (16)); + } } /// \brief Underlying thread