From ebd67dc0cc8a0175964562ce837b1f23f14e65c7 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 6 Mar 2017 00:39:50 -0500 Subject: [PATCH] update finder_info_helper. --- finder_info_helper.cpp | 151 +++++++++++++++++++++++++++++++++-------- finder_info_helper.h | 44 ++++++++++-- set_file_type.cpp | 5 +- 3 files changed, 164 insertions(+), 36 deletions(-) diff --git a/finder_info_helper.cpp b/finder_info_helper.cpp index 58170d6..e88ca18 100644 --- a/finder_info_helper.cpp +++ b/finder_info_helper.cpp @@ -206,6 +206,12 @@ namespace { } + 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. */ @@ -293,19 +299,30 @@ namespace { + int fi_open(const std::wstring &path, int perm) { +#if defined(_WIN32) + std::wstring s(path); + s.append(L":" XATTR_FINDERINFO_NAME); + if (perm == 1) return open(s.c_str(), O_RDONLY | O_BINARY); + else return open(s.c_str(), O_RDWR | O_CREAT | O_BINARY, 0666); +#else - int fi_open(const std::string &path, bool read_only) { +#endif + } + + int fi_open(const std::string &path, int perm) { #if defined(__sun__) - if (read_only) return attropen(path.c_str(), XATTR_FINDERINFO_NAME, O_RDONLY); + 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); #elif defined(_WIN32) std::string s(path); s.append(":" XATTR_FINDERINFO_NAME); - if (read_only) return open(s.c_str(), O_RDONLY | O_BINARY); + if (perm == 1) return open(s.c_str(), O_RDONLY | O_BINARY); else return open(s.c_str(), O_RDWR | O_CREAT | O_BINARY, 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 } @@ -370,10 +387,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 { @@ -400,36 +419,86 @@ finder_info_helper::~finder_info_helper() { if (_fd >= 0) close(_fd); } -bool finder_info_helper::open(const std::string &name, bool read_only) { +bool finder_info_helper::open(const std::string &name, std::error_code &ec, open_mode perm) { + + ec.clear(); if (_fd >= 0) { close(_fd); _fd = -1; } - int fd = fi_open(name, read_only); + + if (perm < 1 || perm > 3) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + + int fd = _(fi_open(name, perm), ec); 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; + // win32 should read even if write-only. + bool ok = read(fd, ec); - if (read_only) close(fd); - else _fd = fd; + if (perm == read_only) { + close(fd); + return ok; + } - 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 0 +bool finder_info_helper::open(const filesystem::path &pathName, std::error_code &ec, open_mode perm) { + + ec.clear(); + + if (_fd >= 0) { + close(_fd); + _fd = -1; + } + + if (perm < 1 || perm > 3) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + + int fd = _(fi_open(pathName.native(), perm), ec); + if (fd < 0) return false; + + // win32 should read even if write-only. + bool ok = read(fd, ec); + + if (perm == read_only) { + close(fd); + return ok; + } + + // write mode, so it's ok if it doesn't exist. + if (!ok) ec.clear(); + _fd = fd; + return true; +} +#endif + +bool finder_info_helper::read(int fd, std::error_code &ec) { #if defined(_WIN32) - int ok = fi_read(fd, &_afp, sizeof(_afp)); + int ok = _(fi_read(fd, &_afp, sizeof(_afp)), ec); + if (ok < 0) { + 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); #else - int ok = fi_read(fd, &_finder_info, sizeof(_finder_info)); + int ok = _(fi_read(fd, &_finder_info, sizeof(_finder_info)), ec); if (ok < 0) { memset(&_finder_info, 0, sizeof(_finder_info)); return false; @@ -439,27 +508,44 @@ bool finder_info_helper::read(int fd) { return true; } -bool finder_info_helper::write(int fd) { +bool finder_info_helper::write(int fd, std::error_code &ec) { #if defined(_WIN32) - return fi_write(fd, &_afp, sizeof(_afp)); + return _(fi_write(fd, &_afp, sizeof(_afp)),ec); #else - return fi_write(fd, &_finder_info, sizeof(_finder_info)); + return _(fi_write(fd, &_finder_info, sizeof(_finder_info)),ec); #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); +bool finder_info_helper::write(const std::string &name, std::error_code &ec) { + ec.clear(); + int fd = _(fi_open(name, write_only), ec); + + if (fd < 0) + return false; + + bool ok = write(fd, ec); close(fd); return ok; } +#if 0 +bool finder_info_helper::write(const filesystem::path &pathName, std::error_code &ec) { + ec.clear(); + int fd = _(fi_open(pathName.native(), write_only), ec); + if (fd < 0) + return false; + + bool ok = write(fd, ec); + close(fd); + return ok; +} +#endif void finder_info_helper::set_prodos_file_type(uint16_t ftype, uint32_t atype) { @@ -481,6 +567,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..45e8f47 100644 --- a/finder_info_helper.h +++ b/finder_info_helper.h @@ -2,6 +2,8 @@ #include #include +#include + #if defined(_WIN32) #pragma pack(push, 2) struct AFP_Info { @@ -22,6 +24,12 @@ class finder_info_helper { public: + enum open_mode { + read_only = 1, + write_only = 2, + read_write = 3, + }; + finder_info_helper(); ~finder_info_helper(); @@ -49,10 +57,33 @@ public: } - 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, ec); + } + + bool write(const std::string &fname, std::error_code &ec); + + bool open( + const std::string &fname, + std::error_code &ec, + open_mode perm = read_only + ); + +#if 0 + bool read(const filesystem::path &pathName, std::error_code &ec) { + return open(pathName, ec); + } + + bool write(const filesystem::path &pathName, std::error_code &ec); + + bool open( + const filesystem::path &pathName, + std::error_code &ec, + open_mode perm = read_only + ); +#endif + + bool write(std::error_code &ec); uint32_t creator_type() const; uint32_t file_type() const; @@ -80,11 +111,12 @@ public: void set_creator_type(uint32_t); bool is_text() const; + bool is_binary() const; private: - bool write(int fd); - bool read(int fd); + bool write(int fd, std::error_code &ec); + bool read(int fd, std::error_code &ec); int _fd = -1; diff --git a/set_file_type.cpp b/set_file_type.cpp index ff3502d..d9c4786 100644 --- a/set_file_type.cpp +++ b/set_file_type.cpp @@ -9,10 +9,11 @@ int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type finder_info_helper fi; bool ok; - ok = fi.open(path, false); + std::error_code ec; + ok = fi.open(path, ec, finder_info_helper::read_write); if (!ok) return -1; fi.set_prodos_file_type(file_type, aux_type); - ok = fi.write(); + ok = fi.write(ec); if (!ok) return -1; return 0;