mirror of
https://github.com/david-schmidt/gsport.git
synced 2024-06-16 16:29:34 +00:00
Need these for Win32
This commit is contained in:
parent
e919ee8352
commit
ea638ad70e
633
src/win32_host_common.c
Normal file
633
src/win32_host_common.c
Normal file
|
@ -0,0 +1,633 @@
|
||||||
|
|
||||||
|
#define _WIN32_WINNT 0x0600 // vista+
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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 strcasecmp(*(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;
|
||||||
|
}
|
1862
src/win32_host_fst.c
Normal file
1862
src/win32_host_fst.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user