diff options
Diffstat (limited to 'src/osd/modules/file')
-rw-r--r-- | src/osd/modules/file/posixdir.cpp | 13 | ||||
-rw-r--r-- | src/osd/modules/file/posixdomain.cpp | 207 | ||||
-rw-r--r-- | src/osd/modules/file/posixfile.cpp | 236 | ||||
-rw-r--r-- | src/osd/modules/file/posixfile.h | 20 | ||||
-rw-r--r-- | src/osd/modules/file/posixptty.cpp | 68 | ||||
-rw-r--r-- | src/osd/modules/file/posixsocket.cpp | 188 | ||||
-rw-r--r-- | src/osd/modules/file/stdfile.cpp | 119 | ||||
-rw-r--r-- | src/osd/modules/file/windir.cpp | 8 | ||||
-rw-r--r-- | src/osd/modules/file/winfile.cpp | 243 | ||||
-rw-r--r-- | src/osd/modules/file/winfile.h | 25 | ||||
-rw-r--r-- | src/osd/modules/file/winptty.cpp | 56 | ||||
-rw-r--r-- | src/osd/modules/file/winrtdir.cpp | 8 | ||||
-rw-r--r-- | src/osd/modules/file/winrtfile.cpp | 26 | ||||
-rw-r--r-- | src/osd/modules/file/winrtfile.h | 2 | ||||
-rw-r--r-- | src/osd/modules/file/winrtptty.cpp | 3 | ||||
-rw-r--r-- | src/osd/modules/file/winrtsocket.cpp | 5 | ||||
-rw-r--r-- | src/osd/modules/file/winsocket.cpp | 135 |
17 files changed, 633 insertions, 729 deletions
diff --git a/src/osd/modules/file/posixdir.cpp b/src/osd/modules/file/posixdir.cpp index 2a755a513fe..282a58acfc9 100644 --- a/src/osd/modules/file/posixdir.cpp +++ b/src/osd/modules/file/posixdir.cpp @@ -22,7 +22,7 @@ #endif #endif -#ifdef WIN32 +#ifdef _WIN32 #define _FILE_OFFSET_BITS 64 #endif @@ -40,6 +40,7 @@ #define _DARWIN_C_SOURCE // to get DT_xxx on OS X #include "osdcore.h" +#include "osdfile.h" #include "modules/lib/osdlib.h" #include "util/strformat.h" @@ -62,13 +63,13 @@ namespace { // CONSTANTS //============================================================ -#if defined(WIN32) +#if defined(_WIN32) constexpr char PATHSEPCH = '\\'; #else constexpr char PATHSEPCH = '/'; #endif -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) using sdl_dirent = struct dirent; using sdl_stat = struct stat; #define sdl_readdir readdir @@ -192,7 +193,7 @@ bool posix_directory::open_impl(std::string const &dirname) { assert(!m_fd); - osd_subst_env(m_path, dirname); + m_path = dirname; m_fd.reset(::opendir(m_path.c_str())); return bool(m_fd); } @@ -223,7 +224,7 @@ directory::ptr directory::open(std::string const &dirname) // osd_subst_env //============================================================ -void osd_subst_env(std::string &dst, std::string const &src) +std::string osd_subst_env(std::string_view src) { std::string result, var; auto start = src.begin(); @@ -291,5 +292,5 @@ void osd_subst_env(std::string &dst, std::string const &src) } } - dst = std::move(result); + return result; } diff --git a/src/osd/modules/file/posixdomain.cpp b/src/osd/modules/file/posixdomain.cpp deleted file mode 100644 index 633187819a7..00000000000 --- a/src/osd/modules/file/posixdomain.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb -//============================================================ -// -// sdldomain.c - SDL socket (unix) access functions -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#include "posixfile.h" - -#include <cassert> -#include <cerrno> -#include <cstdio> - -#include <sys/select.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/time.h> -#include <unistd.h> -#include <fcntl.h> - - -namespace { -char const *const posixfile_domain_identifier = "domain."; - - -class posix_osd_domain : public osd_file -{ -public: - posix_osd_domain(posix_osd_domain const &) = delete; - posix_osd_domain(posix_osd_domain &&) = delete; - posix_osd_domain& operator=(posix_osd_domain const &) = delete; - posix_osd_domain& operator=(posix_osd_domain &&) = delete; - - posix_osd_domain(int sock, bool listening) - : m_sock(sock) - , m_listening(listening) - { - assert(m_sock >= 0); - } - - virtual ~posix_osd_domain() - { - ::close(m_sock); - } - - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override - { - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(m_sock, &readfds); - - struct timeval timeout; - timeout.tv_sec = timeout.tv_usec = 0; - - if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0) - { - char line[80]; - std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__); - std::perror(line); - return errno_to_file_error(errno); - } - else if (FD_ISSET(m_sock, &readfds)) - { - if (!m_listening) - { - // connected socket - ssize_t const result = ::read(m_sock, buffer, count); - if (result < 0) - { - return errno_to_file_error(errno); - } - else - { - actual = std::uint32_t(size_t(result)); - return error::NONE; - } - } - else - { - // listening socket - int const accepted = ::accept(m_sock, nullptr, nullptr); - if (accepted < 0) - { - return errno_to_file_error(errno); - } - else - { - ::close(m_sock); - m_sock = accepted; - m_listening = false; - actual = 0; - - return error::NONE; - } - } - } - else - { - return error::FAILURE; - } - } - - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override - { - ssize_t const result = ::write(m_sock, buffer, count); - if (result < 0) - return errno_to_file_error(errno); - - actual = std::uint32_t(size_t(result)); - return error::NONE; - } - - virtual error truncate(std::uint64_t offset) override - { - // doesn't make sense on socket - return error::INVALID_ACCESS; - } - - virtual error flush() override - { - // there's no simple way to flush buffers on a socket anyway - return error::NONE; - } - -private: - int m_sock; - bool m_listening; -}; - -} // anonymous namespace - - -bool posix_check_domain_path(std::string const &path) -{ - if (strncmp(path.c_str(), posixfile_domain_identifier, strlen(posixfile_domain_identifier)) == 0) - return true; - return false; -} - - -osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) -{ - struct sockaddr_un sau; - memset(&sau, 0, sizeof(sau)); - sau.sun_family = AF_UNIX; - strncpy(sau.sun_path, &path.c_str()[strlen(posixfile_domain_identifier)], sizeof(sau.sun_path)-1); - - int const sock = ::socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - return errno_to_file_error(errno); - - fcntl(sock, F_SETFL, O_NONBLOCK); - - // listening socket support - if (openflags & OPEN_FLAG_CREATE) - { - if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sau), sizeof(struct sockaddr_un)) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } - - // start to listen... - if (::listen(sock, 1) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } - - // mark socket as "listening" - try - { - file = std::make_unique<posix_osd_domain>(sock, true); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) - { - ::close(sock); - return osd_file::error::OUT_OF_MEMORY; - } - } - else - { - if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sau), sizeof(struct sockaddr_un)) < 0) - { - ::close(sock); - return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure - } - try - { - file = std::make_unique<posix_osd_domain>(sock, false); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) - { - ::close(sock); - return osd_file::error::OUT_OF_MEMORY; - } - } -} diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp index 8c78d28cbd5..8aebde2adc2 100644 --- a/src/osd/modules/file/posixfile.cpp +++ b/src/osd/modules/file/posixfile.cpp @@ -22,7 +22,7 @@ #endif #endif -#ifdef WIN32 +#ifdef _WIN32 #define _FILE_OFFSET_BITS 64 #endif @@ -37,8 +37,14 @@ #endif #endif +// Fix for MacOS compilation errors +#if defined(__APPLE__) && !defined(_DARWIN_C_SOURCE) +#define _DARWIN_C_SOURCE +#endif + // MAME headers #include "posixfile.h" +#include "osdcore.h" #include "unicode.h" #include <cassert> @@ -50,19 +56,20 @@ #include <vector> #include <fcntl.h> -#include <limits.h> +#include <climits> #include <sys/stat.h> -#include <stdlib.h> +#include <cstdlib> #include <unistd.h> namespace { + //============================================================ // CONSTANTS //============================================================ -#if defined(WIN32) +#if defined(_WIN32) constexpr char PATHSEPCH = '\\'; constexpr char INVPATHSEPCH = '/'; #else @@ -79,7 +86,7 @@ public: posix_osd_file& operator=(posix_osd_file const &) = delete; posix_osd_file& operator=(posix_osd_file &&) = delete; - posix_osd_file(int fd) : m_fd(fd) + posix_osd_file(int fd) noexcept : m_fd(fd) { assert(m_fd >= 0); } @@ -89,68 +96,68 @@ public: ::close(m_fd); } - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { ssize_t result; #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__) result = ::pread(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); -#elif defined(WIN32) || defined(SDLMAME_NO64BITIO) +#elif defined(_WIN32) || defined(SDLMAME_NO64BITIO) if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0) - return errno_to_file_error(errno) + return std::error_condition(errno, std::generic_category()); result = ::read(m_fd, buffer, size_t(count)); #else result = ::pread64(m_fd, buffer, size_t(count), off64_t(offset)); #endif if (result < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); actual = std::uint32_t(std::size_t(result)); - return error::NONE; + return std::error_condition(); } - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { ssize_t result; #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__) result = ::pwrite(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); -#elif defined(WIN32) || defined(SDLMAME_NO64BITIO) +#elif defined(_WIN32) || defined(SDLMAME_NO64BITIO) if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0) - return errno_to_file_error(errno) + return std::error_condition(errno, std::generic_category()); result = ::write(m_fd, buffer, size_t(count)); #else result = ::pwrite64(m_fd, buffer, size_t(count), off64_t(offset)); #endif if (result < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); actual = std::uint32_t(std::size_t(result)); - return error::NONE; + return std::error_condition(); } - virtual error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { int result; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) result = ::ftruncate(m_fd, off_t(std::make_unsigned_t<off_t>(offset))); #else result = ::ftruncate64(m_fd, off64_t(offset)); #endif if (result < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); - return error::NONE; + return std::error_condition(); } - virtual error flush() override + virtual std::error_condition flush() noexcept override { // no user-space buffering on unistd I/O - return error::NONE; + return std::error_condition(); } private: @@ -162,9 +169,9 @@ private: // is_path_separator //============================================================ -bool is_path_separator(char c) +bool is_path_separator(char c) noexcept { -#if defined(WIN32) +#if defined(_WIN32) return (c == PATHSEPCH) || (c == INVPATHSEPCH); #else return c == PATHSEPCH; @@ -176,31 +183,36 @@ bool is_path_separator(char c) // create_path_recursive //============================================================ -osd_file::error create_path_recursive(std::string const &path) +std::error_condition create_path_recursive(std::string_view path) noexcept { // if there's still a separator, and it's not the root, nuke it and recurse auto const sep = path.rfind(PATHSEPCH); - if ((sep != std::string::npos) && (sep > 0) && (path[sep - 1] != PATHSEPCH)) + if ((sep != std::string_view::npos) && (sep > 0) && (path[sep - 1] != PATHSEPCH)) { - osd_file::error const err = create_path_recursive(path.substr(0, sep)); - if (err != osd_file::error::NONE) + std::error_condition err = create_path_recursive(path.substr(0, sep)); + if (err) return err; } + // need a NUL-terminated version of the subpath + std::string p; + try { p = path; } + catch (...) { return std::errc::not_enough_memory; } + // if the path already exists, we're done struct stat st; - if (!::stat(path.c_str(), &st)) - return osd_file::error::NONE; + if (!::stat(p.c_str(), &st)) + return std::error_condition(); // create the path -#ifdef WIN32 - if (mkdir(path.c_str()) < 0) +#ifdef _WIN32 + if (mkdir(p.c_str()) < 0) #else - if (mkdir(path.c_str(), 0777) < 0) + if (mkdir(p.c_str(), 0777) < 0) #endif - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); else - return osd_file::error::NONE; + return std::error_condition(); } } // anonymous namespace @@ -210,7 +222,7 @@ osd_file::error create_path_recursive(std::string const &path) // osd_file::open //============================================================ -osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) +std::error_condition osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept { std::string dst; if (posix_check_socket_path(path)) @@ -233,23 +245,22 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, } else { - return error::INVALID_ACCESS; + return std::errc::invalid_argument; } -#if defined(WIN32) +#if defined(_WIN32) access |= O_BINARY; #endif // convert the path into something compatible dst = path; -#if defined(WIN32) +#if defined(_WIN32) for (auto it = dst.begin(); it != dst.end(); ++it) *it = (INVPATHSEPCH == *it) ? PATHSEPCH : *it; #endif - osd_subst_env(dst, dst); // attempt to open the file int fd = -1; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) fd = ::open(dst.c_str(), access, 0666); #else fd = ::open64(dst.c_str(), access, 0666); @@ -257,6 +268,9 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, if (fd < 0) { + // save the error from the first attempt to open the file + std::error_condition openerr(errno, std::generic_category()); + // create the path if necessary if ((openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS)) { @@ -264,29 +278,33 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, if (pathsep != std::string::npos) { // create the path up to the file - osd_file::error const error = create_path_recursive(dst.substr(0, pathsep)); + std::error_condition const createrr = create_path_recursive(dst.substr(0, pathsep)); // attempt to reopen the file - if (error == osd_file::error::NONE) + if (!createrr) { -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) fd = ::open(dst.c_str(), access, 0666); #else fd = ::open64(dst.c_str(), access, 0666); #endif } + if (fd < 0) + { + openerr.assign(errno, std::generic_category()); + } } } // if we still failed, clean up and free if (fd < 0) { - return errno_to_file_error(errno); + return openerr; } } // get the file size -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) struct stat st; if (::fstat(fd, &st) < 0) #else @@ -294,22 +312,20 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, if (::fstat64(fd, &st) < 0) #endif { - int const error = errno; + std::error_condition staterr(errno, std::generic_category()); ::close(fd); - return errno_to_file_error(error); + return staterr; } - filesize = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size)); - try - { - file = std::make_unique<posix_osd_file>(fd); - return error::NONE; - } - catch (...) + osd_file::ptr result(new (std::nothrow) posix_osd_file(fd)); + if (!result) { ::close(fd); - return error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } + file = std::move(result); + filesize = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size)); + return std::error_condition(); } @@ -317,9 +333,9 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, // osd_file::openpty //============================================================ -osd_file::error osd_file::openpty(ptr &file, std::string &name) +std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept { - std::uint64_t filesize; + std::uint64_t filesize; return posix_open_ptty(OPEN_FLAG_READ | OPEN_FLAG_WRITE, file, filesize, name); } @@ -328,12 +344,12 @@ osd_file::error osd_file::openpty(ptr &file, std::string &name) // osd_file::remove //============================================================ -osd_file::error osd_file::remove(std::string const &filename) +std::error_condition osd_file::remove(std::string const &filename) noexcept { if (::unlink(filename.c_str()) < -1) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); else - return error::NONE; + return std::error_condition(); } @@ -341,7 +357,7 @@ osd_file::error osd_file::remove(std::string const &filename) // osd_get_physical_drive_geometry //============================================================ -bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) +bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept { return false; // no, no way, huh-uh, forget it } @@ -353,7 +369,7 @@ bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path) { -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__) struct stat st; int const err = ::stat(path.c_str(), &st); #else @@ -364,13 +380,17 @@ std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path) // create an osd_directory_entry; be sure to make sure that the caller can // free all resources by just freeing the resulting osd_directory_entry - osd::directory::entry *result; - try { result = reinterpret_cast<osd::directory::entry *>(::operator new(sizeof(*result) + path.length() + 1)); } - catch (...) { return nullptr; } + auto const result = reinterpret_cast<osd::directory::entry *>( + ::operator new( + sizeof(osd::directory::entry) + path.length() + 1, + std::align_val_t(alignof(osd::directory::entry)), + std::nothrow)); + if (!result) return nullptr; new (result) osd::directory::entry; - std::strcpy(reinterpret_cast<char *>(result) + sizeof(*result), path.c_str()); - result->name = reinterpret_cast<char *>(result) + sizeof(*result); + auto const resultname = reinterpret_cast<char *>(result) + sizeof(*result); + std::strcpy(resultname, path.c_str()); + result->name = resultname; result->type = S_ISDIR(st.st_mode) ? osd::directory::entry::entry_type::DIR : osd::directory::entry::entry_type::FILE; result->size = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size)); result->last_modified = std::chrono::system_clock::from_time_t(st.st_mtime); @@ -383,58 +403,58 @@ std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path) // osd_get_full_path //============================================================ -osd_file::error osd_get_full_path(std::string &dst, std::string const &path) +std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept { try { -#if defined(WIN32) +#if defined(_WIN32) std::vector<char> path_buffer(MAX_PATH); if (::_fullpath(&path_buffer[0], path.c_str(), MAX_PATH)) { dst = &path_buffer[0]; - return osd_file::error::NONE; + return std::error_condition(); } else { - return osd_file::error::FAILURE; + return std::errc::io_error; // TODO: better error reporting? } #else std::unique_ptr<char, void (*)(void *)> canonical(::realpath(path.c_str(), nullptr), &std::free); if (canonical) { dst = canonical.get(); - return osd_file::error::NONE; + return std::error_condition(); } std::vector<char> path_buffer(PATH_MAX); if (::realpath(path.c_str(), &path_buffer[0])) { dst = &path_buffer[0]; - return osd_file::error::NONE; + return std::error_condition(); } else if (path[0] == PATHSEPCH) { dst = path; - return osd_file::error::NONE; + return std::error_condition(); } else { while (!::getcwd(&path_buffer[0], path_buffer.size())) { if (errno != ERANGE) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); else path_buffer.resize(path_buffer.size() * 2); } dst.assign(&path_buffer[0]).push_back(PATHSEPCH); dst.append(path); - return osd_file::error::NONE; + return std::error_condition(); } #endif } catch (...) { - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } } @@ -443,11 +463,11 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path) // osd_is_absolute_path //============================================================ -bool osd_is_absolute_path(std::string const &path) +bool osd_is_absolute_path(std::string const &path) noexcept { if (!path.empty() && is_path_separator(path[0])) return true; -#if !defined(WIN32) +#if !defined(_WIN32) else if (!path.empty() && (path[0] == '.') && (!path[1] || is_path_separator(path[1]))) // FIXME: why is this even here? foo/./bar is a valid way to refer to foo/bar return true; #elif !defined(UNDER_CE) @@ -463,12 +483,22 @@ bool osd_is_absolute_path(std::string const &path) // osd_get_volume_name //============================================================ -const char *osd_get_volume_name(int idx) +std::string osd_get_volume_name(int idx) { if (idx == 0) return "/"; else - return nullptr; + return std::string(); +} + + +//============================================================ +// osd_get_volume_names +//============================================================ + +std::vector<std::string> osd_get_volume_names() +{ + return std::vector<std::string>{ "/" }; } @@ -476,12 +506,12 @@ const char *osd_get_volume_name(int idx) // osd_is_valid_filename_char //============================================================ -bool osd_is_valid_filename_char(char32_t uchar) +bool osd_is_valid_filename_char(char32_t uchar) noexcept { // The only one that's actually invalid is the slash // The other two are just problematic because they're the escape character and path separator return osd_is_valid_filepath_char(uchar) -#if defined(WIN32) +#if defined(_WIN32) && uchar != PATHSEPCH && uchar != INVPATHSEPCH #else @@ -496,12 +526,12 @@ bool osd_is_valid_filename_char(char32_t uchar) // osd_is_valid_filepath_char //============================================================ -bool osd_is_valid_filepath_char(char32_t uchar) +bool osd_is_valid_filepath_char(char32_t uchar) noexcept { // One could argue that colon should be in here too because it functions as path separator return uchar >= 0x20 && !(uchar >= '\x7F' && uchar <= '\x9F') -#if defined(WIN32) +#if defined(_WIN32) && uchar != '<' && uchar != '>' && uchar != '\"' @@ -511,39 +541,3 @@ bool osd_is_valid_filepath_char(char32_t uchar) #endif && uchar_isvalid(uchar); } - - -//============================================================ -// errno_to_file_error -//============================================================ - -osd_file::error errno_to_file_error(int error) -{ - switch (error) - { - case 0: - return osd_file::error::NONE; - - case ENOENT: - case ENOTDIR: - return osd_file::error::NOT_FOUND; - - case EACCES: - case EROFS: -#ifndef WIN32 - case ETXTBSY: -#endif - case EEXIST: - case EPERM: - case EISDIR: - case EINVAL: - return osd_file::error::ACCESS_DENIED; - - case ENFILE: - case EMFILE: - return osd_file::error::TOO_MANY_FILES; - - default: - return osd_file::error::FAILURE; - } -} diff --git a/src/osd/modules/file/posixfile.h b/src/osd/modules/file/posixfile.h index 6f585ff827a..eb6f010859e 100644 --- a/src/osd/modules/file/posixfile.h +++ b/src/osd/modules/file/posixfile.h @@ -7,25 +7,29 @@ // SDLMAME by Olivier Galibert and R. Belmont // //============================================================ +#ifndef MAME_OSD_MODULES_FILE_POSIXFILE_H +#define MAME_OSD_MODULES_FILE_POSIXFILE_H +#pragma once -#include "osdcore.h" +#include "osdfile.h" #include <cstdint> #include <string> +#include <system_error> //============================================================ // PROTOTYPES //============================================================ -bool posix_check_socket_path(std::string const &path); -osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); +bool posix_check_socket_path(std::string const &path) noexcept; +std::error_condition posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept; -bool posix_check_domain_path(std::string const &path); -osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); +bool posix_check_domain_path(std::string const &path) noexcept; +std::error_condition posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept; -bool posix_check_ptty_path(std::string const &path); -osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name); +bool posix_check_ptty_path(std::string const &path) noexcept; +std::error_condition posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name) noexcept; -osd_file::error errno_to_file_error(int error); +#endif // MAME_OSD_MODULES_FILE_POSIXFILE_H diff --git a/src/osd/modules/file/posixptty.cpp b/src/osd/modules/file/posixptty.cpp index 6e468cf172f..57ff069a2ce 100644 --- a/src/osd/modules/file/posixptty.cpp +++ b/src/osd/modules/file/posixptty.cpp @@ -15,11 +15,11 @@ #include <cstring> #include <fcntl.h> -#include <limits.h> +#include <climits> #include <unistd.h> -#include <stdlib.h> +#include <cstdlib> -#if defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#if defined(__FreeBSD__) || defined(__DragonFly__) #include <termios.h> #include <libutil.h> #elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) @@ -52,7 +52,7 @@ public: posix_osd_ptty& operator=(posix_osd_ptty const &) = delete; posix_osd_ptty& operator=(posix_osd_ptty &&) = delete; - posix_osd_ptty(int fd) : m_fd(fd) + posix_osd_ptty(int fd) noexcept : m_fd(fd) { assert(m_fd >= 0); } @@ -62,36 +62,36 @@ public: ::close(m_fd); } - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { ssize_t const result = ::read(m_fd, buffer, count); if (result < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); actual = std::uint32_t(size_t(result)); - return error::NONE; + return std::error_condition(); } - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { ssize_t const result = ::write(m_fd, buffer, count); if (result < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); actual = std::uint32_t(size_t(result)); - return error::NONE; + return std::error_condition(); } - virtual error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { // doesn't make sense on ptty - return error::INVALID_ACCESS; + return std::errc::bad_file_descriptor; } - virtual error flush() override + virtual std::error_condition flush() noexcept override { // no userspace buffers on read/write - return error::NONE; + return std::error_condition(); } private: @@ -101,14 +101,18 @@ private: } // anonymous namespace -bool posix_check_ptty_path(std::string const &path) +bool posix_check_ptty_path(std::string const &path) noexcept { return strncmp(path.c_str(), posix_ptty_identifier, strlen(posix_ptty_identifier)) == 0; } -osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name) +std::error_condition posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name) noexcept { +#if defined(__ANDROID__) + return std::errc::not_supported; // TODO: revisit this error code +#else // defined(__ANDROID__) + // TODO: handling of the slave path is insecure - should use ptsname_r/ttyname_r in a loop #if (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)) int access = O_NOCTTY; if (openflags & OPEN_FLAG_WRITE) @@ -116,11 +120,11 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st else if (openflags & OPEN_FLAG_READ) access |= O_RDONLY; else - return osd_file::error::INVALID_ACCESS; + return std::errc::invalid_argument; int const masterfd = ::posix_openpt(access); if (masterfd < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); // grant access to slave device and check that it can be opened char const *slavepath; @@ -130,9 +134,9 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st ((slavepath = ::ptsname(masterfd)) == nullptr) || ((slavefd = ::open(slavepath, O_RDWR | O_NOCTTY)) < 0)) { - int const err = errno; + std::error_condition err(errno, std::generic_category()); ::close(masterfd); - return errno_to_file_error(err); + return err; } // check that it's possible to stack BSD-compatibility STREAMS modules @@ -140,23 +144,20 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st (::ioctl(slavefd, I_PUSH, "ldterm") < 0) || (::ioctl(slavefd, I_PUSH, "ttcompat") < 0)) { - int const err = errno; + std::error_condition err(errno, std::generic_category()); ::close(slavefd); ::close(masterfd); - return errno_to_file_error(err); + return err; } -#elif defined(__ANDROID__) - int masterfd = -1, slavefd = -1; - char slavepath[PATH_MAX]; #else struct termios tios; std::memset(&tios, 0, sizeof(tios)); - ::cfmakeraw(&tios); + ::cfmakeraw(&tios); // TODO: this is a non-standard BSDism - should set flags some other way int masterfd = -1, slavefd = -1; char slavepath[PATH_MAX]; if (::openpty(&masterfd, &slavefd, slavepath, &tios, nullptr) < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); #endif ::close(slavefd); @@ -164,16 +165,16 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st int const oldflags = ::fcntl(masterfd, F_GETFL, 0); if (oldflags < 0) { - int const err = errno; + std::error_condition err(errno, std::generic_category()); ::close(masterfd); - return errno_to_file_error(err); + return err; } if (::fcntl(masterfd, F_SETFL, oldflags | O_NONBLOCK) < 0) { - int const err = errno; + std::error_condition err(errno, std::generic_category()); ::close(masterfd); - return errno_to_file_error(err); + return err; } try @@ -181,11 +182,12 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st name = slavepath; file = std::make_unique<posix_osd_ptty>(masterfd); filesize = 0; - return osd_file::error::NONE; + return std::error_condition(); } catch (...) { ::close(masterfd); - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } +#endif // defined(__ANDROID__) } diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp index edb95816077..6a23e747ea1 100644 --- a/src/osd/modules/file/posixsocket.cpp +++ b/src/osd/modules/file/posixsocket.cpp @@ -2,7 +2,8 @@ // copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb //============================================================ // -// sdlsocket.c - SDL socket (inet) access functions +// sdlsocket.c - SDL socket (inet, unix domain) access +// functions // // SDLMAME by Olivier Galibert and R. Belmont // @@ -13,19 +14,24 @@ #include <cassert> #include <cerrno> #include <cstdio> +#include <cstring> #include <arpa/inet.h> +#include <fcntl.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <sys/select.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/un.h> #include <unistd.h> namespace { + char const *const posixfile_socket_identifier = "socket."; +char const *const posixfile_domain_identifier = "domain."; class posix_osd_socket : public osd_file @@ -36,7 +42,7 @@ public: posix_osd_socket& operator=(posix_osd_socket const &) = delete; posix_osd_socket& operator=(posix_osd_socket &&) = delete; - posix_osd_socket(int sock, bool listening) + posix_osd_socket(int sock, bool listening) noexcept : m_sock(sock) , m_listening(listening) { @@ -48,7 +54,7 @@ public: ::close(m_sock); } - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { fd_set readfds; FD_ZERO(&readfds); @@ -57,12 +63,9 @@ public: struct timeval timeout; timeout.tv_sec = timeout.tv_usec = 0; - if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0) + if (::select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0) { - char line[80]; - std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__); - std::perror(line); - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); } else if (FD_ISSET(m_sock, &readfds)) { @@ -72,12 +75,12 @@ public: ssize_t const result = ::read(m_sock, buffer, count); if (result < 0) { - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); } else { actual = std::uint32_t(size_t(result)); - return error::NONE; + return std::error_condition(); } } else @@ -86,7 +89,7 @@ public: int const accepted = ::accept(m_sock, nullptr, nullptr); if (accepted < 0) { - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); } else { @@ -95,36 +98,38 @@ public: m_listening = false; actual = 0; - return error::NONE; + return std::error_condition(); } } } else { - return error::FAILURE; + // no data available + actual = 0; + return std::errc::operation_would_block; } } - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { ssize_t const result = ::write(m_sock, buffer, count); if (result < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); actual = std::uint32_t(size_t(result)); - return error::NONE; + return std::error_condition(); } - virtual error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { // doesn't make sense on socket - return error::INVALID_ACCESS; + return std::errc::bad_file_descriptor; } - virtual error flush() override + virtual std::error_condition flush() noexcept override { // there's no simple way to flush buffers on a socket anyway - return error::NONE; + return std::error_condition(); } private: @@ -132,6 +137,54 @@ private: bool m_listening; }; + +template <typename T> +std::error_condition create_socket(T const &sa, int sock, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept +{ + osd_file::ptr result; + if (openflags & OPEN_FLAG_CREATE) + { + // listening socket support + // bind socket... + if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sa), sizeof(sa)) < 0) + { + std::error_condition binderr(errno, std::generic_category()); + ::close(sock); + return binderr; + } + + // start to listen... + if (::listen(sock, 1) < 0) + { + std::error_condition lstnerr(errno, std::generic_category()); + ::close(sock); + return lstnerr; + } + + // mark socket as "listening" + result.reset(new (std::nothrow) posix_osd_socket(sock, true)); + } + else + { + if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sa), sizeof(sa)) < 0) + { + std::error_condition connerr(errno, std::generic_category()); + ::close(sock); + return connerr; + } + result.reset(new (std::nothrow) posix_osd_socket(sock, false)); + } + + if (!result) + { + ::close(sock); + return std::errc::not_enough_memory; + } + file = std::move(result); + filesize = 0; + return std::error_condition(); +} + } // anonymous namespace @@ -140,7 +193,7 @@ private: specification has the format "socket." host ":" port. Host may be simple or fully qualified. Port must be between 1 and 65535. */ -bool posix_check_socket_path(std::string const &path) +bool posix_check_socket_path(std::string const &path) noexcept { if (strncmp(path.c_str(), posixfile_socket_identifier, strlen(posixfile_socket_identifier)) == 0 && strchr(path.c_str(), ':') != nullptr) return true; @@ -148,7 +201,15 @@ bool posix_check_socket_path(std::string const &path) } -osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +bool posix_check_domain_path(std::string const &path) noexcept +{ + if (strncmp(path.c_str(), posixfile_domain_identifier, strlen(posixfile_domain_identifier)) == 0) + return true; + return false; +} + + +std::error_condition posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept { char hostname[256]; int port; @@ -156,7 +217,7 @@ osd_file::error posix_open_socket(std::string const &path, std::uint32_t openfla struct hostent const *const localhost = ::gethostbyname(hostname); if (!localhost) - return osd_file::error::NOT_FOUND; + return std::errc::no_such_file_or_directory; struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); @@ -166,75 +227,38 @@ osd_file::error posix_open_socket(std::string const &path, std::uint32_t openfla int const sock = ::socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); int const flag = 1; - if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) + if ((::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) || + (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0)) { - int const err = errno; + std::error_condition sockopterr(errno, std::generic_category()); ::close(sock); - return errno_to_file_error(err); + return sockopterr; } - if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } + return create_socket(sai, sock, openflags, file, filesize); +} - // listening socket support - if (openflags & OPEN_FLAG_CREATE) - { - //printf("Listening for client at '%s' on port '%d'\n", hostname, port); - // bind socket... - if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } +std::error_condition posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept +{ + struct sockaddr_un sau; + memset(&sau, 0, sizeof(sau)); + sau.sun_family = AF_UNIX; + strncpy(sau.sun_path, &path.c_str()[strlen(posixfile_domain_identifier)], sizeof(sau.sun_path)-1); - // start to listen... - if (::listen(sock, 1) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } + int const sock = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return std::error_condition(errno, std::generic_category()); - // mark socket as "listening" - try - { - file = std::make_unique<posix_osd_socket>(sock, true); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) - { - ::close(sock); - return osd_file::error::OUT_OF_MEMORY; - } - } - else + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { - //printf("Connecting to server '%s' on port '%d'\n", hostname, port); - if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0) - { - ::close(sock); - return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure - } - try - { - file = std::make_unique<posix_osd_socket>(sock, false); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) - { - ::close(sock); - return osd_file::error::OUT_OF_MEMORY; - } + std::error_condition cntlerr(errno, std::generic_category()); + ::close(sock); + return cntlerr; } + + return create_socket(sau, sock, openflags, file, filesize); } diff --git a/src/osd/modules/file/stdfile.cpp b/src/osd/modules/file/stdfile.cpp index cb1f1b536b2..4fd4662b884 100644 --- a/src/osd/modules/file/stdfile.cpp +++ b/src/osd/modules/file/stdfile.cpp @@ -7,11 +7,14 @@ //============================================================ #include "osdcore.h" +#include "osdfile.h" #include <cassert> +#include <cerrno> #include <cstdint> #include <cstdio> #include <cstdlib> +#include <limits> #include <string> #include <stdio.h> // for fileno @@ -19,11 +22,15 @@ namespace { + class std_osd_file : public osd_file { public: - std_osd_file(FILE *f) : m_file(f) { assert(m_file); } + std_osd_file(FILE *f) noexcept : m_file(f) + { + assert(m_file); + } //============================================================ // osd_close @@ -32,59 +39,81 @@ public: virtual ~std_osd_file() override { // close the file handle - if (m_file) std::fclose(m_file); + if (m_file) + std::fclose(m_file); } //============================================================ // osd_read //============================================================ - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override { - // seek to the new location; note that most fseek implementations are limited to 32 bits + // seek to the new location; note that most fseek implementations are limited to the range of long int + if (std::numeric_limits<long>::max() < offset) + return std::errc::invalid_argument; if (std::fseek(m_file, offset, SEEK_SET) < 0) - return error::FAILURE; + return std::error_condition(errno, std::generic_category()); // perform the read std::size_t const count = std::fread(buffer, 1, length, m_file); + if ((count < length) && std::ferror(m_file)) + { + std::clearerr(m_file); + return std::error_condition(errno, std::generic_category()); + } actual = count; - return error::NONE; + return std::error_condition(); } //============================================================ // osd_write //============================================================ - virtual error write(const void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + virtual std::error_condition write(const void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override { - // seek to the new location; note that most fseek implementations are limited to 32 bits + // seek to the new location; note that most fseek implementations are limited to the range of long int + if (std::numeric_limits<long>::max() < offset) + return std::errc::invalid_argument; if (std::fseek(m_file, offset, SEEK_SET) < 0) - return error::FAILURE; + return std::error_condition(errno, std::generic_category()); // perform the write std::size_t const count = std::fwrite(buffer, 1, length, m_file); + if (count < length) + { + std::clearerr(m_file); + return std::error_condition(errno, std::generic_category()); + } actual = count; - return error::NONE; + return std::error_condition(); } //============================================================ // osd_truncate //============================================================ - error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { - return (ftruncate(fileno(m_file), offset) < 0) ? error::FAILURE : error::NONE; + // this is present in POSIX but not C/C++ + if (::ftruncate(::fileno(m_file), offset) < 0) + return std::error_condition(errno, std::generic_category()); + else + return std::error_condition(); } //============================================================ // osd_fflush //============================================================ - virtual error flush() override + virtual std::error_condition flush() noexcept override { - return (std::fflush(m_file) == EOF) ? error::FAILURE : error::NONE; + if (!std::fflush(m_file)) + return std::error_condition(); + else + return std::error_condition(errno, std::generic_category()); } private: @@ -98,7 +127,7 @@ private: // osd_open //============================================================ -osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) +std::error_condition osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept { // based on the flags, choose a mode const char *mode; @@ -112,12 +141,12 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, else if (openflags & OPEN_FLAG_READ) mode = "rb"; else - return error::INVALID_ACCESS; + return std::errc::invalid_argument; // open the file FILE *const fileptr = std::fopen(path.c_str(), mode); if (!fileptr) - return error::NOT_FOUND; + return std::error_condition(errno, std::generic_category()); // get the size -- note that most fseek/ftell implementations are limited to 32 bits long length; @@ -125,21 +154,20 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ((length = std::ftell(fileptr)) < 0) || (std::fseek(fileptr, 0, SEEK_SET) < 0)) { + std::error_condition err(errno, std::generic_category()); std::fclose(fileptr); - return error::FAILURE; + return err; } - try - { - file = std::make_unique<std_osd_file>(fileptr); - filesize = std::int64_t(length); - return error::NONE; - } - catch (...) + osd_file::ptr result(new (std::nothrow) std_osd_file(fileptr)); + if (!result) { std::fclose(fileptr); - return error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } + file = std::move(result); + filesize = std::int64_t(length); + return std::error_condition(); } @@ -147,9 +175,9 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, // osd_openpty //============================================================ -osd_file::error osd_file::openpty(ptr &file, std::string &name) +std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept { - return error::FAILURE; + return std::errc::not_supported; } @@ -157,9 +185,12 @@ osd_file::error osd_file::openpty(ptr &file, std::string &name) // osd_rmfile //============================================================ -osd_file::error osd_file::remove(std::string const &filename) +std::error_condition osd_file::remove(std::string const &filename) noexcept { - return (std::remove(filename.c_str()) < 0) ? error::FAILURE : error::NONE; + if (!std::remove(filename.c_str())) + return std::error_condition(); + else + return std::error_condition(errno, std::generic_category()); } @@ -167,7 +198,7 @@ osd_file::error osd_file::remove(std::string const &filename) // osd_get_physical_drive_geometry //============================================================ -bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) +bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept { // there is no standard way of doing this, so we always return false, indicating // that a given path is not a physical drive @@ -179,7 +210,7 @@ bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, // osd_uchar_from_osdchar //============================================================ -int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count) +int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count) noexcept { // we assume a standard 1:1 mapping of characters to the first 256 unicode characters *uchar = (uint8_t)*osdchar; @@ -219,13 +250,14 @@ osd_directory_entry *osd_stat(const std::string &path) // osd_get_full_path //============================================================ -osd_file::error osd_get_full_path(std::string &dst, std::string const &path) +std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept { // derive the full path of the file in an allocated string // for now just fake it since we don't presume any underlying file system - dst = path; + try { dst = path; } + catch (...) { return std::errc::not_enough_memory; } - return osd_file::error::NONE; + return std::error_condition(); } @@ -233,7 +265,7 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path) // osd_is_absolute_path //============================================================ -bool osd_is_absolute_path(std::string const &path) +bool osd_is_absolute_path(std::string const &path) noexcept { // assume no for everything return false; @@ -244,8 +276,19 @@ bool osd_is_absolute_path(std::string const &path) // osd_get_volume_name //============================================================ -const char *osd_get_volume_name(int idx) +std::string osd_get_volume_name(int idx) +{ + // we don't expose volumes + return std::string(); +} + + +//============================================================ +// osd_get_volume_names +//============================================================ + +std::vector<std::string> osd_get_volume_names() { // we don't expose volumes - return nullptr; + return std::vector<std::string>(); } diff --git a/src/osd/modules/file/windir.cpp b/src/osd/modules/file/windir.cpp index f9575b27e74..34606dcba6f 100644 --- a/src/osd/modules/file/windir.cpp +++ b/src/osd/modules/file/windir.cpp @@ -12,7 +12,7 @@ #include <tchar.h> // MAME headers -#include "osdcore.h" +#include "osdfile.h" #include "strformat.h" // MAMEOS headers @@ -20,8 +20,8 @@ #include "winutil.h" // standard C headers -#include <stdio.h> -#include <ctype.h> +#include <cstdio> +#include <cctype> #include <cassert> #include <cstring> @@ -108,7 +108,7 @@ bool win_directory::open_impl(std::string const &dirname) assert(m_find == INVALID_HANDLE_VALUE); // append \*.* to the directory name - std::string dirfilter = string_format("%s\\*.*", dirname); + std::string dirfilter = util::string_format("%s\\*.*", dirname); // convert the path to TCHARs osd::text::tstring t_dirfilter = osd::text::to_tstring(dirfilter); diff --git a/src/osd/modules/file/winfile.cpp b/src/osd/modules/file/winfile.cpp index 5df7c4bb8b1..84c754cdd6f 100644 --- a/src/osd/modules/file/winfile.cpp +++ b/src/osd/modules/file/winfile.cpp @@ -6,7 +6,6 @@ // //============================================================ - #include "winfile.h" // MAMEOS headers @@ -20,17 +19,19 @@ #include <cassert> #include <cstring> +#include <memory> // standard windows headers #include <windows.h> #include <winioctl.h> #include <tchar.h> #include <shlwapi.h> -#include <stdlib.h> -#include <ctype.h> +#include <cstdlib> +#include <cctype> namespace { + //============================================================ // TYPE DEFINITIONS //============================================================ @@ -43,7 +44,7 @@ public: win_osd_file& operator=(win_osd_file const &) = delete; win_osd_file& operator=(win_osd_file &&) = delete; - win_osd_file(HANDLE handle) : m_handle(handle) + win_osd_file(HANDLE handle) noexcept : m_handle(handle) { assert(m_handle); assert(INVALID_HANDLE_VALUE != m_handle); @@ -55,59 +56,59 @@ public: CloseHandle(m_handle); } - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override { // attempt to set the file pointer LARGE_INTEGER largeOffset; largeOffset.QuadPart = offset; if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); // then perform the read DWORD result = 0; if (!ReadFile(m_handle, buffer, length, &result, nullptr)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); actual = result; - return error::NONE; + return std::error_condition(); } - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override { // attempt to set the file pointer LARGE_INTEGER largeOffset; largeOffset.QuadPart = offset; if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); // then perform the write DWORD result = 0; if (!WriteFile(m_handle, buffer, length, &result, nullptr)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); actual = result; - return error::NONE; + return std::error_condition(); } - virtual error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { // attempt to set the file pointer LARGE_INTEGER largeOffset; largeOffset.QuadPart = offset; if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); // then perform the truncation if (!SetEndOfFile(m_handle)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); else - return error::NONE; + return std::error_condition(); } - virtual error flush() override + virtual std::error_condition flush() noexcept override { // shouldn't be any userspace buffers on the file handle - return error::NONE; + return std::error_condition(); } private: @@ -160,22 +161,19 @@ DWORD create_path_recursive(TCHAR *path) // osd_open //============================================================ -osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, ptr &file, std::uint64_t &filesize) +std::error_condition osd_file::open(std::string const &path, uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept { - std::string path; - try { osd_subst_env(path, orig_path); } - catch (...) { return error::OUT_OF_MEMORY; } - if (win_check_socket_path(path)) return win_open_socket(path, openflags, file, filesize); else if (win_check_ptty_path(path)) return win_open_ptty(path, openflags, file, filesize); // convert path to TCHAR - osd::text::tstring t_path = osd::text::to_tstring(path); + osd::text::tstring t_path; + try { t_path = osd::text::to_tstring(path); } + catch (...) { return std::errc::not_enough_memory; } - // convert the path into something Windows compatible (the actual interesting part appears - // to have been commented out???) + // convert the path into something Windows compatible (the actual interesting part appears to have been commented out???) for (auto iter = t_path.begin(); iter != t_path.end(); iter++) *iter = /* ('/' == *iter) ? '\\' : */ *iter; @@ -185,7 +183,8 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, { disposition = (!is_path_to_physical_drive(path.c_str()) && (openflags & OPEN_FLAG_CREATE)) ? CREATE_ALWAYS : OPEN_EXISTING; access = (openflags & OPEN_FLAG_READ) ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE; - if (is_path_to_physical_drive(path.c_str())) access |= GENERIC_READ; + if (is_path_to_physical_drive(path.c_str())) + access |= GENERIC_READ; sharemode = FILE_SHARE_READ; } else if (openflags & OPEN_FLAG_READ) @@ -196,7 +195,7 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, } else { - return error::INVALID_ACCESS; + return std::errc::invalid_argument; } // attempt to open the file @@ -226,7 +225,7 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, // if we still failed, clean up and free if (INVALID_HANDLE_VALUE == h) - return win_error_to_file_error(err); + return win_error_to_error_condition(err); } // get the file size @@ -256,21 +255,19 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, if (NO_ERROR != err) { CloseHandle(h); - return win_error_to_file_error(err); + return win_error_to_error_condition(err); } } - try - { - file = std::make_unique<win_osd_file>(h); - filesize = (std::uint64_t(upper) << 32) | lower; - return error::NONE; - } - catch (...) + osd_file::ptr result(new (std::nothrow) win_osd_file(h)); + if (!result) { CloseHandle(h); - return error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } + file = std::move(result); + filesize = (std::uint64_t(upper) << 32) | lower; + return std::error_condition(); } @@ -279,9 +276,9 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, // osd_openpty //============================================================ -osd_file::error osd_file::openpty(ptr &file, std::string &name) +std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept { - return error::FAILURE; + return std::errc::not_supported; // TODO: revisit this error code } @@ -290,13 +287,15 @@ osd_file::error osd_file::openpty(ptr &file, std::string &name) // osd_rmfile //============================================================ -osd_file::error osd_file::remove(std::string const &filename) +std::error_condition osd_file::remove(std::string const &filename) noexcept { - osd::text::tstring tempstr = osd::text::to_tstring(filename); + osd::text::tstring tempstr; + try { tempstr = osd::text::to_tstring(filename); } + catch (...) { return std::errc::not_enough_memory; } - error filerr = error::NONE; + std::error_condition filerr; if (!DeleteFile(tempstr.c_str())) - filerr = win_error_to_file_error(GetLastError()); + filerr = win_error_to_error_condition(GetLastError()); return filerr; } @@ -307,7 +306,7 @@ osd_file::error osd_file::remove(std::string const &filename) // osd_get_physical_drive_geometry //============================================================ -bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) +bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept { DISK_GEOMETRY dg; DWORD bytesRead; @@ -319,10 +318,17 @@ bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, return false; // do a create file on the drive - auto t_filename = osd::text::to_tstring(filename); - file = CreateFile(t_filename.c_str(), GENERIC_READ, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr); - if (file == INVALID_HANDLE_VALUE) + try + { + auto t_filename = osd::text::to_tstring(filename); + file = CreateFile(t_filename.c_str(), GENERIC_READ, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr); + if (file == INVALID_HANDLE_VALUE) + return false; + } + catch (...) + { return false; + } // device I/O control should return the geometry result = DeviceIoControl(file, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0, &dg, sizeof(dg), &bytesRead, nullptr); @@ -397,19 +403,29 @@ std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path) // osd_get_full_path //============================================================ -osd_file::error osd_get_full_path(std::string &dst, std::string const &path) +std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept { - // convert the path to TCHARs - osd::text::tstring t_path = osd::text::to_tstring(path); - - // canonicalize the path - TCHAR buffer[MAX_PATH]; - if (!GetFullPathName(t_path.c_str(), ARRAY_LENGTH(buffer), buffer, nullptr)) - return win_error_to_file_error(GetLastError()); - - // convert the result back to UTF-8 - osd::text::from_tstring(dst, buffer); - return osd_file::error::NONE; + try + { + // get the length of the full path + std::wstring const w_path(osd::text::to_wstring(path)); + DWORD const length(GetFullPathNameW(w_path.c_str(), 0, nullptr, nullptr)); + if (!length) + return win_error_to_error_condition(GetLastError()); + + // allocate a buffer and get the canonical path + std::unique_ptr<wchar_t []> buffer(std::make_unique<wchar_t []>(length)); + if (!GetFullPathNameW(w_path.c_str(), length, buffer.get(), nullptr)) + return win_error_to_error_condition(GetLastError()); + + // convert the result back to UTF-8 + osd::text::from_wstring(dst, buffer.get()); + return std::error_condition(); + } + catch (...) + { + return std::errc::not_enough_memory; // the string conversions can throw bad_alloc + } } @@ -418,10 +434,9 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path) // osd_is_absolute_path //============================================================ -bool osd_is_absolute_path(std::string const &path) +bool osd_is_absolute_path(std::string const &path) noexcept { - osd::text::tstring t_path = osd::text::to_tstring(path); - return !PathIsRelative(t_path.c_str()); + return !PathIsRelativeW(osd::text::to_wstring(path).c_str()); } @@ -430,20 +445,57 @@ bool osd_is_absolute_path(std::string const &path) // osd_get_volume_name //============================================================ -const char *osd_get_volume_name(int idx) +std::string osd_get_volume_name(int idx) { - static char szBuffer[128]; - const char *p; + std::vector<wchar_t> buffer; + DWORD length(GetLogicalDriveStringsW(0, nullptr)); + while (length && (buffer.size() < (length + 1))) + { + buffer.clear(); + buffer.resize(length + 1); + length = GetLogicalDriveStringsW(length, &buffer[0]); + } + if (!length) + return std::string(); + + wchar_t const *p(&buffer[0]); + while (idx-- && *p) + { + while (*p++) { } + } + + std::string result; + osd::text::from_wstring(result, p); + return result; +} - GetLogicalDriveStringsA(ARRAY_LENGTH(szBuffer), szBuffer); - p = szBuffer; - while(idx--) { - p += strlen(p) + 1; - if (!*p) return nullptr; +//============================================================ +// osd_get_volume_names +//============================================================ + +std::vector<std::string> osd_get_volume_names() +{ + std::vector<std::string> result; + std::vector<wchar_t> buffer; + DWORD length(GetLogicalDriveStringsW(0, nullptr)); + while (length && (buffer.size() < (length + 1))) + { + buffer.clear(); + buffer.resize(length + 1); + length = GetLogicalDriveStringsW(length, &buffer[0]); } + if (!length) + return result; - return p; + wchar_t const *p(&buffer[0]); + std::wstring vol; + while (*p) + { + osd::text::from_wstring(result.emplace_back(), p); + while (*p++) { } + } + return result; } @@ -452,7 +504,7 @@ const char *osd_get_volume_name(int idx) // osd_is_valid_filename_char //============================================================ -bool osd_is_valid_filename_char(char32_t uchar) +bool osd_is_valid_filename_char(char32_t uchar) noexcept { return osd_is_valid_filepath_char(uchar) && uchar != '/' @@ -466,7 +518,7 @@ bool osd_is_valid_filename_char(char32_t uchar) // osd_is_valid_filepath_char //============================================================ -bool osd_is_valid_filepath_char(char32_t uchar) +bool osd_is_valid_filepath_char(char32_t uchar) noexcept { return uchar >= 0x20 && uchar != '<' @@ -478,46 +530,3 @@ bool osd_is_valid_filepath_char(char32_t uchar) && !(uchar >= '\x7F' && uchar <= '\x9F') && uchar_isvalid(uchar); } - - - -//============================================================ -// win_error_to_file_error -//============================================================ - -osd_file::error win_error_to_file_error(DWORD error) -{ - osd_file::error filerr; - - // convert a Windows error to a osd_file::error - switch (error) - { - case ERROR_SUCCESS: - filerr = osd_file::error::NONE; - break; - - case ERROR_OUTOFMEMORY: - filerr = osd_file::error::OUT_OF_MEMORY; - break; - - case ERROR_FILE_NOT_FOUND: - case ERROR_FILENAME_EXCED_RANGE: - case ERROR_PATH_NOT_FOUND: - case ERROR_INVALID_NAME: - filerr = osd_file::error::NOT_FOUND; - break; - - case ERROR_ACCESS_DENIED: - filerr = osd_file::error::ACCESS_DENIED; - break; - - case ERROR_SHARING_VIOLATION: - filerr = osd_file::error::ALREADY_OPEN; - break; - - default: - filerr = osd_file::error::FAILURE; - break; - } - return filerr; -} diff --git a/src/osd/modules/file/winfile.h b/src/osd/modules/file/winfile.h index 9a6f1b8fc34..90cf6e69a60 100644 --- a/src/osd/modules/file/winfile.h +++ b/src/osd/modules/file/winfile.h @@ -5,13 +5,16 @@ // winfile.h - File access functions // //============================================================ -#ifndef MAME_OSD_WINDOWS_WINFILE_H -#define MAME_OSD_WINDOWS_WINFILE_H +#ifndef MAME_OSD_MODULES_FILE_WINFILE_H +#define MAME_OSD_MODULES_FILE_WINFILE_H -#include "osdcore.h" +#pragma once + +#include "osdfile.h" #include <cstdint> #include <string> +#include <system_error> #include <winsock2.h> @@ -20,15 +23,13 @@ // PROTOTYPES //============================================================ -bool win_init_sockets(); -void win_cleanup_sockets(); - -bool win_check_socket_path(std::string const &path); -osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); +bool win_init_sockets() noexcept; +void win_cleanup_sockets() noexcept; -bool win_check_ptty_path(std::string const &path); -osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); +bool win_check_socket_path(std::string const &path) noexcept; +std::error_condition win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept; -osd_file::error win_error_to_file_error(DWORD error); +bool win_check_ptty_path(std::string const &path) noexcept; +std::error_condition win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept; -#endif // MAME_OSD_WINDOWS_WINFILE_H +#endif // MAME_OSD_MODULES_FILE_WINFILE_H diff --git a/src/osd/modules/file/winptty.cpp b/src/osd/modules/file/winptty.cpp index 943f1fbaa52..9aac0c5a990 100644 --- a/src/osd/modules/file/winptty.cpp +++ b/src/osd/modules/file/winptty.cpp @@ -8,12 +8,14 @@ #include "winutil.h" #include <cassert> +#include <cstdlib> +#include <cstring> #include <windows.h> -#include <stdlib.h> namespace { + char const *const winfile_ptty_identifier = "\\\\.\\pipe\\"; @@ -25,7 +27,7 @@ public: win_osd_ptty& operator=(win_osd_ptty const &) = delete; win_osd_ptty& operator=(win_osd_ptty &&) = delete; - win_osd_ptty(HANDLE handle) : m_handle(handle) + win_osd_ptty(HANDLE handle) noexcept : m_handle(handle) { assert(m_handle); assert(INVALID_HANDLE_VALUE != m_handle); @@ -38,36 +40,36 @@ public: CloseHandle(m_handle); } - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { DWORD bytes_read; if (!ReadFile(m_handle, buffer, count, &bytes_read, nullptr)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); actual = bytes_read; - return error::NONE; + return std::error_condition(); } - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { DWORD bytes_written; if (!WriteFile(m_handle, buffer, count, &bytes_written, nullptr)) - return win_error_to_file_error(GetLastError()); + return win_error_to_error_condition(GetLastError()); actual = bytes_written; - return error::NONE; + return std::error_condition(); } - virtual error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { // doesn't make sense for a PTTY - return error::INVALID_ACCESS; + return std::errc::bad_file_descriptor; } - virtual error flush() override + virtual std::error_condition flush() noexcept override { // don't want to wait for client to read all data as implied by FlushFileBuffers - return error::NONE; + return std::error_condition(); } private: @@ -77,40 +79,42 @@ private: } // anonymous namespace -bool win_check_ptty_path(std::string const &path) +bool win_check_ptty_path(std::string const &path) noexcept { if (strncmp(path.c_str(), winfile_ptty_identifier, strlen(winfile_ptty_identifier)) == 0) return true; return false; } -osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +std::error_condition win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept { - osd::text::tstring t_name = osd::text::to_tstring(path); + osd::text::tstring t_name; + try { t_name = osd::text::to_tstring(path); } + catch (...) { return std::errc::not_enough_memory; } HANDLE pipe = CreateFileW(t_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if (INVALID_HANDLE_VALUE == pipe) { - pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr); + if (openflags & OPEN_FLAG_CREATE) + pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr); if (INVALID_HANDLE_VALUE == pipe) - return osd_file::error::ACCESS_DENIED; + return win_error_to_error_condition(GetLastError()); } else { DWORD state = PIPE_NOWAIT; - SetNamedPipeHandleState(pipe, &state, NULL, NULL); + SetNamedPipeHandleState(pipe, &state, nullptr, nullptr); + // TODO: check for error? } - try - { - file = std::make_unique<win_osd_ptty>(pipe); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) + osd_file::ptr result(new (std::nothrow) win_osd_ptty(pipe)); + if (!result) { CloseHandle(pipe); - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } + file = std::move(result); + filesize = 0; + return std::error_condition(); } diff --git a/src/osd/modules/file/winrtdir.cpp b/src/osd/modules/file/winrtdir.cpp index be42b6fd874..19c328ea094 100644 --- a/src/osd/modules/file/winrtdir.cpp +++ b/src/osd/modules/file/winrtdir.cpp @@ -12,16 +12,16 @@ #include <tchar.h> // MAME headers -#include "osdcore.h" #include "strformat.h" // MAMEOS headers +#include "osdfile.h" #include "strconv.h" #include "../../windows/winutil.h" // standard C headers -#include <stdio.h> -#include <ctype.h> +#include <cstdio> +#include <cctype> #include <cassert> #include <cstring> @@ -108,7 +108,7 @@ bool win_directory::open_impl(std::string const &dirname) assert(m_find == INVALID_HANDLE_VALUE); // append \*.* to the directory name - std::string dirfilter = string_format("%s\\*.*", dirname); + std::string dirfilter = util::string_format("%s\\*.*", dirname); // convert the path to TCHARs osd::text::tstring t_dirfilter = osd::text::to_tstring(dirfilter); diff --git a/src/osd/modules/file/winrtfile.cpp b/src/osd/modules/file/winrtfile.cpp index 83d8d7c4915..5053f6e0199 100644 --- a/src/osd/modules/file/winrtfile.cpp +++ b/src/osd/modules/file/winrtfile.cpp @@ -26,8 +26,8 @@ #include <winioctl.h> #include <tchar.h> #include <shlwapi.h> -#include <stdlib.h> -#include <ctype.h> +#include <cstdlib> +#include <cctype> namespace { @@ -160,12 +160,8 @@ DWORD create_path_recursive(TCHAR *path) // osd_open //============================================================ -osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, ptr &file, std::uint64_t &filesize) +osd_file::error osd_file::open(std::string const &path, uint32_t openflags, ptr &file, std::uint64_t &filesize) { - std::string path; - try { osd_subst_env(path, orig_path); } - catch (...) { return error::OUT_OF_MEMORY; } - if (win_check_socket_path(path)) return win_open_socket(path, openflags, file, filesize); else if (win_check_ptty_path(path)) @@ -350,7 +346,7 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path) // canonicalize the path TCHAR buffer[MAX_PATH]; - if (!GetFullPathName(t_path.c_str(), ARRAY_LENGTH(buffer), buffer, nullptr)) + if (!GetFullPathName(t_path.c_str(), std::size(buffer), buffer, nullptr)) return win_error_to_file_error(GetLastError()); // convert the result back to UTF-8 @@ -380,9 +376,19 @@ bool osd_is_absolute_path(std::string const &path) // osd_get_volume_name //============================================================ -const char *osd_get_volume_name(int idx) +std::string osd_get_volume_name(int idx) +{ + return std::string(); +} + + +//============================================================ +// osd_get_volume_names +//============================================================ + +std::vector<std::string> osd_get_volume_names() { - return nullptr; + return std::vector<std::string>(); } diff --git a/src/osd/modules/file/winrtfile.h b/src/osd/modules/file/winrtfile.h index 9a6f1b8fc34..927cb299545 100644 --- a/src/osd/modules/file/winrtfile.h +++ b/src/osd/modules/file/winrtfile.h @@ -8,7 +8,7 @@ #ifndef MAME_OSD_WINDOWS_WINFILE_H #define MAME_OSD_WINDOWS_WINFILE_H -#include "osdcore.h" +#include "osdfile.h" #include <cstdint> #include <string> diff --git a/src/osd/modules/file/winrtptty.cpp b/src/osd/modules/file/winrtptty.cpp index ec1e6e73b38..cda1f128503 100644 --- a/src/osd/modules/file/winrtptty.cpp +++ b/src/osd/modules/file/winrtptty.cpp @@ -9,7 +9,8 @@ #include <cassert> #include <windows.h> -#include <stdlib.h> +#include <cstdlib> +#include <cstring> namespace { diff --git a/src/osd/modules/file/winrtsocket.cpp b/src/osd/modules/file/winrtsocket.cpp index 3f2241c25b5..d66551870f9 100644 --- a/src/osd/modules/file/winrtsocket.cpp +++ b/src/osd/modules/file/winrtsocket.cpp @@ -14,13 +14,14 @@ #include <cassert> #include <cstdio> +#include <cstring> // standard windows headers #include <windows.h> #include <winioctl.h> #include <tchar.h> -#include <stdlib.h> -#include <ctype.h> +#include <cstdlib> +#include <cctype> namespace { diff --git a/src/osd/modules/file/winsocket.cpp b/src/osd/modules/file/winsocket.cpp index a383a876f9d..d04538963ea 100644 --- a/src/osd/modules/file/winsocket.cpp +++ b/src/osd/modules/file/winsocket.cpp @@ -6,7 +6,6 @@ // //============================================================ - #include "winfile.h" // MAMEOS headers @@ -17,16 +16,18 @@ #include <cassert> #include <cstdio> +#include <cstring> // standard windows headers #include <windows.h> #include <winioctl.h> #include <tchar.h> -#include <stdlib.h> -#include <ctype.h> +#include <cstdlib> +#include <cctype> namespace { + char const *const winfile_socket_identifier = "socket."; @@ -38,7 +39,7 @@ public: win_osd_socket& operator=(win_osd_socket const &) = delete; win_osd_socket& operator=(win_osd_socket &&) = delete; - win_osd_socket(SOCKET s, bool l) + win_osd_socket(SOCKET s, bool l) noexcept : m_socket(s) , m_listening(l) { @@ -50,7 +51,7 @@ public: closesocket(m_socket); } - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override { fd_set readfds; FD_ZERO(&readfds); @@ -61,10 +62,7 @@ public: if (select(m_socket + 1, &readfds, nullptr, nullptr, &timeout) < 0) { - char line[80]; - std::sprintf(line, "win_read_socket : %s : %d ", __FILE__, __LINE__); - std::perror(line); - return error::FAILURE; + return wsa_error_to_file_error(WSAGetLastError()); } else if (FD_ISSET(m_socket, &readfds)) { @@ -79,7 +77,7 @@ public: else { actual = result; - return error::NONE; + return std::error_condition(); } } else @@ -97,50 +95,82 @@ public: m_listening = false; actual = 0; - return error::NONE; + return std::error_condition(); } } } else { - return error::FAILURE; + // no data available + actual = 0; + return std::errc::operation_would_block; } } - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override { auto const result = send(m_socket, reinterpret_cast<const char *>(buffer), length, 0); if (result < 0) return wsa_error_to_file_error(WSAGetLastError()); actual = result; - return error::NONE; + return std::error_condition(); } - virtual error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { // doesn't make sense for a socket - return error::INVALID_ACCESS; + return std::errc::bad_file_descriptor; } - virtual error flush() override + virtual std::error_condition flush() noexcept override { // no buffers to flush - return error::NONE; + return std::error_condition(); } - static error wsa_error_to_file_error(int err) + static std::error_condition wsa_error_to_file_error(int err) { + // TODO: determine if there's a better way to do this switch (err) { - case 0: return error::NONE; - case WSAEACCES: return error::ACCESS_DENIED; - case WSAEADDRINUSE: return error::ALREADY_OPEN; - case WSAEADDRNOTAVAIL: return error::NOT_FOUND; - case WSAECONNREFUSED: return error::NOT_FOUND; - case WSAEHOSTUNREACH: return error::NOT_FOUND; - case WSAENETUNREACH: return error::NOT_FOUND; - default: return error::FAILURE; + case 0: return std::error_condition(); + case WSA_NOT_ENOUGH_MEMORY: return std::errc::not_enough_memory; + case WSA_INVALID_PARAMETER: return std::errc::invalid_argument; + case WSAEINTR: return std::errc::interrupted; + case WSAEBADF: return std::errc::bad_file_descriptor; + case WSAEACCES: return std::errc::permission_denied; + case WSAEFAULT: return std::errc::bad_address; + case WSAEINVAL: return std::errc::invalid_argument; + case WSAEMFILE: return std::errc::too_many_files_open; + case WSAENETRESET: return std::errc::network_reset; + case WSAECONNABORTED: return std::errc::connection_aborted; + case WSAEWOULDBLOCK: return std::errc::operation_would_block; + case WSAEINPROGRESS: return std::errc::operation_in_progress; + case WSAEALREADY: return std::errc::connection_already_in_progress; + case WSAENOTSOCK: return std::errc::not_a_socket; + case WSAEDESTADDRREQ: return std::errc::destination_address_required; + case WSAEMSGSIZE: return std::errc::message_size; + case WSAEPROTOTYPE: return std::errc::wrong_protocol_type; + case WSAENOPROTOOPT: return std::errc::no_protocol_option; + case WSAEPROTONOSUPPORT: return std::errc::protocol_not_supported; + case WSAEOPNOTSUPP: return std::errc::operation_not_supported; + case WSAEAFNOSUPPORT: return std::errc::address_family_not_supported; + case WSAEADDRINUSE: return std::errc::address_in_use; + case WSAEADDRNOTAVAIL: return std::errc::address_not_available; + case WSAENETDOWN: return std::errc::network_down; + case WSAENETUNREACH: return std::errc::network_unreachable; + case WSAECONNRESET: return std::errc::connection_reset; + case WSAENOBUFS: return std::errc::no_buffer_space; + case WSAEISCONN: return std::errc::already_connected; + case WSAENOTCONN: return std::errc::not_connected; + case WSAETIMEDOUT: return std::errc::timed_out; + case WSAECONNREFUSED: return std::errc::connection_refused; + case WSAEHOSTUNREACH: return std::errc::host_unreachable; + case WSAECANCELLED: return std::errc::operation_canceled; + + // TODO: better default error code? + default: return std::errc::io_error; } } @@ -152,7 +182,7 @@ private: } // anonymous namespace -bool win_init_sockets() +bool win_init_sockets() noexcept { WSADATA wsaData; WORD const version = MAKEWORD(2, 0); @@ -178,13 +208,13 @@ bool win_init_sockets() } -void win_cleanup_sockets() +void win_cleanup_sockets() noexcept { WSACleanup(); } -bool win_check_socket_path(std::string const &path) +bool win_check_socket_path(std::string const &path) noexcept { if (strncmp(path.c_str(), winfile_socket_identifier, strlen(winfile_socket_identifier)) == 0 && strchr(path.c_str(), ':') != nullptr) return true; @@ -192,7 +222,7 @@ bool win_check_socket_path(std::string const &path) } -osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +std::error_condition win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept { char hostname[256]; int port; @@ -200,7 +230,7 @@ osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags struct hostent const *const localhost = gethostbyname(hostname); if (!localhost) - return osd_file::error::NOT_FOUND; + return std::errc::no_such_file_or_directory; struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); @@ -221,11 +251,12 @@ osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags } // listening socket support + osd_file::ptr result; if (openflags & OPEN_FLAG_CREATE) { //printf("Listening for client at '%s' on port '%d'\n", hostname, port); // bind socket... - if (bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) == SOCKET_ERROR) + if (bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(sai)) == SOCKET_ERROR) { int const err = WSAGetLastError(); closesocket(sock); @@ -241,36 +272,26 @@ osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags } // mark socket as "listening" - try - { - file = std::make_unique<win_osd_socket>(sock, true); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) - { - closesocket(sock); - return osd_file::error::OUT_OF_MEMORY; - } + result.reset(new (std::nothrow) win_osd_socket(sock, true)); } else { //printf("Connecting to server '%s' on port '%d'\n", hostname, port); - if (connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) == SOCKET_ERROR) - { - closesocket(sock); - return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure - } - try - { - file = std::make_unique<win_osd_socket>(sock, false); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) + if (connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(sai)) == SOCKET_ERROR) { + int const err = WSAGetLastError(); closesocket(sock); - return osd_file::error::OUT_OF_MEMORY; + return win_osd_socket::wsa_error_to_file_error(err); } + result.reset(new (std::nothrow) win_osd_socket(sock, false)); + } + + if (!result) + { + closesocket(sock); + return std::errc::not_enough_memory; } + file = std::move(result); + filesize = 0; + return std::error_condition(); } |