From d12a961627d1ebb64a64c59b8a82874f9069b936 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sun, 23 Jul 2017 15:29:28 -0400 Subject: [PATCH] updated finder_info, mapped_file, etc --- appledouble.cpp | 29 ++- applesingle.cpp | 27 ++- dot_clean.cpp | 7 +- finder_info_helper.cpp | 417 ++++++++++++++++++++++++++++++++++++----- finder_info_helper.h | 68 +++++-- mapped_file.cpp | 58 ++++-- mapped_file.h | 76 ++++++-- 7 files changed, 570 insertions(+), 112 deletions(-) diff --git a/appledouble.cpp b/appledouble.cpp index 5beb925..9bef760 100644 --- a/appledouble.cpp +++ b/appledouble.cpp @@ -29,6 +29,12 @@ #include "applefile.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + + #if defined(__linux__) #define XATTR_RESOURCEFORK_NAME "user.com.apple.ResourceFork" #endif @@ -78,12 +84,12 @@ std::vector read_resource_fork(const std::string &path, std::error_code struct stat st; #if defined(__sun__) - fd = attropen(path.c_str(), XATTR_RESOURCEFORK_NAME, O_RDONLY); + fd = attropen(path.c_str(), XATTR_RESOURCEFORK_NAME, O_RDONLY | O_BINARY); #else std::string p(path); p += ":" XATTR_RESOURCEFORK_NAME; - fd = open(p.c_str(), O_RDONLY); + fd = open(p.c_str(), O_RDONLY | O_BINARY); #endif if (fd < 0) { ec = std::error_code(errno, std::generic_category()); @@ -117,7 +123,7 @@ std::vector read_resource_fork(const std::string &path, std::error_code return rv; #else - int fd = open(path.c_str(), O_RDONLY); + int fd = open(path.c_str(), O_RDONLY | O_BINARY); if (fd < 0) { ec = std::error_code(errno, std::generic_category()); return rv; @@ -127,8 +133,11 @@ std::vector read_resource_fork(const std::string &path, std::error_code ssize_t size = size_xattr(fd, XATTR_RESOURCEFORK_NAME); if (size < 0) { if (errno == EINTR) continue; - if (errno != ENOATTR) - ec = std::error_code(errno, std::generic_category()); + if (errno == ENOATTR) { + rv.clear(); + break; + } + ec = std::error_code(errno, std::generic_category()); close(fd); return rv; } @@ -138,6 +147,10 @@ std::vector read_resource_fork(const std::string &path, std::error_code ssize_t rsize = read_xattr(fd, XATTR_RESOURCEFORK_NAME, rv.data(), size); if (rsize < 0) { if (errno == ERANGE || errno == EINTR) continue; // try again. + if (errno == ENOATTR) { + rv.clear(); + break; + } ec = std::error_code(errno, std::generic_category()); rv.clear(); break; @@ -210,13 +223,13 @@ void one_file(const std::string &infile, const std::string &outfile) { std::error_code ec; finder_info_helper fi; - bool fi_ok = fi.open(infile); + bool fi_ok = fi.open(infile, ec); // ENOATTR is ok... but that's not an errc... std::vector resource = read_resource_fork(infile, ec); - if (ec && ec.value() != ENOATTR) { + if (ec) { warnc(ec.value(), "%s resource fork\n", infile.c_str()); return; } @@ -230,7 +243,7 @@ void one_file(const std::string &infile, const std::string &outfile) { if (fi_ok) count++; - int fd = open(outfile.c_str(), O_WRONLY | O_CREAT, 0666); + int fd = open(outfile.c_str(), O_WRONLY | O_CREAT | O_BINARY, 0666); memset(&head, 0, sizeof(head)); head.magicNum = htonl(APPLEDOUBLE_MAGIC); head.versionNum = htonl(0x00020000); diff --git a/applesingle.cpp b/applesingle.cpp index e91c14b..77f187a 100644 --- a/applesingle.cpp +++ b/applesingle.cpp @@ -28,6 +28,9 @@ #include "applefile.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif #if defined(__linux__) #define XATTR_RESOURCEFORK_NAME "user.com.apple.ResourceFork" @@ -78,12 +81,12 @@ std::vector read_resource_fork(const std::string &path, std::error_code struct stat st; #if defined(__sun__) - fd = attropen(path.c_str(), XATTR_RESOURCEFORK_NAME, O_RDONLY); + fd = attropen(path.c_str(), XATTR_RESOURCEFORK_NAME, O_RDONLY | O_BINARY); #else std::string p(path); p += ":" XATTR_RESOURCEFORK_NAME; - fd = open(p.c_str(), O_RDONLY); + fd = open(p.c_str(), O_RDONLY | O_BINARY); #endif if (fd < 0) { ec = std::error_code(errno, std::generic_category()); @@ -117,7 +120,7 @@ std::vector read_resource_fork(const std::string &path, std::error_code return rv; #else - int fd = open(path.c_str(), O_RDONLY); + int fd = open(path.c_str(), O_RDONLY | O_BINARY); if (fd < 0) { ec = std::error_code(errno, std::generic_category()); return rv; @@ -127,8 +130,11 @@ std::vector read_resource_fork(const std::string &path, std::error_code ssize_t size = size_xattr(fd, XATTR_RESOURCEFORK_NAME); if (size < 0) { if (errno == EINTR) continue; - if (errno != ENOATTR) - ec = std::error_code(errno, std::generic_category()); + if (errno == ENOATTR) { + rv.clear(); + break; + } + ec = std::error_code(errno, std::generic_category()); close(fd); return rv; } @@ -138,6 +144,10 @@ std::vector read_resource_fork(const std::string &path, std::error_code ssize_t rsize = read_xattr(fd, XATTR_RESOURCEFORK_NAME, rv.data(), size); if (rsize < 0) { if (errno == ERANGE || errno == EINTR) continue; // try again. + if (errno == ENOATTR) { + rv.clear(); + break; + } ec = std::error_code(errno, std::generic_category()); rv.clear(); break; @@ -210,13 +220,14 @@ void one_file(const std::string &infile, const std::string &outfile) { std::error_code ec; finder_info_helper fi; - bool fi_ok = fi.open(infile); + + bool fi_ok = fi.open(infile, ec); // ENOATTR is ok... but that's not an errc... std::vector resource = read_resource_fork(infile, ec); - if (ec && ec.value() != ENOATTR) { + if (ec) { warnc(ec.value(), "%s resource fork\n", infile.c_str()); return; } @@ -230,7 +241,7 @@ void one_file(const std::string &infile, const std::string &outfile) { if (fi_ok) count++; - int fd = open(outfile.c_str(), O_WRONLY | O_CREAT, 0666); + int fd = open(outfile.c_str(), O_WRONLY | O_CREAT | O_BINARY, 0666); memset(&head, 0, sizeof(head)); head.magicNum = htonl(APPLESINGLE_MAGIC); head.versionNum = htonl(0x00020000); diff --git a/dot_clean.cpp b/dot_clean.cpp index dbe65b5..5f587d9 100644 --- a/dot_clean.cpp +++ b/dot_clean.cpp @@ -267,10 +267,11 @@ void one_file(const std::string &data, const std::string &rsrc) noexcept try { }); finder_info_helper fi; - bool fi_ok = false; + std::error_code ec; bool update_fi = false; + bool fi_ok = false; - fi_ok = fi.open(data, false); + fi_ok = fi.open(data, finder_info_helper::read_write, ec); std::for_each(begin, end, [&](const ASEntry &tmp){ @@ -320,7 +321,7 @@ void one_file(const std::string &data, const std::string &rsrc) noexcept try { }); if (update_fi) { - if (!fi.write()) { + if (!fi.write(ec)) { throw_errno("com.apple.FinderInfo"); } } diff --git a/finder_info_helper.cpp b/finder_info_helper.cpp index 470579a..bfa9125 100644 --- a/finder_info_helper.cpp +++ b/finder_info_helper.cpp @@ -8,19 +8,28 @@ #include #include -#include "xattr.h" - #if defined(__APPLE__) #include #endif #if defined(__linux__) +#include #define XATTR_FINDERINFO_NAME "user.com.apple.FinderInfo" #define XATTR_RESOURCEFORK_NAME "user.com.apple.ResourceFork" #endif +#if defined(__FreeBSD__) +#include +#include +#endif + +#if defined(_AIX) +#include +#endif + #if defined (_WIN32) +#include #define XATTR_FINDERINFO_NAME "AFP_AfpInfo" #endif @@ -198,24 +207,241 @@ namespace { } - int fi_open(const std::string &path, bool read_only) { + template + T _(const T t, std::error_code &ec) { + if (t < 0) ec = std::error_code(errno, std::generic_category()); + return t; + } + + /* + * extended attributes functions. + */ + #if defined(__APPLE__) + ssize_t size_xattr(int fd, const char *xattr) { + return fgetxattr(fd, xattr, NULL, 0, 0, 0); + } + + ssize_t read_xattr(int fd, const char *xattr, void *buffer, size_t size) { + return fgetxattr(fd, xattr, buffer, size, 0, 0); + } + + ssize_t write_xattr(int fd, const char *xattr, const void *buffer, size_t size) { + if (fsetxattr(fd, xattr, buffer, size, 0, 0) < 0) return -1; + return size; + } + + int remove_xattr(int fd, const char *xattr) { + return fremovexattr(fd, xattr, 0); + } + + #elif defined(__linux__) + ssize_t size_xattr(int fd, const char *xattr) { + return fgetxattr(fd, xattr, NULL, 0); + } + + ssize_t read_xattr(int fd, const char *xattr, void *buffer, size_t size) { + return fgetxattr(fd, xattr, buffer, size); + } + + ssize_t write_xattr(int fd, const char *xattr, const void *buffer, size_t size) { + if (fsetxattr(fd, xattr, buffer, size, 0) < 0) return -1; + return size; + } + + int remove_xattr(int fd, const char *xattr) { + return fremovexattr(fd, xattr); + } + + #elif defined(__FreeBSD__) + ssize_t size_xattr(int fd, const char *xattr) { + return extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, xattr, NULL, 0); + } + + ssize_t read_xattr(int fd, const char *xattr, void *buffer, size_t size) { + return extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, xattr, buffer, size); + } + + ssize_t write_xattr(int fd, const char *xattr, const void *buffer, size_t size) { + return extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, xattr, buffer, size); + } + + int remove_xattr(int fd, const char *xattr) { + return extattr_delete_fd(fd, EXTATTR_NAMESPACE_USER, xattr); + } + + #elif defined(_AIX) + ssize_t size_xattr(int fd, const char *xattr) { + /* + struct stat64x st; + if (fstatea(fd, xattr, &st) < 0) return -1; + return st.st_size; + */ + return fgetea(fd, xattr, NULL, 0); + } + + ssize_t read_xattr(int fd, const char *xattr, void *buffer, size_t size) { + return fgetea(fd, xattr, buffer, size); + } + + ssize_t write_xattr(int fd, const char *xattr, const void *buffer, size_t size) { + if (fsetea(fd, xattr, buffer, size, 0) < 0) return -1; + return size; + } + + int remove_xattr(int fd, const char *xattr) { + return fremoveea(fd, xattr); + } + + #endif + + + void set_or_throw_error(std::error_code *ec, int error, const std::string &what) { + if (ec) *ec = std::error_code(error, std::system_category()); + else throw std::system_error(error, std::system_category(), what); + } + + + + +#if defined(_WIN32) + + /* + * allocating a new string could reset GetLastError() to 0. + */ + void set_or_throw_error(std::error_code *ec, const char *what) { + auto e = GetLastError(); + set_or_throw_error(ec, e, what); + } + + void set_or_throw_error(std::error_code *ec, const std::string &what) { + auto e = GetLastError(); + set_or_throw_error(ec, e, what); + } + + template + HANDLE CreateFileX(const std::string &s, Args... args) { + return CreateFileA(s.c_str(), std::forward(args)...); + } + + template + HANDLE CreateFileX(const std::wstring &s, Args... args) { + return CreateFileW(s.c_str(), std::forward(args)...); + } + + void fi_close(void *fd) { + CloseHandle(fd); + } + + void *fi_open(const std::string &path, int perm, std::error_code &ec) { + + ec.clear(); - #if defined(__sun__) - if (read_only) return attropen(path.c_str(), XATTR_FINDERINFO_NAME, O_RDONLY); - else return attropen(path.c_str(), XATTR_FINDERINFO_NAME, O_RDWR | O_CREAT, 0666); - #elif defined(_WIN32) std::string s(path); s.append(":" XATTR_FINDERINFO_NAME); - if (read_only) return open(s.c_str(), O_RDONLY | O_BINARY); - else return open(s.c_str(), O_RDWR | O_CREAT | O_BINARY, 0666); - #else + HANDLE fh; + bool ro = perm == 1; + + fh = CreateFileX(s, + ro ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + nullptr, + ro ? OPEN_EXISTING : OPEN_ALWAYS, + ro ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL, + nullptr); + + if (fh == INVALID_HANDLE_VALUE) + set_or_throw_error(&ec, "CreateFile"); + + return fh; + } + + void *fi_open(const std::wstring &path, int perm, std::error_code &ec) { + + ec.clear(); + + std::wstring s(path); + s.append(L":" XATTR_FINDERINFO_NAME); + + HANDLE fh; + bool ro = perm == 1; + + fh = CreateFileX(s, + ro ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + nullptr, + ro ? OPEN_EXISTING : OPEN_ALWAYS, + ro ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL, + nullptr); + + if (fh == INVALID_HANDLE_VALUE) + set_or_throw_error(&ec, "CreateFile"); + + return fh; + } + + int fi_write(void *handle, const void *data, int length, std::error_code &ec) { + + ec.clear(); + DWORD rv = 0; + BOOL ok; + + LARGE_INTEGER zero = { 0 }; + + ok = SetFilePointerEx(handle, zero, nullptr, FILE_BEGIN); + if (!ok) { + set_or_throw_error(&ec, "SetFilePointerEx"); + return 0; + } + ok = WriteFile(handle, data, length, &rv, nullptr); + if (!ok) { + set_or_throw_error(&ec, "WriteFile"); + return 0; + } + return rv; + } + + int fi_read(void *handle, void *data, int length, std::error_code &ec) { + + ec.clear(); + DWORD rv = 0; + BOOL ok; + LARGE_INTEGER zero = { 0 }; + + ok = SetFilePointerEx(handle, zero, nullptr, FILE_BEGIN); + if (!ok) { + set_or_throw_error(&ec, "SetFilePointerEx"); + return 0; + } + ok = ReadFile(handle, data, length, &rv, nullptr); + if (!ok) { + set_or_throw_error(&ec, "ReadFile"); + return 0; + } + return rv; + } + +#else + + void fi_close(int fd) { + close(fd); + } + + int fi_open(const std::string &path, int perm, std::error_code &ec) { + + #if defined(__sun__) + if (perm == 1) return attropen(path.c_str(), XATTR_FINDERINFO_NAME, O_RDONLY); + else return attropen(path.c_str(), XATTR_FINDERINFO_NAME, O_RDWR | O_CREAT, 0666); + #else + // linux needs to open as read/write to write it? + //return open(path.c_str(), read_only ? O_RDONLY : O_RDWR); return open(path.c_str(), O_RDONLY); #endif } - int fi_write(int fd, const void *data, int length) { - #if defined(__sun__) || defined(_WIN32) + + int fi_write(int fd, const void *data, int length, std::error_code &ec) { + #if defined(__sun__) lseek(fd, 0, SEEK_SET); return write(fd, data, length); #else @@ -223,8 +449,8 @@ namespace { #endif } - int fi_read(int fd, void *data, int length) { - #if defined(__sun__) || defined(_WIN32) + int fi_read(int fd, void *data, int length, std::error_code &ec) { + #if defined(__sun__) lseek(fd, 0, SEEK_SET); return read(fd, data, length); #else @@ -232,6 +458,9 @@ namespace { #endif } +#endif + + #if defined(_WIN32) void afp_init(struct AFP_Info *info) { //static_assert(sizeof(AFP_Info) == 60, "Incorrect AFP_Info size"); @@ -274,10 +503,12 @@ enum { void afp_synchronize(struct AFP_Info *info, int trust) { // if ftype/auxtype is inconsistent between prodos and finder info, use // prodos as source of truth. - uint16_t f; - uint32_t a; - if (finder_info_to_filetype(info->finder_info, &f, &a) != 0) return; - if (f == info->prodos_file_type && a == info->prodos_aux_type) return; + uint16_t f = 0; + uint32_t a = 0; + if (finder_info_to_filetype(info->finder_info, &f, &a)) { + if (f == info->prodos_file_type && a == info->prodos_aux_type) return; + } + if (trust == trust_prodos) file_type_to_finder_info(info->finder_info, info->prodos_file_type, info->prodos_aux_type); else { @@ -300,71 +531,150 @@ finder_info_helper::finder_info_helper() { #endif } -finder_info_helper::~finder_info_helper() { +void finder_info_helper::close() { +#if _WIN32 + if (_fd != INVALID_HANDLE_VALUE) CloseHandle(_fd); + _fd = INVALID_HANDLE_VALUE; +#else if (_fd >= 0) close(_fd); + _fd = -1; +#endif + +} +finder_info_helper::~finder_info_helper() { + close(); } -bool finder_info_helper::open(const std::string &name, bool read_only) { +bool finder_info_helper::open(const std::string &name, open_mode perm, std::error_code &ec) { - if (_fd >= 0) { - close(_fd); - _fd = -1; + ec.clear(); + + close(); + + if (perm < 1 || perm > 3) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; } - int fd = fi_open(name, read_only); - if (fd < 0) return false; - int ok = read(fd); - // if write mode, it's ok if finder info doesn't exist (yet). - if (!read_only && !ok) ok = true; + auto fd = fi_open(name, perm, ec); + if (ec) return false; - if (read_only) close(fd); - else _fd = fd; + // win32 should read even if write-only. + bool ok = read(_fd, ec); - return ok; + if (perm == read_only) { + fi_close(fd); + return ok; + } + + // write mode, so it's ok if it doesn't exist. + if (!ok) ec.clear(); + _fd = fd; + return true; +} +#if _WIN32 + +bool finder_info_helper::open(const std::wstring &name, open_mode perm, std::error_code &ec) { + + ec.clear(); + + close(); + + if (perm < 1 || perm > 3) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + + auto fd = fi_open(name, perm, ec); + if (ec) return false; + + // win32 should read even if write-only. + bool ok = read(_fd, ec); + + if (perm == read_only) { + fi_close(fd); + return ok; + } + + // write mode, so it's ok if it doesn't exist. + if (!ok) ec.clear(); + _fd = fd; + return true; } -bool finder_info_helper::read(int fd) { -#if defined(_WIN32) - int ok = fi_read(fd, &_afp, sizeof(_afp)); +bool finder_info_helper::read(void *fd, std::error_code &ec) { + + int ok = fi_read(fd, &_afp, sizeof(_afp), ec); + if (ec) { + afp_init(&_afp); + return false; + } if (ok < sizeof(_afp) || !afp_verify(&_afp)) { + ec = std::make_error_code(std::errc::illegal_byte_sequence); // close enough! afp_init(&_afp); return false; } if (!_afp.prodos_file_type && !_afp.prodos_aux_type) afp_synchronize(&_afp, trust_hfs); + + return true; +} + +bool finder_info_helper::write(void *fd, std::error_code &ec) { + return fi_write(fd, &_afp, sizeof(_afp), ec) == sizeof(_afp); +} + #else - int ok = fi_read(fd, &_finder_info, sizeof(_finder_info)); + +bool finder_info_helper::read(int fd, std::error_code &ec) { + + int ok = fi_read(fd, &_finder_info, sizeof(_finder_info), ec); if (ok < 0) { memset(&_finder_info, 0, sizeof(_finder_info)); return false; } finder_info_to_filetype(_finder_info, &_prodos_file_type, &_prodos_aux_type); -#endif return true; } -bool finder_info_helper::write(int fd) { -#if defined(_WIN32) - return fi_write(fd, &_afp, sizeof(_afp)); -#else - return fi_write(fd, &_finder_info, sizeof(_finder_info)); +bool finder_info_helper::write(int fd, std::error_code &ec) { + return fi_write(fd, &_finder_info, sizeof(_finder_info), ec) == sizeof(_finder_info); +} + #endif -} -bool finder_info_helper::write() { - return write(_fd); +bool finder_info_helper::write(std::error_code &ec) { + ec.clear(); + return write(_fd, ec); } -bool finder_info_helper::write(const std::string &name) { - int fd = fi_open(name, false); - if (fd < 0) return false; - bool ok = write(fd); - close(fd); +bool finder_info_helper::write(const std::string &name, std::error_code &ec) { + ec.clear(); + auto fd = fi_open(name, write_only, ec); + + if (ec) + return false; + + bool ok = write(fd, ec); + fi_close(fd); return ok; } +#ifdef _WIN32 +bool finder_info_helper::write(const std::wstring &name, std::error_code &ec) { + ec.clear(); + auto fd = fi_open(name, write_only, ec); + if (ec) + return false; + + bool ok = write(fd, ec); + fi_close(fd); + return ok; +} + +#endif void finder_info_helper::set_prodos_file_type(uint16_t ftype, uint32_t atype) { _prodos_file_type = ftype; @@ -385,6 +695,15 @@ bool finder_info_helper::is_text() const { return false; } +bool finder_info_helper::is_binary() const { + if (is_text()) return false; + if (_prodos_file_type || _prodos_aux_type) return true; + + if (memcmp(_finder_info, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) return false; + return true; +} + + uint32_t finder_info_helper::file_type() const { uint32_t rv = 0; diff --git a/finder_info_helper.h b/finder_info_helper.h index 116d971..a727eea 100644 --- a/finder_info_helper.h +++ b/finder_info_helper.h @@ -2,6 +2,9 @@ #include #include +#include + + #if defined(_WIN32) #pragma pack(push, 2) struct AFP_Info { @@ -22,6 +25,12 @@ class finder_info_helper { public: + enum open_mode { + read_only = 1, + write_only = 2, + read_write = 3, + }; + finder_info_helper(); ~finder_info_helper(); @@ -33,26 +42,50 @@ public: const uint8_t *finder_info() const { - #if defined(_WIN32) +#if defined(_WIN32) return _afp.finder_info; - #else +#else return _finder_info; - #endif +#endif } uint8_t *finder_info() { - #if defined(_WIN32) +#if defined(_WIN32) return _afp.finder_info; - #else +#else return _finder_info; - #endif +#endif } - bool read(const std::string &fname); - bool write(const std::string &fname); - bool open(const std::string &fname, bool read_only = true); - bool write(); + bool read(const std::string &fname, std::error_code &ec) { + return open(fname, read_only, ec); + } + + bool write(const std::string &fname, std::error_code &ec); + + bool open(const std::string &fname, open_mode perm, std::error_code &ec); + bool open(const std::string &fname, std::error_code &ec) { + return open(fname, read_only, ec); + } + + +#if defined(_WIN32) + bool read(const std::wstring &pathName, std::error_code &ec) { + return open(pathName, read_only, ec); + } + + bool write(const std::wstring &pathName, std::error_code &ec); + + bool open(const std::wstring &fname, open_mode perm, std::error_code &ec); + bool open(const std::wstring &fname, std::error_code &ec) { + return open(fname, read_only, ec); + } + +#endif + + + bool write(std::error_code &ec); uint32_t creator_type() const; uint32_t file_type() const; @@ -80,17 +113,26 @@ public: void set_creator_type(uint32_t); bool is_text() const; + bool is_binary() const; private: - bool write(int fd); - bool read(int fd); + void close(); - int _fd = -1; +#if defined(_WIN32) + bool write(void *handle, std::error_code &ec); + bool read(void *handle, std::error_code &ec); +#else + bool write(int fd, std::error_code &ec); + bool read(int fd, std::error_code &ec); +#endif #if defined(_WIN32) + void *_fd = (void *)-1; AFP_Info _afp; #else + int _fd = -1; + uint16_t _prodos_file_type = 0; uint32_t _prodos_aux_type = 0; uint8_t _finder_info[32] = {}; diff --git a/mapped_file.cpp b/mapped_file.cpp index c014b2d..61f7f22 100644 --- a/mapped_file.cpp +++ b/mapped_file.cpp @@ -32,6 +32,17 @@ namespace { set_or_throw_error(ec, e, what); } + + template + HANDLE CreateFileX(const std::string &s, Args... args) { + return CreateFileA(s.c_str(), std::forward(args)...); + } + + template + HANDLE CreateFileX(const std::wstring &s, Args... args) { + return CreateFileW(s.c_str(), std::forward(args)...); + } + } void mapped_file_base::close() { @@ -44,7 +55,8 @@ void mapped_file_base::close() { } } -void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, size_t offset, std::error_code *ec) { +template +void mapped_file_base::open_common(const T& p, mapmode flags, size_t length, size_t offset, std::error_code *ec) { if (ec) ec->clear(); @@ -56,7 +68,7 @@ void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, si if (is_open()) close(); - fh = CreateFile(p.c_str(), + fh = CreateFileX(p, flags == readonly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, @@ -73,7 +85,7 @@ void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, si if (length == -1) { LARGE_INTEGER file_size; GetFileSizeEx(fh, &file_size); - length = file_size.QuadPart; + length = (size_t)file_size.QuadPart; } if (length == 0) return; @@ -102,10 +114,13 @@ void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, si auto mh_close = make_unique_resource(mh, CloseHandle); + ULARGE_INTEGER ll; + ll.QuadPart = offset; + _data = MapViewOfFileEx(mh, access, - (DWORD)(offset >> 32), - (DWORD)offset, + ll.HighPart, + ll.LowPart, length, nullptr); if (!_data) @@ -118,8 +133,19 @@ void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, si _flags = flags; } +void mapped_file_base::open(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code *ec) { + open_common(p, flags, length, offset, ec); +} -void mapped_file_base::create(const path_type& p, size_t length, std::error_code *ec) { +void mapped_file_base::open(const std::wstring &p, mapmode flags, size_t length, size_t offset, std::error_code *ec) { + open_common(p, flags, length, offset, ec); +} + + + + +template +void mapped_file_base::create_common(const T& p, size_t length, std::error_code *ec) { if (ec) ec->clear(); @@ -135,7 +161,7 @@ void mapped_file_base::create(const path_type& p, size_t length, std::error_code if (is_open()) close(); - fh = CreateFile(p.c_str(), + fh = CreateFileX(p, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, @@ -163,10 +189,13 @@ void mapped_file_base::create(const path_type& p, size_t length, std::error_code auto mh_close = make_unique_resource(mh, CloseHandle); + ULARGE_INTEGER ll; + ll.QuadPart = offset; + _data = MapViewOfFileEx(mh, access, - (DWORD)(offset >> 32), - (DWORD)offset, + ll.HighPart, + ll.LowPart, length, nullptr); @@ -180,7 +209,12 @@ void mapped_file_base::create(const path_type& p, size_t length, std::error_code _flags = readwrite; } - +void mapped_file_base::create(const std::string &p, size_t length, std::error_code *ec) { + create_common(p, length, ec); +} +void mapped_file_base::create(const std::wstring &p, size_t length, std::error_code *ec) { + create_common(p, length, ec); +} #else @@ -213,7 +247,7 @@ void mapped_file_base::close() { } -void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, size_t offset, std::error_code *ec) { +void mapped_file_base::open(const std::string& p, mapmode flags, size_t length, size_t offset, std::error_code *ec) { if (ec) ec->clear(); @@ -267,7 +301,7 @@ void mapped_file_base::open(const path_type& p, mapmode flags, size_t length, si _flags = flags; } -void mapped_file_base::create(const path_type& p, size_t length, std::error_code *ec) { +void mapped_file_base::create(const std::string& p, size_t length, std::error_code *ec) { if (ec) ec->clear(); diff --git a/mapped_file.h b/mapped_file.h index 115a632..a914fe8 100644 --- a/mapped_file.h +++ b/mapped_file.h @@ -1,15 +1,13 @@ #ifndef __mapped_file_h__ #define __mapped_file_h__ -#include - #include #include +#include class mapped_file_base { public: - typedef std::string path_type; enum mapmode { readonly, readwrite, priv }; enum createmode { truncate, exclusive }; @@ -33,8 +31,22 @@ protected: void swap(mapped_file_base &rhs); - void open(const path_type& p, mapmode flags, size_t length, size_t offset, std::error_code *ec); - void create(const path_type &p, size_t new_size, std::error_code *ec); // always creates readwrite. + void open(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code *ec); + void create(const std::string &p, size_t new_size, std::error_code *ec); // always creates readwrite. + +#ifdef _WIN32 + + void open(const std::wstring &p, mapmode flags, size_t length, size_t offset, std::error_code *ec); + void create(const std::wstring &p, size_t new_size, std::error_code *ec); // always creates readwrite. + + template + void open_common(const S &p, mapmode flags, size_t length, size_t offset, std::error_code *ec); + + template + void create_common(const S &p, size_t new_size, std::error_code *ec); // always creates readwrite. + +#endif + void reset(); @@ -68,22 +80,22 @@ public: mapped_file() = default; - mapped_file(const path_type& p, mapmode flags = readonly, size_t length = -1, size_t offset = 0) { + mapped_file(const std::string &p, mapmode flags = readonly, size_t length = -1, size_t offset = 0) { open(p, flags, length, offset); } - mapped_file(const path_type &p, std::error_code &ec) noexcept { + mapped_file(const std::string &p, std::error_code &ec) noexcept { open(p, readonly, -1, 0, ec); } - mapped_file(const path_type &p, mapmode flags, std::error_code &ec) noexcept { + mapped_file(const std::string &p, mapmode flags, std::error_code &ec) noexcept { open(p, flags, -1, 0, ec); } - mapped_file(const path_type &p, mapmode flags, size_t length, std::error_code &ec) noexcept { + mapped_file(const std::string &p, mapmode flags, size_t length, std::error_code &ec) noexcept { open(p, flags, length, 0, ec); } - mapped_file(const path_type &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept { + mapped_file(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept { open(p, flags, length, offset, ec); } @@ -95,31 +107,57 @@ public: mapped_file &operator=(const mapped_file &) = delete; - void open(const path_type& p, mapmode flags, size_t length = -1, size_t offset = 0) { + void open(const std::string &p, mapmode flags, size_t length = -1, size_t offset = 0) { base::open(p, flags, length, offset, nullptr); } - - void open(const path_type &p, std::error_code &ec) noexcept { + void open(const std::string &p, std::error_code &ec) noexcept { base::open(p, readonly, -1, 0, &ec); } - void open(const path_type &p, mapmode flags, std::error_code &ec) noexcept { + void open(const std::string &p, mapmode flags, std::error_code &ec) noexcept { base::open(p, flags, -1, 0, &ec); } - void open(const path_type &p, mapmode flags, size_t length, std::error_code &ec) noexcept { + void open(const std::string &p, mapmode flags, size_t length, std::error_code &ec) noexcept { base::open(p, flags, length, 0, &ec); } - void open(const path_type &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept { + void open(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept { base::open(p, flags, length, offset, &ec); } - void create(const path_type &p, size_t size) { - base::create(p, size, nullptr); +#ifdef _WIN32 + void open(const std::wstring &p, mapmode flags, size_t length = -1, size_t offset = 0) { + base::open(p, flags, length, offset, nullptr); + } + void open(const std::wstring &p, std::error_code &ec) noexcept { + base::open(p, readonly, -1, 0, &ec); + } + void open(const std::wstring &p, mapmode flags, std::error_code &ec) noexcept { + base::open(p, flags, -1, 0, &ec); + } + void open(const std::wstring &p, mapmode flags, size_t length, std::error_code &ec) noexcept { + base::open(p, flags, length, 0, &ec); + } + void open(const std::wstring &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept { + base::open(p, flags, length, offset, &ec); } - void create(const path_type &p, size_t size, std::error_code &ec) noexcept { +#endif + + void create(const std::string &p, size_t size) { + base::create(p, size, nullptr); + } + void create(const std::string &p, size_t size, std::error_code &ec) noexcept { base::create(p, size, &ec); } +#ifdef _WIN32 + void create(const std::wstring &p, size_t size) { + base::create(p, size, nullptr); + } + void create(const std::wstring &p, size_t size, std::error_code &ec) noexcept { + base::create(p, size, &ec); + } +#endif + const value_type *data() const { return (const value_type *)_data;