fixup error code handling

This commit is contained in:
Kelvin Sherlock 2017-07-25 18:15:38 -04:00
parent b9ae110fde
commit b9b674aa9e
1 changed files with 70 additions and 121 deletions

View File

@ -1,9 +1,9 @@
#include "finder_info.h"
#include "xattr.h"
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <cstdint>
#include <cstring>
#include <cctype>
#include <string>
#if defined (_WIN32)
@ -37,8 +37,11 @@
namespace {
// ENOATTR is not standard enough, so use ENODATA.
#if defined(ENOATTR) && ENOATTR != ENODATA
int remap_errno(int e) {
if (e == ENOATTR) return ENODATA;
return e;
@ -208,29 +211,21 @@ namespace {
return true;
}
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);
BOOL _(BOOL x, std::error_code &ec) {
if (!x) ec = std::error_code(GetLastError(), std::system_category());
return x;
}
void set_or_throw_error(std::error_code *ec, const std::string &what) {
auto e = GetLastError();
set_or_throw_error(ec, e, what);
HANDLE _(HANDLE x, std::error_code &ec) {
if (x == INVALID_HANDLE_VALUE)
ec = std::error_code(GetLastError(), std::system_category());
return x;
}
template<class ...Args>
HANDLE CreateFileX(const std::string &s, Args... args) {
return CreateFileA(s.c_str(), std::forward<Args>(args)...);
@ -242,44 +237,40 @@ namespace {
}
template<class StringType>
HANDLE CreateFileX(const StringType &s, afp::resource_fork::open_mode mode, std::error_code &ec) {
HANDLE CreateFileX(const StringType &s, afp::finder_info::open_mode mode, std::error_code &ec) {
DWORD access = 0;
DWORD create = 0;
switch (mode) {
case afp::resource_fork::read_only:
case afp::finder_info::read_only:
access = GENERIC_READ;
create = OPEN_EXISTING;
break;
case afp::resource_fork::read_write:
case afp::finder_info::read_write:
access = GENERIC_READ | GENERIC_WRITE;
create = OPEN_ALWAYS;
break;
case afp::resource_fork::write_only:
case afp::finder_info::write_only:
access = GENERIC_READ | GENERIC_WRITE; // we always read existing info on file.
create = OPEN_ALWAYS;
break;
}
HANDLE h = CreateFileX(s, access, FILE_SHARE_READ, nullptr, create, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h == INVALID_HANDLE_VALUE) {
set_or_throw_error(&ec, "CreateFile");
}
return h;
return _(CreateFileX(s, access, FILE_SHARE_READ, nullptr, create, FILE_ATTRIBUTE_NORMAL, nullptr), ec);
}
#else
void set_or_throw_error(std::error_code *ec, const std::string &what) {
auto e = errno;
set_or_throw_error(ec, e, what);
template<class T>
T _(T x, std::error_code &ec) {
if (x < 0) ec = std::error_code( remap_errno(errno), std::system_category());
return x;
}
#endif
#if defined(_WIN32)
@ -354,7 +345,7 @@ void finder_info::close() {
if (_fd != INVALID_HANDLE_VALUE) CloseHandle(_fd);
_fd = INVALID_HANDLE_VALUE;
}
void _finder_info::clear() {
void finder_info::clear() {
std::memset(&_afp, sizeof(_afp), 0);
afp_init(&_afp);
}
@ -367,7 +358,7 @@ void finder_info::close() {
if (_fd >= 0) ::close(_fd);
_fd = -1;
}
void _finder_info::clear() {
void finder_info::clear() {
std::memset(&_finder_info, sizeof(+_finder_info), 0);
_prodos_file_type = 0;
_prodos_aux_type = 0;
@ -406,20 +397,19 @@ bool finder_info::open(const std::string &path, open_mode mode, std::error_code
// always read the data.
DWORD transferred = 0;
BOOL ok = ReadFile(_fd, _afp, sizeof(_afp), &transferred, nullptr);
auto e = GetLastError();
BOOL ok = _(ReadFile(_fd, &_afp, sizeof(_afp), &transferred, nullptr), ec);
if (mode == read_only) close();
if (!ok) {
if (ec) {
afp_init(&_afp);
set_or_throw_error(&ec, e, "ReadFile");
return false;
}
// warn if incorrect size or data.
if (transferred != sizeof(_afp) || !afp_verify(&_afp)) {
afp_init(&_afp);
if (mode != write_only) {
ec = std::errc::illegal_byte_sequence;
ec = std::make_error_code(std::errc::illegal_byte_sequence);
return false;
}
}
@ -427,51 +417,45 @@ bool finder_info::open(const std::string &path, open_mode mode, std::error_code
}
bool finder_info::write(std::error_code &ec) {
ec.clear();
LARGE_INTEGER ll;
BOOL ok;
ll.QuadPart = 0;
ok = SetFilePointerEx(_fd, ll, nullptr, FILE_BEGIN);
if (!ok) {
set_or_throw_error(&ec, "SetFilePointerEx");
return false;
}
ok = _(SetFilePointerEx(_fd, ll, nullptr, FILE_BEGIN), ec);
if (ec) return false;
ok = _(WriteFile(_fd, &_afp, sizeof(_afp), nullptr, nullptr), ec);
if (ec) return false;
ok = WriteFile(_fd, &_afp, sizeof(_afp), nullptr, nullptr);
if (!ok) {
set_or_throw_error(&ec, "WriteFile");
return false;
}
return true;
}
bool finder_info::write(const std::string &path, std::error_code &ec) {
BOOL ok;
ec.clear();
std::string s(path);
s += ":" XATTR_FINDERINFO_NAME;
HANDLE h = CreateFileX(s,
HANDLE h = _(CreateFileX(s,
GENERIC_WRITE,
FILE_SHARE_READ,
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr);
nullptr), ec);
if (h == INVALID_HANDLE_VALUE) {
set_or_throw_error(&ec, "CreateFile");
return false;
}
if (ec) return false;
ok = WriteFile(h, &_afp, sizeof(_afp), nullptr, nullptr);
int e = GetLastError();
ok = _(WriteFile(h, &_afp, sizeof(_afp), nullptr, nullptr), ec);
CloseHandle(h);
if (!ok) {
set_or_throw_error(&ec, e, "WriteFile");
return false;
}
if (ec) return false;
return true;
}
@ -491,42 +475,30 @@ bool finder_info::open(const std::string &path, open_mode mode, std::error_code
// attropen is a front end for open / openat.
// do it ourselves so we can distinguish file doesn't exist vs attr doesn't exist.
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0) {
set_or_throw_error(&ec, "open");
return false;
}
int fd = _(open(path.c_str(), O_RDONLY), ec);
if (ec) return false;
_fd = openat(fd, XATTR_FINDERINFO_NAME, umode | O_XATTR, 0666);
int e = remap_errno();
_fd = _(openat(fd, XATTR_FINDERINFO_NAME, umode | O_XATTR, 0666), ec);
::close(fd);
if (_fd < 0) {
if (e == ENOENT) e = ENODATA;
set_or_throw_error(&ec, e, "openat");
if (ec) {
if (ec.value() == ENOENT) ec = std::make_error_code(std::errc::no_message_available); // ENODATA.
return false;
}
if (mode == read_only || mode == read_write) {
// read it...
auto ok = ::pread(_fd, &_finder_info, 32, 0);
e = remap_errno();
auto ok = _(::pread(_fd, &_finder_info, 32, 0), ec);
if (mode == read_only) close();
if (ok < 0) {
set_or_throw_error(&ec, e, "pread");
return false;
}
if (ec) return false;
}
return true;
}
bool finder_info::write(std::error_code &ec) {
ec.clear();
auto ok = ::pwrite(_fd, &_finder_info, 32, 0);
if (ok < 0) {
set_or_throw_error(&ec, remap_errno(), "pwrite");
return false;
}
auto ok = _(::pwrite(_fd, &_finder_info, 32, 0), ec);
if (ec) return false;
return true;
}
@ -536,20 +508,11 @@ bool finder_info::write(const std::string &path, std::error_code &ec) {
int e;
// attropen safe to use here.
int fd = attropen(path.c_str, XATTR_FINDERINFO_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666);
e = remap_errno();
if (fd < 0) {
set_or_throw_error(&ec, e, "attropen");
return false;
}
auto ok = ::pwrite(fd, &_finder_info, 32, 0);
e = remap_errno();
int fd = _(::attropen(path.c_str, XATTR_FINDERINFO_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666), ec);
if (ec) return false;
auto ok = _(::pwrite(fd, &_finder_info, 32, 0), ec);
::close(fd);
if (ok < 0) {
set_or_throw_error(&ec, e, "pwrite");
return false;
}
if (ec) return false;
return true;
}
#else
@ -558,18 +521,13 @@ bool finder_info::open(const std::string &path, open_mode mode, std::error_code
close();
clear();
_fd = open(path.c_str(), O_RDONLY);
if (_fd < 0) {
set_or_throw_error(&ec, "open");
return false;
}
_fd = _(::open(path.c_str(), O_RDONLY), ec);
if (ec) return false;
if (mode == read_only || mode == read_write) {
auto ok = read_xattr(_fd, XATTR_FINDERINFO_NAME, 32);
e = remap_errno();
auto ok = _(::read_xattr(_fd, XATTR_FINDERINFO_NAME, &_finder_info, 32), ec);
if (mode == read_only) close();
if (ok < 0) {
set_or_throw_error(&ec, e, "read_xattr");
if (ec) {
return false;
}
}
@ -579,30 +537,21 @@ bool finder_info::open(const std::string &path, open_mode mode, std::error_code
bool finder_info::write(std::error_code &ec) {
ec.clear();
// n.b. no way to differentiate closed vs opened read-only.
auto ok = write_xattr(_fd, XATTR_FINDERINFO_NAME, _finder_info, 32);
if (ok < 0) {
set_or_throw_error(&ec, remap_errno(), "write_xattr");
return false;
}
auto ok = _(::write_xattr(_fd, XATTR_FINDERINFO_NAME, _finder_info, 32), ec);
if (ec) return false;
return true;
}
bool finder_info::write(const std::string &path, std::error_code &ec) {
ec.clear();
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0) {
set_or_throw_error(&ec, "open");
return false;
}
int fd = _(::open(path.c_str(), O_RDONLY), ec);
if (ec) return false;
auto ok = write_xattr(fd, XATTR_FINDERINFO_NAME, _finder_info, 32);
int e = remap_errno();
auto ok = _(::write_xattr(fd, XATTR_FINDERINFO_NAME, _finder_info, 32), ec);
::close(fd);
if (ok < 0) {
set_or_throw_error(&ec, e, "write_xattr");
return false;
}
if (ec) return false;
return true;
}