diff options
Diffstat (limited to 'src/osd/modules/file/posixfile.cpp')
-rw-r--r-- | src/osd/modules/file/posixfile.cpp | 236 |
1 files changed, 115 insertions, 121 deletions
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; - } -} |