libstdc++ (mingw, cygwin, msys, etc) don't support windows errors. remap to posix.

This commit is contained in:
Kelvin Sherlock 2017-07-26 22:12:08 -04:00
parent d7660c16cc
commit 92070e2e65
6 changed files with 216 additions and 20 deletions

View File

@ -1,12 +1,17 @@
cmake_minimum_required(VERSION 3.1)
set(PROJECT_NAME afp)
set(PROJECT_TYPE CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_EXTENSIONS FALSE)
if (CYGWIN OR MSYS OR MINGW)
set(REMAP src/remap_os_error.c)
endif()
add_library(afp src/finder_info.cpp src/resource_fork.cpp src/xattr.c)
add_library(afp src/finder_info.cpp src/resource_fork.cpp src/xattr.c ${REMAP})
target_include_directories(afp INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
target_include_directories(afp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/afp)

View File

@ -6,8 +6,11 @@
#include <system_error>
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
#define AFP_WIN32
#endif
#if defined(_WIN32)
#if defined(AFP_WIN32)
#pragma pack(push, 2)
struct AFP_Info {
uint32_t magic;
@ -56,7 +59,7 @@ namespace afp {
}
#if defined(_WIN32)
#if defined(AFP_WIN32)
bool read(const std::wstring &path, std::error_code &ec) {
return open(path, read_only, ec);
}
@ -75,7 +78,7 @@ namespace afp {
uint32_t creator_type() const;
uint32_t file_type() const;
#if defined(_WIN32)
#if defined(AFP_WIN32)
const uint8_t *data() const {
return _afp.finder_info;
}
@ -114,11 +117,12 @@ namespace afp {
void clear();
private:
void close();
#if defined(_WIN32)
private:
#if defined(AFP_WIN32)
void *_fd = (void *)-1;
AFP_Info _afp;
#else
@ -130,6 +134,8 @@ namespace afp {
#endif
};
}
#undef AFP_WIN32
#endif

View File

@ -4,6 +4,10 @@
#include <string>
#include <system_error>
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
#define AFP_WIN32
#endif
namespace afp {
class resource_fork {
@ -26,7 +30,7 @@ namespace afp {
~resource_fork() { close(); }
static size_t size(const std::string &path, std::error_code &ec);
#ifdef _WIN32
#ifdef AFP_WIN32
static size_t size(const std::wstring &path, std::error_code &ec);
#endif
@ -36,7 +40,7 @@ namespace afp {
return open(s, read_only, ec);
}
#ifdef _WIN32
#ifdef AFP_WIN32
bool open(const std::wstring &s, open_mode mode, std::error_code &ec);
bool open(const std::wstring &s, std::error_code &ec) {
return open(s, read_only, ec);
@ -53,7 +57,7 @@ namespace afp {
private:
#ifdef _WIN32
#ifdef AFP_WIN32
void *_fd = (void *)-1;
#else
int _fd = -1;
@ -66,5 +70,6 @@ namespace afp {
};
}
#undef AFP_WIN32
#endif

View File

@ -6,6 +6,13 @@
#include <cctype>
#include <string>
#if defined(__CYGWIN__) || defined(__MSYS__)
#if !defined(_WIN32)
#define _WIN32
#endif
#endif
#if defined (_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@ -13,6 +20,7 @@
#else
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#if defined(__APPLE__)
@ -51,22 +59,28 @@ namespace {
#endif
#if defined(_WIN32)
#ifdef MSVC
#define AFP_ERROR_FILE_NOT_FOUND ERROR_FILE_NOT_FOUND
#define remap_os_error(x) x
#else
#define AFP_ERROR_FILE_NOT_FOUND ENOENT
extern "C" int remap_os_error(unsigned long);
#endif
BOOL _(BOOL x, std::error_code &ec) {
if (!x) ec = std::error_code(GetLastError(), std::system_category());
if (!x) ec = std::error_code(remap_os_error(GetLastError()), std::system_category());
return x;
}
HANDLE _(HANDLE x, std::error_code &ec) {
if (x == INVALID_HANDLE_VALUE)
ec = std::error_code(GetLastError(), std::system_category());
ec = std::error_code(remap_os_error(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)...);
@ -80,7 +94,6 @@ namespace {
template<class StringType>
HANDLE CreateFileX(const StringType &s, afp::finder_info::open_mode mode, std::error_code &ec) {
DWORD access = 0;
DWORD create = 0;
@ -102,6 +115,33 @@ namespace {
return _(CreateFileX(s, access, FILE_SHARE_READ, nullptr, create, FILE_ATTRIBUTE_NORMAL, nullptr), ec);
}
DWORD GetFileAttributesX(const std::string &path) {
return GetFileAttributesA(path.c_str());
}
DWORD GetFileAttributesX(const std::wstring &path) {
return GetFileAttributesW(path.c_str());
}
template<class StringType>
bool regular_file(const StringType &path, std::error_code &ec) {
// make sure this isn't a directory.
DWORD st = GetFileAttributesX(path);
if (st == INVALID_FILE_ATTRIBUTES) {
ec = std::error_code(remap_os_error(GetLastError()), std::system_category());
return false;
}
if (st & FILE_ATTRIBUTE_DIRECTORY) {
ec = std::make_error_code(std::errc::is_a_directory);
return false;
}
if (st & FILE_ATTRIBUTE_DEVICE) {
ec = std::make_error_code(std::errc::invalid_seek);
return false;
}
return true;
}
#else
@ -111,6 +151,31 @@ namespace {
return x;
}
bool regular_file(int fd, std::error_code &ec) {
struct stat st;
if (_(::fstat(fd, &st), ec) < 0) {
return false;
}
if (S_ISREG(st.st_mode)) return true;
if (S_ISDIR(st.st_mode)) {
ec = std::make_error_code(std::errc::is_a_directory);
} else {
ec = std::make_error_code(std::errc::invalid_seek); // ESPIPE.
}
return false;
}
/* opens a file read-only and verifies it's a regular file */
int openX(const std::string &path, std::error_code &ec) {
int fd = _(::open(path.c_str(), O_RDONLY, O_NONBLOCK), ec);
if (fd >= 0 && !regular_file(fd, ec)) {
::close(fd);
fd = -1;
}
return fd;
}
#endif
@ -423,13 +488,17 @@ bool finder_info::open(const std::string &path, open_mode mode, std::error_code
s += ":" XATTR_FINDERINFO_NAME;
/* open the base file, then the finder info, so we can clarify the error */
if (!regular_file(path, ec)) {
return false;
}
HANDLE h = CreateFileX(path, read_only, ec);
if (ec) return false;
_fd = CreateFileX(s, mode, ec);
CloseHandle(h);
if (ec) {
if (ec.value() == ERROR_FILE_NOT_FOUND)
if (ec.value() == AFP_ERROR_FILE_NOT_FOUND)
ec = std::make_error_code(std::errc::no_message_available);
return false;
}
@ -466,13 +535,17 @@ bool finder_info::open(const std::wstring &path, open_mode mode, std::error_code
s += L":" XATTR_FINDERINFO_NAME;
/* open the base file, then the finder info, so we can clarify the error */
if (!regular_file(path, ec)) {
return false;
}
HANDLE h = CreateFileX(path, read_only, ec);
if (ec) return false;
_fd = CreateFileX(s, mode, ec);
CloseHandle(h);
if (ec) {
if (ec.value() == ERROR_FILE_NOT_FOUND)
if (ec.value() == AFP_ERROR_FILE_NOT_FOUND)
ec = std::make_error_code(std::errc::no_message_available);
return false;
}
@ -584,7 +657,7 @@ 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), ec);
int fd = openX(path, ec);
if (ec) return false;
_fd = _(::openat(fd, XATTR_FINDERINFO_NAME, umode | O_XATTR, 0666), ec);
@ -631,7 +704,7 @@ bool finder_info::open(const std::string &path, open_mode mode, std::error_code
close();
clear();
_fd = _(::open(path.c_str(), O_RDONLY), ec);
_fd = openX(path, ec);
if (ec) return false;
if (mode == read_only || mode == read_write) {

100
src/remap_os_error.c Normal file
View File

@ -0,0 +1,100 @@
/*
* libstdc++ (cygwin, msys, mingw, etc) use posix errno for std::system_category()
* rather than create a new category, just remap to a posix errno.
*/
#include <errno.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
int remap_os_error(unsigned long e) {
switch(e) {
case NO_ERROR: return 0;
default: return EIO;
case ERROR_INVALID_HANDLE:
return EBADF;
case ERROR_CANTOPEN:
case ERROR_CANTREAD:
case ERROR_CANTWRITE:
case ERROR_OPEN_FAILED:
case ERROR_READ_FAULT:
case ERROR_SEEK:
case ERROR_WRITE_FAULT:
return EIO;
case ERROR_ACCESS_DENIED:
case ERROR_CANNOT_MAKE:
case ERROR_CURRENT_DIRECTORY:
case ERROR_INVALID_ACCESS:
case ERROR_NOACCESS:
case ERROR_SHARING_VIOLATION:
case ERROR_WRITE_PROTECT:
return EACCES;
case ERROR_ALREADY_EXISTS:
case ERROR_FILE_EXISTS:
return EEXIST;
case ERROR_BAD_UNIT:
case ERROR_DEV_NOT_EXIST:
case ERROR_INVALID_DRIVE:
return ENODEV;
case ERROR_BUFFER_OVERFLOW:
return ENAMETOOLONG;
case ERROR_BUSY:
case ERROR_BUSY_DRIVE:
case ERROR_DEVICE_IN_USE:
case ERROR_OPEN_FILES:
return EBUSY;
case ERROR_DIR_NOT_EMPTY:
return ENOTEMPTY;
case ERROR_DIRECTORY:
case ERROR_INVALID_NAME:
case ERROR_NEGATIVE_SEEK:
case ERROR_INVALID_PARAMETER:
return EINVAL;
case ERROR_DISK_FULL:
case ERROR_HANDLE_DISK_FULL:
return ENOSPC;
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_BAD_NETPATH:
case ERROR_BAD_NET_NAME:
return ENOENT;
case ERROR_INVALID_FUNCTION:
return ENOSYS;
case ERROR_LOCK_VIOLATION:
case ERROR_LOCKED:
return ENOLCK;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
case ERROR_NOT_ENOUGH_QUOTA:
return ENOMEM;
case ERROR_NOT_READY:
case ERROR_RETRY:
return EAGAIN;
case ERROR_NOT_SAME_DEVICE:
return EXDEV;
case ERROR_OPERATION_ABORTED:
return ECANCELED;
case ERROR_TOO_MANY_OPEN_FILES:
return EMFILE;
}
}

View File

@ -3,6 +3,13 @@
#include <cstring>
#if defined(__CYGWIN__) || defined(__MSYS__)
#if !defined(_WIN32)
#define _WIN32
#endif
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>