summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/file/posixfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/file/posixfile.cpp')
-rw-r--r--src/osd/modules/file/posixfile.cpp236
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;
- }
-}