#include #include #include /* undocumented, so check if these really hold */ #if SEEK_SET != FILE_BEGIN || \ SEEK_CUR != FILE_CURRENT || \ SEEK_END != FILE_END #error "Standard and WinAPI seek modes not compatible" #endif static wchar_t * UTF8ToUnicode(const char *str) { const int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); wchar_t * const result = (wchar_t *)MVM_malloc(len * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, str, -1, result, len); return result; } MVMint64 MVM_platform_lseek(int fd, MVMint64 offset, int origin) { HANDLE hf; LARGE_INTEGER li; hf = (HANDLE)_get_osfhandle(fd); if (hf == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } if (GetFileType(hf) != 1) { errno = ESPIPE; return -1; } li.QuadPart = offset; li.LowPart = SetFilePointer(hf, li.LowPart, &li.HighPart, origin); if (li.LowPart == INVALID_SET_FILE_POINTER) { errno = ESPIPE; return -1; } return li.QuadPart; } int MVM_platform_unlink(const char *pathname) { /* Must using UTF8ToUnicode for supporting CJK Windows file name. */ wchar_t *wpathname = UTF8ToUnicode(pathname); int str_len = wcslen(wpathname); int r; DWORD attrs; if (str_len > MAX_PATH) { wchar_t abs_wpathname[4096]; /* 4096 should be enough for absolute path */ wchar_t *lpp_part; /* You cannot use the "\\?\" prefix with a relative path, * relative paths are always limited to a total of MAX_PATH characters. * see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx */ if (!GetFullPathNameW(wpathname, 4096, abs_wpathname, &lpp_part)) { errno = ENOENT; return -1; } MVM_free(wpathname); str_len = wcslen(abs_wpathname); wpathname = (wchar_t *)MVM_malloc((str_len + 4) * sizeof(wchar_t)); wcscpy(wpathname, L"\\\\?\\"); wcscat(wpathname, abs_wpathname); } attrs = GetFileAttributesW(wpathname); if (attrs == INVALID_FILE_ATTRIBUTES) { MVM_free(wpathname); errno = ENOENT; return -1; } else if (attrs & FILE_ATTRIBUTE_READONLY) { (void)SetFileAttributesW(wpathname, attrs & ~FILE_ATTRIBUTE_READONLY); r = DeleteFileW(wpathname); if (r == 0) { (void)SetFileAttributesW(wpathname, attrs); } } else { r = DeleteFileW(wpathname); } if (r == 0) { DWORD LastError = GetLastError(); MVM_free(wpathname); if (LastError == ERROR_FILE_NOT_FOUND) { errno = ENOENT; } else if (LastError == ERROR_ACCESS_DENIED) { errno = EACCES; } return -1; } MVM_free(wpathname); return 0; } int MVM_platform_fsync(int fd) { if (FlushFileBuffers((HANDLE)_get_osfhandle(fd))) return 0; errno = GetLastError(); if (errno == ENXIO) return 0; /* Not something we can flush. */ return -1; } int MVM_platform_open(const char *pathname, int flags, ...) { va_list args; wchar_t *wpathname = UTF8ToUnicode(pathname); int res; if (flags & _O_CREAT) { va_start(args, flags); res = _wopen(wpathname, flags, va_arg(args, int)); va_end(args); } else { res = _wopen(wpathname, flags); } MVM_free(wpathname); return res; } FILE *MVM_platform_fopen(const char *pathname, const char *mode) { wchar_t *wpathname = UTF8ToUnicode(pathname); wchar_t *wmode = UTF8ToUnicode(mode); FILE *res = _wfopen(wpathname, wmode); MVM_free(wpathname); MVM_free(wmode); return res; }