add static write / remove functions for resource forks.

This commit is contained in:
Kelvin Sherlock 2017-08-09 23:09:58 -04:00
parent 2c68e8e473
commit 3d031fe451
2 changed files with 242 additions and 2 deletions

View File

@ -30,10 +30,19 @@ namespace afp {
~resource_fork() { close(); }
static size_t size(const std::string &path, std::error_code &ec);
static bool remove(const std::string &path, std::error_code &ec);
static size_t write(const std::string &path, const void *buffer, size_t n, std::error_code &ec);
#ifdef AFP_WIN32
static size_t size(const std::wstring &path, std::error_code &ec);
static bool remove(const std::wstring &path, std::error_code &ec);
static size_t write(const std::wstring &path, const void *buffer, size_t n, std::error_code &ec);
#endif
bool open(const std::string &s, open_mode mode, std::error_code &ec);
bool open(const std::string &s, std::error_code &ec) {

View File

@ -84,6 +84,8 @@ extern "C" int remap_os_error(unsigned long);
}
#undef CreateFile
#undef DeleteFile
template<class ...Args>
HANDLE CreateFile(const std::string &s, Args... args) {
return CreateFileA(s.c_str(), std::forward<Args>(args)...);
@ -121,6 +123,15 @@ extern "C" int remap_os_error(unsigned long);
return h;
}
BOOL DeleteFile(const std::string &path) { return DeleteFileA(path.c_str()); }
BOOL DeleteFile(const std::wstring &path) { return DeleteFileW(path.c_str()); }
template<class StringType>
bool DeleteFileX(const StringType &path, std::error_code &ec) {
return _(DeleteFile(path), ec);
}
DWORD GetFileAttributesX(const std::string &path) {
return GetFileAttributesA(path.c_str());
}
@ -258,6 +269,104 @@ namespace afp {
}
size_t resource_fork::write(const std::string &path, const void *buffer, size_t n, std::error_code &ec) {
ec.clear();
if (!regular_file(path, ec)) return 0;
std::string s(path);
s += ":" XATTR_RESOURCEFORK_NAME;
HANDLE h = CreateFileX(path, read_only, ec);
if (ec) return 0;
HANDLE fd = _(CreateFile(s, GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr), ec);
if (ec) return 0;
DWORD transferred = 0;
BOOL ok = _(WriteFile(fd, buffer, n, &transferred, nullptr), ec);
CloseHandle(h);
CloseHandle(fd);
if (ec) return 0;
return transferred;
}
size_t resource_fork::write(const std::wstring &path, const void *buffer, size_t n, std::error_code &ec) {
ec.clear();
if (!regular_file(path, ec)) return 0;
std::wstring s(path);
s += L":" XATTR_RESOURCEFORK_NAME;
HANDLE h = CreateFileX(path, read_only, ec);
if (ec) return 0;
HANDLE fd = _(CreateFile(s, GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr), ec);
if (ec) return 0;
DWORD transferred = 0;
BOOL ok = _(WriteFile(fd, buffer, n, &transferred, nullptr), ec);
CloseHandle(h);
CloseHandle(fd);
if (ec) return 0;
return transferred;
}
bool resource_fork::remove(const std::string &path, std::error_code &ec) {
ec.clear();
if (!regular_file(path, ec)) return false;
std::string s(path);
s += ":" XATTR_RESOURCEFORK_NAME;
HANDLE h = CreateFileX(path, read_only, ec);
if (ec) return false;
CloseHandle(h);
bool ok = DeleteFileX(s, ec);
if (ec.value() == ERROR_FILE_NOT_FOUND) {
ec = std::make_error_code(std::errc::no_message_available);
return true;
}
return ok;
}
bool resource_fork::remove(const std::wstring &path, std::error_code &ec) {
ec.clear();
if (!regular_file(path, ec)) return false;
std::wstring s(path);
s += L":" XATTR_RESOURCEFORK_NAME;
HANDLE h = CreateFileX(path, read_only, ec);
if (ec) return false;
CloseHandle(h);
bool ok = DeleteFileX(s, ec);
if (ec.value() == ERROR_FILE_NOT_FOUND) {
ec = std::make_error_code(std::errc::no_message_available);
return true;
}
return ok;
}
void resource_fork::close() {
CloseHandle(_fd);
_fd = INVALID_HANDLE_VALUE;
@ -340,7 +449,7 @@ namespace afp {
int fd = openX(path, ec);
if (ec) return false;
_fd = ::openat(path.c_str(), XATTR_RESOURCEFORK_NAME, umode | O_XATTR, 0666);
_fd = _(::openat(path.c_str(), XATTR_RESOURCEFORK_NAME, umode | O_XATTR, 0666), ec);
::close(fd);
if (ec) {
@ -352,6 +461,54 @@ namespace afp {
return true;
}
bool resource_fork::remove(const std::string &path, std::error_code &ec) {
ec.clear();
int fd = openX(path, ec);
if (ec) return false;
int dirfd = _(::openat(fd, ".", O_RDONLY | O_XATTR), ec);
::close(fd);
if (ec) return false;
int ok = _(::unlinkat(dirfd, XATTR_RESOURCEFORK_NAME), ec);
::close(dirfd);
if (ec.value() == ENOENT) {
ec = std::make_error_code(std::errc::no_message_available); // ENODATA.
return true;
}
return ok == 0;
}
size_t resource_fork::write(const std::string &path, const void *buffer, size_t n, std::error_code &ec) {
ec.clear();
int fd = openX(path, ec);
if (ec) return 0;
rfd = _(::openat(path.c_str(), XATTR_RESOURCEFORK_NAME, O_WRONLY | O_CREAT | O_TRUNC | O_XATTR, 0666), ec);
::close(fd);
if (ec) {
if (ec.value() == ENOENT)
ec = std::make_error_code(std::errc::no_message_available); // ENODATA.
return 0;
}
auto rv = _(::write(rfd, buffer, n), ec);
::close(rfd);
if (rv < 0) return 0;
return rv;
}
#endif
@ -385,6 +542,44 @@ namespace afp {
return true;
}
bool resource_fork::remove(const std::string &path, std::error_code &ec) {
ec.clear();
std::string s(path);
s += _PATH_RSRCFORKSPEC;
int fd = openX(path, ec);
if (ec) return false;
::close(fd);
int ok = _(::unlink(s.c_str()), ec);
if (ec.value() == ENOENT) {
ec = std::make_error_code(std::errc::no_message_available);
return true;
}
return ok == 0;
}
size_t resource_fork::write(const std::string &path, const void *buffer, size_t n, std::error_code &ec) {
ec.clear();
std::string s(path);
s += _PATH_RSRCFORKSPEC;
int fd = openX(path, ec);
if (ec) return false;
::close(fd);
int rfd = _(::open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666), ec);
if (rfd < 0) return 0;
auto rv = _(::write(rfd, buffer, n), ec);
::close(rfd);
if (rv < 0) return 0;
return rv;
}
#endif
#ifdef FD_RESOURCE_FORK
@ -474,7 +669,7 @@ namespace afp {
auto rv = _(::size_xattr(_fd, XATTR_RESOURCEFORK_NAME), ec);
if (ec) {
remap_enoattr(ec);
return false;
return 0;
}
return rv;
}
@ -576,6 +771,42 @@ namespace afp {
}
bool resource_fork::remove(const std::string &path, std::error_code &ec) {
ec.clear();
int fd = openX(path, ec);
if (ec) return false;
int rv = _(::remove_xattr(fd, XATTR_RESOURCEFORK_NAME), ec);
::close(fd);
if (rv < 0) {
remap_enoattr(ec);
if (ec.value() == ENODATA) return true;
}
return rv == 0;
}
size_t resource_fork::write(const std::string &path, const void *buffer, size_t n, std::error_code &ec) {
ec.clear();
int fd = openX(path, ec);
if (ec) return false;
auto rv = _(::write_xattr(fd, XATTR_RESOURCEFORK_NAME, buffer, n), ec);
::close(fd);
if (rv < 0) {
remap_enoattr(ec);
return 0;
}
return rv;
}
#endif
size_t resource_fork::size(const std::string &path, std::error_code &ec) {