From 8f2b86b8822625bcaa45cc418bf656a9d4d9307b Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 11 Jan 2017 14:05:12 -0500 Subject: [PATCH] set file type. --- Makefile | 2 +- link.cpp | 15 ++- set_file_type.cpp | 275 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 set_file_type.cpp diff --git a/Makefile b/Makefile index 40ed5af..ac3ee3e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CXXFLAGS = -std=c++14 -g -Wall CCFLAGS = -g DUMP_OBJS = dumpobj.o disassembler.o zrdz_disassembler.o -LINK_OBJS = link.o expression.o omf.o +LINK_OBJS = link.o expression.o omf.o set_file_type.o #UNAME_S := $(shell uname -s) #ifeq ($(UNAME_S),MINGW64_NT-10.0) diff --git a/link.cpp b/link.cpp index fda144e..5679248 100644 --- a/link.cpp +++ b/link.cpp @@ -39,6 +39,8 @@ struct { std::string _o; unsigned _errors = 0; + uint16_t _file_type; + uint32_t _aux_type; } flags; enum class endian { @@ -1026,7 +1028,7 @@ int main(int argc, char **argv) { int c; - while ((c = getopt(argc, argv, "vCXL:l:o:")) != -1) { + while ((c = getopt(argc, argv, "vCXL:l:o:t:")) != -1) { switch(c) { case 'v': flags._v = true; break; case 'X': flags._X = true; break; @@ -1035,6 +1037,12 @@ int main(int argc, char **argv) { case 'l': _l.emplace_back(optarg); break; case 'L': _L.emplace_back(optarg); break; case 'h': help(); break; + case 't': { + // -t xx[:xxxx] -- set file/auxtype. + std::string tmp=optarg; + break; + } + case ':': case '?': default: @@ -1094,9 +1102,14 @@ int main(int argc, char **argv) { } if (flags._o.empty()) flags._o = "out.omf"; + if (!flags._file_type) { + flags._file_type = 0xb3; + } void save_omf(std::vector &segments, bool expressload, const std::string &path); + int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type); save_omf(omf_segments, !flags._X, flags._o); + set_file_type(flags._o, flags._file_type, flags._aux_type); } diff --git a/set_file_type.cpp b/set_file_type.cpp new file mode 100644 index 0000000..fba9cfb --- /dev/null +++ b/set_file_type.cpp @@ -0,0 +1,275 @@ +#include +#include +#include + +#include +#include + + +#if defined(__APPLE__) +#include +#include + +#elif defined(__linux__) +#include +#define XATTR_FINDERINFO_NAME "user.com.apple.FinderInfo" + +#elif defined(__FreeBSD__) +#include +#include + +#elif defined(_AIX) +#include + +#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; +} + +#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->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 0; + + if (info->magic != 0x00504641) return 0; + if (info->version != 0x00010000) return 0; + + return 1; +} + + +int set_file_type(const std::string &path, uint16_t ftype, uint32_t auxtype) { + AFP_Info info; + int ok; + struct stat st; + + ok = stat(path, &st); + if (ok == 0 && ! S_ISDIR(st.st_mode)) { + + std::string xpath(path); + xpath.append(":AFP_AfpInfo"); + + int fd = open(path.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, filetype, auxtype) + } else { + info.prodos_file_type = filetype; + info.prodos_aux_type = auxtype; + 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 ftype, uint32_t auxtype) { + + + 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, ftype, auxtype); + 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, ftype, auxtype); + ok = write_xattr(fd, XATTR_FINDERINFO_NAME, buffer, 32); +#endif + } + + close(fd); + if (ok > 0) ok = 0; + return ok; +} + +#endif