diff options
author | 2021-08-22 09:06:15 +1000 | |
---|---|---|
committer | 2021-08-22 09:06:15 +1000 | |
commit | e8bbea1fc6e94e14768509d322f6c624403ffb36 (patch) | |
tree | 74dd1606a900d83de8aecff17a6737af4113308d /src/osd/modules/file/posixfile.cpp | |
parent | e319bde5fc3696d7f48f62b15b6366c4377fe5d1 (diff) |
formats, osd, util: Started refactoring file I/O stuff. (#8456)
Added more modern generic I/O interfaces with implementation backed by stdio, osd_file and core_file, replacing io_generic. Also replaced core_file's build-in zlib compression with a filter.
unzip.cpp, un7z.cpp: Added option to supply abstract I/O interface rather than filename.
Converted osd_file, core_file, archive_file, chd_file and device_image_interface to use std::error_condition rather than their own error enums.
Allow mounting TI-99 RPK from inside archives.
Diffstat (limited to 'src/osd/modules/file/posixfile.cpp')
-rw-r--r-- | src/osd/modules/file/posixfile.cpp | 166 |
1 files changed, 71 insertions, 95 deletions
diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp index ffdd4c4d477..b7c1cde7442 100644 --- a/src/osd/modules/file/posixfile.cpp +++ b/src/osd/modules/file/posixfile.cpp @@ -64,6 +64,7 @@ namespace { + //============================================================ // CONSTANTS //============================================================ @@ -85,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); } @@ -95,7 +96,7 @@ 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; @@ -103,20 +104,20 @@ public: result = ::pread(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); #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; @@ -124,20 +125,20 @@ public: result = ::pwrite(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); #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; @@ -148,15 +149,15 @@ public: #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: @@ -168,7 +169,7 @@ private: // is_path_separator //============================================================ -bool is_path_separator(char c) +bool is_path_separator(char c) noexcept { #if defined(WIN32) return (c == PATHSEPCH) || (c == INVPATHSEPCH); @@ -182,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) + 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 @@ -216,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)) @@ -239,7 +245,7 @@ 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) access |= O_BINARY; @@ -251,7 +257,8 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, for (auto it = dst.begin(); it != dst.end(); ++it) *it = (INVPATHSEPCH == *it) ? PATHSEPCH : *it; #endif - osd_subst_env(dst, dst); + try { osd_subst_env(dst, dst); } + catch (...) { return std::errc::not_enough_memory; } // attempt to open the file int fd = -1; @@ -263,6 +270,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)) { @@ -270,10 +280,10 @@ 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__) fd = ::open(dst.c_str(), access, 0666); @@ -281,13 +291,17 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, 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; } } @@ -300,22 +314,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(); } @@ -323,9 +335,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); } @@ -334,12 +346,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(); } @@ -347,7 +359,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 } @@ -389,7 +401,7 @@ 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 { @@ -398,49 +410,49 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &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; } } @@ -449,7 +461,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 { if (!path.empty() && is_path_separator(path[0])) return true; @@ -492,7 +504,7 @@ std::vector<std::string> osd_get_volume_names() // 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 @@ -512,7 +524,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 { // One could argue that colon should be in here too because it functions as path separator return uchar >= 0x20 @@ -527,39 +539,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; - } -} |