From 192cfc724b39638586924d87edf97e09fcd5cfbb Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Thu, 23 Aug 2018 00:38:53 -0400 Subject: [PATCH 1/4] win32 host mli support this also moves a lot of common host_fst / host_mli / win_host_fst into host_common / unix_host_common / win32_host_common Currently untested. --- src/host_common.c | 466 +-------------- src/host_common.h | 80 ++- src/host_fst.c | 2 +- src/host_mli.c | 461 +++++++++------ src/unix_host_common.c | 510 ++++++++++++++++ src/win32_host_common.c | 629 ++++++++++++++++++++ src/win32_host_fst.c | 1239 ++++----------------------------------- 7 files changed, 1630 insertions(+), 1757 deletions(-) create mode 100644 src/unix_host_common.c create mode 100644 src/win32_host_common.c diff --git a/src/host_common.c b/src/host_common.c index 158db53..6cab5ab 100644 --- a/src/host_common.c +++ b/src/host_common.c @@ -14,47 +14,14 @@ #include "gsos.h" #include "fst.h" +#ifdef _WIN32 +#include +#endif + #include "host_common.h" -#if defined(__APPLE__) -#include -#include -#include -#endif -#ifdef __linux__ -#include - -#endif - - -#if defined(_WIN32) || defined(WIN_SDL) -#include -#include -#endif - -#if defined(__FreeBSD__) -#include -#include -#endif - -#if defined(_AIX) -#include -#endif - -#ifndef XATTR_FINDERINFO_NAME -#define XATTR_FINDERINFO_NAME "com.apple.FinderInfo" -#endif - -#ifndef XATTR_RESOURCEFORK_NAME -#define XATTR_RESOURCEFORK_NAME "com.apple.ResourceFork" -#endif - - -ino_t root_ino = 0; -dev_t root_dev = 0; char *host_root = NULL; -int host_read_only = 0; char *g_cfg_host_path = ""; // must not be null. int g_cfg_host_read_only = 0; @@ -64,42 +31,6 @@ int g_cfg_host_merlin = 0; -unsigned host_startup(void) { - - struct stat st; - - if (!g_cfg_host_path) return invalidFSTop; - if (!*g_cfg_host_path) return invalidFSTop; - if (host_root) free(host_root); - host_root = strdup(g_cfg_host_path); - - host_read_only = g_cfg_host_read_only; - - if (stat(host_root, &st) < 0) { - fprintf(stderr, "%s does not exist\n", host_root); - return invalidFSTop; - } - if (!S_ISDIR(st.st_mode)) { - fprintf(stderr, "%s is not a directory\n", host_root); - return invalidFSTop; - } - - root_ino = st.st_ino; - root_dev = st.st_dev; - - return 0; -} - -void host_shutdown(void) { - if (host_root) free(host_root); - host_root = NULL; - root_ino = 0; - root_dev = 0; -} - -int host_is_root(struct stat *st) { - return st->st_ino == root_ino && st->st_dev == root_dev; -} /* @@ -245,7 +176,9 @@ word32 host_map_errno(int xerrno) { case 0: return 0; case EBADF: return invalidAccess; +#ifdef EDQUOT case EDQUOT: +#endif case EFBIG: return volumeFull; case ENOENT: @@ -438,7 +371,7 @@ static int hex(byte c) { } -static int finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type) { +int host_finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type) { if (!memcmp("pdos", buffer + 4, 4)) { @@ -552,68 +485,6 @@ int host_file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_typ } -#if defined(__APPLE__) -void host_get_file_xinfo(const char *path, struct file_info *fi) { - - ssize_t tmp; - tmp = getxattr(path, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0); - if (tmp < 0) tmp = 0; - fi->resource_eof = tmp; - fi->resource_blocks = (tmp + 511) / 512; - - tmp = getxattr(path, XATTR_FINDERINFO_NAME, fi->finder_info, 32, 0, 0); - if (tmp == 16 || tmp == 32) { - fi->has_fi = 1; - - finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); - } -} -#elif defined(__sun) -void host_get_file_xinfo(const char *path, struct file_info *fi) { - - struct stat st; - - // can't stat an xattr directly? - int fd; - fd = attropen(path, XATTR_RESOURCEFORK_NAME, O_RDONLY); - if (fd >= 0) { - if (fstat(fd, &st) == 0) { - fi->resource_eof = st.st_size; - fi->resource_blocks = st.st_blocks; - } - close(fd); - } - - fd = attropen(path, XATTR_FINDERINFO_NAME, O_RDONLY); - if (fd >= 0) { - int tmp = read(fd, fi->finder_info, 32); - if (tmp == 16 || tmp == 32) { - fi->has_fi = 1; - finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); - } - close(fd); - } -} -#elif defined(__linux__) -void host_get_file_xinfo(const char *path, struct file_info *fi) { - - ssize_t tmp; - tmp = getxattr(path, "user.com.apple.ResourceFork", NULL, 0); - if (tmp < 0) tmp = 0; - fi->resource_eof = tmp; - fi->resource_blocks = (tmp + 511) / 512; - - tmp = getxattr(path, "user.com.apple.FinderInfo", fi->finder_info, 32); - if (tmp == 16 || tmp == 32) { - fi->has_fi = 1; - - finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); - } -} -#else -void host_get_file_xinfo(const char *path, struct file_info *fi) { -} -#endif #undef _ #define _(a, b, c) { a, sizeof(a) - 1, b, c } @@ -646,311 +517,31 @@ static struct ftype_entry prefixes[] = { #undef _ -word32 host_get_file_info(const char *path, struct file_info *fi) { - struct stat st; - memset(fi, 0, sizeof(*fi)); +void host_synthesize_file_xinfo(const char *path, struct file_info *fi) { - int ok = stat(path, &st); - if (ok < 0) return host_map_errno(errno); + /* guess the file type / auxtype based on extension */ + int n; + const char *dot = NULL; + const char *slash = NULL; - fi->eof = st.st_size; - fi->blocks = st.st_blocks; - - fi->create_date = st.st_ctime; - fi->modified_date = st.st_mtime; - -#if defined(__APPLE__) - fi->create_date = st.st_birthtime; -#endif - - - fi->st_mode = st.st_mode; - - if (S_ISDIR(st.st_mode)) { - fi->storage_type = directoryFile; - fi->file_type = 0x0f; - if (host_is_root(&st)) - fi->storage_type = 0x0f; - } else if (S_ISREG(st.st_mode)) { - fi->file_type = 0x06; - if (st.st_size < 0x200) fi->storage_type = seedling; - else if (st.st_size < 0x20000) fi->storage_type = sapling; - else fi->storage_type = tree; - } else { - fi->storage_type = st.st_mode & S_IFMT; - fi->file_type = 0; + for(n = 0;; ++n) { + char c = path[n]; + if (c == 0) break; + else if (c == '/') { slash = path + n + 1; dot = NULL; } + else if (c == '.') dot = path + n + 1; } - // 0x01 = read enable - // 0x02 = write enable - // 0x04 = invisible - // 0x08 = reserved - // 0x10 = reserved - // 0x20 = backup needed - // 0x40 = rename enable - // 0x80 = destroy enable - fi->access = 0xc3; // placeholder... - - if (S_ISREG(st.st_mode)) { - host_get_file_xinfo(path, fi); - - if (!fi->has_fi) { - /* guess the file type / auxtype based on extension */ - int n; - const char *dot = NULL; - const char *slash = NULL; - - for(n = 0;; ++n) { - char c = path[n]; - if (c == 0) break; - else if (c == '/') { slash = path + n + 1; dot = NULL; } - else if (c == '.') dot = path + n + 1; - } - - if (dot && *dot) { - for (n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) { - if (!suffixes[n].ext) break; - if (!strcasecmp(dot, suffixes[n].ext)) { - fi->file_type = suffixes[n].file_type; - fi->aux_type = suffixes[n].aux_type; - break; - } - } + if (dot && *dot) { + for (n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) { + if (!suffixes[n].ext) break; + if (!strcasecmp(dot, suffixes[n].ext)) { + fi->file_type = suffixes[n].file_type; + fi->aux_type = suffixes[n].aux_type; + return; } } } - - // get file type/aux type - - if (fi->resource_eof) fi->storage_type = extendedFile; - - return 0; -} - - - - -#if defined(__APPLE__) -word32 host_set_file_info(const char *path, struct file_info *fi) { - - int ok; - struct attrlist list; - unsigned i = 0; - struct timespec dates[2]; - - if (fi->has_fi && fi->storage_type != 0x0d) { - ok = setxattr(path, XATTR_FINDERINFO_NAME, fi->finder_info, 32, 0, 0); - if (ok < 0) return host_map_errno(errno); - } - - - memset(&list, 0, sizeof(list)); - memset(dates, 0, sizeof(dates)); - - list.bitmapcount = ATTR_BIT_MAP_COUNT; - list.commonattr = 0; - - if (fi->create_date) - { - dates[i++].tv_sec = fi->create_date; - list.commonattr |= ATTR_CMN_CRTIME; - } - - if (fi->modified_date) - { - dates[i++].tv_sec = fi->modified_date; - list.commonattr |= ATTR_CMN_MODTIME; - } - - ok = 0; - if (i) ok = setattrlist(path, &list, dates, i * sizeof(struct timespec), 0); - return 0; -} -#elif defined(__sun) -word32 host_set_file_info(const char *path, struct file_info *fi) { - - if (fi->has_fi && fi->storage_type != 0x0d) { - int fd = attropen(path, XATTR_FINDERINFO_NAME, O_WRONLY | O_CREAT, 0666); - if (fd < 0) return host_map_errno(errno); - write(fd, fi->finder_info, 32); - close(fd); - } - - if (fi->modified_date) { - struct timeval times[2]; - - memset(times, 0, sizeof(times)); - - //times[0] = 0; // access - times[1].tv_sec = fi.modified_date; // modified - int ok = utimes(path, times); - if (ok < 0) return host_map_errno(errno); - } - return 0; -} -#elif defined(__linux__) -word32 host_set_file_info(const char *path, struct file_info *fi) { - - if (fi->has_fi && fi->storage_type != 0x0d) { - int ok = setxattr(path, "user.apple.FinderInfo", fi->finder_info, 32, 0); - if (ok < 0) return host_map_errno(errno); - } - - if (fi->modified_date) { - struct timeval times[2]; - - memset(times, 0, sizeof(times)); - - //times[0] = 0; // access - times[1].tv_sec = fi->modified_date; // modified - int ok = utimes(path, times); - if (ok < 0) return host_map_errno(errno); - } - return 0; -} - -#else - -word32 host_set_file_info(const char *path, struct file_info *fi) { - - if (fi->modified_date) { - - struct timeval times[2]; - - memset(times, 0, sizeof(times)); - - times[0] = 0; // access - times[1].tv_sec = fi->modified_date; // modified - - int ok = utimes(path, times); - if (ok < 0) return host_map_errno(errno); - } - return 0; -} - -#endif - - -/* - * Date/time conversion - */ - -/* - * converts time_t to a gs/os readhextime date/time record. - */ - -void host_set_date_time_rec(word32 ptr, time_t time) { - - if (time == 0) { - for (int i = 0; i < 8; ++i) set_memory_c(ptr++, 0, 0); - return; - } - - struct tm *tm = localtime(&time); - if (tm->tm_sec == 60) tm->tm_sec = 59; /* leap second */ - - set_memory_c(ptr++, tm->tm_sec, 0); - set_memory_c(ptr++, tm->tm_min, 0); - set_memory_c(ptr++, tm->tm_hour, 0); - set_memory_c(ptr++, tm->tm_year, 0); - set_memory_c(ptr++, tm->tm_mday - 1, 0); - set_memory_c(ptr++, tm->tm_mon, 0); - set_memory_c(ptr++, 0, 0); - set_memory_c(ptr++, tm->tm_wday + 1, 0); -} - -/* - * converts time_t to a prodos16 date/time record. - */ -void host_set_date_time(word32 ptr, time_t time) { - - if (time == 0) { - for (int i = 0; i < 4; ++i) set_memory_c(ptr++, 0, 0); - return; - } - - struct tm *tm = localtime(&time); - - word16 tmp = 0; - tmp |= (tm->tm_year % 100) << 9; - tmp |= tm->tm_mon << 5; - tmp |= tm->tm_mday; - - set_memory16_c(ptr, tmp, 0); - ptr += 2; - - tmp = 0; - tmp |= tm->tm_hour << 8; - tmp |= tm->tm_min; - set_memory16_c(ptr, tmp, 0); -} - -word32 host_convert_date_time(time_t time) { - - if (time == 0) return 0; - - struct tm *tm = localtime(&time); - - word16 dd = 0; - dd |= (tm->tm_year % 100) << 9; - dd |= tm->tm_mon << 5; - dd |= tm->tm_mday; - - word16 tt = 0; - tt |= tm->tm_hour << 8; - tt |= tm->tm_min; - - - return (tt << 16) | dd; -} - - -time_t host_get_date_time(word32 ptr) { - - word16 a = get_memory16_c(ptr + 0, 0); - word16 b = get_memory16_c(ptr + 2, 0); - if (!a && !b) return 0; - - struct tm tm; - memset(&tm, 0, sizeof(tm)); - - tm.tm_year = (a >> 9) & 0x7f; - tm.tm_mon = ((a >> 5) & 0x0f) - 1; - tm.tm_mday = (a >> 0) & 0x1f; - - tm.tm_hour = (b >> 8) & 0x1f; - tm.tm_min = (b >> 0) & 0x3f; - tm.tm_sec = 0; - - tm.tm_isdst = -1; - - // 00 - 39 => 2000-2039 - // 40 - 99 => 1940-1999 - if (tm.tm_year < 40) tm.tm_year += 100; - - - return mktime(&tm); -} - -time_t host_get_date_time_rec(word32 ptr) { - - byte buffer[8]; - for (int i = 0; i < 8; ++i) buffer[i] = get_memory_c(ptr++, 0); - - if (!memcmp(buffer, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) return 0; - - struct tm tm; - memset(&tm, 0, sizeof(tm)); - - tm.tm_sec = buffer[0]; - tm.tm_min = buffer[1]; - tm.tm_hour = buffer[2]; - tm.tm_year = buffer[3]; - tm.tm_mday = buffer[4] + 1; - tm.tm_mon = buffer[5]; - tm.tm_isdst = -1; - - return mktime(&tm); + return; } @@ -1028,3 +619,10 @@ void host_hexdump_native(void *data, unsigned address, int size) { } printf("\n"); } + + + +void host_free_directory(char **data, size_t count) { + for (int i = 0; i < count; ++i) free(data[i]); + free(data); +} diff --git a/src/host_common.h b/src/host_common.h index ee4cb71..6708fea 100644 --- a/src/host_common.h +++ b/src/host_common.h @@ -1,3 +1,41 @@ + + + +#ifdef _WIN32 + +#include + +#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) + +void afp_init(struct AFP_Info *info, word16 file_type, word32 aux_type); +BOOL afp_verify(struct AFP_Info *info); +int afp_to_filetype(struct AFP_Info *info, word16 *file_type, word32 *aux_type); +enum { prefer_prodos, prefer_hfs }; +void afp_synchronize(struct AFP_Info *info, int preference); + +#endif + +#ifdef _WIN32 +typedef FILETIME host_time_t; +typedef struct AFP_Info host_finder_info_t; +#else +typedef time_t host_time_t; +typedef unsigned char host_finder_info_t[32]; +#endif + + + enum { file_non, file_regular, @@ -15,8 +53,8 @@ enum { struct file_info { - time_t create_date; - time_t modified_date; + host_time_t create_date; + host_time_t modified_date; word16 access; word16 storage_type; word16 file_type; @@ -25,9 +63,12 @@ struct file_info { word32 blocks; word32 resource_eof; word32 resource_blocks; - mode_t st_mode; int has_fi; + #ifdef _WIN32 + struct AFP_Info afp; + #else byte finder_info[32]; + #endif }; @@ -53,6 +94,7 @@ enum { N = 0x80 }; +extern char *g_cfg_host_path; extern int g_cfg_host_read_only; extern int g_cfg_host_crlf; extern int g_cfg_host_merlin; @@ -61,7 +103,11 @@ extern char *host_root; unsigned host_startup(void); void host_shutdown(void); +#ifdef _WIN32 +int host_is_root(const BY_HANDLE_FILE_INFORMATION *info); +#else int host_is_root(struct stat *); +#endif /* garbage collected string routines */ @@ -82,24 +128,40 @@ word32 host_map_errno(int xerrno); word32 host_map_errno_path(int xerrno, const char *path); const char *host_error_name(word16 error); -/* file info */ +#ifdef _WIN32 +word32 host_map_win32_error(DWORD); +word32 host_map_win32_error_path(DWORD, const char *path); +#endif +/* file info */ +int host_finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type); int host_file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_type); + void host_get_file_xinfo(const char *path, struct file_info *fi); word32 host_get_file_info(const char *path, struct file_info *fi); word32 host_set_file_info(const char *path, struct file_info *fi); +/* guesses filetype/auxtype from extension */ +void host_synthesize_file_xinfo(const char *path, struct file_info *fi); -void host_set_date_time_rec(word32 ptr, time_t time); -void host_set_date_time(word32 ptr, time_t time); +void host_set_date_time_rec(word32 ptr, host_time_t time); +void host_set_date_time(word32 ptr, host_time_t time); -time_t host_get_date_time(word32 ptr); -time_t host_get_date_time_rec(word32 ptr); +host_time_t host_get_date_time(word32 ptr); +host_time_t host_get_date_time_rec(word32 ptr); /* convert to prodos date/time */ -word32 host_convert_date_time(time_t time); +word32 host_convert_date_time(host_time_t time); +/* scan a directory, return array of char * */ +unsigned host_scan_directory(const char *path, char ***out, size_t *entries, unsigned p8); +void host_free_directory(char **data, size_t count); + + +/* 0x01, 0x0d, 0x0f, 0 on error */ +unsigned host_storage_type(const char *path, word16 *error_ptr); + void host_hexdump(word32 address, int size); void host_hexdump_native(void *data, unsigned address, int size); diff --git a/src/host_fst.c b/src/host_fst.c index c1cfbd1..425a7c1 100644 --- a/src/host_fst.c +++ b/src/host_fst.c @@ -893,7 +893,7 @@ static word32 fst_open(int class, const char *path) { if (access > 3) return paramRangeErr; // special access checks for directories. - if (S_ISDIR(fi.st_mode)) { + if (fi.storage_type == 0x0d || fi.storage_type == 0x0f) { if (resource_number) return resForkNotFound; switch (request_access) { case readEnableAllowWrite: diff --git a/src/host_mli.c b/src/host_mli.c index 2d2c0e2..c0ca991 100644 --- a/src/host_mli.c +++ b/src/host_mli.c @@ -1,18 +1,23 @@ #define _BSD_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifdef _WIN32 +#include +#else + +#include +#include +#include +#include +#include + +#endif -#include #include +#include +#include +#include + #include "defc.h" #include "gsos.h" @@ -75,47 +80,18 @@ enum { QUIT = 0x65 }; -#if 0 -enum { - noError = 0x0000, - invalidCallNum = 0x01, - invalidPcount = 0x04, - intTableFull = 0x25, - ioError = 0x27, - noDevConnect = 0x28, - writeProtectErr = 0x2B, - diskSwitchErr = 0x2E, - badPathname = 0x40, - fcbFullErr = 0x42, - badFileRefNum = 0x43, - pathNotFound = 0x44, - volumeNotFound = 0x45, - fileNotFound = 0x46, - dupFileName = 0x47, - volumeFullErr = 0x48, - dirFullErr = 0x49, - versionErr = 0x4A, - badStoreType = 0x4B, - eofEncountered = 0x4C, - positionRangeErr = 0x4D, - accessErr = 0x4E, - fileOpenErr = 0x50, - dirDamaged = 0x51, - badVolType = 0x52, - paramRangeErr = 0x53, - vcbFullErr = 0x55, - badBufferAddress = 0x56, - dupVolumeErr = 0x57, - blkNumRangeErr = 0x5A -}; -#endif #define badBufferAddress 0x56 - struct file_entry { unsigned type; unsigned translate; + +#ifdef _WIN32 + HANDLE h; +#else int fd; +#endif + unsigned buffer; unsigned level; unsigned newline_mask; @@ -183,45 +159,6 @@ static char *is_host_path(unsigned pathname) { } - -static int scandir_sort(const struct dirent **a, const struct dirent **b) { - return strcasecmp((**a).d_name, (**b).d_name); -} - -static int scandir_filter(const struct dirent *d) { - int i; - const char *name = d->d_name; - - if (name[0] == '.') return 0; - for (i = 0;; ++i) { - unsigned char c = name[i]; - if (c & 0x80) return 0; - if (c == 0) break; - } - if (i > 15) return 0; - return 1; -} - -static int count_directory_entries(const char *path) { - DIR *dir; - int rv; - - dir = opendir(path); - if (!dir) return 0; - - for(rv = 0;;) { - struct dirent *dp = readdir(dir); - if (!dp) break; - if (!scandir_filter(dp)) continue; - ++rv; - } - - closedir(dir); - return rv; -} - - - static unsigned lowercase_bits(const char *name) { unsigned rv = 0x8000; unsigned bit = 0x4000; @@ -235,10 +172,10 @@ static unsigned lowercase_bits(const char *name) { /* name is relative to the host directory. */ -void *create_directory_file(const char *name, const char *path, unsigned *error_ptr, unsigned *block_ptr) { +void *create_directory_file(const char *name, const char *path, word16 *error_ptr, unsigned *block_ptr) { - byte *data; + byte *data = NULL; int capacity = 0; int count = 0; unsigned offset = 0; @@ -249,15 +186,14 @@ void *create_directory_file(const char *name, const char *path, unsigned *error_ word32 w32; - struct dirent **entries = NULL; - int entry_count = 0; - entry_count = scandir(path, &entries, scandir_filter, scandir_sort); - if (entry_count < 0) { - *error_ptr = host_map_errno_path(errno, path); - goto exit; + char **entries = NULL; + size_t entry_count = 0; + terr = host_scan_directory(path, &entries, &entry_count, 1); + if (terr) { + *error_ptr = terr; + return NULL; } - /* also need space for volume/directory header */ capacity = 1 + (1 + entry_count) / ENTRIES_PER_BLOCK; capacity *= 512; @@ -276,8 +212,7 @@ void *create_directory_file(const char *name, const char *path, unsigned *error_ goto exit; } - /* TODO -- this is wrong. */ - /* trailing /s should be stripped */ + /* trailing /s should already be stripped */ const char *base_name = strchr(name, '/'); base_name = base_name ? base_name + 1 : name; if (!base_name || !*base_name) base_name = "HOST"; @@ -351,7 +286,7 @@ void *create_directory_file(const char *name, const char *path, unsigned *error_ blocks = 1; for (int j = 0; j < entry_count; ++j) { - char *name = entries[j]->d_name; + char *name = entries[j]; int len = strlen(name); char *tmp = malloc(path_len + 2 + len); if (!tmp) continue; @@ -428,12 +363,7 @@ void *create_directory_file(const char *name, const char *path, unsigned *error_ *block_ptr = blocks; exit: - if (entries) { - for (i = 0; i < entry_count; ++i) { - free(entries[i]); - } - free(entries); - } + if (entries) host_free_directory(entries, entry_count); return data; } @@ -560,10 +490,25 @@ static int mli_create(unsigned dcb, const char *path) { // todo -- remap access. if (fi.storage_type == 0x0d) { - int ok = mkdir(path, 0777); - if (ok < 0) +#if _WIN32 + if (!CreateDirectory(path, NULL)) + return host_map_win32_error(GetLastError()); +#else + if (mkdir(path, 0777) < 0) return host_map_errno_path(errno, path); +#endif } else { +#if _WIN32 + HANDLE h = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + afp_init(&fi.afp, fi.file_type, fi.aux_type); + fi.has_fi = 1; + + // set ftype, auxtype... + host_set_file_info(path, &fi); + CloseHandle(h); +#else int fd = open(path, O_CREAT | O_EXCL | O_RDONLY, 0666); if (fd < 0) return host_map_errno_path(errno, path); @@ -572,49 +517,69 @@ static int mli_create(unsigned dcb, const char *path) { fi.has_fi = 1; host_set_file_info(path, &fi); close(fd); +#endif } return 0; } static int mli_destroy(unsigned dcb, const char *path) { - /* can't delete the root directory */ - struct stat st; - if (stat(path, &st) < 0) { - return host_map_errno_path(errno, path); + + word16 terr = 0; + unsigned type = host_storage_type(path, &terr); + if (type == 0) return terr; + + switch(type) { + case 0: return terr; + case 0x0f: return badPathSyntax; /* root directory */ + case 0x0d: +#if _WIN32 + if (!RemoveDirectory(path)) + return host_map_win32_error(GetLastError()); +#else + if (rmdir(path) < 0) + return host_map_errno_path(errno, path); +#endif + break; + case 1: + case 2: + case 3: + case 5: +#if _WIN32 + if (!DeleteFile(path)) + return host_map_win32_error(GetLastError()); +#else + if (unlink(path) < 0) + return host_map_errno_path(errno, path); +#endif + default: + return badStoreType; } - - if (host_is_root(&st)) - return badPathSyntax; - - int ok = S_ISDIR(st.st_mode) ? rmdir(path) : unlink(path); - - if (ok < 0) return host_map_errno(errno); return 0; } static int mli_rename(unsigned dcb, const char *path1, const char *path2) { /* can't rename the root directory */ - struct stat st; + word16 terr = 0; + unsigned type; if (!path1 || !path2) return badPathSyntax; - if (stat(path1, &st) < 0) { - return host_map_errno_path(errno, path1); - } - if (host_is_root(&st)) - return badPathSyntax; + type = host_storage_type(path1, &terr); + if (!type) return terr; + if (type == 0x0f) return badPathSyntax; + type = host_storage_type(path2, &terr); + if (type) return dupPathname; - if (stat(path2, &st) == 0) { - return dupPathname; - } - if (host_is_root(&st)) - return badPathSyntax; - - int ok = rename(path1, path2); - if (ok < 0) return host_map_errno(errno); +#if _WIN32 + if (!MoveFile(path1, path2)) + return host_map_win32_error(GetLastError()); +#else + if (rename(path1, path2) < 0) + return host_map_errno(errno); +#endif return 0; } @@ -649,9 +614,18 @@ static int mli_write(unsigned dcb, struct file_entry *file) { break; } +#if _WIN32 + DWORD rv; + LARGE_INTEGER li; + li.QuadPart = file->mark; + if (!SetFilePointerEx(file->h, li, NULL, FILE_BEGIN)) + return host_map_win32_error(GetLastError()); + if (!WriteFile(file->h, data, request_count, &rv, NULL)) + return host_map_win32_error(GetLastError()); +#else int rv = pwrite(file->fd, data, request_count, file->mark); if (rv < 0) return host_map_errno(errno); - +#endif set_memory16_c(dcb + 6, rv, 0); file->mark += rv; @@ -700,8 +674,20 @@ static int mli_read(unsigned dcb, struct file_entry *file) { byte *data = host_gc_malloc(request_count); if (!data) return drvrIOError; +#if _WIN32 + LARGE_INTEGER li; + DWORD rv; + li.QuadPart = file->mark; + if (!SetFilePointerEx(file->h, li, NULL, FILE_BEGIN)) + return host_map_win32_error(GetLastError()); + + if (!ReadFile(file->h, data, request_count, &rv, NULL)) + return host_map_win32_error(GetLastError()); +#else int rv = pread(file->fd, data, request_count, file->mark); if (rv < 0) return host_map_errno(errno); +#endif + if (rv == 0) return eofEncountered; count = rv; @@ -752,6 +738,10 @@ static int mli_set_buf(unsigned dcb, struct file_entry *file) { static int mli_get_eof(unsigned dcb, struct file_entry *file) { off_t eof = 0; +#if _WIN32 + LARGE_INTEGER tmp; +#endif + switch (file->type) { default: @@ -762,8 +752,14 @@ static int mli_get_eof(unsigned dcb, struct file_entry *file) { break; case file_regular: +#if _WIN32 + if (!GetFileSizeEx(file->h, &tmp)) + return host_map_win32_error(GetLastError()); + eof = tmp.QuadPart; +#else eof = lseek(file->fd, SEEK_END, 0); if (eof < 0) return host_map_errno(errno); +#endif break; } if (eof > 0xffffff) return outOfRange; @@ -775,6 +771,9 @@ static int mli_get_eof(unsigned dcb, struct file_entry *file) { static int mli_set_eof(unsigned dcb, struct file_entry *file) { off_t eof = get_memory24_c(dcb + 2, 0); +#if _WIN32 + LARGE_INTEGER tmp; +#endif switch (file->type) { default: @@ -785,8 +784,16 @@ static int mli_set_eof(unsigned dcb, struct file_entry *file) { break; case file_regular: +#if _WIN32 + tmp.QuadPart = eof; + if (!SetFilePointerEx(file->h, tmp, NULL, FILE_BEGIN)) + return host_map_win32_error(GetLastError()); + if (!SetEndOfFile(file->h)) + return host_map_win32_error(GetLastError()); +#else if (ftruncate(file->fd, eof) < 0) return host_map_errno(errno); +#endif break; } return 0; @@ -814,6 +821,11 @@ static int mli_get_mark(unsigned dcb, struct file_entry *file) { static int mli_set_mark(unsigned dcb, struct file_entry *file) { off_t eof = 0; + +#if _WIN32 + LARGE_INTEGER tmp; +#endif + word32 position = get_memory24_c(dcb + 2, 0); switch (file->type) { @@ -823,8 +835,14 @@ static int mli_set_mark(unsigned dcb, struct file_entry *file) { eof = file->eof; break; case file_regular: +#if _WIN32 + if (!GetFileSizeEx(file->h, &tmp)) + return host_map_win32_error(GetLastError()); + eof = tmp.QuadPart; +#else eof = lseek(file->fd, SEEK_END, 0); if (eof < 0) return host_map_errno(errno); +#endif break; } @@ -842,6 +860,54 @@ static int mli_newline(unsigned dcb, struct file_entry *file) { return 0; } +#ifdef _WIN32 +static word16 file_close(struct file_entry *file) { + + if (!file->type) return invalidRefNum; + + if (file->h != INVALID_HANDLE_VALUE) CloseHandle(file->h); + + if (file->directory_buffer) free(file->directory_buffer); + memset(file, 0, sizeof(*file)); + file->h = INVALID_HANDLE_VALUE; + + return 0; +} + +static word16 file_flush(struct file_entry *file) { + if (!file->type) return invalidRefNum; + + if (file->h != INVALID_HANDLE_VALUE) + FlushFileBuffers(file->h); + + return 0; +} + +#else +static word16 file_close(struct file_entry *file) { + + if (!file->type) return invalidRefNum; + + if (file->fd >= 0) close(file->fd); + + if (file->directory_buffer) free(file->directory_buffer); + memset(file, 0, sizeof(*file)); + file->fd = -1; + return 0; +} + +static word16 file_flush(struct file_entry *file) { + if (!file->type) return invalidRefNum; + + if (file->fd >= 0) + fsync(file->fd); + + return 0; +} + + +#endif + static int mli_close(unsigned dcb, struct file_entry *file) { if (!file) { @@ -851,18 +917,12 @@ static int mli_close(unsigned dcb, struct file_entry *file) { file = &files[i]; if (!file->type) continue; if (file->level < level) continue; - mli_close(dcb, file); + file_close(file); } return -1; /* pass to prodos mli */ } - if (!file->type) return invalidRefNum; - if (file->fd >= 0) close(file->fd); - if (file->directory_buffer) free(file->directory_buffer); - memset(file, 0, sizeof(*file)); - file->fd = -1; - - return 0; + return file_close(file); } @@ -876,16 +936,11 @@ static int mli_flush(unsigned dcb, struct file_entry *file) { if (!file->type) continue; if (file->level < level) continue; - if (file->fd >= 0) - fsync(file->fd); + file_flush(file); } return -1; /* pass to prodos mli */ } - - if (!file->type) return invalidRefNum; - if (file->fd >= 0) fsync(file->fd); - - return 0; + return file_flush(file); } @@ -898,10 +953,23 @@ static int mli_quit(unsigned dcb) { for (i = 0; i < MAX_FILES; ++i) { struct file_entry *file = &files[i]; if (!file->type) continue; - if (file->fd >= 0) close(file->fd); + +#if _WIN32 + if (file->h != INVALID_HANDLE_VALUE) CloseHandle(file->h); +#else + if (file->fd >= 0) close(file->fd); +#endif + if (file->directory_buffer) free(file->directory_buffer); memset(file, 0, sizeof(*file)); - file->fd = -1; + +#if _WIN32 + file->h = INVALID_HANDLE_VALUE; +#else + file->fd = -1; +#endif + + } /* need a better way to know... */ /* host_shutdown(); */ @@ -909,11 +977,51 @@ static int mli_quit(unsigned dcb) { } -static int mli_open(unsigned dcb, const char *name, const char *path) { +#if _WIN32 +static word16 file_open(const char *path, struct file_entry *file) { + + HANDLE h; + + if (g_cfg_host_read_only) { + h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } else { + h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + } + + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + file->h = h; + return 0; +} + +#else + +static word16 file_open(const char *path, struct file_entry *file) { int fd; + + if (g_cfg_host_read_only) { + fd = open(path, O_RDONLY | O_NONBLOCK); + } else { + fd = open(path, O_RDWR | O_NONBLOCK); + if (fd < 0) { + fd = open(path, O_RDONLY | O_NONBLOCK); + } + } + if (fd < 0) return host_map_errno_path(errno, path); + + file->fd = fd; + return 0; +} +#endif + + +static int mli_open(unsigned dcb, const char *name, const char *path) { + int refnum = 0; - unsigned type; struct file_entry *file = NULL; for (unsigned i = 0; i < MAX_FILES; ++i) { @@ -929,44 +1037,24 @@ static int mli_open(unsigned dcb, const char *name, const char *path) { //if (buffer == 0) return badBufferAddress; if (buffer & 0xff) return badBufferAddress; - - if (g_cfg_host_read_only) { - fd = open(path, O_RDONLY | O_NONBLOCK); - } else { - fd = open(path, O_RDWR | O_NONBLOCK); - if (fd < 0) { - if (errno == EACCES || errno == EISDIR) - fd = open(path, O_RDONLY | O_NONBLOCK); - } - } - - if (fd < 0) { - return host_map_errno_path(errno, path); - } - struct file_info fi; - unsigned terr = host_get_file_info(path, &fi); - if (terr) { - close(fd); - return terr; - } + word16 terr = host_get_file_info(path, &fi); + if (terr) return terr; - type = 0; - if (S_ISDIR(fi.st_mode)) { - unsigned blocks; - unsigned error; - void *tmp; - type = file_directory; - tmp = create_directory_file(name, path, &error, &blocks); - close(fd); - fd = -1; - if (!tmp) return error; - file->directory_buffer = tmp; - file->eof = blocks * 512; - } else if (S_ISREG(fi.st_mode)) { + if (fi.storage_type == 0x0f || fi.storage_type == 0x0d) { + unsigned blocks; + void *tmp; + tmp = create_directory_file(name, path, &terr, &blocks); + if (!tmp) return terr; + file->type = file_directory; + file->directory_buffer = tmp; + file->eof = blocks * 512; + } else { + terr = file_open(path, file); + if (terr) return terr; - type = file_regular; + file->type = file_regular; if (g_cfg_host_crlf) { if (fi.file_type == 0x04 || fi.file_type == 0xb0) @@ -978,17 +1066,10 @@ static int mli_open(unsigned dcb, const char *name, const char *path) { if (n >= 3 && path[n-1] == 'S' && path[n-2] == '.') file->translate = translate_merlin; } - - } else { - close(fd); - return badStoreType; } - file->type = type; file->level = get_memory_c(LEVEL, 0); file->buffer = buffer; - file->fd = fd; - file->type = type; file->mark = 0; set_memory_c(dcb + 5, refnum, 0); return 0; diff --git a/src/unix_host_common.c b/src/unix_host_common.c new file mode 100644 index 0000000..eb1f9a7 --- /dev/null +++ b/src/unix_host_common.c @@ -0,0 +1,510 @@ + +#define _BSD_SOURCE + +#include +#include +#include +#include + +#if defined(__APPLE__) +#include +#include +#include +#endif + +#ifdef __linux__ +#include +#endif + +#if defined(__FreeBSD__) +#include +#include +#endif + +#if defined(_AIX) +#include +#endif + +#ifndef XATTR_FINDERINFO_NAME +#define XATTR_FINDERINFO_NAME "com.apple.FinderInfo" +#endif + +#ifndef XATTR_RESOURCEFORK_NAME +#define XATTR_RESOURCEFORK_NAME "com.apple.ResourceFork" +#endif + + + + +#include "defc.h" +#include "gsos.h" + +#include "host_common.h" + + +static ino_t root_ino = 0; +static dev_t root_dev = 0; + + +unsigned host_startup(void) { + + struct stat st; + + if (!g_cfg_host_path) return invalidFSTop; + if (!*g_cfg_host_path) return invalidFSTop; + if (host_root) free(host_root); + host_root = strdup(g_cfg_host_path); + + if (stat(host_root, &st) < 0) { + fprintf(stderr, "%s does not exist\n", host_root); + return invalidFSTop; + } + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "%s is not a directory\n", host_root); + return invalidFSTop; + } + + root_ino = st.st_ino; + root_dev = st.st_dev; + + return 0; +} + +void host_shutdown(void) { + if (host_root) free(host_root); + host_root = NULL; + root_ino = 0; + root_dev = 0; +} + +int host_is_root(struct stat *st) { + return st->st_ino == root_ino && st->st_dev == root_dev; +} + + +/* + * Date/time conversion + */ + +/* + * converts time_t to a gs/os readhextime date/time record. + */ + +void host_set_date_time_rec(word32 ptr, time_t time) { + + if (time == 0) { + for (int i = 0; i < 8; ++i) set_memory_c(ptr++, 0, 0); + return; + } + + struct tm *tm = localtime(&time); + if (tm->tm_sec == 60) tm->tm_sec = 59; /* leap second */ + + set_memory_c(ptr++, tm->tm_sec, 0); + set_memory_c(ptr++, tm->tm_min, 0); + set_memory_c(ptr++, tm->tm_hour, 0); + set_memory_c(ptr++, tm->tm_year, 0); + set_memory_c(ptr++, tm->tm_mday - 1, 0); + set_memory_c(ptr++, tm->tm_mon, 0); + set_memory_c(ptr++, 0, 0); + set_memory_c(ptr++, tm->tm_wday + 1, 0); +} + +/* + * converts time_t to a prodos16 date/time record. + */ +void host_set_date_time(word32 ptr, time_t time) { + + if (time == 0) { + for (int i = 0; i < 4; ++i) set_memory_c(ptr++, 0, 0); + return; + } + + struct tm *tm = localtime(&time); + + word16 tmp = 0; + tmp |= (tm->tm_year % 100) << 9; + tmp |= tm->tm_mon << 5; + tmp |= tm->tm_mday; + + set_memory16_c(ptr, tmp, 0); + ptr += 2; + + tmp = 0; + tmp |= tm->tm_hour << 8; + tmp |= tm->tm_min; + set_memory16_c(ptr, tmp, 0); +} + +word32 host_convert_date_time(time_t time) { + + if (time == 0) return 0; + + struct tm *tm = localtime(&time); + + word16 dd = 0; + dd |= (tm->tm_year % 100) << 9; + dd |= tm->tm_mon << 5; + dd |= tm->tm_mday; + + word16 tt = 0; + tt |= tm->tm_hour << 8; + tt |= tm->tm_min; + + + return (tt << 16) | dd; +} + + +time_t host_get_date_time(word32 ptr) { + + word16 a = get_memory16_c(ptr + 0, 0); + word16 b = get_memory16_c(ptr + 2, 0); + if (!a && !b) return 0; + + struct tm tm; + memset(&tm, 0, sizeof(tm)); + + tm.tm_year = (a >> 9) & 0x7f; + tm.tm_mon = ((a >> 5) & 0x0f) - 1; + tm.tm_mday = (a >> 0) & 0x1f; + + tm.tm_hour = (b >> 8) & 0x1f; + tm.tm_min = (b >> 0) & 0x3f; + tm.tm_sec = 0; + + tm.tm_isdst = -1; + + // 00 - 39 => 2000-2039 + // 40 - 99 => 1940-1999 + if (tm.tm_year < 40) tm.tm_year += 100; + + + return mktime(&tm); +} + +time_t host_get_date_time_rec(word32 ptr) { + + byte buffer[8]; + for (int i = 0; i < 8; ++i) buffer[i] = get_memory_c(ptr++, 0); + + if (!memcmp(buffer, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) return 0; + + struct tm tm; + memset(&tm, 0, sizeof(tm)); + + tm.tm_sec = buffer[0]; + tm.tm_min = buffer[1]; + tm.tm_hour = buffer[2]; + tm.tm_year = buffer[3]; + tm.tm_mday = buffer[4] + 1; + tm.tm_mon = buffer[5]; + tm.tm_isdst = -1; + + return mktime(&tm); +} + + + +#if defined(__APPLE__) +void host_get_file_xinfo(const char *path, struct file_info *fi) { + + ssize_t tmp; + tmp = getxattr(path, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0); + if (tmp < 0) tmp = 0; + fi->resource_eof = tmp; + fi->resource_blocks = (tmp + 511) / 512; + + tmp = getxattr(path, XATTR_FINDERINFO_NAME, fi->finder_info, 32, 0, 0); + if (tmp == 16 || tmp == 32) { + fi->has_fi = 1; + + host_finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); + } +} +#elif defined(__sun) +void host_get_file_xinfo(const char *path, struct file_info *fi) { + + struct stat st; + + // can't stat an xattr directly? + int fd; + fd = attropen(path, XATTR_RESOURCEFORK_NAME, O_RDONLY); + if (fd >= 0) { + if (fstat(fd, &st) == 0) { + fi->resource_eof = st.st_size; + fi->resource_blocks = st.st_blocks; + } + close(fd); + } + + fd = attropen(path, XATTR_FINDERINFO_NAME, O_RDONLY); + if (fd >= 0) { + int tmp = read(fd, fi->finder_info, 32); + if (tmp == 16 || tmp == 32) { + fi->has_fi = 1; + host_finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); + } + close(fd); + } +} +#elif defined(__linux__) +void host_get_file_xinfo(const char *path, struct file_info *fi) { + + ssize_t tmp; + tmp = getxattr(path, "user.com.apple.ResourceFork", NULL, 0); + if (tmp < 0) tmp = 0; + fi->resource_eof = tmp; + fi->resource_blocks = (tmp + 511) / 512; + + tmp = getxattr(path, "user.com.apple.FinderInfo", fi->finder_info, 32); + if (tmp == 16 || tmp == 32) { + fi->has_fi = 1; + + host_finder_info_to_filetype(fi->finder_info, &fi->file_type, &fi->aux_type); + } +} +#else +void host_get_file_xinfo(const char *path, struct file_info *fi) { +} +#endif + + + +word32 host_get_file_info(const char *path, struct file_info *fi) { + struct stat st; + memset(fi, 0, sizeof(*fi)); + + int ok = stat(path, &st); + if (ok < 0) return host_map_errno(errno); + + fi->eof = st.st_size; + fi->blocks = st.st_blocks; + + fi->create_date = st.st_ctime; + fi->modified_date = st.st_mtime; + +#if defined(__APPLE__) + fi->create_date = st.st_birthtime; +#endif + + + if (S_ISDIR(st.st_mode)) { + fi->storage_type = directoryFile; + fi->file_type = 0x0f; + if (host_is_root(&st)) + fi->storage_type = 0x0f; + } else if (S_ISREG(st.st_mode)) { + fi->file_type = 0x06; + if (st.st_size < 0x200) fi->storage_type = seedling; + else if (st.st_size < 0x20000) fi->storage_type = sapling; + else fi->storage_type = tree; + } else { + fi->storage_type = st.st_mode & S_IFMT; + fi->file_type = 0; + } + // 0x01 = read enable + // 0x02 = write enable + // 0x04 = invisible + // 0x08 = reserved + // 0x10 = reserved + // 0x20 = backup needed + // 0x40 = rename enable + // 0x80 = destroy enable + + fi->access = 0xc3; // placeholder... + + if (S_ISREG(st.st_mode)) { + host_get_file_xinfo(path, fi); + + if (!fi->has_fi) { + host_synthesize_file_xinfo(path, fi); + } + } + + // get file type/aux type + + if (fi->resource_eof) fi->storage_type = extendedFile; + + return 0; +} + + + + +#if defined(__APPLE__) +word32 host_set_file_info(const char *path, struct file_info *fi) { + + int ok; + struct attrlist list; + unsigned i = 0; + struct timespec dates[2]; + + if (fi->has_fi && fi->storage_type != 0x0d) { + ok = setxattr(path, XATTR_FINDERINFO_NAME, fi->finder_info, 32, 0, 0); + if (ok < 0) return host_map_errno(errno); + } + + + memset(&list, 0, sizeof(list)); + memset(dates, 0, sizeof(dates)); + + list.bitmapcount = ATTR_BIT_MAP_COUNT; + list.commonattr = 0; + + if (fi->create_date) + { + dates[i++].tv_sec = fi->create_date; + list.commonattr |= ATTR_CMN_CRTIME; + } + + if (fi->modified_date) + { + dates[i++].tv_sec = fi->modified_date; + list.commonattr |= ATTR_CMN_MODTIME; + } + + ok = 0; + if (i) ok = setattrlist(path, &list, dates, i * sizeof(struct timespec), 0); + return 0; +} +#elif defined(__sun) +word32 host_set_file_info(const char *path, struct file_info *fi) { + + if (fi->has_fi && fi->storage_type != 0x0d) { + int fd = attropen(path, XATTR_FINDERINFO_NAME, O_WRONLY | O_CREAT, 0666); + if (fd < 0) return host_map_errno(errno); + write(fd, fi->finder_info, 32); + close(fd); + } + + if (fi->modified_date) { + struct timeval times[2]; + + memset(times, 0, sizeof(times)); + + //times[0] = 0; // access + times[1].tv_sec = fi.modified_date; // modified + int ok = utimes(path, times); + if (ok < 0) return host_map_errno(errno); + } + return 0; +} +#elif defined(__linux__) +word32 host_set_file_info(const char *path, struct file_info *fi) { + + if (fi->has_fi && fi->storage_type != 0x0d) { + int ok = setxattr(path, "user.apple.FinderInfo", fi->finder_info, 32, 0); + if (ok < 0) return host_map_errno(errno); + } + + if (fi->modified_date) { + struct timeval times[2]; + + memset(times, 0, sizeof(times)); + + //times[0] = 0; // access + times[1].tv_sec = fi->modified_date; // modified + int ok = utimes(path, times); + if (ok < 0) return host_map_errno(errno); + } + return 0; +} + +#else + +word32 host_set_file_info(const char *path, struct file_info *fi) { + + if (fi->modified_date) { + + struct timeval times[2]; + + memset(times, 0, sizeof(times)); + + times[0] = 0; // access + times[1].tv_sec = fi->modified_date; // modified + + int ok = utimes(path, times); + if (ok < 0) return host_map_errno(errno); + } + return 0; +} + +#endif + + +static int qsort_callback(const void *a, const void *b) { + return strcasecmp(*(const char **)a, *(const char **)b); +} + +unsigned host_scan_directory(const char *path, char ***out, size_t *entries, unsigned p8) { + + DIR *dp; + char **data = NULL; + size_t capacity = 0; + size_t count = 0; + + dp = opendir(path); + if (!dp) return host_map_errno_path(errno, path); + + for(;;) { + struct dirent *d = readdir(dp); + if (!dp) break; + + const char *name = d->d_name; + + if (name[0] == 0) continue; + if (name[0] == '.') continue; + if (p8) { + int ok = 1; + int n = strlen(name); + if (n > 15) continue; + /* check for invalid characters? */ + for (int i = 0; i < n; ++i) { + unsigned char c = name[i]; + if (isalpha(c) || isdigit(c) || c == '.') continue; + ok = 0; + break; + } + if (!ok) continue; + } + if (count == capacity) { + char **tmp; + tmp = realloc(data, (capacity + 100) * sizeof(char *)); + if (!tmp) { + closedir(dp); + host_free_directory(data, count); + return outOfMem; + } + data = tmp; + for (int i = count; i < capacity; ++i) data[i] = 0; + capacity += 100; + } + data[count++] = strdup(name); + } + closedir(dp); + + qsort(data, count, sizeof(char *), qsort_callback); + *entries = count; + *out = data; + + return 0; +} + +unsigned host_storage_type(const char *path, word16 *error) { + struct stat st; + if (!path) { + *error = badPathSyntax; + return 0; + } + if (stat(path, &st) < 0) { + *error = host_map_errno_path(errno, path); + return 0; + } + if (S_ISREG(st.st_mode)) { + return host_is_root(&st) ? 0x0f : directoryFile; + } + if (S_ISDIR(st.st_mode)) return standardFile; + *error = badStoreType; + return 0; +} diff --git a/src/win32_host_common.c b/src/win32_host_common.c new file mode 100644 index 0000000..6eb39d4 --- /dev/null +++ b/src/win32_host_common.c @@ -0,0 +1,629 @@ + +#define _WIN32_WINNT 0x0600 // vista+ +#include + +#include "defc.h" +#include "gsos.h" + +#include "host_common.h" + + + +void afp_init(struct AFP_Info *info, word16 file_type, word32 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) + host_file_type_to_finder_info(info->finder_info, file_type, aux_type); +} + +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 afp_to_filetype(struct AFP_Info *info, word16 *file_type, word32 *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 = host_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 preference) { + // if ftype/auxtype is inconsistent between prodos and finder info, use + // prodos as source of truth. + word16 f; + word32 a; + if (host_finder_info_to_filetype(info->finder_info, &f, &a) != 0) return; + if (f == info->prodos_file_type && a == info->prodos_aux_type) return; + if (preference == prefer_prodos) + host_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; + } +} + + + +static DWORD root_file_id[3] = {}; + +unsigned host_startup(void) { + + + if (!g_cfg_host_path) return invalidFSTop; + if (!*g_cfg_host_path) return invalidFSTop; + if (host_root) free(host_root); + host_root = strdup(g_cfg_host_path); + + + HANDLE h = CreateFile(host_root, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h == INVALID_HANDLE_VALUE) { + fprintf(stderr, "%s does not exist or is not accessible\n", host_root); + return invalidFSTop; + } + FILE_BASIC_INFO fbi; + BY_HANDLE_FILE_INFORMATION info; + + GetFileInformationByHandle(h, &info); + GetFileInformationByHandleEx(h, FileBasicInfo, &fbi, sizeof(fbi)); + // can't delete volume root. + CloseHandle(h); + + root_file_id[0] = info.dwVolumeSerialNumber; + root_file_id[1] = info.nFileIndexHigh; + root_file_id[2] = info.nFileIndexLow; + + + if (!(fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + fprintf(stderr, "%s is not a directory\n", host_root); + CloseHandle(h); + return invalidFSTop; + } + CloseHandle(h); + + return 0; +} + +void host_shutdown(void) { + if (host_root) free(host_root); + host_root = NULL; + memset(root_file_id, 0, sizeof(root_file_id)); +} + +int host_is_root(const BY_HANDLE_FILE_INFORMATION *info) { + DWORD id[3] = { info->dwVolumeSerialNumber, info->nFileIndexHigh, info->nFileIndexLow }; + + return memcmp(&id, &root_file_id, sizeof(root_file_id)) == 0; +} + + +/* + * Date/time conversion + */ + + +static int dayofweek(int y, int m, int d) { + /* 1 <= m <= 12, y > 1752 (in the U.K.) */ + static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; + y -= m < 3; + return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; +} + +/* + * converts time_t to a gs/os readhextime date/time record. + */ + +void host_set_date_time_rec(word32 ptr, FILETIME utc) { + + if (utc.dwLowDateTime == 0 && utc.dwHighDateTime == 0) { + for (int i = 0; i < 8; ++i) set_memory_c(ptr++, 0, 0); + return; + } + + + SYSTEMTIME tmLocal; + SYSTEMTIME tmUTC; + + FileTimeToSystemTime(&utc, &tmUTC); + SystemTimeToTzSpecificLocalTime(NULL, &tmUTC, &tmLocal); + + if (tmLocal.wYear < 1900 || tmLocal.wYear > 1900 + 255) { + for (int i = 0; i < 8; ++i) set_memory_c(ptr++, 0, 0); + return; + } + if (tmLocal.wSecond == 60) tmLocal.wSecond = 59; /* leap second */ + + int dow = dayofweek(tmLocal.wYear, tmLocal.wMonth, tmLocal.wDay); + set_memory_c(ptr++, tmLocal.wSecond, 0); + set_memory_c(ptr++, tmLocal.wMinute, 0); + set_memory_c(ptr++, tmLocal.wHour, 0); + set_memory_c(ptr++, tmLocal.wYear - 1900, 0); + set_memory_c(ptr++, tmLocal.wDay - 1, 0); // 1 = sunday + set_memory_c(ptr++, tmLocal.wMonth - 1, 0); + set_memory_c(ptr++, 0, 0); + set_memory_c(ptr++, dow + 1, 0); +} + +/* + * converts time_t to a prodos16 date/time record. + */ +void host_set_date_time(word32 ptr, FILETIME utc) { + + if (utc.dwLowDateTime == 0 && utc.dwHighDateTime == 0) { + for (int i = 0; i < 4; ++i) set_memory_c(ptr++, 0, 0); + return; + } + + SYSTEMTIME tmLocal; + SYSTEMTIME tmUTC; + + FileTimeToSystemTime(&utc, &tmUTC); + SystemTimeToTzSpecificLocalTime(NULL, &tmUTC, &tmLocal); + + if (tmLocal.wYear < 1940 || tmLocal.wYear > 2039) { + for (int i = 0; i < 4; ++i) set_memory_c(ptr++, 0, 0); + return; + } + if (tmLocal.wSecond == 60) tmLocal.wSecond = 59; /* leap second */ + + word16 tmp = 0; + tmp |= (tmLocal.wYear % 100) << 9; + tmp |= tmLocal.wMonth << 5; + tmp |= tmLocal.wDay; + + set_memory16_c(ptr, tmp, 0); + ptr += 2; + + tmp = 0; + tmp |= tmLocal.wHour << 8; + tmp |= tmLocal.wMinute; + set_memory16_c(ptr, tmp, 0); +} + + +FILETIME host_get_date_time(word32 ptr) { + + FILETIME utc = {0, 0}; + + word16 a = get_memory16_c(ptr + 0, 0); + word16 b = get_memory16_c(ptr + 2, 0); + if (!a && !b) return utc; + + + SYSTEMTIME tmLocal; + SYSTEMTIME tmUTC; + memset(&tmLocal, 0, sizeof(tmLocal)); + memset(&tmUTC, 0, sizeof(tmUTC)); + + tmLocal.wYear = ((a >> 9) & 0x7f) + 1900; + tmLocal.wMonth = ((a >> 5) & 0x0f); + tmLocal.wDay = (a >> 0) & 0x1f; + + tmLocal.wHour = (b >> 8) & 0x1f; + tmLocal.wMinute = (b >> 0) & 0x3f; + tmLocal.wSecond = 0; + + + // 00 - 39 => 2000-2039 + // 40 - 99 => 1940-1999 + if (tmLocal.wYear < 40) tmLocal.wYear += 100; + + + TzSpecificLocalTimeToSystemTime(NULL, &tmLocal, &tmUTC); + if (!SystemTimeToFileTime(&tmUTC, &utc)) utc =(FILETIME){0, 0}; + + return utc; +} + +FILETIME host_get_date_time_rec(word32 ptr) { + + FILETIME utc = {0, 0}; + + byte buffer[8]; + for (int i = 0; i < 8; ++i) buffer[i] = get_memory_c(ptr++, 0); + + if (!memcmp(buffer, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) return utc; + + SYSTEMTIME tmLocal; + SYSTEMTIME tmUTC; + memset(&tmLocal, 0, sizeof(tmLocal)); + memset(&tmUTC, 0, sizeof(tmUTC)); + + tmLocal.wSecond = buffer[0]; + tmLocal.wMinute = buffer[1]; + tmLocal.wHour = buffer[2]; + tmLocal.wYear = 1900 + buffer[3]; + tmLocal.wDay = buffer[4] + 1; + tmLocal.wMonth = buffer[5] + 1; + + TzSpecificLocalTimeToSystemTime(NULL, &tmLocal, &tmUTC); + if (!SystemTimeToFileTime(&tmUTC, &utc)) utc =(FILETIME){0, 0}; + + return utc; +} + + +word32 host_convert_date_time(FILETIME utc) { + + if (utc.dwLowDateTime == 0 && utc.dwHighDateTime == 0) { + return 0; + } + + SYSTEMTIME tmLocal; + SYSTEMTIME tmUTC; + + FileTimeToSystemTime(&utc, &tmUTC); + SystemTimeToTzSpecificLocalTime(NULL, &tmUTC, &tmLocal); + + if (tmLocal.wYear < 1940 || tmLocal.wYear > 2039) { + return 0; + } + if (tmLocal.wSecond == 60) tmLocal.wSecond = 59; /* leap second */ + + word16 dd = 0; + dd |= (tmLocal.wYear % 100) << 9; + dd |= tmLocal.wMonth << 5; + dd |= tmLocal.wDay; + + + word16 tt = 0; + tt |= tmLocal.wHour << 8; + tt |= tmLocal.wMinute; + + return (tt << 16) | dd; +} + + +word32 host_map_win32_error(DWORD e) { + switch (e) { + case ERROR_NO_MORE_FILES: + return endOfDir; + case ERROR_FILE_NOT_FOUND: + return fileNotFound; + case ERROR_PATH_NOT_FOUND: + return pathNotFound; + case ERROR_INVALID_ACCESS: + return invalidAccess; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + return dupPathname; + case ERROR_DISK_FULL: + return volumeFull; + case ERROR_INVALID_PARAMETER: + return paramRangeErr; + case ERROR_DRIVE_LOCKED: + return drvrWrtProt; + case ERROR_NEGATIVE_SEEK: + return outOfRange; + case ERROR_SHARING_VIOLATION: + return fileBusy; // destroy open file, etc. + case ERROR_DIR_NOT_EMPTY: + return invalidAccess; + + // ... + default: + fprintf(stderr, "GetLastError: %08x - %d\n", (int)e, (int)e); + return drvrIOError; + } +} + + +void host_get_file_xinfo(const char *path, struct file_info *fi) { + + HANDLE h; + + char *p = host_gc_append_string(path, ":AFP_Resource"); + LARGE_INTEGER size = { 0 }; + + + h = CreateFile(p, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h != INVALID_HANDLE_VALUE) { + GetFileSizeEx(h, &size); + CloseHandle(h); + } + fi->resource_eof = size.LowPart; + fi->resource_blocks = (size.LowPart + 511) / 512; + + + p = host_gc_append_string(path, ":AFP_AfpInfo"); + + h = CreateFile(p, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (h != INVALID_HANDLE_VALUE) { + DWORD read = 0; + if (ReadFile(h, &fi->afp, sizeof(struct AFP_Info), &read, NULL) && read == sizeof(struct AFP_Info)) { + if (afp_verify(&fi->afp)) fi->has_fi = 1; + afp_to_filetype(&fi->afp, &fi->file_type, &fi->aux_type); + } + CloseHandle(h); + } +} + +static word16 map_attributes(DWORD dwFileAttributes) { + + // 0x01 = read enable + // 0x02 = write enable + // 0x04 = invisible + // 0x08 = reserved + // 0x10 = reserved + // 0x20 = backup needed + // 0x40 = rename enable + // 0x80 = destroy enable + + word16 access = 0; + + if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) + access = readEnable; + else + access = readEnable | writeEnable | renameEnable | destroyEnable; + + if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + access |= fileInvisible; + + // map FILE_ATTRIBUTE_ARCHIVE to backup needed bit? + + return access; +} + + +word32 host_get_file_info(const char *path, struct file_info *fi) { + + + HANDLE h = CreateFile(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + //FILE_BASIC_INFO fbi; + //FILE_STANDARD_INFO fsi; + //FILE_ID_INFO fii; + BY_HANDLE_FILE_INFORMATION info; + + + memset(fi, 0, sizeof(*fi)); + //memset(&fbi, 0, sizeof(fbi)); + //memset(&fsi, 0, sizeof(fsi)); + + GetFileInformationByHandle(h, &info); + //GetFileInformationByHandleEx(h, FileBasicInfo, &fbi, sizeof(fbi)); + //GetFileInformationByHandleEx(h, FileStandardInfo, &fsi, sizeof(fsi)); + //GetFileInformationByHandleEx(h, FileIdInfo, &fii, sizeof(fii)); + + word32 size = info.nFileSizeLow; + + fi->eof = size; + fi->blocks = (size + 511) / 512; + + fi->create_date = info.ftCreationTime; + fi->modified_date = info.ftLastWriteTime; + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + fi->storage_type = directoryFile; + fi->file_type = 0x0f; + + if (host_is_root(&info)) fi->storage_type = 0x0f; + } else { + fi->file_type = 0x06; + if (size < 0x200) fi->storage_type = seedling; + else if (size < 0x20000) fi->storage_type = sapling; + else fi->storage_type = tree; + + host_get_file_xinfo(path, fi); + if (fi->resource_eof) fi->storage_type = extendedFile; + + if (!fi->has_fi) host_synthesize_file_xinfo(path, fi); + } + + // 0x01 = read enable + // 0x02 = write enable + // 0x04 = invisible + // 0x08 = reserved + // 0x10 = reserved + // 0x20 = backup needed + // 0x40 = rename enable + // 0x80 = destroy enable + + word16 access = 0; + + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + access = 0x01; + else + access = 0x01 | 0x02 | 0x40 | 0x80; + + if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + access |= 0x04; + + // map FILE_ATTRIBUTE_ARCHIVE to backup needed bit? + + fi->access = map_attributes(info.dwFileAttributes); + + + CloseHandle(h); + return 0; +} + + +word32 host_set_file_info(const char *path, struct file_info *fi) { + + if (fi->has_fi && fi->storage_type != 0x0d && fi->storage_type != 0x0f) { + char *rpath = host_gc_append_string(path, ":AFP_AfpInfo"); + + HANDLE h = CreateFile(rpath, GENERIC_WRITE, + FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + WriteFile(h, &fi->afp, sizeof(struct AFP_Info), NULL, NULL); + CloseHandle(h); + } + + + if (fi->create_date.dwLowDateTime || fi->create_date.dwHighDateTime + || fi->modified_date.dwLowDateTime || fi->modified_date.dwHighDateTime) { + // SetFileInformationByHandle can modify dates. + HANDLE h; + h = CreateFile(path, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + FILE_BASIC_INFO fbi; + FILE_BASIC_INFO newfbi; + memset(&fbi, 0, sizeof(fbi)); + memset(&newfbi, 0, sizeof(newfbi)); + + BOOL ok; + ok = GetFileInformationByHandleEx(h, FileBasicInfo, &fbi, sizeof(fbi)); + + int delta = 0; + + word16 old_access = map_attributes(fbi.FileAttributes); + if (fi->access && fi->access != old_access) { + newfbi.FileAttributes = fbi.FileAttributes; + + if (fi->access & fileInvisible) { + delta = 1; + newfbi.FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + // hfs fst only marks it read enable if all are clear. + word16 locked = writeEnable | destroyEnable | renameEnable; + if ((fi->access & locked) == 0) { + delta = 1; + newfbi.FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + } + + // todo -- compare against nt file time to see if it's actually changed. + // to prevent time stamp truncation. + + if (fi->create_date.dwLowDateTime || fi->create_date.dwHighDateTime) { + delta = 1; + newfbi.CreationTime.LowPart = fi->create_date.dwLowDateTime; + newfbi.CreationTime.HighPart = fi->create_date.dwHighDateTime; + } + if (fi->modified_date.dwLowDateTime || fi->modified_date.dwHighDateTime) { + delta = 1; + newfbi.LastWriteTime.LowPart = fi->modified_date.dwLowDateTime; + newfbi.LastWriteTime.HighPart = fi->modified_date.dwHighDateTime; + //newfbi.ChangeTime.LowPart = fi->modified_date.dwLowDateTime; //? + //newfbi.ChangeTime.HighPart = fi->modified_date.dwHighDateTime; //? + } + + if (delta) + ok = SetFileInformationByHandle(h, FileBasicInfo, &newfbi, sizeof(newfbi)); + CloseHandle(h); + } + return 0; +} + + +static int qsort_callback(const void *a, const void *b) { + return stricmp(*(const char **)a, *(const char **)b); +} + +unsigned host_scan_directory(const char *path, char ***out, size_t *entries, unsigned p8) { + + WIN32_FIND_DATA fdata; + HANDLE h; + char **data = NULL; + size_t capacity = 0; + size_t count = 0; + DWORD e; + + path = host_gc_append_path(path, "*"); + + h = FindFirstFile(path, &fdata); + if (h == INVALID_HANDLE_VALUE) { + e = GetLastError(); + if (e == ERROR_FILE_NOT_FOUND) { + /* empty directory */ + *out = NULL; + *entries = 0; + return 0; + } + return host_map_win32_error(e); + } + + do { + char *name = fdata.cFileName; + if (name[0] == 0) continue; + if (name[0] == '.') continue; + if (p8) { + int ok = 1; + int n = strlen(name); + if (n > 15) continue; + /* check for invalid characters? */ + for (int i = 0; i < n; ++i) { + unsigned char c = name[i]; + if (isalpha(c) || isdigit(c) || c == '.') continue; + ok = 0; + break; + } + if (!ok) continue; + } + if (count == capacity) { + char **tmp; + tmp = realloc(data, (capacity + 100) * sizeof(char *)); + if (!tmp) { + FindClose(h); + host_free_directory(data, count); + return outOfMem; + } + data = tmp; + for (int i = count; i < capacity; ++i) data[i] = 0; + capacity += 100; + } + data[count++] = strdup(name); + + } while (FindNextFile(h, &fdata) != 0); + + e = GetLastError(); + FindClose(h); + + if (e && e != ERROR_NO_MORE_FILES) { + host_free_directory(data, count); + return host_map_win32_error(e); + } + qsort(data, count, sizeof(char *), qsort_callback); + *entries = count; + *out = data; + + return 0; +} + + +unsigned host_storage_type(const char *path, word16 *error) { + if (!path) { + *error = badPathSyntax; + return 0; + } + HANDLE h; + h = CreateFile(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h == INVALID_HANDLE_VALUE) { + *error = host_map_win32_error(GetLastError()); + return 0; + } + + BY_HANDLE_FILE_INFORMATION info; + GetFileInformationByHandle(h, &info); + CloseHandle(h); + + if (host_is_root(&info)) return 0x0f; + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return directoryFile; + + return standardFile; +} diff --git a/src/win32_host_fst.c b/src/win32_host_fst.c index 8c40aa9..05f3360 100644 --- a/src/win32_host_fst.c +++ b/src/win32_host_fst.c @@ -18,6 +18,7 @@ #include "gsos.h" #include "fst.h" +#include "host_common.h" extern Engine_reg engine; @@ -34,17 +35,6 @@ extern Engine_reg engine; #define global_buffer 0x009a00 -enum { - regular_file, - resource_file, - directory_file, -}; - -enum { - translate_none, - translate_crlf, - translate_merlin, -}; struct directory { int displacement; @@ -63,79 +53,12 @@ struct fd_entry { struct directory *dir; }; -#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 free_directory(struct directory *dd); static struct directory *read_directory(const char *path, word16 *error); -static int file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_type); -static int finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type); - - -static void afp_init(struct AFP_Info *info, word16 file_type, word32 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; -} - - -static int afp_to_filetype(struct AFP_Info *info, word16 *file_type, word32 *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; -} - -enum { prefer_prodos, prefer_hfs }; -static void afp_synchronize(struct AFP_Info *info, int preference) { - // if ftype/auxtype is inconsistent between prodos and finder info, use - // prodos as source of truth. - word16 f; - word32 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 (preference == prefer_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; - } -} - #define COOKIE_BASE 0x8000 @@ -173,139 +96,7 @@ static int free_cookie(int cookie) { static struct fd_entry *fd_head = NULL; -static DWORD root_file_id[3] = {}; -//static ino_t root_ino = 0; -//static dev_t root_dev = 0; -static char *root = NULL; -static int read_only = 0; -char *g_cfg_host_path = ""; // must not be null. -int g_cfg_host_read_only = 0; -int g_cfg_host_crlf = 1; -int g_cfg_host_merlin = 0; - - -/* - * simple malloc pool to simplify code. Should never need > 4 allocations. - * - */ -static void *gc[16]; -static void **gc_ptr = &gc[0]; -static void *gc_malloc(size_t size) { - if (gc_ptr == &gc[16]) { - errno = ENOMEM; - return NULL; - } - - void *ptr = malloc(size); - if (ptr) { - *gc_ptr++ = ptr; - } - return ptr; -} - - -static void gc_free(void) { - - while (gc_ptr > gc) free(*--gc_ptr); - -} - -static char *append_path(const char *a, const char *b) { - int aa = strlen(a); - int bb = strlen(b); - - char *cp = gc_malloc(aa + bb + 2); - if (!cp) return NULL; - memcpy(cp, a, aa); - int len = aa; - if (len && cp[len-1] != '/' && b[0] != '/') cp[len++] = '/'; - memcpy(cp + len, b, bb); - len += bb; - cp[len] = 0; - while (len > 2 && cp[len - 1] == '/') cp[--len] = 0; - return cp; -} - - -static char *append_string(const char *a, const char *b) { - int aa = strlen(a); - int bb = strlen(b); - - char *cp = gc_malloc(aa + bb + 2); - if (!cp) return NULL; - memcpy(cp, a, aa); - int len = aa; - memcpy(cp + len, b, bb); - len += bb; - cp[len] = 0; - return cp; -} - -static char *gc_strdup(const char *src) { - if (!src) return ""; - if (!*src) return ""; - int len = strlen(src) + 1; - char *cp = gc_malloc(len); - memcpy(cp, src, len); - return cp; -} - - -static word32 map_errno() { - switch(errno) { - case 0: return 0; - case EBADF: - return invalidAccess; -#ifdef EDQUOT - case EDQUOT: -#endif - case EFBIG: - return volumeFull; - case ENOENT: - return fileNotFound; - case ENOTDIR: - return pathNotFound; - case ENOMEM: - return outOfMem; - case EEXIST: - return dupPathname; - default: - return drvrIOError; - } -} - -static word32 map_last_error() { - DWORD e = GetLastError(); - switch (e) { - case ERROR_NO_MORE_FILES: - return endOfDir; - case ERROR_FILE_NOT_FOUND: - return fileNotFound; - case ERROR_PATH_NOT_FOUND: - return pathNotFound; - case ERROR_INVALID_ACCESS: - return invalidAccess; - case ERROR_FILE_EXISTS: - case ERROR_ALREADY_EXISTS: - return dupPathname; - case ERROR_DISK_FULL: - return volumeFull; - case ERROR_INVALID_PARAMETER: - return paramRangeErr; - case ERROR_DRIVE_LOCKED: - return drvrWrtProt; - case ERROR_NEGATIVE_SEEK: - return outOfRange; - case ERROR_SHARING_VIOLATION: - return fileBusy; // destroy open file, etc. - case ERROR_DIR_NOT_EMPTY: - // ... - default: - fprintf(stderr, "GetLastError: %08x - %d\n", (int)e, (int)e); - return drvrIOError; - } -} static struct fd_entry *find_fd(int cookie) { struct fd_entry *head = fd_head; @@ -354,444 +145,6 @@ static word32 remove_fd(int cookie) { } -static void cr_to_lf(byte *buffer, size_t size) { - size_t i; - for (i = 0; i < size; ++i) { - if (buffer[i] == '\r') buffer[i] = '\n'; - } -} - -static void lf_to_cr(byte *buffer, size_t size) { - size_t i; - for (i = 0; i < size; ++i) { - if (buffer[i] == '\n') buffer[i] = '\r'; - } -} - -static void merlin_to_text(byte *buffer, size_t size) { - size_t i; - for (i = 0; i < size; ++i) { - byte b = buffer[i]; - if (b == 0xa0) b = '\t'; - b &= 0x7f; - if (b == '\r') b = '\n'; - buffer[i] = b; - } -} - -static void text_to_merlin(byte *buffer, size_t size) { - size_t i; - for (i = 0; i < size; ++i) { - byte b = buffer[i]; - if (b == '\t') b = 0xa0; - if (b == '\n') b = '\r'; - if (b != ' ') b |= 0x80; - buffer[i] = b; - } -} - -struct file_info { - - FILETIME create_date; - FILETIME modified_date; - - word16 access; - word16 storage_type; - word16 file_type; - word32 aux_type; - word32 eof; - word32 blocks; - word32 resource_eof; - word32 resource_blocks; - int has_fi; - //byte finder_info[32]; - struct AFP_Info afp; -}; - -static int hex(byte 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; -} - - - -static int finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type) { - - if (!memcmp("pdos", buffer + 4, 4)) - { - if (buffer[0] == 'p') { - *file_type = buffer[1]; - *aux_type = (buffer[2] << 8) | buffer[3]; - return 0; - } - if (!memcmp("PSYS", buffer, 4)) { - *file_type = 0xff; - *aux_type = 0x0000; - return 0; - } - if (!memcmp("PS16", buffer, 4)) { - *file_type = 0xb3; - *aux_type = 0x0000; - return 0; - } - - // 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 0; - } - } - if (!memcmp("TEXT", buffer, 4)) { - *file_type = 0x04; - *aux_type = 0x0000; - return 0; - } - if (!memcmp("BINA", buffer, 4)) { - *file_type = 0x00; - *aux_type = 0x0000; - return 0; - } - if (!memcmp("dImgdCpy", buffer, 8)) { - *file_type = 0xe0; - *aux_type = 0x0005; - return 0; - } - - if (!memcmp("MIDI", buffer, 4)) { - *file_type = 0xd7; - *aux_type = 0x0000; - return 0; - } - - if (!memcmp("AIFF", buffer, 4)) { - *file_type = 0xd8; - *aux_type = 0x0000; - return 0; - } - - if (!memcmp("AIFC", buffer, 4)) { - *file_type = 0xd8; - *aux_type = 0x0001; - return 0; - } - - return -1; -} - -static int file_type_to_finder_info(byte *buffer, word16 file_type, word32 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; -} - - - -static void get_file_xinfo(const char *path, struct file_info *fi) { - - HANDLE h; - - char *p = append_string(path, ":AFP_Resource"); - LARGE_INTEGER size = { 0 }; - - - h = CreateFile(p, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h != INVALID_HANDLE_VALUE) { - GetFileSizeEx(h, &size); - CloseHandle(h); - } - fi->resource_eof = size.LowPart; - fi->resource_blocks = (size.LowPart + 511) / 512; - - - p = append_string(path, ":AFP_AfpInfo"); - - h = CreateFile(p, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (h != INVALID_HANDLE_VALUE) { - DWORD read = 0; - if (ReadFile(h, &fi->afp, sizeof(struct AFP_Info), &read, NULL) && read == sizeof(struct AFP_Info)) { - if (afp_verify(&fi->afp)) fi->has_fi = 1; - afp_to_filetype(&fi->afp, &fi->file_type, &fi->aux_type); - } - CloseHandle(h); - } -} - -static word16 map_attributes(DWORD dwFileAttributes) { - - // 0x01 = read enable - // 0x02 = write enable - // 0x04 = invisible - // 0x08 = reserved - // 0x10 = reserved - // 0x20 = backup needed - // 0x40 = rename enable - // 0x80 = destroy enable - - word16 access = 0; - - if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) - access = readEnable; - else - access = readEnable | writeEnable | renameEnable | destroyEnable; - - if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) - access |= fileInvisible; - - // map FILE_ATTRIBUTE_ARCHIVE to backup needed bit? - - return access; -} - -#undef _ -#define _(a, b, c) { a, sizeof(a) - 1, b, c } -struct ftype_entry { - char *ext; - unsigned length; - unsigned file_type; - unsigned aux_type; -}; - -static struct ftype_entry suffixes[] = { - _("c", 0xb0, 0x0008), - _("cc", 0xb0, 0x0008), - _("h", 0xb0, 0x0008), - _("rez", 0xb0, 0x0015), - _("asm", 0xb0, 0x0003), - _("mac", 0xb0, 0x0003), - _("pas", 0xb0, 0x0005), - _("txt", 0x04, 0x0000), - _("text", 0x04, 0x0000), - _("s", 0x04, 0x0000), - { 0, 0, 0, 0} -}; - -static struct ftype_entry prefixes[] = { - _("m16.", 0xb0, 0x0003), - _("e16.", 0xb0, 0x0003), - { 0, 0, 0, 0} -}; - -#undef _ - - - -static word32 get_file_info(const char *path, struct file_info *fi) { - - - HANDLE h = CreateFile(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) return map_last_error(); - - //FILE_BASIC_INFO fbi; - //FILE_STANDARD_INFO fsi; - //FILE_ID_INFO fii; - BY_HANDLE_FILE_INFORMATION info; - - - memset(fi, 0, sizeof(*fi)); - //memset(&fbi, 0, sizeof(fbi)); - //memset(&fsi, 0, sizeof(fsi)); - - GetFileInformationByHandle(h, &info); - //GetFileInformationByHandleEx(h, FileBasicInfo, &fbi, sizeof(fbi)); - //GetFileInformationByHandleEx(h, FileStandardInfo, &fsi, sizeof(fsi)); - //GetFileInformationByHandleEx(h, FileIdInfo, &fii, sizeof(fii)); - - word32 size = info.nFileSizeLow; - - fi->eof = size; - fi->blocks = (size + 511) / 512; - - fi->create_date = info.ftCreationTime; - fi->modified_date = info.ftLastWriteTime; - - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - fi->storage_type = directoryFile; - fi->file_type = 0x0f; - - DWORD id[3] = { info.dwVolumeSerialNumber, info.nFileIndexHigh, info.nFileIndexLow }; - if (memcmp(&id, &root_file_id, sizeof(root_file_id)) == 0) { - fi->storage_type = 0x0f; - } - } else { - fi->file_type = 0x06; - if (size < 0x200) fi->storage_type = seedling; - else if (size < 0x20000) fi->storage_type = sapling; - else fi->storage_type = tree; - - get_file_xinfo(path, fi); - if (fi->resource_eof) fi->storage_type = extendedFile; - - if (!fi->has_fi) { - /* guess the file type / auxtype based on extension */ - int n; - const char *dot = NULL; - const char *slash = NULL; - - for(n = 0;; ++n) { - char c = path[n]; - if (c == 0) break; - else if (c == '/') { slash = path + n + 1; dot = NULL; } - else if (c == '.') dot = path + n + 1; - } - - if (dot && *dot) { - for (n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) { - if (!suffixes[n].ext) break; - if (!strcasecmp(dot, suffixes[n].ext)) { - fi->file_type = suffixes[n].file_type; - fi->aux_type = suffixes[n].aux_type; - break; - } - } - } - } - } - - // 0x01 = read enable - // 0x02 = write enable - // 0x04 = invisible - // 0x08 = reserved - // 0x10 = reserved - // 0x20 = backup needed - // 0x40 = rename enable - // 0x80 = destroy enable - - word16 access = 0; - - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) - access = 0x01; - else - access = 0x01 | 0x02 | 0x40 | 0x80; - - if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) - access |= 0x04; - - // map FILE_ATTRIBUTE_ARCHIVE to backup needed bit? - - fi->access = map_attributes(info.dwFileAttributes); - - - CloseHandle(h); - return 0; -} - - -static word32 set_file_info(const char *path, struct file_info *fi) { - - if (fi->has_fi && fi->storage_type != 0x0d && fi->storage_type != 0x0f) { - char *rpath = append_string(path, ":AFP_AfpInfo"); - - HANDLE h = CreateFile(rpath, GENERIC_WRITE, - FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) return map_last_error(); - - WriteFile(h, &fi->afp, sizeof(struct AFP_Info), NULL, NULL); - CloseHandle(h); - } - - - if (fi->create_date.dwLowDateTime || fi->create_date.dwHighDateTime - || fi->modified_date.dwLowDateTime || fi->modified_date.dwHighDateTime) { - // SetFileInformationByHandle can modify dates. - HANDLE h; - h = CreateFile(path, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) return map_last_error(); - - FILE_BASIC_INFO fbi; - FILE_BASIC_INFO newfbi; - memset(&fbi, 0, sizeof(fbi)); - memset(&newfbi, 0, sizeof(newfbi)); - - BOOL ok; - ok = GetFileInformationByHandleEx(h, FileBasicInfo, &fbi, sizeof(fbi)); - - int delta = 0; - - word16 old_access = map_attributes(fbi.FileAttributes); - if (fi->access && fi->access != old_access) { - newfbi.FileAttributes = fbi.FileAttributes; - - if (fi->access & fileInvisible) { - delta = 1; - newfbi.FileAttributes |= FILE_ATTRIBUTE_HIDDEN; - } - // hfs fst only marks it read enable if all are clear. - word16 locked = writeEnable | destroyEnable | renameEnable; - if ((fi->access & locked) == 0) { - delta = 1; - newfbi.FileAttributes |= FILE_ATTRIBUTE_READONLY; - } - } - - // todo -- compare against nt file time to see if it's actually changed. - // to prevent time stamp truncation. - - if (fi->create_date.dwLowDateTime || fi->create_date.dwHighDateTime) { - delta = 1; - newfbi.CreationTime.LowPart = fi->create_date.dwLowDateTime; - newfbi.CreationTime.HighPart = fi->create_date.dwHighDateTime; - } - if (fi->modified_date.dwLowDateTime || fi->modified_date.dwHighDateTime) { - delta = 1; - newfbi.LastWriteTime.LowPart = fi->modified_date.dwLowDateTime; - newfbi.LastWriteTime.HighPart = fi->modified_date.dwHighDateTime; - //newfbi.ChangeTime.LowPart = fi->modified_date.dwLowDateTime; //? - //newfbi.ChangeTime.HighPart = fi->modified_date.dwHighDateTime; //? - } - - if (delta) - ok = SetFileInformationByHandle(h, FileBasicInfo, &newfbi, sizeof(newfbi)); - CloseHandle(h); - } - return 0; -} /* * if this is an absolute path, verify and skip past :Host: @@ -834,7 +187,7 @@ static char * get_gsstr(word32 ptr) { if (!ptr) return NULL; int length = get_memory16_c(ptr, 0); ptr += 2; - char *str = gc_malloc(length + 1); + char *str = host_gc_malloc(length + 1); for (int i = 0; i < length; ++i) { char c = get_memory_c(ptr+i, 0); if (c == ':') c = '/'; @@ -848,7 +201,7 @@ static char * get_pstr(word32 ptr) { if (!ptr) return NULL; int length = get_memory_c(ptr, 0); ptr += 1; - char *str = gc_malloc(length + 1); + char *str = host_gc_malloc(length + 1); for (int i = 0; i < length; ++i) { char c = get_memory_c(ptr+i, 0); if (c == ':') c = '/'; @@ -958,144 +311,6 @@ static word32 set_option_list(word32 ptr, word16 fstID, const byte *data, int si } -static int dayofweek(int y, int m, int d) { /* 1 <= m <= 12, y > 1752 (in the U.K.) */ - static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - y -= m < 3; - return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; -} -/* - * converts time_t to a gs/os readhextime date/time record. - */ - -static void set_date_time_rec(word32 ptr, FILETIME utc) { - - if (utc.dwLowDateTime == 0 && utc.dwHighDateTime == 0) { - for (int i = 0; i < 8; ++i) set_memory_c(ptr++, 0, 0); - return; - } - - - SYSTEMTIME tmLocal; - SYSTEMTIME tmUTC; - - FileTimeToSystemTime(&utc, &tmUTC); - SystemTimeToTzSpecificLocalTime(NULL, &tmUTC, &tmLocal); - - if (tmLocal.wYear < 1900 || tmLocal.wYear > 1900 + 255) { - for (int i = 0; i < 8; ++i) set_memory_c(ptr++, 0, 0); - return; - } - if (tmLocal.wSecond == 60) tmLocal.wSecond = 59; /* leap second */ - - int dow = dayofweek(tmLocal.wYear, tmLocal.wMonth, tmLocal.wDay); - set_memory_c(ptr++, tmLocal.wSecond, 0); - set_memory_c(ptr++, tmLocal.wMinute, 0); - set_memory_c(ptr++, tmLocal.wHour, 0); - set_memory_c(ptr++, tmLocal.wYear - 1900, 0); - set_memory_c(ptr++, tmLocal.wDay - 1, 0); // 1 = sunday - set_memory_c(ptr++, tmLocal.wMonth - 1, 0); - set_memory_c(ptr++, 0, 0); - set_memory_c(ptr++, dow + 1, 0); -} - -/* - * converts time_t to a prodos16 date/time record. - */ -static void set_date_time(word32 ptr, FILETIME utc) { - - if (utc.dwLowDateTime == 0 && utc.dwHighDateTime == 0) { - for (int i = 0; i < 4; ++i) set_memory_c(ptr++, 0, 0); - return; - } - - SYSTEMTIME tmLocal; - SYSTEMTIME tmUTC; - - FileTimeToSystemTime(&utc, &tmUTC); - SystemTimeToTzSpecificLocalTime(NULL, &tmUTC, &tmLocal); - - if (tmLocal.wYear < 1940 || tmLocal.wYear > 2039) { - for (int i = 0; i < 4; ++i) set_memory_c(ptr++, 0, 0); - return; - } - if (tmLocal.wSecond == 60) tmLocal.wSecond = 59; /* leap second */ - - word16 tmp = 0; - tmp |= (tmLocal.wYear % 100) << 9; - tmp |= tmLocal.wMonth << 5; - tmp |= tmLocal.wDay; - - set_memory16_c(ptr, tmp, 0); - ptr += 2; - - tmp = 0; - tmp |= tmLocal.wHour << 8; - tmp |= tmLocal.wMinute; - set_memory16_c(ptr, tmp, 0); -} - - -static FILETIME get_date_time(word32 ptr) { - - FILETIME utc = {0, 0}; - - word16 a = get_memory16_c(ptr + 0, 0); - word16 b = get_memory16_c(ptr + 2, 0); - if (!a && !b) return utc; - - - SYSTEMTIME tmLocal; - SYSTEMTIME tmUTC; - memset(&tmLocal, 0, sizeof(tmLocal)); - memset(&tmUTC, 0, sizeof(tmUTC)); - - tmLocal.wYear = ((a >> 9) & 0x7f) + 1900; - tmLocal.wMonth = ((a >> 5) & 0x0f); - tmLocal.wDay = (a >> 0) & 0x1f; - - tmLocal.wHour = (b >> 8) & 0x1f; - tmLocal.wMinute = (b >> 0) & 0x3f; - tmLocal.wSecond = 0; - - - // 00 - 39 => 2000-2039 - // 40 - 99 => 1940-1999 - if (tmLocal.wYear < 40) tmLocal.wYear += 100; - - - TzSpecificLocalTimeToSystemTime(NULL, &tmLocal, &tmUTC); - if (!SystemTimeToFileTime(&tmUTC, &utc)) utc =(FILETIME){0, 0}; - - return utc; -} - -static FILETIME get_date_time_rec(word32 ptr) { - - FILETIME utc = {0, 0}; - - byte buffer[8]; - for (int i = 0; i < 8; ++i) buffer[i] = get_memory_c(ptr++, 0); - - if (!memcmp(buffer, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) return utc; - - SYSTEMTIME tmLocal; - SYSTEMTIME tmUTC; - memset(&tmLocal, 0, sizeof(tmLocal)); - memset(&tmUTC, 0, sizeof(tmUTC)); - - tmLocal.wSecond = buffer[0]; - tmLocal.wMinute = buffer[1]; - tmLocal.wHour = buffer[2]; - tmLocal.wYear = 1900 + buffer[3]; - tmLocal.wDay = buffer[4] + 1; - tmLocal.wMonth = buffer[5] + 1; - - TzSpecificLocalTimeToSystemTime(NULL, &tmLocal, &tmUTC); - if (!SystemTimeToFileTime(&tmUTC, &utc)) utc =(FILETIME){0, 0}; - - return utc; -} - static char *get_path1(void) { word32 direct = engine.direct; @@ -1114,9 +329,6 @@ static char *get_path2(void) { } -#define SEC() engine.psr |= 1 -#define CLC() engine.psr &= ~1 - static word32 fst_shutdown(void) { @@ -1128,53 +340,18 @@ static word32 fst_shutdown(void) { free_fd(head); head = next; } + host_shutdown(); return 0; } static word32 fst_startup(void) { // if restart, close any previous files. - - if (!g_cfg_host_path) return invalidFSTop; - if (!*g_cfg_host_path) return invalidFSTop; - if (root) free(root); - root = strdup(g_cfg_host_path); - - read_only = g_cfg_host_read_only; - fst_shutdown(); memset(&cookies, 0, sizeof(cookies)); - HANDLE h = CreateFile(root, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - fprintf(stderr, "%s does not exist or is not accessible\n", root); - return invalidFSTop; - } - FILE_BASIC_INFO fbi; - BY_HANDLE_FILE_INFORMATION info; - - GetFileInformationByHandle(h, &info); - GetFileInformationByHandleEx(h, FileBasicInfo, &fbi, sizeof(fbi)); - // can't delete volume root. - CloseHandle(h); - - root_file_id[0] = info.dwVolumeSerialNumber; - root_file_id[1] = info.nFileIndexHigh; - root_file_id[2] = info.nFileIndexLow; - - - if (!(fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - fprintf(stderr, "%s is not a directory\n", root); - CloseHandle(h); - return invalidFSTop; - } - CloseHandle(h); - - //root_ino = st.st_ino; - //root_dev = st.st_dev; - - return 0; + return host_startup(); } @@ -1207,7 +384,7 @@ static word32 fst_create(int class, const char *path) { fi.file_type = get_memory16_c(pb + CreateRec_fileType, 0); fi.aux_type = get_memory32_c(pb + CreateRec_auxType, 0); fi.storage_type = get_memory16_c(pb + CreateRec_storageType, 0); - fi.create_date = get_date_time(pb + CreateRec_createDate); + fi.create_date = host_get_date_time(pb + CreateRec_createDate); afp_init(&fi.afp, fi.file_type, fi.aux_type); fi.has_fi = 1; @@ -1219,7 +396,7 @@ static word32 fst_create(int class, const char *path) { if (fi.storage_type == 0x0d) { ok = CreateDirectory(path, NULL); - if (!ok) return map_last_error(); + if (!ok) return host_map_win32_error(GetLastError()); if (class) { if (pcount >= 5) set_memory16_c(pb + CreateRecGS_storageType, fi.storage_type, 0); @@ -1239,9 +416,9 @@ static word32 fst_create(int class, const char *path) { CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) return map_last_error(); + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); // set ftype, auxtype... - set_file_info(path, &fi); // set_file_info_handle(...); + host_set_file_info(path, &fi); CloseHandle(h); fi.storage_type = 1; @@ -1259,7 +436,7 @@ static word32 fst_create(int class, const char *path) { if (fi.storage_type == 0x8005) { // convert an existing file to an extended file. // this checks that the file exists and has a 0-sized resource. - word32 rv = get_file_info(path, &fi); + word32 rv = host_get_file_info(path, &fi); if (rv) return rv; if (fi.storage_type == extendedFile) return resExistsErr; if (fi.storage_type < seedling || fi.storage_type > tree) return resAddErr; @@ -1271,40 +448,14 @@ static word32 fst_create(int class, const char *path) { } -static word16 storage_type(const char *path, word16 *error) { - if (!path) { - *error = badPathSyntax; - return 0; // ? - } - HANDLE h; - h = CreateFile(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - *error = map_last_error(); - return 0; - } - - BY_HANDLE_FILE_INFORMATION info; - GetFileInformationByHandle(h, &info); - CloseHandle(h); - - DWORD id[3] = { info.dwVolumeSerialNumber, info.nFileIndexHigh, info.nFileIndexLow }; - if (memcmp(&id, &root_file_id, sizeof(root_file_id)) == 0) { - return 0x0f; - } - - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - return directoryFile; - - return standardFile; -} static word32 fst_destroy(int class, const char *path) { word16 rv = 0; BOOL ok = 0; - word16 type = storage_type(path, &rv); + word16 type = host_storage_type(path, &rv); if (rv) return rv; - if (read_only) return drvrWrtProt; + if (g_cfg_host_read_only) return drvrWrtProt; switch(type) { case 0: return fileNotFound; @@ -1322,16 +473,16 @@ static word32 fst_destroy(int class, const char *path) { break; } - if (!ok) return map_last_error(); + if (!ok) return host_map_win32_error(GetLastError()); return 0; } static word32 fst_set_file_info(int class, const char *path) { word16 rv = 0; - word16 type = storage_type(path, &rv); + word16 type = host_storage_type(path, &rv); if (rv) return rv; - if (read_only) return drvrWrtProt; + if (g_cfg_host_read_only) return drvrWrtProt; word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); @@ -1341,7 +492,7 @@ static word32 fst_set_file_info(int class, const char *path) { // load up existing file types / finder info. - get_file_xinfo(path, &fi); + host_get_file_xinfo(path, &fi); word32 option_list = 0; if (class) { @@ -1352,8 +503,8 @@ static word32 fst_set_file_info(int class, const char *path) { if (pcount >= 4) fi.aux_type = get_memory32_c(pb + FileInfoRecGS_auxType, 0); // reserved. //if (pcount >= 5) fi.storage_type = get_memory16_c(pb + FileInfoRecGS_storageType, 0); - if (pcount >= 6) fi.create_date = get_date_time_rec(pb + FileInfoRecGS_createDateTime); - if (pcount >= 7) fi.modified_date = get_date_time_rec(pb + FileInfoRecGS_modDateTime); + if (pcount >= 6) fi.create_date = host_get_date_time_rec(pb + FileInfoRecGS_createDateTime); + if (pcount >= 7) fi.modified_date = host_get_date_time_rec(pb + FileInfoRecGS_modDateTime); if (pcount >= 8) option_list = get_memory24_c(pb + FileInfoRecGS_optionList, 0); // remainder reserved @@ -1368,8 +519,8 @@ static word32 fst_set_file_info(int class, const char *path) { fi.aux_type = get_memory32_c(pb + FileRec_auxType, 0); // reserved. //fi.storage_type = get_memory32_c(pb + FileRec_storageType, 0); - fi.create_date = get_date_time(pb + FileRec_createDate); - fi.modified_date = get_date_time(pb + FileRec_modDate); + fi.create_date = host_get_date_time(pb + FileRec_createDate); + fi.modified_date = host_get_date_time(pb + FileRec_modDate); } @@ -1404,7 +555,7 @@ static word32 fst_set_file_info(int class, const char *path) { // update finder info if (fi.has_fi) afp_synchronize(&fi.afp, prefer_prodos); - return set_file_info(path, &fi); + return host_set_file_info(path, &fi); } static word32 fst_get_file_info(int class, const char *path) { @@ -1414,7 +565,7 @@ static word32 fst_get_file_info(int class, const char *path) { struct file_info fi; int rv = 0; - rv = get_file_info(path, &fi); + rv = host_get_file_info(path, &fi); if (rv) return rv; if (class) { @@ -1426,8 +577,8 @@ static word32 fst_get_file_info(int class, const char *path) { if (pcount >= 4) set_memory32_c(pb + FileInfoRecGS_auxType, fi.aux_type, 0); if (pcount >= 5) set_memory16_c(pb + FileInfoRecGS_storageType, fi.storage_type, 0); - if (pcount >= 6) set_date_time_rec(pb + FileInfoRecGS_createDateTime, fi.create_date); - if (pcount >= 7) set_date_time_rec(pb + FileInfoRecGS_modDateTime, fi.modified_date); + if (pcount >= 6) host_set_date_time_rec(pb + FileInfoRecGS_createDateTime, fi.create_date); + if (pcount >= 7) host_set_date_time_rec(pb + FileInfoRecGS_modDateTime, fi.modified_date); if (pcount >= 8) { word16 fst_id = hfsFSID; @@ -1447,8 +598,8 @@ static word32 fst_get_file_info(int class, const char *path) { set_memory32_c(pb + FileRec_auxType, fi.aux_type, 0); set_memory16_c(pb + FileRec_storageType, fi.storage_type, 0); - set_date_time(pb + FileRec_createDate, fi.create_date); - set_date_time(pb + FileRec_modDate, fi.modified_date); + host_set_date_time(pb + FileRec_createDate, fi.create_date); + host_set_date_time(pb + FileRec_modDate, fi.modified_date); set_memory32_c(pb + FileRec_blocksUsed, fi.blocks, 0); } @@ -1528,9 +679,9 @@ static word32 fst_volume(int class) { static word32 fst_clear_backup(int class, const char *path) { word16 rv = 0; - word16 type = storage_type(path, &rv); + word16 type = host_storage_type(path, &rv); if (rv) return rv; - if (read_only) return drvrWrtProt; + if (g_cfg_host_read_only) return drvrWrtProt; return invalidFSTop; } @@ -1574,10 +725,10 @@ static struct directory *read_directory(const char *path, word16 *error) { memset(&data, 0, sizeof(data)); - char *p = append_path(path, "*"); + char *p = host_gc_append_path(path, "*"); h = FindFirstFile(p, &data); if (h == INVALID_HANDLE_VALUE) { - *error = map_last_error(); + *error = host_map_win32_error(GetLastError()); return NULL; } @@ -1595,7 +746,7 @@ static struct directory *read_directory(const char *path, word16 *error) { size = sizeof(struct directory) + capacity * sizeof(char *); struct directory * tmp = realloc(dd, size); if (!tmp) { - *error = map_errno(); + *error = host_map_errno(errno); free_directory(dd); FindClose(h); return NULL; @@ -1606,7 +757,8 @@ static struct directory *read_directory(const char *path, word16 *error) { } while (FindNextFile(h, &data) != 0); //? - if (GetLastError() != ERROR_NO_MORE_FILES) *error = map_last_error(); + DWORD e = GetLastError(); + if (e != ERROR_NO_MORE_FILES) *error = host_map_win32_error(e); FindClose(h); @@ -1653,14 +805,14 @@ static HANDLE open_data_fork(const char *path, word16 *access, word16 *error) { break; } if (h == INVALID_HANDLE_VALUE) { - *error = map_last_error(); + *error = host_map_win32_error(GetLastError()); } return h; } static HANDLE open_resource_fork(const char *path, word16 *access, word16 *error) { - char *rpath = append_string(path, ":AFP_Resource"); + char *rpath = host_gc_append_string(path, ":AFP_Resource"); HANDLE h = INVALID_HANDLE_VALUE; for (;;) { @@ -1698,7 +850,7 @@ static HANDLE open_resource_fork(const char *path, word16 *access, word16 *error break; } if (h == INVALID_HANDLE_VALUE) { - *error = map_last_error(); + *error = host_map_win32_error(GetLastError()); } return h; } @@ -1713,12 +865,12 @@ static word32 fst_open(int class, const char *path) { struct file_info fi; word16 rv = 0; - rv = get_file_info(path, &fi); + rv = host_get_file_info(path, &fi); if (rv) return rv; HANDLE h = INVALID_HANDLE_VALUE; - int type = regular_file; + int type = file_regular; struct directory *dd = NULL; word16 pcount = 0; @@ -1733,7 +885,7 @@ static word32 fst_open(int class, const char *path) { if (resource_number) { if (resource_number > 1) return paramRangeErr; - type = resource_file; + type = file_resource; } if (access > 3) return paramRangeErr; @@ -1749,11 +901,11 @@ static word32 fst_open(int class, const char *path) { case readWriteEnable: return invalidAccess; } - type = directory_file; + type = file_directory; } - if (read_only) { + if (g_cfg_host_read_only) { switch (request_access) { case readEnableAllowWrite: request_access = readEnable; @@ -1767,13 +919,13 @@ static word32 fst_open(int class, const char *path) { access = request_access; switch(type) { - case regular_file: + case file_regular: h = open_data_fork(path, &access, &rv); break; - case resource_file: + case file_resource: h = open_resource_fork(path, &access, &rv); break; - case directory_file: + case file_directory: dd = read_directory(path, &rv); break; } @@ -1787,8 +939,8 @@ static word32 fst_open(int class, const char *path) { if (pcount >= 7) set_memory32_c(pb + OpenRecGS_auxType, fi.aux_type, 0); if (pcount >= 8) set_memory16_c(pb + OpenRecGS_storageType, fi.storage_type, 0); - if (pcount >= 9) set_date_time_rec(pb + OpenRecGS_createDateTime, fi.create_date); - if (pcount >= 10) set_date_time_rec(pb + OpenRecGS_modDateTime, fi.modified_date); + if (pcount >= 9) host_set_date_time_rec(pb + OpenRecGS_createDateTime, fi.create_date); + if (pcount >= 10) host_set_date_time_rec(pb + OpenRecGS_modDateTime, fi.modified_date); if (pcount >= 11) { word16 fst_id = hfsFSID; @@ -1823,7 +975,7 @@ static word32 fst_open(int class, const char *path) { return tooManyFilesOpen; } - if (type == regular_file) { + if (type == file_regular) { if (g_cfg_host_crlf) { if (fi.file_type == 0x04 || fi.file_type == 0xb0) @@ -1862,7 +1014,7 @@ static word32 fst_read(int class) { if (!e) return invalidRefNum; switch (e->type) { - case directory_file: + case file_directory: return badStoreType; } @@ -1903,16 +1055,16 @@ static word32 fst_read(int class) { byte b; DWORD read_count; ok = ReadFile(e->handle, &b, 1, &read_count, NULL); - if (!ok) return map_last_error(); + if (!ok) return host_map_win32_error(GetLastError()); if (read_count == 0) break; transfer_count++; switch(e->translate) { case translate_crlf: - lf_to_cr(&b, 1); + host_lf_to_cr(&b, 1); break; case translate_merlin: - text_to_merlin(&b, 1); + host_text_to_merlin(&b, 1); break; } @@ -1923,20 +1075,20 @@ static word32 fst_read(int class) { } else { DWORD read_count; - byte *data = gc_malloc(request_count); + byte *data = host_gc_malloc(request_count); if (!data) return outOfMem; ok = ReadFile(e->handle, data, request_count, &read_count, NULL); - if (!ok) rv = map_last_error(); + if (!ok) rv = host_map_win32_error(GetLastError()); else if (read_count == 0) rv = eofEncountered; if (read_count > 0) { transfer_count = read_count; switch(e->translate) { case translate_crlf: - lf_to_cr(data, transfer_count); + host_lf_to_cr(data, transfer_count); break; case translate_merlin: - text_to_merlin(data, transfer_count); + host_text_to_merlin(data, transfer_count); break; } for (size_t i = 0; i < transfer_count; ++i) { @@ -1963,10 +1115,10 @@ static word32 fst_write(int class) { if (!e) return invalidRefNum; switch (e->type) { - case directory_file: + case file_directory: return badStoreType; } - if (read_only) return drvrWrtProt; + if (g_cfg_host_read_only) return drvrWrtProt; if (!(e->access & writeEnable)) return invalidAccess; @@ -1988,7 +1140,7 @@ static word32 fst_write(int class) { } if (request_count == 0) return 0; - byte *data = gc_malloc(request_count); + byte *data = host_gc_malloc(request_count); if (!data) return outOfMem; for (word32 i = 0; i < request_count; ++i) { @@ -1997,16 +1149,16 @@ static word32 fst_write(int class) { switch (e->translate) { case translate_crlf: - cr_to_lf(data, request_count); + host_cr_to_lf(data, request_count); break; case translate_merlin: - merlin_to_text(data, request_count); + host_merlin_to_text(data, request_count); break; } word32 rv = 0; DWORD write_count = 0; int ok = WriteFile(e->handle, data, request_count, &write_count, NULL); - if (!ok) rv = map_last_error(); + if (!ok) rv = host_map_win32_error(GetLastError()); if (write_count > 0) { if (class) set_memory32_c(pb + IORecGS_transferCount, write_count, 0); @@ -2032,11 +1184,11 @@ static word32 fst_flush(int class) { if (!e) return invalidRefNum; switch (e->type) { - case directory_file: + case file_directory: return badStoreType; } - if (!FlushFileBuffers(e->handle)) return map_last_error(); + if (!FlushFileBuffers(e->handle)) return host_map_win32_error(GetLastError()); return 0; } @@ -2066,7 +1218,7 @@ static word16 win_seek(HANDLE h, word16 base, word32 displacement, LARGE_INTEGER return paramRangeErr; } - if (!SetFilePointerEx(h, d, position, m)) return map_last_error(); + if (!SetFilePointerEx(h, d, position, m)) return host_map_win32_error(GetLastError()); return 0; } @@ -2078,7 +1230,7 @@ static word32 fst_set_mark(int class) { if (!e) return invalidRefNum; switch (e->type) { - case directory_file: + case file_directory: return badStoreType; } @@ -2105,10 +1257,10 @@ static word32 fst_set_eof(int class) { if (!e) return invalidRefNum; switch (e->type) { - case directory_file: + case file_directory: return badStoreType; } - if (read_only) return drvrWrtProt; + if (g_cfg_host_read_only) return drvrWrtProt; if (!(e->access & writeEnable)) return invalidAccess; @@ -2135,7 +1287,7 @@ static word32 fst_set_eof(int class) { if (rv) return rv; // SetEndOfFile sets the current positions as eof. - if (!SetEndOfFile(e->handle)) return map_last_error(); + if (!SetEndOfFile(e->handle)) return host_map_win32_error(GetLastError()); // restore old mark. ??? SetFilePointerEx(e->handle, mark, NULL, FILE_BEGIN); @@ -2153,14 +1305,14 @@ static word32 fst_get_mark(int class) { word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); switch (e->type) { - case directory_file: + case file_directory: return badStoreType; } // get the current mark LARGE_INTEGER pos; LARGE_INTEGER zero; zero.QuadPart = 0; - if (!SetFilePointerEx(e->handle, zero, &pos, FILE_CURRENT)) return map_last_error(); + if (!SetFilePointerEx(e->handle, zero, &pos, FILE_CURRENT)) return host_map_win32_error(GetLastError()); if (class) { set_memory32_c(pb + PositionRecGS_position, pos.LowPart, 0); @@ -2182,13 +1334,13 @@ static word32 fst_get_eof(int class) { switch (e->type) { - case directory_file: + case file_directory: return badStoreType; } LARGE_INTEGER eof; - if (!GetFileSizeEx(e->handle, &eof)) return map_last_error(); + if (!GetFileSizeEx(e->handle, &eof)) return host_map_win32_error(GetLastError()); // what if > 32 bits? @@ -2212,7 +1364,7 @@ static word32 fst_get_dir_entry(int class) { if (!e) return invalidRefNum; - if (e->type != directory_file) return badFileFormat; + if (e->type != file_directory) return badFileFormat; word32 pb = get_memory24_c(engine.direct + dp_param_blk_ptr, 0); @@ -2269,9 +1421,9 @@ static word32 fst_get_dir_entry(int class) { word32 rv = 0; const char *dname = e->dir->entries[displacement++]; e->dir->displacement = displacement; - char *fullpath = append_path(e->path, dname); + char *fullpath = host_gc_append_path(e->path, dname); struct file_info fi; - rv = get_file_info(fullpath, &fi); + rv = host_get_file_info(fullpath, &fi); if (dname) fprintf(stderr, " - %s", dname); @@ -2287,8 +1439,8 @@ static word32 fst_get_dir_entry(int class) { if (pcount >= 8) set_memory32_c(pb + DirEntryRecGS_eof, fi.eof, 0); if (pcount >= 9) set_memory32_c(pb + DirEntryRecGS_blockCount, fi.blocks, 0); - if (pcount >= 10) set_date_time_rec(pb + DirEntryRecGS_createDateTime, fi.create_date); - if (pcount >= 11) set_date_time_rec(pb + DirEntryRecGS_modDateTime, fi.modified_date); + if (pcount >= 10) host_set_date_time_rec(pb + DirEntryRecGS_createDateTime, fi.create_date); + if (pcount >= 11) host_set_date_time_rec(pb + DirEntryRecGS_modDateTime, fi.modified_date); if (pcount >= 12) set_memory16_c(pb + DirEntryRecGS_access, fi.access, 0); if (pcount >= 13) set_memory32_c(pb + DirEntryRecGS_auxType, fi.aux_type, 0); @@ -2313,8 +1465,8 @@ static word32 fst_get_dir_entry(int class) { set_memory32_c(pb + DirEntryRec_endOfFile, fi.eof, 0); set_memory32_c(pb + DirEntryRec_blockCount, fi.blocks, 0); - set_date_time_rec(pb + DirEntryRec_createTime, fi.create_date); - set_date_time_rec(pb + DirEntryRec_modTime, fi.modified_date); + host_set_date_time_rec(pb + DirEntryRec_createTime, fi.create_date); + host_set_date_time_rec(pb + DirEntryRec_modTime, fi.modified_date); set_memory16_c(pb + DirEntryRec_access, fi.access, 0); set_memory32_c(pb + DirEntryRec_auxType, fi.aux_type, 0); @@ -2331,12 +1483,12 @@ static word32 fst_change_path(int class, const char *path1, const char *path2) { BOOL ok = 0; word16 rv = 0; - word16 type = storage_type(path1, &rv); + word16 type = host_storage_type(path1, &rv); if (rv) return rv; if (type == 0x0f) return badStoreType; - if (read_only) return drvrWrtProt; + if (g_cfg_host_read_only) return drvrWrtProt; - if (!MoveFile(path1, path2)) return map_last_error(); + if (!MoveFile(path1, path2)) return host_map_win32_error(GetLastError()); return 0; } @@ -2348,6 +1500,26 @@ static word32 fst_erase(int class) { return notBlockDev; } +#ifdef __CYGWIN__ + +#include + +static char *expand_path(const char *path, word32 *error) { + + char buffer[PATH_MAX]; + ssize_t ok = cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, buffer, sizeof(buffer)); + if (ok < 0) { + *error = fstError; + return NULL; + } + return host_gc_strdup(buffer); +} + + +#else +#define expand_path(x, y) (x) +#endif + static const char *call_name(word16 call) { static char* class1[] = { // 0x00 @@ -2476,181 +1648,6 @@ static const char *call_name(word16 call) { return ""; } -static const char *error_name(word16 error) { - static char *errors[] = { - "", - "badSystemCall", - "", - "", - "invalidPcount", - "", - "", - "gsosActive", - "", - "", - "", - "", - "", - "", - "", - "", - // 0x10 - "devNotFound", - "invalidDevNum", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - // 0x20 - "drvrBadReq", - "drvrBadCode", - "drvrBadParm", - "drvrNotOpen", - "drvrPriorOpen", - "irqTableFull", - "drvrNoResrc", - "drvrIOError", - "drvrNoDevice", - "drvrBusy", - "", - "drvrWrtProt", - "drvrBadCount", - "drvrBadBlock", - "drvrDiskSwitch", - "drvrOffLine", - // 0x30 - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - // 0x40 - "badPathSyntax", - "", - "tooManyFilesOpen", - "invalidRefNum", - "pathNotFound", - "volNotFound", - "fileNotFound", - "dupPathname", - "volumeFull", - "volDirFull", - "badFileFormat", - "badStoreType", - "eofEncountered", - "outOfRange", - "invalidAccess", - "buffTooSmall", - // 0x50 - "fileBusy", - "dirError", - "unknownVol", - "paramRangeErr", - "outOfMem", - "", - "", - "dupVolume", - "notBlockDev", - "invalidLevel", - "damagedBitMap", - "badPathNames", - "notSystemFile", - "osUnsupported", - "", - "stackOverflow", - // 0x60 - "dataUnavail", - "endOfDir", - "invalidClass", - "resForkNotFound", - "invalidFSTID", - "invalidFSTop", - "fstCaution", - "devNameErr", - "defListFull", - "supListFull", - "fstError", - "", - "", - "", - "", - "", - //0x70 - "resExistsErr", - "resAddErr", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - //0x80 - "", - "", - "", - "", - "", - "", - "", - "", - "networkError" - }; - - if (error < sizeof(errors) / sizeof(errors[0])) - return errors[error]; - return ""; -} - -#ifdef __CYGWIN__ - -#include - -static char *expand_path(const char *path, word32 *error) { - - char buffer[PATH_MAX]; - ssize_t ok = cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, buffer, sizeof(buffer)); - if (ok < 0) { - *error = fstError; - return NULL; - } - return gc_strdup(buffer); -} - - -#else -#define expand_path(x, y) (x) -#endif - - void host_fst(void) { /* @@ -2689,11 +1686,11 @@ void host_fst(void) { } } else { - if (!root) { + if (!host_root) { acc = networkError; engine.acc = acc; SEC(); - fprintf(stderr, " %02x %s\n", acc, error_name(acc)); + fprintf(stderr, " %02x %s\n", acc, host_error_name(acc)); return; } @@ -2706,7 +1703,7 @@ void host_fst(void) { acc = invalidClass; engine.acc = acc; SEC(); - fprintf(stderr, " %02x %s\n", acc, error_name(acc)); + fprintf(stderr, " %02x %s\n", acc, host_error_name(acc)); return; } @@ -2740,7 +1737,7 @@ void host_fst(void) { case 0x01: cp = check_path(path1, &acc); if (acc) break; - path3 = append_path(root, cp); + path3 = host_gc_append_path(host_root, cp); path3 = expand_path(path3, &acc); if (acc) break; @@ -2749,7 +1746,7 @@ void host_fst(void) { case 0x02: cp = check_path(path1, &acc); if (acc) break; - path3 = append_path(root, cp); + path3 = host_gc_append_path(host_root, cp); path3 = expand_path(path3, &acc); if (acc) break; @@ -2759,13 +1756,13 @@ void host_fst(void) { cp = check_path(path1, &acc); if (acc) break; - path3 = append_path(root, cp); + path3 = host_gc_append_path(host_root, cp); path3 = expand_path(path3, &acc); if (acc) break; cp = check_path(path2, &acc); if (acc) break; - path4 = append_path(root, cp); + path4 = host_gc_append_path(host_root, cp); path4 = expand_path(path4, &acc); if (acc) break; @@ -2774,7 +1771,7 @@ void host_fst(void) { case 0x05: cp = check_path(path1, &acc); if (acc) break; - path3 = append_path(root, cp); + path3 = host_gc_append_path(host_root, cp); path3 = expand_path(path3, &acc); if (acc) break; @@ -2783,7 +1780,7 @@ void host_fst(void) { case 0x06: cp = check_path(path1, &acc); if (acc) break; - path3 = append_path(root, cp); + path3 = host_gc_append_path(host_root, cp); path3 = expand_path(path3, &acc); if (acc) break; @@ -2798,7 +1795,7 @@ void host_fst(void) { case 0x0b: cp = check_path(path1, &acc); if (acc) break; - path3 = append_path(root, cp); + path3 = host_gc_append_path(host_root, cp); path3 = expand_path(path3, &acc); if (acc) break; @@ -2807,7 +1804,7 @@ void host_fst(void) { case 0x10: cp = check_path(path1, &acc); if (acc) break; - path3 = append_path(root, cp); + path3 = host_gc_append_path(host_root, cp); path3 = expand_path(path3, &acc); if (acc) break; @@ -2854,16 +1851,12 @@ void host_fst(void) { fputs("\n", stderr); } - if (acc) fprintf(stderr, " %02x %s\n", acc, error_name(acc)); + if (acc) fprintf(stderr, " %02x %s\n", acc, host_error_name(acc)); - gc_free(); + host_gc_free(); engine.acc = acc; if (acc) SEC(); else CLC(); } - -// placeholder to build on win32 until it support host MLI -void host_mli_head() {} -void host_mli_tail() {} From 7b66b3a0704178765ce322747c8f33b05074c413 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Thu, 23 Aug 2018 10:56:09 -0400 Subject: [PATCH 2/4] bug fixes and more cleanup --- src/Makefile | 2 +- src/host_mli.c | 265 +++++++++++++++++++++++------------------ src/unix_host_common.c | 2 +- 3 files changed, 151 insertions(+), 118 deletions(-) diff --git a/src/Makefile b/src/Makefile index 7d753cf..c920567 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,7 +8,7 @@ OBJECTS1 = adb.o clock.o config.o debug.o dis.o engine_c.o scc.o iwm.o \ ATOBJ = atbridge/aarp.o atbridge/atbridge.o atbridge/elap.o atbridge/llap.o atbridge/port.o PCAPOBJ = atbridge/pcap_delay.o TFEOBJ = tfe/tfe.o tfe/tfearch.o tfe/tfesupp.o -FSTOBJ = host_common.o host_fst.o host_mli.o +FSTOBJ = unix_host_common.o host_common.o host_fst.o host_mli.o include vars diff --git a/src/host_mli.c b/src/host_mli.c index c0ca991..6cc1119 100644 --- a/src/host_mli.c +++ b/src/host_mli.c @@ -109,6 +109,121 @@ struct file_entry { struct file_entry files[MAX_FILES]; + + +#if _WIN32 +static word16 file_open(const char *path, struct file_entry *file) { + + HANDLE h; + + if (g_cfg_host_read_only) { + h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } else { + h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + } + + if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); + + file->h = h; + return 0; +} + +static word16 file_close(struct file_entry *file) { + + if (!file->type) return invalidRefNum; + + if (file->h != INVALID_HANDLE_VALUE) CloseHandle(file->h); + + if (file->directory_buffer) free(file->directory_buffer); + memset(file, 0, sizeof(*file)); + file->h = INVALID_HANDLE_VALUE; + + return 0; +} + +static word16 file_flush(struct file_entry *file) { + if (!file->type) return invalidRefNum; + + if (file->h != INVALID_HANDLE_VALUE) + FlushFileBuffers(file->h); + + return 0; +} + +static word16 file_eof(struct file_entry *file) { + LARGE_INTEGER li; + if (!GetFileSizeEx(file->h, &li)) + return host_map_win32_error(GetLastError()); + if (li.QuadPart > 0xffffff) { + file->eof = 0xffffff; + return outOfRange; + } + file->eof = li.QuadPart; + return 0; +} + + +#else + +static word16 file_open(const char *path, struct file_entry *file) { + + int fd; + + if (g_cfg_host_read_only) { + fd = open(path, O_RDONLY | O_NONBLOCK); + } else { + fd = open(path, O_RDWR | O_NONBLOCK); + if (fd < 0) { + fd = open(path, O_RDONLY | O_NONBLOCK); + } + } + if (fd < 0) return host_map_errno_path(errno, path); + + file->fd = fd; + return 0; +} + +static word16 file_close(struct file_entry *file) { + + if (!file->type) return invalidRefNum; + + if (file->fd >= 0) close(file->fd); + + if (file->directory_buffer) free(file->directory_buffer); + memset(file, 0, sizeof(*file)); + file->fd = -1; + return 0; +} + +static word16 file_flush(struct file_entry *file) { + if (!file->type) return invalidRefNum; + + if (file->fd >= 0) + fsync(file->fd); + + return 0; +} + +static word16 file_eof(struct file_entry *file) { + off_t eof; + eof = lseek(file->fd, 0, SEEK_END); + if (eof < 0) return host_map_errno(errno); + if (eof > 0xffffff) { + file->eof = 0xffffff; + return outOfRange; + } + file->eof = eof; + return 0; +} + +#endif + + + + static char *get_pstr(word32 ptr) { if (!ptr) return NULL; int length = get_memory_c(ptr, 0); @@ -737,33 +852,22 @@ static int mli_set_buf(unsigned dcb, struct file_entry *file) { static int mli_get_eof(unsigned dcb, struct file_entry *file) { - off_t eof = 0; -#if _WIN32 - LARGE_INTEGER tmp; -#endif - + word16 terr = 0; switch (file->type) { default: return invalidRefNum; case file_directory: - eof = file->eof; break; case file_regular: -#if _WIN32 - if (!GetFileSizeEx(file->h, &tmp)) - return host_map_win32_error(GetLastError()); - eof = tmp.QuadPart; -#else - eof = lseek(file->fd, SEEK_END, 0); - if (eof < 0) return host_map_errno(errno); -#endif + terr = file_eof(file); + if (terr) return terr; break; - } - if (eof > 0xffffff) return outOfRange; - set_memory24_c(dcb + 2, eof, 0); + } + + set_memory24_c(dcb + 2, file->eof, 0); return 0; } @@ -821,10 +925,7 @@ static int mli_get_mark(unsigned dcb, struct file_entry *file) { static int mli_set_mark(unsigned dcb, struct file_entry *file) { off_t eof = 0; - -#if _WIN32 - LARGE_INTEGER tmp; -#endif + word16 terr = 0; word32 position = get_memory24_c(dcb + 2, 0); @@ -835,18 +936,12 @@ static int mli_set_mark(unsigned dcb, struct file_entry *file) { eof = file->eof; break; case file_regular: -#if _WIN32 - if (!GetFileSizeEx(file->h, &tmp)) - return host_map_win32_error(GetLastError()); - eof = tmp.QuadPart; -#else - eof = lseek(file->fd, SEEK_END, 0); - if (eof < 0) return host_map_errno(errno); -#endif + terr = file_eof(file); + if (terr) return terr; break; } - if (position > eof) return outOfRange; + if (position > file->eof) return outOfRange; file->mark = position; return 0; @@ -860,53 +955,7 @@ static int mli_newline(unsigned dcb, struct file_entry *file) { return 0; } -#ifdef _WIN32 -static word16 file_close(struct file_entry *file) { - if (!file->type) return invalidRefNum; - - if (file->h != INVALID_HANDLE_VALUE) CloseHandle(file->h); - - if (file->directory_buffer) free(file->directory_buffer); - memset(file, 0, sizeof(*file)); - file->h = INVALID_HANDLE_VALUE; - - return 0; -} - -static word16 file_flush(struct file_entry *file) { - if (!file->type) return invalidRefNum; - - if (file->h != INVALID_HANDLE_VALUE) - FlushFileBuffers(file->h); - - return 0; -} - -#else -static word16 file_close(struct file_entry *file) { - - if (!file->type) return invalidRefNum; - - if (file->fd >= 0) close(file->fd); - - if (file->directory_buffer) free(file->directory_buffer); - memset(file, 0, sizeof(*file)); - file->fd = -1; - return 0; -} - -static word16 file_flush(struct file_entry *file) { - if (!file->type) return invalidRefNum; - - if (file->fd >= 0) - fsync(file->fd); - - return 0; -} - - -#endif static int mli_close(unsigned dcb, struct file_entry *file) { @@ -977,46 +1026,6 @@ static int mli_quit(unsigned dcb) { } -#if _WIN32 -static word16 file_open(const char *path, struct file_entry *file) { - - HANDLE h; - - if (g_cfg_host_read_only) { - h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } else { - h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } - } - - if (h == INVALID_HANDLE_VALUE) return host_map_win32_error(GetLastError()); - - file->h = h; - return 0; -} - -#else - -static word16 file_open(const char *path, struct file_entry *file) { - - int fd; - - if (g_cfg_host_read_only) { - fd = open(path, O_RDONLY | O_NONBLOCK); - } else { - fd = open(path, O_RDWR | O_NONBLOCK); - if (fd < 0) { - fd = open(path, O_RDONLY | O_NONBLOCK); - } - } - if (fd < 0) return host_map_errno_path(errno, path); - - file->fd = fd; - return 0; -} -#endif static int mli_open(unsigned dcb, const char *name, const char *path) { @@ -1238,6 +1247,30 @@ static const char *call_name(unsigned call) { } } + +#ifdef __CYGWIN__ + +#include + +static char *expand_path(const char *path, word32 *error) { + + char buffer[PATH_MAX]; + if (!path) return path; + + ssize_t ok = cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, buffer, sizeof(buffer)); + if (ok < 0) { + *error = fstError; + return NULL; + } + return host_gc_strdup(buffer); +} + + +#else +#define expand_path(x, y) (x) +#endif + + /* * mli head patch. called before ProDOS mli. * this call will either diff --git a/src/unix_host_common.c b/src/unix_host_common.c index eb1f9a7..84295d7 100644 --- a/src/unix_host_common.c +++ b/src/unix_host_common.c @@ -449,7 +449,7 @@ unsigned host_scan_directory(const char *path, char ***out, size_t *entries, uns for(;;) { struct dirent *d = readdir(dp); - if (!dp) break; + if (!d) break; const char *name = d->d_name; From 2b38b6bf8d4a8d4cd3ed2516e6364137d1c8ca01 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Thu, 23 Aug 2018 15:27:23 -0400 Subject: [PATCH 3/4] win32 prefix fix. --- src/host_mli.c | 22 +++++++++++----------- src/unix_host_common.c | 8 +++++--- src/win32_host_common.c | 6 +++++- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/host_mli.c b/src/host_mli.c index 6cc1119..28cce65 100644 --- a/src/host_mli.c +++ b/src/host_mli.c @@ -924,7 +924,6 @@ static int mli_get_mark(unsigned dcb, struct file_entry *file) { static int mli_set_mark(unsigned dcb, struct file_entry *file) { - off_t eof = 0; word16 terr = 0; word32 position = get_memory24_c(dcb + 2, 0); @@ -933,7 +932,6 @@ static int mli_set_mark(unsigned dcb, struct file_entry *file) { default: return invalidRefNum; case file_directory: - eof = file->eof; break; case file_regular: terr = file_eof(file); @@ -1107,21 +1105,22 @@ static int mli_set_prefix(unsigned dcb, char *name, char *path) { return saved_prefix ? -2 : -1; } - int l; - struct stat st; + unsigned type; + word16 terr; - if (stat(path, &st) < 0) - return host_map_errno_path(errno, path); - - if (!S_ISDIR(st.st_mode)) { - return badStoreType; + type = host_storage_type(path, &terr); + switch(type) { + case 0x0f: + case 0x0d: + break; + case 0: return terr; + default: return badStoreType; } - /* /HOST/ was previously stripped... add it back. */ name = host_gc_append_path("/HOST", name); - l = strlen(name); + int l = strlen(name); /* trim trailing / */ while (l > 1 && name[l-1] == '/') --l; name[l] = 0; @@ -1472,6 +1471,7 @@ void host_mli_head() { } fputs("\n", stderr); + fflush(stderr); host_gc_free(); diff --git a/src/unix_host_common.c b/src/unix_host_common.c index 84295d7..0df5b91 100644 --- a/src/unix_host_common.c +++ b/src/unix_host_common.c @@ -1,10 +1,12 @@ #define _BSD_SOURCE -#include -#include -#include #include +#include +#include +#include +#include +#include #if defined(__APPLE__) #include diff --git a/src/win32_host_common.c b/src/win32_host_common.c index 6eb39d4..1b3e016 100644 --- a/src/win32_host_common.c +++ b/src/win32_host_common.c @@ -2,6 +2,10 @@ #define _WIN32_WINNT 0x0600 // vista+ #include +#include +#include +#include + #include "defc.h" #include "gsos.h" @@ -530,7 +534,7 @@ word32 host_set_file_info(const char *path, struct file_info *fi) { static int qsort_callback(const void *a, const void *b) { - return stricmp(*(const char **)a, *(const char **)b); + return strcasecmp(*(const char **)a, *(const char **)b); } unsigned host_scan_directory(const char *path, char ***out, size_t *entries, unsigned p8) { From fcf8dea873560a7e9b380e1ed0832ad3f5e330d0 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Thu, 23 Aug 2018 20:47:09 -0400 Subject: [PATCH 4/4] host mli - convert cygwin paths to Win32 paths before using with Win32 API. --- src/host_mli.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/host_mli.c b/src/host_mli.c index 28cce65..5356e94 100644 --- a/src/host_mli.c +++ b/src/host_mli.c @@ -1258,7 +1258,7 @@ static char *expand_path(const char *path, word32 *error) { ssize_t ok = cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, buffer, sizeof(buffer)); if (ok < 0) { - *error = fstError; + if (error) *error = fstError; return NULL; } return host_gc_strdup(buffer); @@ -1283,6 +1283,7 @@ void host_mli_head() { saved_call = get_memory_c(rts + 1, 0); saved_dcb = get_memory16_c(rts + 2, 0); saved_p = engine.psr; + word16 terr = 0; /* do pcount / path stuff here */ char *path1 = NULL; @@ -1311,27 +1312,30 @@ void host_mli_head() { path1 = is_host_path(get_memory16_c(saved_dcb + 1, 0)); if (!path1) goto prodos_mli; path3 = host_gc_append_path(host_root, path1); + path3 = expand_path(path3, &terr); break; + case RENAME: path1 = is_host_path(get_memory16_c(saved_dcb + 1,0)); path2 = is_host_path(get_memory16_c(saved_dcb + 3,0)); if (!path1 && !path2) goto prodos_mli; if (path1) path3 = host_gc_append_path(host_root, path1); if (path2) path4 = host_gc_append_path(host_root, path2); + path3 = expand_path(path3, &terr); + path4 = expand_path(path4, &terr); break; case SET_PREFIX: path1 = is_host_path(get_memory16_c(saved_dcb + 1,0)); if (!path1 && !saved_prefix) goto prodos_mli; if (path1) path3 = host_gc_append_path(host_root, path1); + path3 = expand_path(path3, &terr); break; - case GET_PREFIX: if (!saved_prefix) goto prodos_mli; break; - /* refnum based */ case NEWLINE: case READ: