mirror of
https://github.com/wiiu-env/ftpiiu_plugin.git
synced 2024-12-22 19:11:47 +01:00
Initial Wii U port
This commit is contained in:
parent
fec8332df6
commit
af2b1be4c8
4
.gitignore
vendored
4
.gitignore
vendored
@ -23,3 +23,7 @@ switch/build
|
||||
switch-classic/build
|
||||
switch/romfs/*.zst
|
||||
switch/romfs/shaders/*.dksh
|
||||
.idea/
|
||||
build/
|
||||
*.rpx
|
||||
*.wuhb
|
||||
|
8
Makefile
8
Makefile
@ -12,9 +12,9 @@ export VERSION_MICRO := 0
|
||||
export VERSION := $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_MICRO)
|
||||
|
||||
###########################################################################
|
||||
all: nds 3dsx nro linux
|
||||
all: wiiu nds 3dsx nro linux
|
||||
|
||||
all-classic: nds 3dsx-classic nro-classic linux
|
||||
all-classic: wiiu nds 3dsx-classic nro-classic linux
|
||||
|
||||
format:
|
||||
@clang-format -style=file -i $(filter-out \
|
||||
@ -36,6 +36,7 @@ format:
|
||||
, $(shell find source include -type f -name \*.c -o -name \*.cpp -o -name \*.h))
|
||||
|
||||
clean:
|
||||
@$(MAKE) -f Makefile.wiiu clean
|
||||
@$(MAKE) -f Makefile.nds clean
|
||||
@$(MAKE) -f Makefile.3ds clean
|
||||
@$(MAKE) -f Makefile.3ds clean CLASSIC="-DCLASSIC"
|
||||
@ -61,6 +62,9 @@ nxlink-classic:
|
||||
@$(MAKE) -f Makefile.switch nxlink CLASSIC="-DCLASSIC"
|
||||
|
||||
###########################################################################
|
||||
wiiu:
|
||||
@$(MAKE) -f Makefile.wiiu CLASSIC="-DCLASSIC"
|
||||
|
||||
nds:
|
||||
@$(MAKE) -f Makefile.nds CLASSIC="-DCLASSIC"
|
||||
|
||||
|
181
Makefile.wiiu
Normal file
181
Makefile.wiiu
Normal file
@ -0,0 +1,181 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
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)/wut/share/wut_rules
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# 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))
|
||||
BUILD := build
|
||||
SOURCES := source source/wiiu
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
CONTENT :=
|
||||
ICON :=
|
||||
TV_SPLASH :=
|
||||
DRC_SPLASH :=
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#-------------------------------------------------------------------------------
|
||||
CFLAGS := -g -Wall -O0 -ffunction-sections \
|
||||
$(MACHDEP)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -DSTATUS_STRING="\"ftpd v$(VERSION)\"" \
|
||||
-DNO_IPV6 -DCLASSIC -DNO_CONSOLE -DFTPDCONFIG="\"/config/ftpd/ftpd.cfg\""
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lwutd -lmocha
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
# containing include and lib
|
||||
#-------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#-------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#-------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#-------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#-------------------------------------------------------------------------------
|
||||
else
|
||||
#-------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#-------------------------------------------------------------------------------
|
||||
endif
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
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
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.wiiu
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).wuhb $(TARGET).rpx $(TARGET).elf
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#-------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).wuhb
|
||||
|
||||
$(OUTPUT).wuhb : $(OUTPUT).rpx
|
||||
$(OUTPUT).rpx : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#-------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#-------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
endif
|
||||
#-------------------------------------------------------------------------------
|
@ -60,7 +60,13 @@ private:
|
||||
/// \brief Command buffer size
|
||||
constexpr static auto COMMAND_BUFFERSIZE = 4096;
|
||||
|
||||
#ifdef NDS
|
||||
#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)
|
||||
/// \brief Response buffer size
|
||||
constexpr static auto RESPONSE_BUFFERSIZE = 4096;
|
||||
|
||||
@ -238,7 +244,7 @@ private:
|
||||
SockAddr m_portAddr;
|
||||
|
||||
/// \brief Current working directory
|
||||
std::string m_cwd = "/";
|
||||
std::string m_cwd = "/fs/vol/external01/";
|
||||
|
||||
/// \brief List working directory
|
||||
std::string m_lwd;
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include <3ds.h>
|
||||
#elif defined(__SWITCH__)
|
||||
#include <switch.h>
|
||||
#elif defined(__WIIU__)
|
||||
#include <wut.h>
|
||||
#include <coreinit/debug.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
@ -35,7 +38,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef CLASSIC
|
||||
#if defined(CLASSIC) && !defined(__WIIU__)
|
||||
extern PrintConsole g_statusConsole;
|
||||
extern PrintConsole g_logConsole;
|
||||
extern PrintConsole g_sessionConsole;
|
||||
|
@ -102,6 +102,8 @@ public:
|
||||
/// \param nonBlocking_ Whether to set non-blocking
|
||||
bool setNonBlocking (bool nonBlocking_ = true);
|
||||
|
||||
bool setWinScale (const int val);
|
||||
|
||||
/// \brief Set reuse address in subsequent bind
|
||||
/// \param reuse_ Whether to reuse address
|
||||
bool setReuseAddress (bool reuse_ = true);
|
||||
|
197
source/IOAbstraction.cpp
Normal file
197
source/IOAbstraction.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
#include "IOAbstraction.h"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sys/dirent.h>
|
||||
#include <vector>
|
||||
|
||||
class VirtualDirectory
|
||||
{
|
||||
public:
|
||||
VirtualDirectory (const std::vector<std::string> &directories)
|
||||
{
|
||||
mDirectories.push_back (".");
|
||||
mDirectories.push_back ("..");
|
||||
mDirectories.insert (mDirectories.end (), directories.begin (), directories.end ());
|
||||
|
||||
mCurIterator = mDirectories.begin ();
|
||||
}
|
||||
|
||||
[[nodiscard]] DIR *getAsDir () const
|
||||
{
|
||||
return (DIR *)this;
|
||||
}
|
||||
|
||||
struct dirent *readdir ()
|
||||
{
|
||||
if (mCurIterator == mDirectories.end ())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
mDir = {};
|
||||
snprintf (mDir.d_name, sizeof (mDir.d_name), "%s", mCurIterator->c_str ());
|
||||
mCurIterator++;
|
||||
return &mDir;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> mDirectories;
|
||||
struct dirent mDir = {};
|
||||
std::vector<std::string>::iterator mCurIterator{};
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<VirtualDirectory>> sOpenVirtualDirectories;
|
||||
std::mutex sOpenVirtualDirectoriesMutex;
|
||||
std::map<std::string, std::vector<std::string>> sVirtualDirs;
|
||||
|
||||
template <typename Container, typename Predicate>
|
||||
typename std::enable_if<std::is_same<Container, std::vector<typename Container::value_type>>::value,
|
||||
bool>::type
|
||||
remove_first_if (Container &container, Predicate pred)
|
||||
{
|
||||
auto it = container.begin ();
|
||||
while (it != container.end ())
|
||||
{
|
||||
if (pred (*it))
|
||||
{
|
||||
container.erase (it);
|
||||
return true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Container, typename Predicate>
|
||||
bool remove_locked_first_if (std::mutex &mutex, Container &container, Predicate pred)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
return remove_first_if (container, pred);
|
||||
}
|
||||
|
||||
static DIR *getVirtualDir (const std::vector<std::string> &subDirectories)
|
||||
{
|
||||
auto virtDir = std::make_unique<VirtualDirectory> (subDirectories);
|
||||
auto *result = virtDir->getAsDir ();
|
||||
std::lock_guard lock (sOpenVirtualDirectoriesMutex);
|
||||
sOpenVirtualDirectories.push_back (std::move (virtDir));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string IOAbstraction::convertPath (std::string_view inPath)
|
||||
{
|
||||
#ifdef __WIIU__
|
||||
if (!inPath.starts_with ('/') || inPath.find (':') != std::string::npos)
|
||||
{
|
||||
return std::string (inPath);
|
||||
}
|
||||
std::string path = std::string (inPath);
|
||||
size_t secondSlashPos = path.find ('/', 1);
|
||||
if (secondSlashPos != std::string::npos)
|
||||
{
|
||||
// Extract the substring between the first and second slashes
|
||||
std::string prefix = path.substr (1, secondSlashPos - 1);
|
||||
std::string suffix = path.substr (secondSlashPos);
|
||||
|
||||
// Concatenate the modified prefix and suffix
|
||||
path = prefix + ":" + suffix;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = std::string (inPath.substr (1)) + ":/";
|
||||
}
|
||||
return path;
|
||||
#else
|
||||
return std::string (inPath);
|
||||
#endif
|
||||
}
|
||||
|
||||
int IOAbstraction::closedir (DIR *dirp)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (sOpenVirtualDirectoriesMutex);
|
||||
if (remove_locked_first_if (sOpenVirtualDirectoriesMutex,
|
||||
sOpenVirtualDirectories,
|
||||
[dirp] (auto &cur) { return cur->getAsDir () == dirp; }))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ::closedir (dirp);
|
||||
}
|
||||
|
||||
DIR *IOAbstraction::opendir (const char *dirname)
|
||||
{
|
||||
auto convertedPath = convertPath (dirname);
|
||||
if (sVirtualDirs.count (convertedPath) > 0)
|
||||
{
|
||||
return getVirtualDir (sVirtualDirs[convertedPath]);
|
||||
}
|
||||
|
||||
return ::opendir (convertedPath.c_str ());
|
||||
}
|
||||
|
||||
FILE *IOAbstraction::fopen (const char *_name, const char *_type)
|
||||
{
|
||||
return std::fopen (convertPath (_name).c_str (), _type);
|
||||
}
|
||||
|
||||
int IOAbstraction::fseek (FILE *f, long pos, int origin)
|
||||
{
|
||||
return std::fseek (f, pos, origin);
|
||||
}
|
||||
|
||||
size_t IOAbstraction::fread (void *buffer, size_t _size, size_t _n, FILE *f)
|
||||
{
|
||||
return std::fread (buffer, _size, _n, f);
|
||||
}
|
||||
|
||||
size_t IOAbstraction::fwrite (const void *buffer, size_t _size, size_t _n, FILE *f)
|
||||
{
|
||||
return std::fwrite (buffer, _size, _n, f);
|
||||
}
|
||||
|
||||
struct dirent *IOAbstraction::readdir (DIR *dirp)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock (sOpenVirtualDirectoriesMutex);
|
||||
auto itr = std::find_if (sOpenVirtualDirectories.begin (),
|
||||
sOpenVirtualDirectories.end (),
|
||||
[dirp] (auto &cur) { return cur->getAsDir () == dirp; });
|
||||
if (itr != sOpenVirtualDirectories.end ())
|
||||
{
|
||||
return (*itr)->readdir ();
|
||||
}
|
||||
}
|
||||
|
||||
return ::readdir (dirp);
|
||||
}
|
||||
|
||||
int IOAbstraction::stat (const char *path, struct stat *sbuf)
|
||||
{
|
||||
auto convertedPath = convertPath (path);
|
||||
auto r = ::stat (convertedPath.c_str (), sbuf);
|
||||
if (r < 0)
|
||||
{
|
||||
if (sVirtualDirs.contains (convertedPath))
|
||||
{
|
||||
*sbuf = {};
|
||||
// TODO: init other values?
|
||||
sbuf->st_mode = _IFDIR;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int IOAbstraction::lstat (const char *path, struct stat *buf)
|
||||
{
|
||||
return IOAbstraction::stat (path, buf);
|
||||
}
|
||||
|
||||
void IOAbstraction::addVirtualPath (const std::string &virtualPath,
|
||||
const std::vector<std::string> &subDirectories)
|
||||
{
|
||||
sVirtualDirs.insert (std::make_pair (virtualPath, subDirectories));
|
||||
}
|
34
source/IOAbstraction.h
Normal file
34
source/IOAbstraction.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <sys/dirent.h>
|
||||
#include <vector>
|
||||
|
||||
class IOAbstraction
|
||||
{
|
||||
public:
|
||||
static std::string convertPath (std::string_view inPath);
|
||||
|
||||
static FILE *fopen (const char *_name, const char *_type);
|
||||
|
||||
static int fseek (FILE *f, long pos, int origin);
|
||||
|
||||
static size_t fread (void *buffer, size_t _size, size_t _n, FILE *f);
|
||||
|
||||
static size_t fwrite (const void *buffer, size_t _size, size_t _n, FILE *f);
|
||||
|
||||
static int closedir (DIR *dirp);
|
||||
|
||||
|
||||
static DIR *opendir (const char *dirname);
|
||||
|
||||
static struct dirent *readdir (DIR *dirp);
|
||||
|
||||
static int stat (const char *path, struct stat *sbuf);
|
||||
|
||||
static int lstat (const char *path, struct stat *buf);
|
||||
|
||||
static void addVirtualPath (const std::string &virtualPath,
|
||||
const std::vector<std::string> &subDirectories);
|
||||
};
|
@ -19,13 +19,14 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "fs.h"
|
||||
#include "IOAbstraction.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#if defined(NDS) || defined(__3DS__) || defined(__SWITCH__)
|
||||
#if defined(NDS) || defined(__3DS__) || defined(__SWITCH__) || defined(__WIIU__)
|
||||
#define getline __getline
|
||||
#endif
|
||||
|
||||
@ -118,7 +119,7 @@ void fs::File::setBufferSize (std::size_t const size_)
|
||||
|
||||
bool fs::File::open (char const *const path_, char const *const mode_)
|
||||
{
|
||||
auto const fp = std::fopen (path_, mode_);
|
||||
auto const fp = IOAbstraction::fopen (path_, mode_);
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
@ -137,7 +138,7 @@ void fs::File::close ()
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::seek (std::size_t const pos_, int const origin_)
|
||||
{
|
||||
return std::fseek (m_fp.get (), pos_, origin_);
|
||||
return IOAbstraction::fseek (m_fp.get (), pos_, origin_);
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::read (void *const buffer_, std::size_t const size_)
|
||||
@ -145,7 +146,7 @@ std::make_signed_t<std::size_t> fs::File::read (void *const buffer_, std::size_t
|
||||
assert (buffer_);
|
||||
assert (size_ > 0);
|
||||
|
||||
return std::fread (buffer_, 1, size_, m_fp.get ());
|
||||
return IOAbstraction::fread (buffer_, 1, size_, m_fp.get ());
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::read (IOBuffer &buffer_)
|
||||
@ -206,7 +207,7 @@ std::make_signed_t<std::size_t> fs::File::write (void const *const buffer_, std:
|
||||
assert (buffer_);
|
||||
assert (size_ > 0);
|
||||
|
||||
return std::fwrite (buffer_, 1, size_, m_fp.get ());
|
||||
return IOAbstraction::fwrite (buffer_, 1, size_, m_fp.get ());
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::write (IOBuffer &buffer_)
|
||||
@ -262,11 +263,11 @@ fs::Dir::operator DIR * () const
|
||||
|
||||
bool fs::Dir::open (char const *const path_)
|
||||
{
|
||||
auto const dp = ::opendir (path_);
|
||||
auto const dp = IOAbstraction::opendir (path_);
|
||||
if (!dp)
|
||||
return false;
|
||||
|
||||
m_dp = std::unique_ptr<DIR, int (*) (DIR *)> (dp, &::closedir);
|
||||
m_dp = std::unique_ptr<DIR, int (*) (DIR *)> (dp, &IOAbstraction::closedir);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -278,5 +279,5 @@ void fs::Dir::close ()
|
||||
struct dirent *fs::Dir::read ()
|
||||
{
|
||||
errno = 0;
|
||||
return ::readdir (m_dp.get ());
|
||||
return IOAbstraction::readdir (m_dp.get ());
|
||||
}
|
||||
|
@ -202,11 +202,13 @@ void FtpServer::draw ()
|
||||
if (m_socket)
|
||||
std::sprintf (port, ":%u", m_socket->sockName ().port ());
|
||||
|
||||
#ifndef NO_CONSOLE
|
||||
consoleSelect (&g_statusConsole);
|
||||
std::printf ("\x1b[0;0H\x1b[32;1m%s \x1b[36;1m%s%s",
|
||||
STATUS_STRING,
|
||||
m_socket ? m_socket->sockName ().name () : "Waiting on WiFi",
|
||||
m_socket ? port : "");
|
||||
#endif
|
||||
|
||||
#ifndef NDS
|
||||
char timeBuffer[16];
|
||||
@ -226,11 +228,14 @@ void FtpServer::draw ()
|
||||
#endif
|
||||
if (!s_freeSpace.empty ())
|
||||
{
|
||||
#ifndef NO_CONSOLE
|
||||
consoleSelect (&g_statusConsole);
|
||||
std::printf ("\x1b[0;%uH\x1b[32;1m%s",
|
||||
static_cast<unsigned> (g_statusConsole.windowWidth - s_freeSpace.size () + 1),
|
||||
s_freeSpace.c_str ());
|
||||
std::fflush (stdout);
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,6 +243,7 @@ void FtpServer::draw ()
|
||||
#ifndef NDS
|
||||
auto const lock = std::scoped_lock (m_lock);
|
||||
#endif
|
||||
#ifndef NO_CONSOLE
|
||||
consoleSelect (&g_sessionConsole);
|
||||
std::fputs ("\x1b[2J", stdout);
|
||||
for (auto &session : m_sessions)
|
||||
@ -247,6 +253,7 @@ void FtpServer::draw ()
|
||||
std::fputc ('\n', stdout);
|
||||
}
|
||||
std::fflush (stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
drawLog ();
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "ftpSession.h"
|
||||
|
||||
#include "IOAbstraction.h"
|
||||
#include "ftpServer.h"
|
||||
#include "log.h"
|
||||
#include "platform.h"
|
||||
@ -169,7 +170,7 @@ std::string resolvePath (std::string_view const path_)
|
||||
|
||||
// make sure parent is a directory
|
||||
struct stat st;
|
||||
if (::stat (dirName (path_).c_str (), &st) != 0)
|
||||
if (IOAbstraction::stat (dirName (path_).c_str (), &st) != 0)
|
||||
return {};
|
||||
|
||||
if (!S_ISDIR (st.st_mode))
|
||||
@ -640,7 +641,9 @@ void FtpSession::closeSocket (SharedSocket &socket_)
|
||||
if (socket_ && socket_.unique ())
|
||||
{
|
||||
socket_->shutdown (SHUT_WR);
|
||||
#ifndef __WIIU__
|
||||
socket_->setLinger (true, 0s);
|
||||
#endif
|
||||
LOCKED (m_pendingCloseSocket.emplace_back (std::move (socket_)));
|
||||
}
|
||||
else
|
||||
@ -685,7 +688,7 @@ bool FtpSession::changeDir (char const *const args_)
|
||||
return false;
|
||||
|
||||
struct stat st;
|
||||
if (::stat (path.c_str (), &st) != 0)
|
||||
if (IOAbstraction::stat (path.c_str (), &st) != 0)
|
||||
return false;
|
||||
|
||||
if (!S_ISDIR (st.st_mode))
|
||||
@ -719,6 +722,9 @@ bool FtpSession::dataAccept ()
|
||||
}
|
||||
|
||||
#ifndef __3DS__
|
||||
#ifdef __WIIU__
|
||||
m_dataSocket->setWinScale (1);
|
||||
#endif
|
||||
m_dataSocket->setRecvBufferSize (SOCK_BUFFERSIZE);
|
||||
m_dataSocket->setSendBufferSize (SOCK_BUFFERSIZE);
|
||||
#endif
|
||||
@ -747,6 +753,9 @@ bool FtpSession::dataConnect ()
|
||||
if (!m_dataSocket)
|
||||
return false;
|
||||
|
||||
#ifdef __WIIU__
|
||||
m_dataSocket->setWinScale (1);
|
||||
#endif
|
||||
m_dataSocket->setRecvBufferSize (SOCK_BUFFERSIZE);
|
||||
m_dataSocket->setSendBufferSize (SOCK_BUFFERSIZE);
|
||||
|
||||
@ -793,7 +802,7 @@ int FtpSession::fillDirent (struct stat const &st_, std::string_view const path_
|
||||
type_ = "file";
|
||||
else if (S_ISDIR (st_.st_mode))
|
||||
type_ = "dir";
|
||||
#if !defined(__3DS__) && !defined(__SWITCH__)
|
||||
#if !defined(__3DS__) && !defined(__SWITCH__) && !defined(__WIIU__)
|
||||
else if (S_ISLNK (st_.st_mode))
|
||||
type_ = "os.unix=symlink";
|
||||
else if (S_ISCHR (st_.st_mode))
|
||||
@ -989,7 +998,7 @@ int FtpSession::fillDirent (struct stat const &st_, std::string_view const path_
|
||||
// clang-format off
|
||||
S_ISREG (st_.st_mode) ? '-' :
|
||||
S_ISDIR (st_.st_mode) ? 'd' :
|
||||
#if !defined(__3DS__) && !defined(__SWITCH__)
|
||||
#if !defined(__3DS__) && !defined(__SWITCH__) && !defined(__WIIU__)
|
||||
S_ISLNK (st_.st_mode) ? 'l' :
|
||||
S_ISCHR (st_.st_mode) ? 'c' :
|
||||
S_ISBLK (st_.st_mode) ? 'b' :
|
||||
@ -1054,7 +1063,7 @@ int FtpSession::fillDirent (struct stat const &st_, std::string_view const path_
|
||||
int FtpSession::fillDirent (std::string const &path_, char const *type_)
|
||||
{
|
||||
struct stat st;
|
||||
if (::stat (path_.c_str (), &st) != 0)
|
||||
if (IOAbstraction::stat (path_.c_str (), &st) != 0)
|
||||
return errno;
|
||||
|
||||
return fillDirent (st, encodePath (path_), type_);
|
||||
@ -1081,7 +1090,7 @@ void FtpSession::xferFile (char const *const args_, XferFileMode const mode_)
|
||||
{
|
||||
// stat the file
|
||||
struct stat st;
|
||||
if (::stat (path.c_str (), &st) != 0)
|
||||
if (IOAbstraction::stat (path.c_str (), &st) != 0)
|
||||
{
|
||||
sendResponse ("450 %s\r\n", std::strerror (errno));
|
||||
return;
|
||||
@ -1219,7 +1228,7 @@ void FtpSession::xferDir (char const *const args_, XferDirMode const mode_, bool
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (::stat (path.c_str (), &st) != 0)
|
||||
if (IOAbstraction::stat (path.c_str (), &st) != 0)
|
||||
{
|
||||
sendResponse ("550 %s\r\n", std::strerror (errno));
|
||||
setState (State::COMMAND, true, true);
|
||||
@ -1719,7 +1728,7 @@ bool FtpSession::listTransfer ()
|
||||
else
|
||||
#endif
|
||||
// lstat the entry
|
||||
if (::lstat (fullPath.c_str (), &st) != 0)
|
||||
if (IOAbstraction::lstat (fullPath.c_str (), &st) != 0)
|
||||
{
|
||||
#ifndef __SWITCH__
|
||||
sendResponse ("550 %s\r\n", std::strerror (errno));
|
||||
@ -2255,7 +2264,10 @@ void FtpSession::PASV (char const *args_)
|
||||
return;
|
||||
}
|
||||
|
||||
// set the socket options
|
||||
// set the socket option
|
||||
#ifdef __WIIU__
|
||||
m_pasvSocket->setWinScale (1);
|
||||
#endif
|
||||
m_pasvSocket->setRecvBufferSize (SOCK_BUFFERSIZE);
|
||||
m_pasvSocket->setSendBufferSize (SOCK_BUFFERSIZE);
|
||||
|
||||
@ -2516,7 +2528,7 @@ void FtpSession::RNFR (char const *args_)
|
||||
|
||||
// make sure the path exists
|
||||
struct stat st;
|
||||
if (::lstat (path.c_str (), &st) != 0)
|
||||
if (IOAbstraction::lstat (path.c_str (), &st) != 0)
|
||||
{
|
||||
sendResponse ("450 %s\r\n", std::strerror (errno));
|
||||
return;
|
||||
@ -2711,7 +2723,7 @@ void FtpSession::SIZE (char const *args_)
|
||||
|
||||
// stat the path
|
||||
struct stat st;
|
||||
if (::stat (path.c_str (), &st) != 0)
|
||||
if (IOAbstraction::stat (path.c_str (), &st) != 0)
|
||||
{
|
||||
sendResponse ("550 %s\r\n", std::strerror (errno));
|
||||
return;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <zstd.h>
|
||||
#endif
|
||||
|
||||
#if !defined(NDS) && !defined(__3DS__) && !defined(__SWITCH__)
|
||||
#if !defined(NDS) && !defined(__3DS__) && !defined(__SWITCH__) && !defined(__WIIU__)
|
||||
#include <GLFW/glfw3.h>
|
||||
#endif
|
||||
|
||||
|
@ -28,6 +28,10 @@
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __WIIU__
|
||||
#include <coreinit/debug.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef __3DS__
|
||||
@ -91,7 +95,9 @@ void drawLog ()
|
||||
#endif
|
||||
|
||||
auto const maxLogs =
|
||||
#ifdef CLASSIC
|
||||
#ifdef __WIIU__
|
||||
1000;
|
||||
#elif defined(CLASSIC)
|
||||
g_logConsole.windowHeight;
|
||||
#else
|
||||
MAX_LOGS;
|
||||
@ -113,6 +119,12 @@ void drawLog ()
|
||||
[RESPONSE] = "\x1b[36;1m", // cyan
|
||||
};
|
||||
|
||||
#ifdef __WIIU__
|
||||
for (auto &cur : s_messages)
|
||||
{
|
||||
OSReport ("%s %s\x1b[0m", s_colors[cur.level], cur.message.c_str ());
|
||||
}
|
||||
#else
|
||||
auto it = std::begin (s_messages);
|
||||
if (s_messages.size () > static_cast<unsigned> (g_logConsole.windowHeight))
|
||||
it = std::next (it, s_messages.size () - g_logConsole.windowHeight);
|
||||
@ -125,6 +137,7 @@ void drawLog ()
|
||||
++it;
|
||||
}
|
||||
std::fflush (stdout);
|
||||
#endif
|
||||
s_messages.clear ();
|
||||
#else
|
||||
ImVec4 const s_colors[] = {
|
||||
@ -236,17 +249,20 @@ void addLog (LogLevel const level_, char const *const fmt_, va_list ap_)
|
||||
if (level_ == DEBUG)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifndef NDS
|
||||
thread_local
|
||||
#endif
|
||||
static char buffer[1024];
|
||||
|
||||
std::vsnprintf (buffer, sizeof (buffer), fmt_, ap_);
|
||||
|
||||
#ifndef NDS
|
||||
auto const lock = std::scoped_lock (s_lock);
|
||||
#endif
|
||||
|
||||
#if !defined(NDS) && !defined(__WIIU__)
|
||||
thread_local
|
||||
#endif
|
||||
#if !defined(__WIIU__)
|
||||
static
|
||||
#endif
|
||||
char buffer[1024];
|
||||
|
||||
std::vsnprintf (buffer, sizeof (buffer), fmt_, ap_);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// std::fprintf (stderr, "%s", s_prefix[level_]);
|
||||
// std::fputs (buffer, stderr);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "platform.h"
|
||||
|
||||
#include "ftpServer.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
@ -58,9 +59,12 @@ int main (int argc_, char *argv_[])
|
||||
|
||||
while (platform::loop ())
|
||||
{
|
||||
#ifndef NO_CONSOLE
|
||||
server->draw ();
|
||||
|
||||
platform::render ();
|
||||
#else
|
||||
drawLog();
|
||||
#endif
|
||||
}
|
||||
|
||||
// clean up resources before exiting switch/3ds services
|
||||
|
@ -65,7 +65,7 @@ SockAddr::SockAddr (struct sockaddr_in const &addr_)
|
||||
assert (m_addr.ss_family == AF_INET);
|
||||
}
|
||||
|
||||
#ifndef __3DS__
|
||||
#if !defined(__3DS__) && !defined(__WIIU__)
|
||||
SockAddr::SockAddr (struct sockaddr_in6 const &addr_)
|
||||
: SockAddr (reinterpret_cast<struct sockaddr const &> (addr_))
|
||||
{
|
||||
@ -84,7 +84,7 @@ SockAddr::operator struct sockaddr_in const & () const
|
||||
return reinterpret_cast<struct sockaddr_in const &> (m_addr);
|
||||
}
|
||||
|
||||
#ifndef __3DS__
|
||||
#if !defined(__3DS__) && !defined(__WIIU__)
|
||||
SockAddr::operator struct sockaddr_in6 const & () const
|
||||
{
|
||||
assert (m_addr.ss_family == AF_INET6);
|
||||
@ -175,7 +175,7 @@ char const *SockAddr::name (char *buffer_, std::size_t size_) const
|
||||
|
||||
char const *SockAddr::name () const
|
||||
{
|
||||
#ifdef NDS
|
||||
#if defined(NDS) || defined(__WIIU__)
|
||||
return inet_ntoa (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr);
|
||||
#else
|
||||
#ifdef NO_IPV6
|
||||
|
@ -236,6 +236,19 @@ bool Socket::setNonBlocking (bool const nonBlocking_)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Socket::setWinScale (const int val)
|
||||
{
|
||||
int const o = val;
|
||||
|
||||
if (::setsockopt (m_fd, SOL_SOCKET, SO_WINSCALE, &o, sizeof (o)) < 0)
|
||||
{
|
||||
error ("setsockopt(SO_WINSCALE, %d): %s\n", val, std::strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Socket::setReuseAddress (bool const reuse_)
|
||||
{
|
||||
int const reuse = reuse_;
|
||||
|
251
source/wiiu/platform.cpp
Normal file
251
source/wiiu/platform.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
// ftpd is a server implementation based on the following:
|
||||
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "../IOAbstraction.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <mocha/mocha.h>
|
||||
#include <nn/ac.h>
|
||||
#include <thread>
|
||||
|
||||
#include <coreinit/thread.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <whb/proc.h>
|
||||
|
||||
#ifndef CLASSIC
|
||||
#error "Wii U must be built in classic mode"
|
||||
#endif
|
||||
|
||||
bool platform::networkVisible ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool platform::networkAddress (SockAddr &addr_)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
nn::ac::GetAssignedAddress (&addr.sin_addr.s_addr);
|
||||
addr_ = addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
MochaUtilsStatus MountWrapper (const char *mount, const char *dev, const char *mountTo)
|
||||
{
|
||||
auto res = Mocha_MountFS (mount, dev, mountTo);
|
||||
if (res == MOCHA_RESULT_ALREADY_EXISTS)
|
||||
{
|
||||
res = Mocha_MountFS (mount, nullptr, mountTo);
|
||||
}
|
||||
if (res == MOCHA_RESULT_SUCCESS)
|
||||
{
|
||||
std::string mountPath = std::string (mount) + ":/";
|
||||
debug ("Mounted %s", mountPath.c_str ());
|
||||
}
|
||||
else
|
||||
{
|
||||
error ("Failed to mount %s: %s [%d]", mount, Mocha_GetStatusStr (res), res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool platform::init ()
|
||||
{
|
||||
nn::ac::Initialize ();
|
||||
nn::ac::ConnectAsync ();
|
||||
WHBProcInit ();
|
||||
|
||||
MochaUtilsStatus res;
|
||||
if ((res = Mocha_InitLibrary ()) == MOCHA_RESULT_SUCCESS)
|
||||
{
|
||||
std::vector<std::string> virtualDirsInRoot;
|
||||
if (MountWrapper ("slccmpt01", "/dev/slccmpt01", "/vol/storage_slccmpt01") ==
|
||||
MOCHA_RESULT_SUCCESS)
|
||||
{
|
||||
virtualDirsInRoot.push_back ("slccmpt01");
|
||||
}
|
||||
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");
|
||||
IOAbstraction::addVirtualPath (":/", virtualDirsInRoot);
|
||||
IOAbstraction::addVirtualPath ("fs:/", std::vector<std::string>{"vol"});
|
||||
IOAbstraction::addVirtualPath ("fs:/vol", std::vector<std::string>{"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:/", {});
|
||||
}
|
||||
else
|
||||
{
|
||||
error ("Failed to init libmocha: %s [%d]", Mocha_GetStatusStr (res), res);
|
||||
}
|
||||
|
||||
::chdir ("fs:/vol/external01");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool platform::loop ()
|
||||
{
|
||||
return WHBProcIsRunning ();
|
||||
}
|
||||
|
||||
void platform::render ()
|
||||
{
|
||||
}
|
||||
|
||||
void platform::exit ()
|
||||
{
|
||||
WHBProcShutdown ();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// \brief Platform thread pimpl
|
||||
class platform::Thread::privateData_t
|
||||
{
|
||||
public:
|
||||
privateData_t () = default;
|
||||
|
||||
/// \brief Parameterized constructor
|
||||
/// \param func_ Thread entry point
|
||||
explicit privateData_t (std::function<void ()> &&func_) : thread (std::move (func_))
|
||||
{
|
||||
auto nativeHandle = (OSThread *)thread.native_handle ();
|
||||
OSSetThreadName (nativeHandle, "ftpd_server");
|
||||
while (!OSSetThreadAffinity (nativeHandle, OS_THREAD_ATTRIB_AFFINITY_CPU2))
|
||||
{
|
||||
OSSleepTicks (OSMillisecondsToTicks (16));
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Underlying thread
|
||||
std::thread thread;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
platform::Thread::~Thread () = default;
|
||||
|
||||
platform::Thread::Thread () : m_d (new privateData_t ())
|
||||
{
|
||||
}
|
||||
|
||||
platform::Thread::Thread (std::function<void ()> &&func_)
|
||||
: m_d (new privateData_t (std::move (func_)))
|
||||
{
|
||||
}
|
||||
|
||||
platform::Thread::Thread (Thread &&that_) : m_d (new privateData_t ())
|
||||
{
|
||||
std::swap (m_d, that_.m_d);
|
||||
}
|
||||
|
||||
platform::Thread &platform::Thread::operator= (Thread &&that_)
|
||||
{
|
||||
std::swap (m_d, that_.m_d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void platform::Thread::join ()
|
||||
{
|
||||
m_d->thread.join ();
|
||||
}
|
||||
|
||||
void platform::Thread::sleep (std::chrono::milliseconds const timeout_)
|
||||
{
|
||||
std::this_thread::sleep_for (timeout_);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#define USE_STD_MUTEX 1
|
||||
|
||||
/// \brief Platform mutex pimpl
|
||||
class platform::Mutex::privateData_t
|
||||
{
|
||||
public:
|
||||
#if USE_STD_MUTEX
|
||||
/// \brief Underlying mutex
|
||||
std::mutex mutex;
|
||||
#else
|
||||
/// \brief Underlying mutex
|
||||
::Mutex mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
platform::Mutex::~Mutex () = default;
|
||||
|
||||
platform::Mutex::Mutex () : m_d (new privateData_t ())
|
||||
{
|
||||
#if !USE_STD_MUTEX
|
||||
mutexInit (&m_d->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void platform::Mutex::lock ()
|
||||
{
|
||||
#if USE_STD_MUTEX
|
||||
m_d->mutex.lock ();
|
||||
#else
|
||||
mutexLock (&m_d->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void platform::Mutex::unlock ()
|
||||
{
|
||||
#if USE_STD_MUTEX
|
||||
m_d->mutex.unlock ();
|
||||
#else
|
||||
mutexUnlock (&m_d->mutex);
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue
Block a user