mirror of
https://github.com/mtheall/ftpd.git
synced 2025-06-18 11:05:52 -04:00
Fix static analysis reports
This commit is contained in:
parent
9a73b92497
commit
41e467f47b
@ -2,6 +2,18 @@ cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(ftpd VERSION 3.2.0)
|
||||
|
||||
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||
list(APPEND CMAKE_C_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
list(APPEND CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
endif()
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(gsl
|
||||
GIT_REPOSITORY https://github.com/microsoft/GSL.git
|
||||
GIT_TAG v4.0.0
|
||||
)
|
||||
FetchContent_Populate(gsl)
|
||||
|
||||
option(FTPD_CLASSIC "Build ${PROJECT_NAME} classic" OFF)
|
||||
|
||||
if(FTPD_CLASSIC AND (NINTENDO_SWITCH OR NINTENDO_3DS))
|
||||
@ -12,6 +24,8 @@ endif()
|
||||
|
||||
add_executable(${FTPD_TARGET})
|
||||
|
||||
target_include_directories(${FTPD_TARGET} PRIVATE ${gsl_SOURCE_DIR}/include)
|
||||
|
||||
if(NINTENDO_SWITCH OR NINTENDO_3DS OR NINTENDO_DS)
|
||||
dkp_target_generate_symbol_list(${FTPD_TARGET})
|
||||
endif()
|
||||
|
28
include/fs.h
28
include/fs.h
@ -3,7 +3,7 @@
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
// Copyright (C) 2024 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
|
||||
@ -22,6 +22,8 @@
|
||||
|
||||
#include "ioBuffer.h"
|
||||
|
||||
#include <gsl/gsl>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <cstdint>
|
||||
@ -29,6 +31,7 @@
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
@ -69,7 +72,7 @@ public:
|
||||
/// \brief Open file
|
||||
/// \param path_ Path to open
|
||||
/// \param mode_ Access mode (\sa std::fopen)
|
||||
bool open (char const *path_, char const *mode_ = "rb");
|
||||
bool open (gsl::not_null<gsl::czstring> path_, gsl::not_null<gsl::czstring> mode_ = "rb");
|
||||
|
||||
/// \brief Close file
|
||||
void close ();
|
||||
@ -77,13 +80,13 @@ public:
|
||||
/// \brief Seek to file position
|
||||
/// \param pos_ File position
|
||||
/// \param origin_ Reference position (\sa std::fseek)
|
||||
std::make_signed_t<std::size_t> seek (std::size_t pos_, int origin_);
|
||||
std::make_signed_t<std::size_t> seek (std::make_signed_t<std::size_t> pos_, int origin_);
|
||||
|
||||
/// \brief Read data
|
||||
/// \param buffer_ Output buffer
|
||||
/// \param size_ Size to read
|
||||
/// \note Can return partial reads
|
||||
std::make_signed_t<std::size_t> read (void *buffer_, std::size_t size_);
|
||||
std::make_signed_t<std::size_t> read (gsl::not_null<void *> buffer_, std::size_t size_);
|
||||
|
||||
/// \brief Read data
|
||||
/// \param buffer_ Output buffer
|
||||
@ -97,13 +100,13 @@ public:
|
||||
/// \param buffer_ Output buffer
|
||||
/// \param size_ Size to read
|
||||
/// \note Fails on partial reads and errors
|
||||
bool readAll (void *buffer_, std::size_t size_);
|
||||
bool readAll (gsl::not_null<void *> buffer_, std::size_t size_);
|
||||
|
||||
/// \brief Write data
|
||||
/// \param buffer_ Input data
|
||||
/// \param size_ Size to write
|
||||
/// \note Can return partial writes
|
||||
std::make_signed_t<std::size_t> write (void const *buffer_, std::size_t size_);
|
||||
std::make_signed_t<std::size_t> write (gsl::not_null<void const *> buffer_, std::size_t size_);
|
||||
|
||||
/// \brief Write data
|
||||
/// \param buffer_ Input data
|
||||
@ -114,20 +117,17 @@ public:
|
||||
/// \param buffer_ Input data
|
||||
/// \param size_ Size to write
|
||||
/// \note Fails on partials writes and errors
|
||||
bool writeAll (void const *buffer_, std::size_t size_);
|
||||
bool writeAll (gsl::not_null<void const *> buffer_, std::size_t size_);
|
||||
|
||||
private:
|
||||
/// \brief Underlying std::FILE*
|
||||
std::unique_ptr<std::FILE, int (*) (std::FILE *)> m_fp{nullptr, nullptr};
|
||||
|
||||
/// \brief Buffer
|
||||
std::unique_ptr<char[]> m_buffer;
|
||||
|
||||
/// \brief Buffer size
|
||||
std::size_t m_bufferSize = 0;
|
||||
std::vector<char> m_buffer;
|
||||
|
||||
/// \brief Line buffer
|
||||
char *m_lineBuffer = nullptr;
|
||||
gsl::owner<char *> m_lineBuffer = nullptr;
|
||||
|
||||
/// \brief Line buffer size
|
||||
std::size_t m_lineBufferSize = 0;
|
||||
@ -161,14 +161,14 @@ public:
|
||||
|
||||
/// \brief Open directory
|
||||
/// \param path_ Path to open
|
||||
bool open (char const *const path_);
|
||||
bool open (gsl::not_null<gsl::czstring> path_);
|
||||
|
||||
/// \brief Close directory
|
||||
void close ();
|
||||
|
||||
/// \brief Read a directory entry
|
||||
/// \note Returns nullptr on end-of-directory or error; check errno
|
||||
struct dirent *read ();
|
||||
dirent *read ();
|
||||
|
||||
private:
|
||||
/// \brief Underlying DIR*
|
||||
|
@ -3,7 +3,7 @@
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2023 Michael Theall
|
||||
// Copyright (C) 2024 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
|
||||
@ -22,10 +22,13 @@
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include <gsl/gsl>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
class FtpConfig;
|
||||
using UniqueFtpConfig = std::unique_ptr<FtpConfig>;
|
||||
@ -41,7 +44,7 @@ public:
|
||||
|
||||
/// \brief Load config
|
||||
/// \param path_ Path to config file
|
||||
static UniqueFtpConfig load (char const *path_);
|
||||
static UniqueFtpConfig load (gsl::not_null<gsl::czstring> path_);
|
||||
|
||||
#ifndef __NDS__
|
||||
std::scoped_lock<platform::Mutex> lockGuard ();
|
||||
@ -49,7 +52,7 @@ public:
|
||||
|
||||
/// \brief Save config
|
||||
/// \param path_ Path to config file
|
||||
bool save (char const *path_);
|
||||
bool save (gsl::not_null<gsl::czstring> path_);
|
||||
|
||||
/// \brief Get user
|
||||
std::string const &user () const;
|
||||
@ -79,15 +82,15 @@ public:
|
||||
|
||||
/// \brief Set user
|
||||
/// \param user_ User
|
||||
void setUser (std::string const &user_);
|
||||
void setUser (std::string user_);
|
||||
|
||||
/// \brief Set password
|
||||
/// \param pass_ Password
|
||||
void setPass (std::string const &pass_);
|
||||
void setPass (std::string pass_);
|
||||
|
||||
/// \brief Set listen port
|
||||
/// \param port_ Listen port
|
||||
bool setPort (std::string const &port_);
|
||||
bool setPort (std::string_view port_);
|
||||
|
||||
/// \brief Set listen port
|
||||
/// \param port_ Listen port
|
||||
@ -106,11 +109,11 @@ public:
|
||||
|
||||
/// \brief Set access point SSID
|
||||
/// \param ssid_ SSID
|
||||
void setSSID (std::string const &ssid_);
|
||||
void setSSID (std::string_view ssid_);
|
||||
|
||||
/// \brief Set access point passphrase
|
||||
/// \param passphrase_ Passphrase
|
||||
void setPassphrase (std::string const &passphrase_);
|
||||
void setPassphrase (std::string_view passphrase_);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -117,7 +117,7 @@ private:
|
||||
std::vector<UniqueFtpSession> m_sessions;
|
||||
|
||||
/// \brief Whether thread should quit
|
||||
std::atomic<bool> m_quit;
|
||||
std::atomic_bool m_quit = false;
|
||||
|
||||
#ifndef CLASSIC
|
||||
/// \brief Log upload cURL context
|
||||
@ -152,7 +152,7 @@ private:
|
||||
std::string m_passSetting;
|
||||
|
||||
/// \brief Port setting
|
||||
std::uint16_t m_portSetting;
|
||||
std::uint16_t m_portSetting = 0;
|
||||
|
||||
#ifdef __3DS__
|
||||
/// \brief getMTime setting
|
||||
@ -161,7 +161,7 @@ private:
|
||||
|
||||
#ifdef __SWITCH__
|
||||
/// \brief Whether an error occurred enabling access point
|
||||
std::atomic<bool> m_apError = false;
|
||||
std::atomic_bool m_apError = false;
|
||||
|
||||
/// \brief Enable access point setting
|
||||
bool m_enableAPSetting;
|
||||
|
@ -27,10 +27,12 @@
|
||||
#include "socket.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
using stat_t = struct stat;
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@ -165,18 +167,18 @@ private:
|
||||
/// \brief Perform stat and apply tz offset to mtime
|
||||
/// \param path_ Path to stat
|
||||
/// \param st_ Output stat
|
||||
int tzStat (char const *const path_, struct stat *st_);
|
||||
int tzStat (char const *const path_, stat_t *st_);
|
||||
|
||||
/// \brief Perform lstat and apply tz offset to mtime
|
||||
/// \param path_ Path to lstat
|
||||
/// \param st_ Output stat
|
||||
int tzLStat (char const *const path_, struct stat *st_);
|
||||
int tzLStat (char const *const path_, stat_t *st_);
|
||||
|
||||
/// \brief Fill directory entry
|
||||
/// \param st_ Entry status
|
||||
/// \param path_ Path name
|
||||
/// \param type_ MLST type
|
||||
int fillDirent (struct stat const &st_, std::string_view path_, char const *type_ = nullptr);
|
||||
int fillDirent (stat_t const &st_, std::string_view path_, char const *type_ = nullptr);
|
||||
|
||||
/// \brief Fill directory entry
|
||||
/// \param path_ Path name
|
||||
|
@ -58,44 +58,46 @@ public:
|
||||
SockAddr &operator= (SockAddr &&that_);
|
||||
|
||||
/// \brief Parameterized constructor
|
||||
/// \param addr_ Address
|
||||
SockAddr (struct sockaddr_in const &addr_);
|
||||
/// \param addr_ Address (network byte order)
|
||||
SockAddr (sockaddr_in const &addr_);
|
||||
|
||||
#ifndef NO_IPV6
|
||||
/// \brief Parameterized constructor
|
||||
/// \param addr_ Address
|
||||
SockAddr (struct sockaddr_in6 const &addr_);
|
||||
/// \param addr_ Address (network byte order)
|
||||
SockAddr (sockaddr_in6 const &addr_);
|
||||
#endif
|
||||
|
||||
/// \brief Parameterized constructor
|
||||
/// \param addr_ Address
|
||||
SockAddr (struct sockaddr_storage const &addr_);
|
||||
/// \param addr_ Address (network byte order)
|
||||
SockAddr (sockaddr_storage const &addr_);
|
||||
|
||||
/// \brief sockaddr_in cast operator
|
||||
operator struct sockaddr_in const & () const;
|
||||
/// \brief sockaddr_in cast operator (network byte order)
|
||||
operator sockaddr_in const & () const;
|
||||
|
||||
#ifndef NO_IPV6
|
||||
/// \brief sockaddr_in6 cast operator
|
||||
operator struct sockaddr_in6 const & () const;
|
||||
/// \brief sockaddr_in6 cast operator (network byte order)
|
||||
operator sockaddr_in6 const & () const;
|
||||
#endif
|
||||
|
||||
/// \brief sockaddr_storage cast operator
|
||||
operator struct sockaddr_storage const & () const;
|
||||
/// \brief sockaddr_storage cast operator (network byte order)
|
||||
operator sockaddr_storage const & () const;
|
||||
|
||||
/// \brief sockaddr* cast operator (network byte order)
|
||||
operator sockaddr * ();
|
||||
|
||||
/// \brief sockaddr const* cast operator (network byte order)
|
||||
operator sockaddr const * () const;
|
||||
|
||||
/// \brief sockaddr* cast operator
|
||||
operator struct sockaddr * ();
|
||||
/// \brief sockaddr const* cast operator
|
||||
operator struct sockaddr const * () const;
|
||||
|
||||
/// \brief sockaddr size
|
||||
socklen_t size () const;
|
||||
|
||||
/// \brief Address port
|
||||
/// \brief Address port (host byte order)
|
||||
std::uint16_t port () const;
|
||||
|
||||
/// \brief Set address port
|
||||
/// \param port_ Port to set
|
||||
bool setPort (std::uint16_t port_);
|
||||
/// \param port_ Port to set (host byte order)
|
||||
void setPort (std::uint16_t port_);
|
||||
|
||||
/// \brief Address name
|
||||
/// \param buffer_ Buffer to hold name
|
||||
@ -110,6 +112,6 @@ public:
|
||||
char const *name () const;
|
||||
|
||||
private:
|
||||
/// \brief Address storage
|
||||
struct sockaddr_storage m_addr = {};
|
||||
/// \brief Address storage (network byte order)
|
||||
sockaddr_storage m_addr = {};
|
||||
};
|
||||
|
@ -3,7 +3,7 @@
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2023 Michael Theall
|
||||
// Copyright (C) 2024 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
|
||||
@ -37,7 +37,7 @@ struct pollfd
|
||||
using socklen_t = int;
|
||||
using nfds_t = unsigned int;
|
||||
|
||||
extern "C" int poll (struct pollfd *fds_, nfds_t nfds_, int timeout_);
|
||||
extern "C" int poll (pollfd *fds_, nfds_t nfds_, int timeout_);
|
||||
|
||||
#define POLLIN (1 << 0)
|
||||
#define POLLPRI (1 << 1)
|
||||
|
@ -70,7 +70,7 @@ static_assert (SOCU_BUFFERSIZE % SOCU_ALIGN == 0);
|
||||
bool s_ndmuLocked = false;
|
||||
|
||||
/// \brief Whether soc:u is active
|
||||
std::atomic<bool> s_socuActive = false;
|
||||
std::atomic_bool s_socuActive = false;
|
||||
/// \brief soc:u buffer
|
||||
u32 *s_socuBuffer = nullptr;
|
||||
/// \brief ac:u fence
|
||||
@ -569,7 +569,7 @@ bool platform::networkVisible ()
|
||||
|
||||
bool platform::networkAddress (SockAddr &addr_)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = gethostid ();
|
||||
|
||||
|
100
source/fs.cpp
100
source/fs.cpp
@ -3,7 +3,7 @@
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2023 Michael Theall
|
||||
// Copyright (C) 2024 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
|
||||
@ -19,11 +19,24 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "fs.h"
|
||||
#include "ioBuffer.h"
|
||||
|
||||
#include <gsl/pointers>
|
||||
#include <gsl/util>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <dirent.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if defined(__NDS__) || defined(__3DS__) || defined(__SWITCH__)
|
||||
#define getline __getline
|
||||
@ -38,7 +51,7 @@ std::string fs::printSize (std::uint64_t const size_)
|
||||
constexpr std::uint64_t const PiB = 1024 * TiB;
|
||||
constexpr std::uint64_t const EiB = 1024 * PiB;
|
||||
|
||||
char buffer[64] = {};
|
||||
std::array<char, 64> buffer{};
|
||||
|
||||
for (auto const &[name, bin] : {
|
||||
// clang-format off
|
||||
@ -56,30 +69,32 @@ std::string fs::printSize (std::uint64_t const size_)
|
||||
if (size_ >= 100 * bin)
|
||||
{
|
||||
// >= 100, print xxxXiB
|
||||
std::sprintf (buffer, "%" PRIu64 "%s", whole, name);
|
||||
return buffer;
|
||||
std::size_t const size = std::sprintf (buffer.data (), "%" PRIu64 "%s", whole, name);
|
||||
return {buffer.data (), size};
|
||||
}
|
||||
|
||||
// get the fractional portion of the number
|
||||
auto const frac = size_ - whole * bin;
|
||||
auto const frac = size_ - (whole * bin);
|
||||
if (size_ >= 10 * bin)
|
||||
{
|
||||
// >= 10, print xx.xXiB
|
||||
std::sprintf (buffer, "%" PRIu64 ".%" PRIu64 "%s", whole, frac * 10 / bin, name);
|
||||
return buffer;
|
||||
std::size_t const size = std::sprintf (
|
||||
buffer.data (), "%" PRIu64 ".%" PRIu64 "%s", whole, frac * 10 / bin, name);
|
||||
return {buffer.data (), size};
|
||||
}
|
||||
|
||||
if (size_ >= 1000 * (bin / KiB))
|
||||
{
|
||||
// >= 1000 of lesser bin, print x.xxXiB
|
||||
std::sprintf (buffer, "%" PRIu64 ".%02" PRIu64 "%s", whole, frac * 100 / bin, name);
|
||||
return buffer;
|
||||
std::size_t const size = std::sprintf (
|
||||
buffer.data (), "%" PRIu64 ".%02" PRIu64 "%s", whole, frac * 100 / bin, name);
|
||||
return {buffer.data (), size};
|
||||
}
|
||||
}
|
||||
|
||||
// < 1KiB, just print the number
|
||||
std::sprintf (buffer, "%" PRIu64 "B", size_);
|
||||
return buffer;
|
||||
std::size_t const size = std::sprintf (buffer.data (), "%" PRIu64 "B", size_);
|
||||
return {buffer.data (), size};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -106,26 +121,24 @@ fs::File::operator FILE * () const
|
||||
|
||||
void fs::File::setBufferSize (std::size_t const size_)
|
||||
{
|
||||
if (m_bufferSize != size_)
|
||||
{
|
||||
m_buffer = std::make_unique<char[]> (size_);
|
||||
m_bufferSize = size_;
|
||||
}
|
||||
if (m_buffer.size () != size_)
|
||||
m_buffer.resize (size_);
|
||||
|
||||
if (m_fp)
|
||||
std::setvbuf (m_fp.get (), m_buffer.get (), _IOFBF, m_bufferSize);
|
||||
(void)std::setvbuf (m_fp.get (), m_buffer.data (), _IOFBF, m_buffer.size ());
|
||||
}
|
||||
|
||||
bool fs::File::open (char const *const path_, char const *const mode_)
|
||||
bool fs::File::open (gsl::not_null<char const *> const path_,
|
||||
gsl::not_null<char const *> const mode_)
|
||||
{
|
||||
auto const fp = std::fopen (path_, mode_);
|
||||
gsl::owner<FILE *> fp = std::fopen (path_, mode_);
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
m_fp = std::unique_ptr<std::FILE, int (*) (std::FILE *)> (fp, &std::fclose);
|
||||
|
||||
if (m_buffer)
|
||||
std::setvbuf (m_fp.get (), m_buffer.get (), _IOFBF, m_bufferSize);
|
||||
if (!m_buffer.empty ())
|
||||
(void)std::setvbuf (m_fp.get (), m_buffer.data (), _IOFBF, m_buffer.size ());
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -135,17 +148,27 @@ void fs::File::close ()
|
||||
m_fp.reset ();
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::seek (std::size_t const pos_, int const origin_)
|
||||
std::make_signed_t<std::size_t> fs::File::seek (std::make_signed_t<std::size_t> const pos_,
|
||||
int const origin_)
|
||||
{
|
||||
return std::fseek (m_fp.get (), pos_, origin_);
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::read (void *const buffer_, std::size_t const size_)
|
||||
std::make_signed_t<std::size_t> fs::File::read (gsl::not_null<void *> const buffer_,
|
||||
std::size_t const size_)
|
||||
{
|
||||
assert (buffer_);
|
||||
assert (size_ > 0);
|
||||
|
||||
return std::fread (buffer_, 1, size_, m_fp.get ());
|
||||
auto const rc = std::fread (buffer_, 1, size_, m_fp.get ());
|
||||
if (rc == 0)
|
||||
{
|
||||
if (std::feof (m_fp.get ()))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return gsl::narrow_cast<std::make_signed_t<std::size_t>> (rc);
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::read (IOBuffer &buffer_)
|
||||
@ -176,37 +199,41 @@ std::string_view fs::File::readLine ()
|
||||
}
|
||||
|
||||
if (rc > 0)
|
||||
return std::string_view (m_lineBuffer, rc);
|
||||
return {m_lineBuffer, gsl::narrow_cast<std::size_t> (rc)};
|
||||
}
|
||||
}
|
||||
|
||||
bool fs::File::readAll (void *const buffer_, std::size_t const size_)
|
||||
bool fs::File::readAll (gsl::not_null<void *> const buffer_, std::size_t const size_)
|
||||
{
|
||||
assert (buffer_);
|
||||
assert (size_ > 0);
|
||||
|
||||
auto p = static_cast<char *> (buffer_);
|
||||
auto const p = static_cast<char *> (buffer_.get ());
|
||||
|
||||
std::size_t bytes = 0;
|
||||
while (bytes < size_)
|
||||
{
|
||||
auto const rc = read (p, size_ - bytes);
|
||||
auto const rc = read (p + bytes, size_ - bytes);
|
||||
if (rc <= 0)
|
||||
return false;
|
||||
|
||||
p += rc;
|
||||
bytes += rc;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::write (void const *const buffer_, std::size_t const size_)
|
||||
std::make_signed_t<std::size_t> fs::File::write (gsl::not_null<void const *> const buffer_,
|
||||
std::size_t const size_)
|
||||
{
|
||||
assert (buffer_);
|
||||
assert (size_ > 0);
|
||||
|
||||
return std::fwrite (buffer_, 1, size_, m_fp.get ());
|
||||
auto const rc = std::fwrite (buffer_, 1, size_, m_fp.get ());
|
||||
if (rc == 0)
|
||||
return -1;
|
||||
|
||||
return gsl::narrow_cast<std::make_signed_t<std::size_t>> (rc);
|
||||
}
|
||||
|
||||
std::make_signed_t<std::size_t> fs::File::write (IOBuffer &buffer_)
|
||||
@ -220,21 +247,20 @@ std::make_signed_t<std::size_t> fs::File::write (IOBuffer &buffer_)
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool fs::File::writeAll (void const *const buffer_, std::size_t const size_)
|
||||
bool fs::File::writeAll (gsl::not_null<void const *> const buffer_, std::size_t const size_)
|
||||
{
|
||||
assert (buffer_);
|
||||
assert (size_ > 0);
|
||||
|
||||
auto p = static_cast<char const *> (buffer_);
|
||||
auto const p = static_cast<char const *> (buffer_.get ());
|
||||
|
||||
std::size_t bytes = 0;
|
||||
while (bytes < size_)
|
||||
{
|
||||
auto const rc = write (p, size_ - bytes);
|
||||
auto const rc = write (p + bytes, size_ - bytes);
|
||||
if (rc <= 0)
|
||||
return false;
|
||||
|
||||
p += rc;
|
||||
bytes += rc;
|
||||
}
|
||||
|
||||
@ -260,7 +286,7 @@ fs::Dir::operator DIR * () const
|
||||
return m_dp.get ();
|
||||
}
|
||||
|
||||
bool fs::Dir::open (char const *const path_)
|
||||
bool fs::Dir::open (gsl::not_null<char const *> const path_)
|
||||
{
|
||||
auto const dp = ::opendir (path_);
|
||||
if (!dp)
|
||||
@ -275,7 +301,7 @@ void fs::Dir::close ()
|
||||
m_dp.reset ();
|
||||
}
|
||||
|
||||
struct dirent *fs::Dir::read ()
|
||||
dirent *fs::Dir::read ()
|
||||
{
|
||||
errno = 0;
|
||||
return ::readdir (m_dp.get ());
|
||||
|
@ -3,7 +3,7 @@
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2023 Michael Theall
|
||||
// Copyright (C) 2024 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
|
||||
@ -22,24 +22,36 @@
|
||||
|
||||
#include "fs.h"
|
||||
#include "log.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <gsl/pointers>
|
||||
|
||||
#include <sys/stat.h>
|
||||
using stat_t = struct stat;
|
||||
|
||||
#include <limits>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr std::uint16_t DEFAULT_PORT = 5000;
|
||||
|
||||
bool mkdirParent (std::string const &path_)
|
||||
bool mkdirParent (std::string_view const path_)
|
||||
{
|
||||
auto pos = path_.find_first_of ('/');
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
auto const dir = path_.substr (0, pos);
|
||||
auto const dir = std::string (path_.substr (0, pos));
|
||||
|
||||
struct stat st;
|
||||
stat_t st{};
|
||||
auto const rc = ::stat (dir.c_str (), &st);
|
||||
if (rc < 0 && errno != ENOENT)
|
||||
return false;
|
||||
@ -57,14 +69,13 @@ bool mkdirParent (std::string const &path_)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string strip (std::string const &str_)
|
||||
std::string_view strip (std::string_view const str_)
|
||||
{
|
||||
auto const start = str_.find_first_not_of (" \t");
|
||||
if (start == std::string::npos)
|
||||
return {};
|
||||
|
||||
auto const end = str_.find_last_not_of (" \t");
|
||||
|
||||
if (end == std::string::npos)
|
||||
return str_.substr (start);
|
||||
|
||||
@ -72,37 +83,21 @@ std::string strip (std::string const &str_)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool parseInt (T &out_, std::string const &val_)
|
||||
bool parseInt (T &out_, std::string_view const val_)
|
||||
{
|
||||
T val = 0;
|
||||
|
||||
for (auto const &c : val_)
|
||||
auto const rc = std::from_chars (val_.data (), val_.data () + val_.size (), out_);
|
||||
if (rc.ec != std::errc{})
|
||||
{
|
||||
if (!std::isdigit (c))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::numeric_limits<T>::max () / 10 < val)
|
||||
{
|
||||
errno = EOVERFLOW;
|
||||
return false;
|
||||
}
|
||||
|
||||
val *= 10;
|
||||
|
||||
auto const v = c - '0';
|
||||
if (std::numeric_limits<T>::max () - v < val)
|
||||
{
|
||||
errno = EOVERFLOW;
|
||||
return false;
|
||||
}
|
||||
|
||||
val += v;
|
||||
errno = static_cast<int> (rc.ec);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rc.ptr != val_.data () + val_.size ())
|
||||
{
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
out_ = val;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -119,7 +114,7 @@ UniqueFtpConfig FtpConfig::create ()
|
||||
return UniqueFtpConfig (new FtpConfig ());
|
||||
}
|
||||
|
||||
UniqueFtpConfig FtpConfig::load (char const *const path_)
|
||||
UniqueFtpConfig FtpConfig::load (gsl::not_null<gsl::czstring> const path_)
|
||||
{
|
||||
auto config = create ();
|
||||
|
||||
@ -139,8 +134,8 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const key = strip (line.substr (0, pos));
|
||||
auto const val = strip (line.substr (pos + 1));
|
||||
auto const key = strip (std::string_view (line).substr (0, pos));
|
||||
auto const val = strip (std::string_view (line).substr (pos + 1));
|
||||
if (key.empty () || val.empty ())
|
||||
{
|
||||
error ("Ignoring '%s'\n", line.c_str ());
|
||||
@ -161,7 +156,9 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
|
||||
else if (val == "1")
|
||||
config->m_getMTime = true;
|
||||
else
|
||||
error ("Invalid value for mtime: %s\n", val.c_str ());
|
||||
error ("Invalid value for mtime: %.*s\n",
|
||||
gsl::narrow_cast<int> (val.size ()),
|
||||
val.data ());
|
||||
}
|
||||
#endif
|
||||
#ifdef __SWITCH__
|
||||
@ -172,7 +169,9 @@ UniqueFtpConfig FtpConfig::load (char const *const path_)
|
||||
else if (val == "1")
|
||||
config->m_enableAP = true;
|
||||
else
|
||||
error ("Invalid value for ap: %s\n", val.c_str ());
|
||||
error ("Invalid value for ap: %.*s\n",
|
||||
gsl::narrow_cast<int> (val.size ()),
|
||||
val.data ());
|
||||
}
|
||||
else if (key == "ssid")
|
||||
config->m_ssid = val;
|
||||
@ -193,9 +192,9 @@ std::scoped_lock<platform::Mutex> FtpConfig::lockGuard ()
|
||||
}
|
||||
#endif
|
||||
|
||||
bool FtpConfig::save (char const *const path_)
|
||||
bool FtpConfig::save (gsl::not_null<gsl::czstring> const path_)
|
||||
{
|
||||
if (!mkdirParent (path_))
|
||||
if (!mkdirParent (path_.get ()))
|
||||
return false;
|
||||
|
||||
auto fp = fs::File ();
|
||||
@ -203,21 +202,21 @@ bool FtpConfig::save (char const *const path_)
|
||||
return false;
|
||||
|
||||
if (!m_user.empty ())
|
||||
std::fprintf (fp, "user=%s\n", m_user.c_str ());
|
||||
(void)std::fprintf (fp, "user=%s\n", m_user.c_str ());
|
||||
if (!m_pass.empty ())
|
||||
std::fprintf (fp, "pass=%s\n", m_pass.c_str ());
|
||||
std::fprintf (fp, "port=%u\n", m_port);
|
||||
(void)std::fprintf (fp, "pass=%s\n", m_pass.c_str ());
|
||||
(void)std::fprintf (fp, "port=%u\n", m_port);
|
||||
|
||||
#ifdef __3DS__
|
||||
std::fprintf (fp, "mtime=%u\n", m_getMTime);
|
||||
(void)std::fprintf (fp, "mtime=%u\n", m_getMTime);
|
||||
#endif
|
||||
|
||||
#ifdef __SWITCH__
|
||||
std::fprintf (fp, "ap=%u\n", m_enableAP);
|
||||
(void)std::fprintf (fp, "ap=%u\n", m_enableAP);
|
||||
if (!m_ssid.empty ())
|
||||
std::fprintf (fp, "ssid=%s\n", m_ssid.c_str ());
|
||||
(void)std::fprintf (fp, "ssid=%s\n", m_ssid.c_str ());
|
||||
if (!m_passphrase.empty ())
|
||||
std::fprintf (fp, "passphrase=%s\n", m_passphrase.c_str ());
|
||||
(void)std::fprintf (fp, "passphrase=%s\n", m_passphrase.c_str ());
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -262,19 +261,19 @@ std::string const &FtpConfig::passphrase () const
|
||||
}
|
||||
#endif
|
||||
|
||||
void FtpConfig::setUser (std::string const &user_)
|
||||
void FtpConfig::setUser (std::string user_)
|
||||
{
|
||||
m_user = user_.substr (0, user_.find_first_of ('\0'));
|
||||
m_user = std::move (user_);
|
||||
}
|
||||
|
||||
void FtpConfig::setPass (std::string const &pass_)
|
||||
void FtpConfig::setPass (std::string pass_)
|
||||
{
|
||||
m_pass = pass_.substr (0, pass_.find_first_of ('\0'));
|
||||
m_pass = std::move (pass_);
|
||||
}
|
||||
|
||||
bool FtpConfig::setPort (std::string const &port_)
|
||||
bool FtpConfig::setPort (std::string_view const port_)
|
||||
{
|
||||
std::uint16_t parsed;
|
||||
std::uint16_t parsed{};
|
||||
if (!parseInt (parsed, port_))
|
||||
return false;
|
||||
|
||||
@ -317,12 +316,12 @@ void FtpConfig::setEnableAP (bool const enable_)
|
||||
m_enableAP = enable_;
|
||||
}
|
||||
|
||||
void FtpConfig::setSSID (std::string const &ssid_)
|
||||
void FtpConfig::setSSID (std::string_view const ssid_)
|
||||
{
|
||||
m_ssid = ssid_.substr (0, ssid_.find_first_of ('\0'));
|
||||
}
|
||||
|
||||
void FtpConfig::setPassphrase (std::string const &passphrase_)
|
||||
void FtpConfig::setPassphrase (std::string_view const passphrase_)
|
||||
{
|
||||
m_passphrase = passphrase_.substr (0, passphrase_.find_first_of ('\0'));
|
||||
}
|
||||
|
@ -21,9 +21,12 @@
|
||||
#include "ftpServer.h"
|
||||
|
||||
#include "fs.h"
|
||||
#include "ftpConfig.h"
|
||||
#include "ftpSession.h"
|
||||
#include "licenses.h"
|
||||
#include "log.h"
|
||||
#include "platform.h"
|
||||
#include "sockAddr.h"
|
||||
#include "socket.h"
|
||||
|
||||
#include "imgui.h"
|
||||
@ -32,22 +35,38 @@
|
||||
#include <dswifi9.h>
|
||||
#endif
|
||||
|
||||
#ifndef CLASSIC
|
||||
#include <jansson.h>
|
||||
#ifdef __3DS__
|
||||
#include <citro3d.h>
|
||||
#endif
|
||||
|
||||
#ifndef CLASSIC
|
||||
#include <jansson.h>
|
||||
|
||||
#include <curl/easy.h>
|
||||
#include <curl/multi.h>
|
||||
#ifndef NDEBUG
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
using statvfs_t = struct statvfs;
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#ifdef __NDS__
|
||||
@ -81,21 +100,33 @@ std::string s_freeSpace;
|
||||
|
||||
#ifndef CLASSIC
|
||||
#ifndef NDEBUG
|
||||
std::string printable (char *const data_, std::size_t const size_)
|
||||
std::string printable (std::string_view const data_)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve (size_);
|
||||
|
||||
for (std::size_t i = 0; i < size_; ++i)
|
||||
unsigned count = 0;
|
||||
for (auto const &c : data_)
|
||||
{
|
||||
if (std::isprint (data_[i]) || std::isspace (data_[i]))
|
||||
result.push_back (data_[i]);
|
||||
if (c != '%' && (std::isprint (c) || std::isspace (c)))
|
||||
++count;
|
||||
else
|
||||
count += 3;
|
||||
}
|
||||
|
||||
std::string result;
|
||||
result.reserve (count);
|
||||
|
||||
for (auto const &c : data_)
|
||||
{
|
||||
if (c != '%' && (std::isprint (c) || std::isspace (c)))
|
||||
result.push_back (c);
|
||||
else
|
||||
{
|
||||
char buffer[5];
|
||||
std::snprintf (
|
||||
buffer, sizeof (buffer), "%%%02u", static_cast<unsigned char> (data_[i]));
|
||||
result += buffer;
|
||||
result.push_back ('%');
|
||||
|
||||
auto const upper = (static_cast<unsigned char> (c) >> 4u) & 0xF;
|
||||
auto const lower = (static_cast<unsigned char> (c) >> 0u) & 0xF;
|
||||
|
||||
result.push_back (gsl::narrow_cast<char> (upper < 10 ? upper + '0' : upper + 'A' - 10));
|
||||
result.push_back (gsl::narrow_cast<char> (lower < 10 ? lower + '0' : lower + 'A' - 10));
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +142,7 @@ int curlDebug (CURL *const handle_,
|
||||
(void)handle_;
|
||||
(void)user_;
|
||||
|
||||
auto const text = printable (data_, size_);
|
||||
auto const text = printable (std::string_view (data_, size_));
|
||||
|
||||
switch (type_)
|
||||
{
|
||||
@ -190,7 +221,8 @@ FtpServer::~FtpServer ()
|
||||
#endif
|
||||
}
|
||||
|
||||
FtpServer::FtpServer (UniqueFtpConfig config_) : m_config (std::move (config_)), m_quit (false)
|
||||
FtpServer::FtpServer (UniqueFtpConfig config_)
|
||||
: m_config (std::move (config_))
|
||||
{
|
||||
#ifndef __NDS__
|
||||
m_thread = platform::Thread (std::bind (&FtpServer::threadFunc, this));
|
||||
@ -279,17 +311,17 @@ void FtpServer::draw ()
|
||||
ImGui::SetNextWindowSize (ImVec2 (width, height));
|
||||
#endif
|
||||
{
|
||||
char title[64];
|
||||
std::array<char, 64> title{};
|
||||
|
||||
{
|
||||
auto const serverLock = std::scoped_lock (m_lock);
|
||||
std::snprintf (title,
|
||||
sizeof (title),
|
||||
std::snprintf (title.data (),
|
||||
title.size (),
|
||||
STATUS_STRING " %s###ftpd",
|
||||
m_socket ? m_name.c_str () : "Waiting for WiFi...");
|
||||
}
|
||||
|
||||
ImGui::Begin (title,
|
||||
ImGui::Begin (title.data (),
|
||||
nullptr,
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize
|
||||
#ifndef __3DS__
|
||||
@ -361,7 +393,7 @@ std::string FtpServer::getFreeSpace ()
|
||||
|
||||
void FtpServer::updateFreeSpace ()
|
||||
{
|
||||
struct statvfs st;
|
||||
statvfs_t st = {};
|
||||
#if defined(__NDS__) || defined(__3DS__) || defined(__SWITCH__)
|
||||
if (::statvfs ("sdmc:/", &st) != 0)
|
||||
#else
|
||||
@ -440,8 +472,9 @@ void FtpServer::handleNetworkLost ()
|
||||
}
|
||||
|
||||
{
|
||||
// destroy command socket
|
||||
UniqueSocket sock;
|
||||
|
||||
// destroy command socket
|
||||
LOCKED (sock = std::move (m_socket));
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#if defined(__NDS__) || defined(__3DS__) || defined(__SWITCH__)
|
||||
@ -60,6 +61,33 @@ namespace
|
||||
/// \brief Idle timeout
|
||||
constexpr auto IDLE_TIMEOUT = 60;
|
||||
|
||||
/// \brief Check if string view is a C string
|
||||
/// \param str_ String to check
|
||||
bool isCString (std::string_view const str_)
|
||||
{
|
||||
return str_.find_first_of ('\0') != std::string_view::npos;
|
||||
}
|
||||
|
||||
/// \brief Case-insensitive string compare
|
||||
/// \param lhs_ Left string
|
||||
/// \param rhs_ Right string
|
||||
int compare (std::string_view const lhs_, std::string_view const rhs_)
|
||||
{
|
||||
if (isCString (lhs_) && isCString (rhs_))
|
||||
return ::strcasecmp (lhs_.data (), rhs_.data ());
|
||||
|
||||
auto const maxLen = std::min (lhs_.size (), rhs_.size ());
|
||||
for (unsigned i = 0; i < maxLen; ++i)
|
||||
{
|
||||
auto const l = std::tolower (lhs_[i]);
|
||||
auto const r = std::tolower (rhs_[i]);
|
||||
if (l != r)
|
||||
return l - r;
|
||||
}
|
||||
|
||||
return gsl::narrow_cast<int> (lhs_.size ()) - gsl::narrow_cast<int> (rhs_.size ());
|
||||
}
|
||||
|
||||
/// \brief Parse command
|
||||
/// \param buffer_ Buffer to parse
|
||||
/// \param size_ Size of buffer
|
||||
@ -171,7 +199,7 @@ std::string resolvePath (std::string_view const path_)
|
||||
assert (path_[0] == '/');
|
||||
|
||||
// make sure parent is a directory
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
if (::stat (dirName (path_).c_str (), &st) != 0)
|
||||
return {};
|
||||
|
||||
@ -385,7 +413,8 @@ void FtpSession::draw ()
|
||||
auto const timeDiff = now - m_filePositionTime;
|
||||
m_filePositionTime = now;
|
||||
|
||||
auto const rate = diff / std::chrono::duration<float> (timeDiff).count ();
|
||||
auto const rate =
|
||||
gsl::narrow_cast<float> (diff) / std::chrono::duration<float> (timeDiff).count ();
|
||||
auto const alpha = 0.01f;
|
||||
m_xferRate = alpha * rate + (1.0f - alpha) * m_xferRate;
|
||||
}
|
||||
@ -469,7 +498,7 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
|
||||
for (auto &pending : session->m_pendingCloseSocket)
|
||||
{
|
||||
assert (pending.unique ());
|
||||
pollInfo.emplace_back (Socket::PollInfo{*pending, POLLIN, 0});
|
||||
pollInfo.emplace_back (*pending, POLLIN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -513,8 +542,7 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
|
||||
{
|
||||
if (session->m_commandSocket)
|
||||
{
|
||||
pollInfo.emplace_back (
|
||||
Socket::PollInfo{*session->m_commandSocket, POLLIN | POLLPRI, 0});
|
||||
pollInfo.emplace_back (*session->m_commandSocket, POLLIN | POLLPRI, 0);
|
||||
if (session->m_responseBuffer.usedSize () != 0)
|
||||
pollInfo.back ().events |= POLLOUT;
|
||||
}
|
||||
@ -530,12 +558,12 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
|
||||
{
|
||||
assert (!session->m_port);
|
||||
// we are waiting for a PASV connection
|
||||
pollInfo.emplace_back (Socket::PollInfo{*session->m_pasvSocket, POLLIN, 0});
|
||||
pollInfo.emplace_back (*session->m_pasvSocket, POLLIN, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are waiting to complete a PORT connection
|
||||
pollInfo.emplace_back (Socket::PollInfo{*session->m_dataSocket, POLLOUT, 0});
|
||||
pollInfo.emplace_back (*session->m_dataSocket, POLLOUT, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -544,12 +572,12 @@ bool FtpSession::poll (std::vector<UniqueFtpSession> const &sessions_)
|
||||
if (session->m_recv)
|
||||
{
|
||||
assert (!session->m_send);
|
||||
pollInfo.emplace_back (Socket::PollInfo{*session->m_dataSocket, POLLIN, 0});
|
||||
pollInfo.emplace_back (*session->m_dataSocket, POLLIN, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (session->m_send);
|
||||
pollInfo.emplace_back (Socket::PollInfo{*session->m_dataSocket, POLLOUT, 0});
|
||||
pollInfo.emplace_back (*session->m_dataSocket, POLLOUT, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -751,7 +779,7 @@ bool FtpSession::changeDir (char const *const args_)
|
||||
if (path.empty ())
|
||||
return false;
|
||||
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
if (tzStat (path.c_str (), &st) != 0)
|
||||
return false;
|
||||
|
||||
@ -834,7 +862,7 @@ bool FtpSession::dataConnect ()
|
||||
return true;
|
||||
}
|
||||
|
||||
int FtpSession::tzStat (char const *const path_, struct stat *st_)
|
||||
int FtpSession::tzStat (char const *const path_, stat_t *st_)
|
||||
{
|
||||
auto const rc = ::stat (path_, st_);
|
||||
if (rc != 0)
|
||||
@ -855,7 +883,7 @@ int FtpSession::tzStat (char const *const path_, struct stat *st_)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FtpSession::tzLStat (char const *const path_, struct stat *st_)
|
||||
int FtpSession::tzLStat (char const *const path_, stat_t *st_)
|
||||
{
|
||||
auto const rc = ::lstat (path_, st_);
|
||||
if (rc != 0)
|
||||
@ -876,7 +904,7 @@ int FtpSession::tzLStat (char const *const path_, struct stat *st_)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FtpSession::fillDirent (struct stat const &st_, std::string_view const path_, char const *type_)
|
||||
int FtpSession::fillDirent (stat_t const &st_, std::string_view const path_, char const *type_)
|
||||
{
|
||||
auto const buffer = m_xferBuffer.freeArea ();
|
||||
auto const size = m_xferBuffer.freeSize ();
|
||||
@ -1162,7 +1190,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;
|
||||
stat_t st;
|
||||
if (tzStat (path_.c_str (), &st) != 0)
|
||||
return errno;
|
||||
|
||||
@ -1189,7 +1217,7 @@ void FtpSession::xferFile (char const *const args_, XferFileMode const mode_)
|
||||
else if (mode_ == XferFileMode::RETR)
|
||||
{
|
||||
// stat the file
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
if (tzStat (path.c_str (), &st) != 0)
|
||||
{
|
||||
sendResponse ("450 %s\r\n", std::strerror (errno));
|
||||
@ -1321,7 +1349,7 @@ void FtpSession::xferDir (char const *const args_, XferDirMode const mode_, bool
|
||||
return;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
if (tzStat (path.c_str (), &st) != 0)
|
||||
{
|
||||
if (needWorkaround)
|
||||
@ -1600,12 +1628,10 @@ void FtpSession::readCommand (int const events_)
|
||||
auto const it = std::lower_bound (std::begin (handlers),
|
||||
std::end (handlers),
|
||||
command,
|
||||
[] (auto const &lhs_, auto const &rhs_) {
|
||||
return ::strcasecmp (lhs_.first.data (), rhs_) < 0;
|
||||
});
|
||||
[] (auto const &lhs_, auto const &rhs_) { return compare (lhs_.first, rhs_) < 0; });
|
||||
|
||||
m_timestamp = std::time (nullptr);
|
||||
if (it == std::end (handlers) || ::strcasecmp (it->first.data (), command) != 0)
|
||||
if (it == std::end (handlers) || compare (it->first, command) != 0)
|
||||
{
|
||||
std::string response = "502 Invalid command \"";
|
||||
response += encodePath (command);
|
||||
@ -1623,9 +1649,9 @@ void FtpSession::readCommand (int const events_)
|
||||
else if (m_state != State::COMMAND)
|
||||
{
|
||||
// only some commands are available during data transfer
|
||||
if (::strcasecmp (command, "ABOR") != 0 && ::strcasecmp (command, "NOOP") != 0 &&
|
||||
::strcasecmp (command, "PWD") != 0 && ::strcasecmp (command, "QUIT") != 0 &&
|
||||
::strcasecmp (command, "STAT") != 0 && ::strcasecmp (command, "XPWD") != 0)
|
||||
if (compare (command, "ABOR") != 0 && compare (command, "NOOP") != 0 &&
|
||||
compare (command, "PWD") != 0 && compare (command, "QUIT") != 0 &&
|
||||
compare (command, "STAT") != 0 && compare (command, "XPWD") != 0)
|
||||
{
|
||||
sendResponse ("503 Invalid command during transfer\r\n");
|
||||
setState (State::COMMAND, true, true);
|
||||
@ -1640,7 +1666,7 @@ void FtpSession::readCommand (int const events_)
|
||||
else
|
||||
{
|
||||
// clear rename for all commands except RNTO
|
||||
if (::strcasecmp (command, "RNTO") != 0)
|
||||
if (compare (command, "RNTO") != 0)
|
||||
m_rename.clear ();
|
||||
|
||||
auto const handler = it->second;
|
||||
@ -1791,7 +1817,7 @@ bool FtpSession::listTransfer ()
|
||||
{
|
||||
// build the path
|
||||
auto const fullPath = buildPath (m_lwd, dent->d_name);
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
|
||||
#ifdef __3DS__
|
||||
// the sdmc directory entry already has the type and size, so no need to do a slow stat
|
||||
@ -2220,7 +2246,7 @@ void FtpSession::MODE (char const *args_)
|
||||
setState (State::COMMAND, false, false);
|
||||
|
||||
// we only accept S (stream) mode
|
||||
if (::strcasecmp (args_, "S") == 0)
|
||||
if (compare (args_, "S") == 0)
|
||||
{
|
||||
sendResponse ("200 OK\r\n");
|
||||
return;
|
||||
@ -2254,8 +2280,8 @@ void FtpSession::OPTS (char const *args_)
|
||||
setState (State::COMMAND, false, false);
|
||||
|
||||
// check UTF8 options
|
||||
if (::strcasecmp (args_, "UTF8") == 0 || ::strcasecmp (args_, "UTF8 ON") == 0 ||
|
||||
::strcasecmp (args_, "UTF8 NLST") == 0)
|
||||
if (compare (args_, "UTF8") == 0 || compare (args_, "UTF8 ON") == 0 ||
|
||||
compare (args_, "UTF8 NLST") == 0)
|
||||
{
|
||||
sendResponse ("200 OK\r\n");
|
||||
return;
|
||||
@ -2371,7 +2397,7 @@ void FtpSession::PASV (char const *args_)
|
||||
m_pasvSocket->setSendBufferSize (SOCK_BUFFERSIZE);
|
||||
|
||||
// create an address to bind
|
||||
struct sockaddr_in addr = m_commandSocket->sockName ();
|
||||
sockaddr_in addr = m_commandSocket->sockName ();
|
||||
#if defined(__NDS__) || defined(__3DS__)
|
||||
static std::uint16_t ephemeralPort = 5001;
|
||||
if (ephemeralPort > 10000)
|
||||
@ -2455,7 +2481,7 @@ void FtpSession::PORT (char const *args_)
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr = {};
|
||||
sockaddr_in addr{};
|
||||
|
||||
// parse the address
|
||||
if (!inet_aton (addrString.data (), &addr.sin_addr))
|
||||
@ -2630,7 +2656,7 @@ void FtpSession::RNFR (char const *args_)
|
||||
}
|
||||
|
||||
// make sure the path exists
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
if (tzLStat (path.c_str (), &st) != 0)
|
||||
{
|
||||
sendResponse ("450 %s\r\n", std::strerror (errno));
|
||||
@ -2687,13 +2713,13 @@ void FtpSession::SITE (char const *args_)
|
||||
{
|
||||
setState (State::COMMAND, false, false);
|
||||
|
||||
auto const str = std::string (args_);
|
||||
auto const str = std::string_view (args_);
|
||||
auto const pos = str.find_first_of (' ');
|
||||
|
||||
auto const command = str.substr (0, pos);
|
||||
auto const arg = pos == std::string::npos ? std::string () : str.substr (pos + 1);
|
||||
auto const arg = pos == std::string::npos ? std::string_view () : str.substr (pos + 1);
|
||||
|
||||
if (::strcasecmp (command.c_str (), "HELP") == 0)
|
||||
if (compare (command.data (), "HELP") == 0)
|
||||
{
|
||||
sendResponse ("211-\r\n"
|
||||
" Show this help: SITE HELP\r\n"
|
||||
@ -2714,31 +2740,31 @@ void FtpSession::SITE (char const *args_)
|
||||
return;
|
||||
}
|
||||
|
||||
if (::strcasecmp (command.c_str (), "USER") == 0)
|
||||
if (compare (command, "USER") == 0)
|
||||
{
|
||||
{
|
||||
#ifndef __NDS__
|
||||
auto const lock = m_config.lockGuard ();
|
||||
#endif
|
||||
m_config.setUser (arg);
|
||||
m_config.setUser (std::string (arg));
|
||||
}
|
||||
|
||||
sendResponse ("200 OK\r\n");
|
||||
return;
|
||||
}
|
||||
else if (::strcasecmp (command.c_str (), "PASS") == 0)
|
||||
else if (compare (command, "PASS") == 0)
|
||||
{
|
||||
{
|
||||
#ifndef __NDS__
|
||||
auto const lock = m_config.lockGuard ();
|
||||
#endif
|
||||
m_config.setPass (arg);
|
||||
m_config.setPass (std::string (arg));
|
||||
}
|
||||
|
||||
sendResponse ("200 OK\r\n");
|
||||
return;
|
||||
}
|
||||
else if (::strcasecmp (command.c_str (), "PORT") == 0)
|
||||
else if (compare (command, "PORT") == 0)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
@ -2759,7 +2785,7 @@ void FtpSession::SITE (char const *args_)
|
||||
return;
|
||||
}
|
||||
#ifdef __3DS__
|
||||
else if (::strcasecmp (command.c_str (), "MTIME") == 0)
|
||||
else if (compare (command, "MTIME") == 0)
|
||||
{
|
||||
if (arg == "0")
|
||||
{
|
||||
@ -2782,7 +2808,7 @@ void FtpSession::SITE (char const *args_)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (::strcasecmp (command.c_str (), "SAVE") == 0)
|
||||
else if (compare (command, "SAVE") == 0)
|
||||
{
|
||||
bool error;
|
||||
|
||||
@ -2825,7 +2851,7 @@ void FtpSession::SIZE (char const *args_)
|
||||
}
|
||||
|
||||
// stat the path
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
if (tzStat (path.c_str (), &st) != 0)
|
||||
{
|
||||
sendResponse ("550 %s\r\n", std::strerror (errno));
|
||||
@ -2915,7 +2941,7 @@ void FtpSession::STRU (char const *args_)
|
||||
setState (State::COMMAND, false, false);
|
||||
|
||||
// we only support F (no structure) mode
|
||||
if (::strcasecmp (args_, "F") == 0)
|
||||
if (compare (args_, "F") == 0)
|
||||
{
|
||||
sendResponse ("200 OK\r\n");
|
||||
return;
|
||||
|
@ -3,7 +3,7 @@
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2023 Michael Theall
|
||||
// Copyright (C) 2024 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
|
||||
@ -29,7 +29,10 @@
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
@ -193,7 +196,7 @@ bool platform::networkVisible ()
|
||||
|
||||
bool platform::networkAddress (SockAddr &addr_)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
// Copyright (C) 2024 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
|
||||
@ -40,7 +40,7 @@ PrintConsole g_sessionConsole;
|
||||
namespace
|
||||
{
|
||||
/// \brief Host address
|
||||
struct in_addr s_addr = {0};
|
||||
in_addr s_addr = {0};
|
||||
/// \brief Which side of double-buffer we're on
|
||||
bool s_backBuffer = false;
|
||||
/// \brief Whether to power backlight
|
||||
@ -75,7 +75,7 @@ bool platform::networkVisible ()
|
||||
|
||||
bool platform::networkAddress (SockAddr &addr_)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
|
@ -39,83 +39,80 @@ SockAddr &SockAddr::operator= (SockAddr const &that_) = default;
|
||||
|
||||
SockAddr &SockAddr::operator= (SockAddr &&that_) = default;
|
||||
|
||||
SockAddr::SockAddr (struct sockaddr_in const &addr_)
|
||||
SockAddr::SockAddr (sockaddr_in const &addr_)
|
||||
{
|
||||
assert (addr_.sin_family == AF_INET);
|
||||
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in));
|
||||
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in));
|
||||
}
|
||||
|
||||
#ifndef NO_IPV6
|
||||
SockAddr::SockAddr (struct sockaddr_in6 const &addr_)
|
||||
SockAddr::SockAddr (sockaddr_in6 const &addr_)
|
||||
{
|
||||
assert (addr_.sin6_family == AF_INET6);
|
||||
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in6));
|
||||
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in6));
|
||||
}
|
||||
#endif
|
||||
|
||||
SockAddr::SockAddr (struct sockaddr_storage const &addr_)
|
||||
SockAddr::SockAddr (sockaddr_storage const &addr_)
|
||||
{
|
||||
switch (addr_.ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
assert (addr_.ss_family == AF_INET);
|
||||
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in));
|
||||
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in));
|
||||
break;
|
||||
|
||||
#ifndef NO_IPV6
|
||||
case AF_INET6:
|
||||
assert (addr_.ss_family == AF_INET6);
|
||||
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in6));
|
||||
std::memcpy (&m_addr, &addr_, sizeof (sockaddr_in6));
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
std::abort ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SockAddr::operator struct sockaddr_in const & () const
|
||||
SockAddr::operator sockaddr_in const & () const
|
||||
{
|
||||
assert (m_addr.ss_family == AF_INET);
|
||||
return reinterpret_cast<struct sockaddr_in const &> (m_addr);
|
||||
return reinterpret_cast<sockaddr_in const &> (m_addr);
|
||||
}
|
||||
|
||||
#ifndef NO_IPV6
|
||||
SockAddr::operator struct sockaddr_in6 const & () const
|
||||
SockAddr::operator sockaddr_in6 const & () const
|
||||
{
|
||||
assert (m_addr.ss_family == AF_INET6);
|
||||
return reinterpret_cast<struct sockaddr_in6 const &> (m_addr);
|
||||
return reinterpret_cast<sockaddr_in6 const &> (m_addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
SockAddr::operator struct sockaddr_storage const & () const
|
||||
SockAddr::operator sockaddr_storage const & () const
|
||||
{
|
||||
return m_addr;
|
||||
}
|
||||
|
||||
SockAddr::operator struct sockaddr * ()
|
||||
SockAddr::operator sockaddr * ()
|
||||
{
|
||||
return reinterpret_cast<struct sockaddr *> (&m_addr);
|
||||
return reinterpret_cast<sockaddr *> (&m_addr);
|
||||
}
|
||||
|
||||
SockAddr::operator struct sockaddr const * () const
|
||||
SockAddr::operator sockaddr const * () const
|
||||
{
|
||||
return reinterpret_cast<struct sockaddr const *> (&m_addr);
|
||||
return reinterpret_cast<sockaddr const *> (&m_addr);
|
||||
}
|
||||
|
||||
bool SockAddr::setPort (std::uint16_t const port_)
|
||||
void SockAddr::setPort (std::uint16_t const port_)
|
||||
{
|
||||
switch (m_addr.ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
reinterpret_cast<struct sockaddr_in *> (&m_addr)->sin_port = htons (port_);
|
||||
return true;
|
||||
break;
|
||||
|
||||
#ifndef NO_IPV6
|
||||
case AF_INET6:
|
||||
reinterpret_cast<struct sockaddr_in6 *> (&m_addr)->sin6_port = htons (port_);
|
||||
return true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
@ -146,11 +143,11 @@ std::uint16_t SockAddr::port () const
|
||||
switch (m_addr.ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return ntohs (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_port);
|
||||
return ntohs (reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_port);
|
||||
|
||||
#ifndef NO_IPV6
|
||||
case AF_INET6:
|
||||
return ntohs (reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_port);
|
||||
return ntohs (reinterpret_cast<sockaddr_in6 const *> (&m_addr)->sin6_port);
|
||||
#endif
|
||||
|
||||
default:
|
||||
@ -167,32 +164,27 @@ char const *SockAddr::name (char *buffer_, std::size_t size_) const
|
||||
#ifdef __NDS__
|
||||
(void)buffer_;
|
||||
(void)size_;
|
||||
return inet_ntoa (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr);
|
||||
return inet_ntoa (reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_addr);
|
||||
#else
|
||||
return inet_ntop (AF_INET,
|
||||
&reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr,
|
||||
buffer_,
|
||||
size_);
|
||||
return inet_ntop (
|
||||
AF_INET, &reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_addr, buffer_, size_);
|
||||
#endif
|
||||
|
||||
#ifndef NO_IPV6
|
||||
case AF_INET6:
|
||||
return inet_ntop (AF_INET6,
|
||||
&reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_addr,
|
||||
buffer_,
|
||||
size_);
|
||||
return inet_ntop (
|
||||
AF_INET6, &reinterpret_cast<sockaddr_in6 const *> (&m_addr)->sin6_addr, buffer_, size_);
|
||||
#endif
|
||||
|
||||
default:
|
||||
std::abort ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char const *SockAddr::name () const
|
||||
{
|
||||
#ifdef __NDS__
|
||||
return inet_ntoa (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr);
|
||||
return inet_ntoa (reinterpret_cast<sockaddr_in const *> (&m_addr)->sin_addr);
|
||||
#else
|
||||
#ifdef NO_IPV6
|
||||
thread_local static char buffer[INET_ADDRSTRLEN];
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "log.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -65,7 +66,7 @@ Socket::Socket (int const fd_, SockAddr const &sockName_, SockAddr const &peerNa
|
||||
UniqueSocket Socket::accept ()
|
||||
{
|
||||
SockAddr addr;
|
||||
socklen_t addrLen = sizeof (struct sockaddr_storage);
|
||||
socklen_t addrLen = sizeof (sockaddr_storage);
|
||||
|
||||
auto const fd = ::accept (m_fd, addr, &addrLen);
|
||||
if (fd < 0)
|
||||
@ -104,7 +105,7 @@ bool Socket::bind (SockAddr const &addr_)
|
||||
if (addr_.port () == 0)
|
||||
{
|
||||
// get socket name due to request for ephemeral port
|
||||
socklen_t addrLen = sizeof (struct sockaddr_storage);
|
||||
socklen_t addrLen = sizeof (sockaddr_storage);
|
||||
if (::getsockname (m_fd, m_sockName, &addrLen) != 0)
|
||||
error ("getsockname: %s\n", std::strerror (errno));
|
||||
}
|
||||
@ -166,7 +167,7 @@ bool Socket::setLinger (bool const enable_, std::chrono::seconds const time_)
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#else
|
||||
struct linger linger;
|
||||
linger linger;
|
||||
linger.l_onoff = enable_;
|
||||
linger.l_linger = time_.count ();
|
||||
|
||||
@ -330,7 +331,7 @@ int Socket::poll (PollInfo *const info_,
|
||||
if (count_ == 0)
|
||||
return 0;
|
||||
|
||||
auto const pfd = std::make_unique<struct pollfd[]> (count_);
|
||||
auto const pfd = std::make_unique<pollfd[]> (count_);
|
||||
for (std::size_t i = 0; i < count_; ++i)
|
||||
{
|
||||
pfd[i].fd = info_[i].socket.get ().m_fd;
|
||||
@ -352,7 +353,7 @@ int Socket::poll (PollInfo *const info_,
|
||||
}
|
||||
|
||||
#ifdef __NDS__
|
||||
extern "C" int poll (struct pollfd *const fds_, nfds_t const nfds_, int const timeout_)
|
||||
extern "C" int poll (pollfd *const fds_, nfds_t const nfds_, int const timeout_)
|
||||
{
|
||||
fd_set readFds;
|
||||
fd_set writeFds;
|
||||
@ -370,7 +371,7 @@ extern "C" int poll (struct pollfd *const fds_, nfds_t const nfds_, int const ti
|
||||
FD_SET (fds_[i].fd, &writeFds);
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
timeval tv;
|
||||
tv.tv_sec = timeout_ / 1000;
|
||||
tv.tv_usec = (timeout_ % 1000) * 1000;
|
||||
auto const rc = ::select (nfds_, &readFds, &writeFds, &exceptFds, &tv);
|
||||
|
@ -5,7 +5,7 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (C) 2023 Michael Theall
|
||||
// Copyright (C) 2024 Michael Theall
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@ -42,6 +42,7 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
using stat_t = struct stat;
|
||||
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
@ -123,7 +124,7 @@ void loadShaders (dk::UniqueDevice &device_)
|
||||
/// \param path_ Path to file
|
||||
static std::size_t getSize (char const *const path_)
|
||||
{
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
auto const rc = ::stat (path_, &st);
|
||||
if (rc != 0)
|
||||
{
|
||||
|
@ -339,7 +339,7 @@ void loadTextures ()
|
||||
unsigned imageOffset = 0;
|
||||
for (auto const &textureInfo : textureInfos)
|
||||
{
|
||||
struct stat st;
|
||||
stat_t st;
|
||||
if (::stat (textureInfo.path, &st) != 0)
|
||||
{
|
||||
std::fprintf (stderr, "stat(%s): %s\n", textureInfo.path, std::strerror (errno));
|
||||
@ -618,14 +618,14 @@ bool platform::init ()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool platform::enableAP (bool const enableAP_,
|
||||
bool platform::enableAP (bool const enable_,
|
||||
std::string const &ssid_,
|
||||
std::string const &passphrase_)
|
||||
{
|
||||
if (s_activeAP == enableAP_)
|
||||
if (s_activeAP == enable_)
|
||||
return true;
|
||||
|
||||
if (enableAP_)
|
||||
if (enable_)
|
||||
{
|
||||
auto const ssidError = validateSSID (ssid_);
|
||||
if (ssidError)
|
||||
@ -781,11 +781,11 @@ bool platform::networkAddress (SockAddr &addr_)
|
||||
return false;
|
||||
}
|
||||
|
||||
addr_ = *reinterpret_cast<struct sockaddr_in *> (ipConfig.ip_addr);
|
||||
addr_ = *reinterpret_cast<sockaddr_in *> (ipConfig.ip_addr);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = gethostid ();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user