mirror of
https://github.com/ksherlock/wdc-utils.git
synced 2024-12-28 15:29:31 +00:00
use finder_info_helper.
This commit is contained in:
parent
06a3c5b5ae
commit
e43ace0d1c
3
Makefile
3
Makefile
@ -3,7 +3,7 @@ CXXFLAGS = -std=c++14 -g -Wall -Wno-sign-compare
|
|||||||
CCFLAGS = -g
|
CCFLAGS = -g
|
||||||
|
|
||||||
DUMP_OBJS = dumpobj.o disassembler.o zrdz_disassembler.o
|
DUMP_OBJS = dumpobj.o disassembler.o zrdz_disassembler.o
|
||||||
LINK_OBJS = link.o expression.o omf.o set_file_type.o
|
LINK_OBJS = link.o expression.o omf.o set_file_type.o finder_info_helper.o
|
||||||
|
|
||||||
#UNAME_S := $(shell uname -s)
|
#UNAME_S := $(shell uname -s)
|
||||||
#ifeq ($(UNAME_S),MINGW64_NT-10.0)
|
#ifeq ($(UNAME_S),MINGW64_NT-10.0)
|
||||||
@ -29,6 +29,7 @@ zrdz_disassembler.o : zrdz_disassembler.cpp zrdz_disassembler.h disassembler.h
|
|||||||
dumpobj.o : dumpobj.cpp zrdz_disassembler.h disassembler.h
|
dumpobj.o : dumpobj.cpp zrdz_disassembler.h disassembler.h
|
||||||
omf.o : omf.cpp omf.h
|
omf.o : omf.cpp omf.h
|
||||||
expression.o : expression.cpp expression.h
|
expression.o : expression.cpp expression.h
|
||||||
|
finder_info_helper.o : finder_info_helper.cpp finder_info_helper.h
|
||||||
mingw/err.o : mingw/err.c mingw/err.h
|
mingw/err.o : mingw/err.c mingw/err.h
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
457
finder_info_helper.cpp
Normal file
457
finder_info_helper.cpp
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
#include "finder_info_helper.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <sys/xattr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <sys/xattr.h>
|
||||||
|
#define XATTR_FINDERINFO_NAME "user.com.apple.FinderInfo"
|
||||||
|
#define XATTR_RESOURCEFORK_NAME "user.com.apple.ResourceFork"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/extattr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_AIX)
|
||||||
|
#include <sys/ea.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined (_WIN32)
|
||||||
|
#define XATTR_FINDERINFO_NAME "AFP_AfpInfo"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef XATTR_FINDERINFO_NAME
|
||||||
|
#define XATTR_FINDERINFO_NAME "com.apple.FinderInfo"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define _prodos_file_type _afp.prodos_file_type
|
||||||
|
#define _prodos_aux_type _afp.prodos_file_type
|
||||||
|
#define _finder_info _afp.finder_info
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int hex(uint8_t c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
|
if (c >= 'a' && c <= 'f') return c + 10 - 'a';
|
||||||
|
if (c >= 'A' && c <= 'F') return c + 10 - 'A';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool finder_info_to_filetype(const uint8_t *buffer, uint16_t *file_type, uint32_t *aux_type) {
|
||||||
|
|
||||||
|
if (!memcmp("pdos", buffer + 4, 4))
|
||||||
|
{
|
||||||
|
if (buffer[0] == 'p') {
|
||||||
|
*file_type = buffer[1];
|
||||||
|
*aux_type = (buffer[2] << 8) | buffer[3];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!memcmp("PSYS", buffer, 4)) {
|
||||||
|
*file_type = 0xff;
|
||||||
|
*aux_type = 0x0000;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!memcmp("PS16", buffer, 4)) {
|
||||||
|
*file_type = 0xb3;
|
||||||
|
*aux_type = 0x0000;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// old mpw method for encoding.
|
||||||
|
if (!isxdigit(buffer[0]) && isxdigit(buffer[1]) && buffer[2] == ' ' && buffer[3] == ' ')
|
||||||
|
{
|
||||||
|
*file_type = (hex(buffer[0]) << 8) | hex(buffer[1]);
|
||||||
|
*aux_type = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!memcmp("TEXT", buffer, 4)) {
|
||||||
|
*file_type = 0x04;
|
||||||
|
*aux_type = 0x0000;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!memcmp("BINA", buffer, 4)) {
|
||||||
|
*file_type = 0x00;
|
||||||
|
*aux_type = 0x0000;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!memcmp("dImgdCpy", buffer, 8)) {
|
||||||
|
*file_type = 0xe0;
|
||||||
|
*aux_type = 0x0005;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp("MIDI", buffer, 4)) {
|
||||||
|
*file_type = 0xd7;
|
||||||
|
*aux_type = 0x0000;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp("AIFF", buffer, 4)) {
|
||||||
|
*file_type = 0xd8;
|
||||||
|
*aux_type = 0x0000;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp("AIFC", buffer, 4)) {
|
||||||
|
*file_type = 0xd8;
|
||||||
|
*aux_type = 0x0001;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_type_to_finder_info(uint8_t *buffer, uint16_t file_type, uint32_t aux_type) {
|
||||||
|
if (file_type > 0xff || aux_type > 0xffff) return false;
|
||||||
|
|
||||||
|
if (!file_type && aux_type == 0x0000) {
|
||||||
|
memcpy(buffer, "BINApdos", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_type == 0x04 && aux_type == 0x0000) {
|
||||||
|
memcpy(buffer, "TEXTpdos", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_type == 0xff && aux_type == 0x0000) {
|
||||||
|
memcpy(buffer, "PSYSpdos", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_type == 0xb3 && aux_type == 0x0000) {
|
||||||
|
memcpy(buffer, "PS16pdos", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_type == 0xd7 && aux_type == 0x0000) {
|
||||||
|
memcpy(buffer, "MIDIpdos", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (file_type == 0xd8 && aux_type == 0x0000) {
|
||||||
|
memcpy(buffer, "AIFFpdos", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (file_type == 0xd8 && aux_type == 0x0001) {
|
||||||
|
memcpy(buffer, "AIFCpdos", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (file_type == 0xe0 && aux_type == 0x0005) {
|
||||||
|
memcpy(buffer, "dImgdCpy", 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
memcpy(buffer, "p pdos", 8);
|
||||||
|
buffer[1] = (file_type) & 0xff;
|
||||||
|
buffer[2] = (aux_type >> 8) & 0xff;
|
||||||
|
buffer[3] = (aux_type) & 0xff;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int fi_open(const std::string &path, bool read_only) {
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
return open(path.c_str(), O_RDONLY);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int fi_write(int fd, const void *data, int length) {
|
||||||
|
#if defined(__sun__) || defined(_WIN32)
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
return write(fd, data, length);
|
||||||
|
#else
|
||||||
|
return write_xattr(fd, XATTR_FINDERINFO_NAME, data, length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int fi_read(int fd, void *data, int length) {
|
||||||
|
#if defined(__sun__) || defined(_WIN32)
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
return read(fd, data, length);
|
||||||
|
#else
|
||||||
|
return read_xattr(fd, XATTR_FINDERINFO_NAME, data, length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
void afp_init(struct AFP_Info *info) {
|
||||||
|
//static_assert(sizeof(AFP_Info) == 60, "Incorrect AFP_Info size");
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
|
info->magic = 0x00504641;
|
||||||
|
info->version = 0x00010000;
|
||||||
|
info->backup_date = 0x80000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int afp_verify(struct AFP_Info *info) {
|
||||||
|
if (!info) return 0;
|
||||||
|
|
||||||
|
if (info->magic != 0x00504641) return 0;
|
||||||
|
if (info->version != 0x00010000) return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int afp_to_filetype(struct AFP_Info *info, uint16_t *file_type, uint32_t *aux_type) {
|
||||||
|
// check for prodos ftype/auxtype...
|
||||||
|
if (info->prodos_file_type || info->prodos_aux_type) {
|
||||||
|
*file_type = info->prodos_file_type;
|
||||||
|
*aux_type = info->prodos_aux_type;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int ok = finder_info_to_filetype(info->finder_info, file_type, aux_type);
|
||||||
|
if (ok == 0) {
|
||||||
|
info->prodos_file_type = *file_type;
|
||||||
|
info->prodos_aux_type = *aux_type;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (trust == trust_prodos)
|
||||||
|
file_type_to_finder_info(info->finder_info, info->prodos_file_type, info->prodos_aux_type);
|
||||||
|
else {
|
||||||
|
info->prodos_file_type = f;
|
||||||
|
info->prodos_aux_type = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
finder_info_helper::finder_info_helper() {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
afp_init(&_afp);
|
||||||
|
#else
|
||||||
|
memset(&_finder_info, 0, sizeof(_finder_info));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
finder_info_helper::~finder_info_helper() {
|
||||||
|
if (_fd >= 0) close(_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool finder_info_helper::open(const std::string &name, bool read_only) {
|
||||||
|
|
||||||
|
if (_fd >= 0) {
|
||||||
|
close(_fd);
|
||||||
|
_fd = -1;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (read_only) close(fd);
|
||||||
|
else _fd = fd;
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool finder_info_helper::read(int fd) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
int ok = fi_read(fd, &_afp, sizeof(_afp));
|
||||||
|
if (ok < sizeof(_afp) || !afp_verify(&_afp)) {
|
||||||
|
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));
|
||||||
|
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));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool finder_info_helper::write() {
|
||||||
|
return write(_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void finder_info_helper::set_prodos_file_type(uint16_t ftype, uint32_t atype) {
|
||||||
|
_prodos_file_type = ftype;
|
||||||
|
_prodos_aux_type = atype;
|
||||||
|
file_type_to_finder_info(_finder_info, ftype, atype);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void finder_info_helper::set_prodos_file_type(uint16_t ftype) {
|
||||||
|
set_prodos_file_type(ftype, _prodos_aux_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool finder_info_helper::is_text() const {
|
||||||
|
if (memcmp(_finder_info, "TEXT", 4) == 0) return true;
|
||||||
|
if (_prodos_file_type == 0x04) return true;
|
||||||
|
if (_prodos_file_type == 0xb0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t finder_info_helper::file_type() const {
|
||||||
|
uint32_t rv = 0;
|
||||||
|
for (unsigned i = 0; i < 4; ++i) {
|
||||||
|
rv <<= 8;
|
||||||
|
rv |= _finder_info[i];
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t finder_info_helper::creator_type() const {
|
||||||
|
uint32_t rv = 0;
|
||||||
|
for (unsigned i = 4; i < 8; ++i) {
|
||||||
|
rv <<= 8;
|
||||||
|
rv |= _finder_info[i];
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
95
finder_info_helper.h
Normal file
95
finder_info_helper.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#pragma pack(push, 2)
|
||||||
|
struct AFP_Info {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t file_id;
|
||||||
|
uint32_t backup_date;
|
||||||
|
uint8_t finder_info[32];
|
||||||
|
uint16_t prodos_file_type;
|
||||||
|
uint32_t prodos_aux_type;
|
||||||
|
uint8_t reserved[6];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class finder_info_helper {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
finder_info_helper();
|
||||||
|
~finder_info_helper();
|
||||||
|
|
||||||
|
finder_info_helper(const finder_info_helper &) = delete;
|
||||||
|
finder_info_helper(finder_info_helper &&) = delete;
|
||||||
|
|
||||||
|
finder_info_helper& operator=(const finder_info_helper &) = delete;
|
||||||
|
finder_info_helper& operator=(finder_info_helper &&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t *finder_info() const {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _afp.finder_info;
|
||||||
|
#else
|
||||||
|
return _finder_info;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *finder_info() {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _afp.finder_info;
|
||||||
|
#else
|
||||||
|
return _finder_info;
|
||||||
|
#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();
|
||||||
|
|
||||||
|
uint32_t creator_type() const;
|
||||||
|
uint32_t file_type() const;
|
||||||
|
|
||||||
|
uint16_t prodos_file_type() const {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _afp.prodos_file_type;
|
||||||
|
#else
|
||||||
|
return _prodos_file_type;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t prodos_aux_type() const {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _afp.prodos_aux_type;
|
||||||
|
#else
|
||||||
|
return _prodos_aux_type;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_prodos_file_type(uint16_t);
|
||||||
|
void set_prodos_file_type(uint16_t, uint32_t);
|
||||||
|
|
||||||
|
bool is_text() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool write(int fd);
|
||||||
|
bool read(int fd);
|
||||||
|
|
||||||
|
int _fd = -1;
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
AFP_Info _afp;
|
||||||
|
#else
|
||||||
|
uint16_t _prodos_file_type = 0;
|
||||||
|
uint32_t _prodos_aux_type = 0;
|
||||||
|
uint8_t _finder_info[32] = {};
|
||||||
|
#endif
|
||||||
|
};
|
@ -1,277 +1,19 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <unistd.h>
|
#include "finder_info_helper.h"
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type) {
|
||||||
#include <sys/xattr.h>
|
|
||||||
|
|
||||||
#elif defined(__linux__)
|
finder_info_helper fi;
|
||||||
#include <sys/xattr.h>
|
|
||||||
#define XATTR_FINDERINFO_NAME "user.com.apple.FinderInfo"
|
|
||||||
|
|
||||||
#elif defined(__FreeBSD__)
|
bool ok;
|
||||||
#include <sys/types.h>
|
ok = fi.open(path, false);
|
||||||
#include <sys/extattr.h>
|
if (!ok) return -1;
|
||||||
|
fi.set_prodos_file_type(file_type, aux_type);
|
||||||
#elif defined(_AIX)
|
ok = fi.write();
|
||||||
#include <sys/ea.h>
|
if (!ok) return -1;
|
||||||
|
|
||||||
#elif defined(__sun)
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#else
|
|
||||||
#error "set_file_type: unsupported OS."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef XATTR_FINDERINFO_NAME
|
|
||||||
#define XATTR_FINDERINFO_NAME "com.apple.FinderInfo"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
|
|
||||||
static int file_type_to_finder_info(uint8_t *buffer, uint16_t file_type, uint32_t aux_type) {
|
|
||||||
if (file_type > 0xff || aux_type > 0xffff) return -1;
|
|
||||||
|
|
||||||
if (!file_type && aux_type == 0x0000) {
|
|
||||||
memcpy(buffer, "BINApdos", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_type == 0x04 && aux_type == 0x0000) {
|
|
||||||
memcpy(buffer, "TEXTpdos", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_type == 0xff && aux_type == 0x0000) {
|
|
||||||
memcpy(buffer, "PSYSpdos", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_type == 0xb3 && aux_type == 0x0000) {
|
|
||||||
memcpy(buffer, "PS16pdos", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_type == 0xd7 && aux_type == 0x0000) {
|
|
||||||
memcpy(buffer, "MIDIpdos", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (file_type == 0xd8 && aux_type == 0x0000) {
|
|
||||||
memcpy(buffer, "AIFFpdos", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (file_type == 0xd8 && aux_type == 0x0001) {
|
|
||||||
memcpy(buffer, "AIFCpdos", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (file_type == 0xe0 && aux_type == 0x0005) {
|
|
||||||
memcpy(buffer, "dImgdCpy", 8);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
memcpy(buffer, "p pdos", 8);
|
|
||||||
buffer[1] = (file_type) & 0xff;
|
|
||||||
buffer[2] = (aux_type >> 8) & 0xff;
|
|
||||||
buffer[3] = (aux_type) & 0xff;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
|
|
||||||
|
|
||||||
#pragma pack(push, 2)
|
|
||||||
struct AFP_Info {
|
|
||||||
uint32_t magic;
|
|
||||||
uint32_t version;
|
|
||||||
uint32_t file_id;
|
|
||||||
uint32_t backup_date;
|
|
||||||
uint8_t finder_info[32];
|
|
||||||
uint16_t prodos_file_type;
|
|
||||||
uint32_t prodos_aux_type;
|
|
||||||
uint8_t reserved[6];
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
static void afp_init(struct AFP_Info *info, uint16_t file_type, uint32_t aux_type) {
|
|
||||||
//static_assert(sizeof(AFP_Info) == 60, "Incorrect AFP_Info size");
|
|
||||||
memset(info, 0, sizeof(*info));
|
|
||||||
info->magic = 0x00504641;
|
|
||||||
info->version = 0x00010000;
|
|
||||||
info->backup_date = 0x80000000;
|
|
||||||
info->prodos_file_type = file_type;
|
|
||||||
info->prodos_aux_type = aux_type;
|
|
||||||
if (file_type || aux_type)
|
|
||||||
file_type_to_finder_info(info->finder_info, file_type, aux_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool afp_verify(struct AFP_Info *info) {
|
|
||||||
if (!info) return false;
|
|
||||||
|
|
||||||
if (info->magic != 0x00504641) return false;
|
|
||||||
if (info->version != 0x00010000) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type) {
|
|
||||||
AFP_Info info;
|
|
||||||
int ok;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
ok = stat(path.c_str(), &st);
|
|
||||||
if (ok == 0 && ! S_ISDIR(st.st_mode)) {
|
|
||||||
|
|
||||||
std::string xpath(path);
|
|
||||||
xpath.append(":AFP_AfpInfo");
|
|
||||||
|
|
||||||
int fd = open(xpath.c_str(), O_RDWR | O_CREAT | O_BINARY, 0666);
|
|
||||||
if (fd < 0) return -1;
|
|
||||||
|
|
||||||
ok = read(fd, &info, sizeof(info));
|
|
||||||
if (ok < sizeof(info) || !afp_verify(&info)) {
|
|
||||||
afp_init(&info, file_type, aux_type);
|
|
||||||
} else {
|
|
||||||
info.prodos_file_type = file_type;
|
|
||||||
info.prodos_aux_type = aux_type;
|
|
||||||
file_type_to_finder_info(info.finder_info, file_type, aux_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
ok = write(fd, &info, sizeof(info));
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (ok > 0) ok = 0;
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type) {
|
|
||||||
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
int ok;
|
|
||||||
struct stat st;
|
|
||||||
fd = open(path.c_str(), O_RDONLY);
|
|
||||||
if (fd < 0) return -1;
|
|
||||||
|
|
||||||
ok = fstat(fd, &st);
|
|
||||||
if (ok == 0 && !S_ISDIR(st.st_mode)) {
|
|
||||||
uint8_t buffer[32];
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
|
||||||
|
|
||||||
#if defined(__sun)
|
|
||||||
int xfd = attropen(path, XATTR_RESOURCEFORK_NAME, O_RDWR | O_CREAT, 0666);
|
|
||||||
if (xfd < 0) {
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ok = read(xfd, buffer, 32);
|
|
||||||
file_type_to_finder_info(buffer, file_type, aux_type);
|
|
||||||
lseek(xfd, 0, SEEK_SET);
|
|
||||||
ok = write(xfd, buffer, 32);
|
|
||||||
close(xfd);
|
|
||||||
#else
|
|
||||||
|
|
||||||
ok = read_xattr(fd, XATTR_FINDERINFO_NAME, buffer, 32);
|
|
||||||
file_type_to_finder_info(buffer, file_type, aux_type);
|
|
||||||
ok = write_xattr(fd, XATTR_FINDERINFO_NAME, buffer, 32);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
if (ok > 0) ok = 0;
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Loading…
Reference in New Issue
Block a user