diff -r 9afb44f030b6 -r 9d1d0fa8db02 misc/physfs/src/platform_windows.c --- a/misc/physfs/src/platform_windows.c Wed Feb 27 16:12:22 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,936 +0,0 @@ -/* - * Windows support routines for PhysicsFS. - * - * Please see the file LICENSE.txt in the source's root directory. - * - * This file written by Ryan C. Gordon, and made sane by Gregory S. Read. - */ - -#define __PHYSICSFS_INTERNAL__ -#include "physfs_platforms.h" - -#ifdef PHYSFS_PLATFORM_WINDOWS - -/* Forcibly disable UNICODE macro, since we manage this ourselves. */ -#ifdef UNICODE -#undef UNICODE -#endif - -#define WIN32_LEAN_AND_MEAN 1 -#include -#include -#include -#include -#include -#include -#include - -#include "physfs_internal.h" - -#define LOWORDER_UINT64(pos) ((PHYSFS_uint32) (pos & 0xFFFFFFFF)) -#define HIGHORDER_UINT64(pos) ((PHYSFS_uint32) ((pos >> 32) & 0xFFFFFFFF)) - -/* - * Users without the platform SDK don't have this defined. The original docs - * for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should - * work as desired. - */ -#define PHYSFS_INVALID_SET_FILE_POINTER 0xFFFFFFFF - -/* just in case... */ -#define PHYSFS_INVALID_FILE_ATTRIBUTES 0xFFFFFFFF - -/* Not defined before the Vista SDK. */ -#define PHYSFS_IO_REPARSE_TAG_SYMLINK 0xA000000C - - -#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \ - if (str == NULL) \ - w_assignto = NULL; \ - else { \ - const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) + 1) * 2); \ - w_assignto = (WCHAR *) __PHYSFS_smallAlloc(len); \ - if (w_assignto != NULL) \ - PHYSFS_utf8ToUtf16(str, (PHYSFS_uint16 *) w_assignto, len); \ - } \ -} \ - -/* Note this counts WCHARs, not codepoints! */ -static PHYSFS_uint64 wStrLen(const WCHAR *wstr) -{ - PHYSFS_uint64 len = 0; - while (*(wstr++)) - len++; - return len; -} /* wStrLen */ - -static char *unicodeToUtf8Heap(const WCHAR *w_str) -{ - char *retval = NULL; - if (w_str != NULL) - { - void *ptr = NULL; - const PHYSFS_uint64 len = (wStrLen(w_str) * 4) + 1; - retval = allocator.Malloc(len); - BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); - PHYSFS_utf8FromUtf16((const PHYSFS_uint16 *) w_str, retval, len); - ptr = allocator.Realloc(retval, strlen(retval) + 1); /* shrink. */ - if (ptr != NULL) - retval = (char *) ptr; - } /* if */ - return retval; -} /* unicodeToUtf8Heap */ - -/* !!! FIXME: do we really need readonly? If not, do we need this struct? */ -typedef struct -{ - HANDLE handle; - int readonly; -} WinApiFile; - -static HANDLE detectCDThreadHandle = NULL; -static HWND detectCDHwnd = 0; -static volatile int initialDiscDetectionComplete = 0; -static volatile DWORD drivesWithMediaBitmap = 0; - - -static PHYSFS_ErrorCode errcodeFromWinApiError(const DWORD err) -{ - /* - * win32 error codes are sort of a tricky thing; Microsoft intentionally - * doesn't list which ones a given API might trigger, there are several - * with overlapping and unclear meanings...and there's 16 thousand of - * them in Windows 7. It looks like the ones we care about are in the - * first 500, but I can't say this list is perfect; we might miss - * important values or misinterpret others. - * - * Don't treat this list as anything other than a work in progress. - */ - switch (err) - { - case ERROR_SUCCESS: return PHYSFS_ERR_OK; - case ERROR_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION; - case ERROR_NETWORK_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION; - case ERROR_NOT_READY: return PHYSFS_ERR_IO; - case ERROR_CRC: return PHYSFS_ERR_IO; - case ERROR_SEEK: return PHYSFS_ERR_IO; - case ERROR_SECTOR_NOT_FOUND: return PHYSFS_ERR_IO; - case ERROR_NOT_DOS_DISK: return PHYSFS_ERR_IO; - case ERROR_WRITE_FAULT: return PHYSFS_ERR_IO; - case ERROR_READ_FAULT: return PHYSFS_ERR_IO; - case ERROR_DEV_NOT_EXIST: return PHYSFS_ERR_IO; - /* !!! FIXME: ?? case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP; */ - case ERROR_BUFFER_OVERFLOW: return PHYSFS_ERR_BAD_FILENAME; - case ERROR_INVALID_NAME: return PHYSFS_ERR_BAD_FILENAME; - case ERROR_BAD_PATHNAME: return PHYSFS_ERR_BAD_FILENAME; - case ERROR_DIRECTORY: return PHYSFS_ERR_BAD_FILENAME; - case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH; - case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH; - case ERROR_DELETE_PENDING: return PHYSFS_ERR_NO_SUCH_PATH; - case ERROR_INVALID_DRIVE: return PHYSFS_ERR_NO_SUCH_PATH; - case ERROR_HANDLE_DISK_FULL: return PHYSFS_ERR_NO_SPACE; - case ERROR_DISK_FULL: return PHYSFS_ERR_NO_SPACE; - /* !!! FIXME: ?? case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH; */ - /* !!! FIXME: ?? case EISDIR: return PHYSFS_ERR_NOT_A_FILE; */ - case ERROR_WRITE_PROTECT: return PHYSFS_ERR_READ_ONLY; - case ERROR_LOCK_VIOLATION: return PHYSFS_ERR_BUSY; - case ERROR_SHARING_VIOLATION: return PHYSFS_ERR_BUSY; - case ERROR_CURRENT_DIRECTORY: return PHYSFS_ERR_BUSY; - case ERROR_DRIVE_LOCKED: return PHYSFS_ERR_BUSY; - case ERROR_PATH_BUSY: return PHYSFS_ERR_BUSY; - case ERROR_BUSY: return PHYSFS_ERR_BUSY; - case ERROR_NOT_ENOUGH_MEMORY: return PHYSFS_ERR_OUT_OF_MEMORY; - case ERROR_OUTOFMEMORY: return PHYSFS_ERR_OUT_OF_MEMORY; - case ERROR_DIR_NOT_EMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY; - default: return PHYSFS_ERR_OS_ERROR; - } /* switch */ -} /* errcodeFromWinApiError */ - -static inline PHYSFS_ErrorCode errcodeFromWinApi(void) -{ - return errcodeFromWinApiError(GetLastError()); -} /* errcodeFromWinApi */ - - -typedef BOOL (WINAPI *fnSTEM)(DWORD, LPDWORD b); - -static DWORD pollDiscDrives(void) -{ - /* Try to use SetThreadErrorMode(), which showed up in Windows 7. */ - HANDLE lib = LoadLibraryA("kernel32.dll"); - fnSTEM stem = NULL; - char drive[4] = { 'x', ':', '\\', '\0' }; - DWORD oldErrorMode = 0; - DWORD drives = 0; - DWORD i; - - if (lib) - stem = (fnSTEM) GetProcAddress(lib, "SetThreadErrorMode"); - - if (stem) - stem(SEM_FAILCRITICALERRORS, &oldErrorMode); - else - oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - - /* Do detection. This may block if a disc is spinning up. */ - for (i = 'A'; i <= 'Z'; i++) - { - DWORD tmp = 0; - drive[0] = (char) i; - if (GetDriveTypeA(drive) != DRIVE_CDROM) - continue; - - /* If this function succeeds, there's media in the drive */ - if (GetVolumeInformationA(drive, NULL, 0, NULL, NULL, &tmp, NULL, 0)) - drives |= (1 << (i - 'A')); - } /* for */ - - if (stem) - stem(oldErrorMode, NULL); - else - SetErrorMode(oldErrorMode); - - if (lib) - FreeLibrary(lib); - - return drives; -} /* pollDiscDrives */ - - -static LRESULT CALLBACK detectCDWndProc(HWND hwnd, UINT msg, - WPARAM wp, LPARAM lparam) -{ - PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lparam; - PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lparam; - const int removed = (wp == DBT_DEVICEREMOVECOMPLETE); - - if (msg == WM_DESTROY) - return 0; - else if ((msg != WM_DEVICECHANGE) || - ((wp != DBT_DEVICEARRIVAL) && (wp != DBT_DEVICEREMOVECOMPLETE)) || - (lpdb->dbch_devicetype != DBT_DEVTYP_VOLUME) || - ((lpdbv->dbcv_flags & DBTF_MEDIA) == 0)) - { - return DefWindowProcW(hwnd, msg, wp, lparam); - } /* else if */ - - if (removed) - drivesWithMediaBitmap &= ~lpdbv->dbcv_unitmask; - else - drivesWithMediaBitmap |= lpdbv->dbcv_unitmask; - - return TRUE; -} /* detectCDWndProc */ - - -static DWORD WINAPI detectCDThread(LPVOID lpParameter) -{ - const char *classname = "PhysicsFSDetectCDCatcher"; - const char *winname = "PhysicsFSDetectCDMsgWindow"; - HINSTANCE hInstance = GetModuleHandleW(NULL); - ATOM class_atom = 0; - WNDCLASSEXA wce; - MSG msg; - - memset(&wce, '\0', sizeof (wce)); - wce.cbSize = sizeof (wce); - wce.lpfnWndProc = detectCDWndProc; - wce.lpszClassName = classname; - wce.hInstance = hInstance; - class_atom = RegisterClassExA(&wce); - if (class_atom == 0) - { - initialDiscDetectionComplete = 1; /* let main thread go on. */ - return 0; - } /* if */ - - detectCDHwnd = CreateWindowExA(0, classname, winname, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL); - - if (detectCDHwnd == NULL) - { - initialDiscDetectionComplete = 1; /* let main thread go on. */ - UnregisterClassA(classname, hInstance); - return 0; - } /* if */ - - /* We'll get events when discs come and go from now on. */ - - /* Do initial detection, possibly blocking awhile... */ - drivesWithMediaBitmap = pollDiscDrives(); - initialDiscDetectionComplete = 1; /* let main thread go on. */ - - do - { - const BOOL rc = GetMessageW(&msg, detectCDHwnd, 0, 0); - if ((rc == 0) || (rc == -1)) - break; /* don't care if WM_QUIT or error break this loop. */ - TranslateMessage(&msg); - DispatchMessageW(&msg); - } while (1); - - /* we've been asked to quit. */ - DestroyWindow(detectCDHwnd); - - do - { - const BOOL rc = GetMessage(&msg, detectCDHwnd, 0, 0); - if ((rc == 0) || (rc == -1)) - break; - TranslateMessage(&msg); - DispatchMessageW(&msg); - } while (1); - - UnregisterClassA(classname, hInstance); - - return 0; -} /* detectCDThread */ - - -void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) -{ - char drive_str[4] = { 'x', ':', '\\', '\0' }; - DWORD drives = 0; - DWORD i; - - /* - * If you poll a drive while a user is inserting a disc, the OS will - * block this thread until the drive has spun up. So we swallow the risk - * once for initial detection, and spin a thread that will get device - * events thereafter, for apps that use this interface to poll for - * disc insertion. - */ - if (!detectCDThreadHandle) - { - initialDiscDetectionComplete = 0; - detectCDThreadHandle = CreateThread(NULL,0,detectCDThread,NULL,0,NULL); - if (detectCDThreadHandle == NULL) - return; /* oh well. */ - - while (!initialDiscDetectionComplete) - Sleep(50); - } /* if */ - - drives = drivesWithMediaBitmap; /* whatever the thread has seen, we take. */ - for (i = 'A'; i <= 'Z'; i++) - { - if (drives & (1 << (i - 'A'))) - { - drive_str[0] = (char) i; - cb(data, drive_str); - } /* if */ - } /* for */ -} /* __PHYSFS_platformDetectAvailableCDs */ - - -char *__PHYSFS_platformCalcBaseDir(const char *argv0) -{ - DWORD buflen = 64; - LPWSTR modpath = NULL; - char *retval = NULL; - - while (1) - { - DWORD rc; - void *ptr; - - if ( (ptr = allocator.Realloc(modpath, buflen*sizeof(WCHAR))) == NULL ) - { - allocator.Free(modpath); - BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); - } /* if */ - modpath = (LPWSTR) ptr; - - rc = GetModuleFileNameW(NULL, modpath, buflen); - if (rc == 0) - { - allocator.Free(modpath); - BAIL_MACRO(errcodeFromWinApi(), NULL); - } /* if */ - - if (rc < buflen) - { - buflen = rc; - break; - } /* if */ - - buflen *= 2; - } /* while */ - - if (buflen > 0) /* just in case... */ - { - WCHAR *ptr = (modpath + buflen) - 1; - while (ptr != modpath) - { - if (*ptr == '\\') - break; - ptr--; - } /* while */ - - if ((ptr == modpath) && (*ptr != '\\')) - __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR); /* oh well. */ - else - { - *(ptr+1) = '\0'; /* chop off filename. */ - retval = unicodeToUtf8Heap(modpath); - } /* else */ - } /* else */ - allocator.Free(modpath); - - return retval; /* w00t. */ -} /* __PHYSFS_platformCalcBaseDir */ - - -char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) -{ - /* - * Vista and later has a new API for this, but SHGetFolderPath works there, - * and apparently just wraps the new API. This is the new way to do it: - * - * SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, - * NULL, &wszPath); - */ - - WCHAR path[MAX_PATH]; - char *utf8 = NULL; - size_t len = 0; - char *retval = NULL; - - if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, - NULL, 0, path))) - BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL); - - utf8 = unicodeToUtf8Heap(path); - BAIL_IF_MACRO(!utf8, ERRPASS, NULL); - len = strlen(utf8) + strlen(org) + strlen(app) + 4; - retval = allocator.Malloc(len); - if (!retval) - { - allocator.Free(utf8); - BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); - } /* if */ - - sprintf(retval, "%s\\%s\\%s\\", utf8, org, app); - return retval; -} /* __PHYSFS_platformCalcPrefDir */ - - -char *__PHYSFS_platformCalcUserDir(void) -{ - typedef BOOL (WINAPI *fnGetUserProfDirW)(HANDLE, LPWSTR, LPDWORD); - fnGetUserProfDirW pGetDir = NULL; - HANDLE lib = NULL; - HANDLE accessToken = NULL; /* Security handle to process */ - char *retval = NULL; - - lib = LoadLibraryA("userenv.dll"); - BAIL_IF_MACRO(!lib, errcodeFromWinApi(), NULL); - pGetDir=(fnGetUserProfDirW) GetProcAddress(lib,"GetUserProfileDirectoryW"); - GOTO_IF_MACRO(!pGetDir, errcodeFromWinApi(), done); - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &accessToken)) - GOTO_MACRO(errcodeFromWinApi(), done); - else - { - DWORD psize = 0; - WCHAR dummy = 0; - LPWSTR wstr = NULL; - BOOL rc = 0; - - /* - * Should fail. Will write the size of the profile path in - * psize. Also note that the second parameter can't be - * NULL or the function fails. - */ - rc = pGetDir(accessToken, &dummy, &psize); - assert(!rc); /* !!! FIXME: handle this gracefully. */ - (void) rc; - - /* Allocate memory for the profile directory */ - wstr = (LPWSTR) __PHYSFS_smallAlloc((psize + 1) * sizeof (WCHAR)); - if (wstr != NULL) - { - if (pGetDir(accessToken, wstr, &psize)) - { - /* Make sure it ends in a dirsep. We allocated +1 for this. */ - if (wstr[psize - 2] != '\\') - { - wstr[psize - 1] = '\\'; - wstr[psize - 0] = '\0'; - } /* if */ - retval = unicodeToUtf8Heap(wstr); - } /* if */ - __PHYSFS_smallFree(wstr); - } /* if */ - - CloseHandle(accessToken); - } /* if */ - -done: - FreeLibrary(lib); - return retval; /* We made it: hit the showers. */ -} /* __PHYSFS_platformCalcUserDir */ - - -void *__PHYSFS_platformGetThreadID(void) -{ - return ( (void *) ((size_t) GetCurrentThreadId()) ); -} /* __PHYSFS_platformGetThreadID */ - - -static int isSymlinkAttrs(const DWORD attr, const DWORD tag) -{ - return ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) && - (tag == PHYSFS_IO_REPARSE_TAG_SYMLINK) ); -} /* isSymlinkAttrs */ - - -void __PHYSFS_platformEnumerateFiles(const char *dirname, - int omitSymLinks, - PHYSFS_EnumFilesCallback callback, - const char *origdir, - void *callbackdata) -{ - HANDLE dir = INVALID_HANDLE_VALUE; - WIN32_FIND_DATAW entw; - size_t len = strlen(dirname); - char *searchPath = NULL; - WCHAR *wSearchPath = NULL; - - /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */ - searchPath = (char *) __PHYSFS_smallAlloc(len + 3); - if (searchPath == NULL) - return; - - /* Copy current dirname */ - strcpy(searchPath, dirname); - - /* if there's no '\\' at the end of the path, stick one in there. */ - if (searchPath[len - 1] != '\\') - { - searchPath[len++] = '\\'; - searchPath[len] = '\0'; - } /* if */ - - /* Append the "*" to the end of the string */ - strcat(searchPath, "*"); - - UTF8_TO_UNICODE_STACK_MACRO(wSearchPath, searchPath); - if (!wSearchPath) - return; /* oh well. */ - - dir = FindFirstFileW(wSearchPath, &entw); - - __PHYSFS_smallFree(wSearchPath); - __PHYSFS_smallFree(searchPath); - if (dir == INVALID_HANDLE_VALUE) - return; - - do - { - const DWORD attr = entw.dwFileAttributes; - const DWORD tag = entw.dwReserved0; - const WCHAR *fn = entw.cFileName; - char *utf8; - - if ((fn[0] == '.') && (fn[1] == '\0')) - continue; - if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0')) - continue; - if ((omitSymLinks) && (isSymlinkAttrs(attr, tag))) - continue; - - utf8 = unicodeToUtf8Heap(fn); - if (utf8 != NULL) - { - callback(callbackdata, origdir, utf8); - allocator.Free(utf8); - } /* if */ - } while (FindNextFileW(dir, &entw) != 0); - - FindClose(dir); -} /* __PHYSFS_platformEnumerateFiles */ - - -int __PHYSFS_platformMkDir(const char *path) -{ - WCHAR *wpath; - DWORD rc; - UTF8_TO_UNICODE_STACK_MACRO(wpath, path); - rc = CreateDirectoryW(wpath, NULL); - __PHYSFS_smallFree(wpath); - BAIL_IF_MACRO(rc == 0, errcodeFromWinApi(), 0); - return 1; -} /* __PHYSFS_platformMkDir */ - - -int __PHYSFS_platformInit(void) -{ - return 1; /* It's all good */ -} /* __PHYSFS_platformInit */ - - -int __PHYSFS_platformDeinit(void) -{ - if (detectCDThreadHandle) - { - if (detectCDHwnd) - PostMessageW(detectCDHwnd, WM_QUIT, 0, 0); - CloseHandle(detectCDThreadHandle); - detectCDThreadHandle = NULL; - initialDiscDetectionComplete = 0; - drivesWithMediaBitmap = 0; - } /* if */ - - return 1; /* It's all good */ -} /* __PHYSFS_platformDeinit */ - - -static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly) -{ - HANDLE fileh; - WinApiFile *retval; - WCHAR *wfname; - - UTF8_TO_UNICODE_STACK_MACRO(wfname, fname); - BAIL_IF_MACRO(!wfname, PHYSFS_ERR_OUT_OF_MEMORY, NULL); - fileh = CreateFileW(wfname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); - __PHYSFS_smallFree(wfname); - - BAIL_IF_MACRO(fileh == INVALID_HANDLE_VALUE,errcodeFromWinApi(), NULL); - - retval = (WinApiFile *) allocator.Malloc(sizeof (WinApiFile)); - if (!retval) - { - CloseHandle(fileh); - BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); - } /* if */ - - retval->readonly = rdonly; - retval->handle = fileh; - return retval; -} /* doOpen */ - - -void *__PHYSFS_platformOpenRead(const char *filename) -{ - return doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1); -} /* __PHYSFS_platformOpenRead */ - - -void *__PHYSFS_platformOpenWrite(const char *filename) -{ - return doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0); -} /* __PHYSFS_platformOpenWrite */ - - -void *__PHYSFS_platformOpenAppend(const char *filename) -{ - void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0); - if (retval != NULL) - { - HANDLE h = ((WinApiFile *) retval)->handle; - DWORD rc = SetFilePointer(h, 0, NULL, FILE_END); - if (rc == PHYSFS_INVALID_SET_FILE_POINTER) - { - const PHYSFS_ErrorCode err = errcodeFromWinApi(); - CloseHandle(h); - allocator.Free(retval); - BAIL_MACRO(err, NULL); - } /* if */ - } /* if */ - - return retval; -} /* __PHYSFS_platformOpenAppend */ - - -PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len) -{ - HANDLE Handle = ((WinApiFile *) opaque)->handle; - PHYSFS_sint64 totalRead = 0; - - if (!__PHYSFS_ui64FitsAddressSpace(len)) - BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); - - while (len > 0) - { - const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len; - DWORD numRead = 0; - if (!ReadFile(Handle, buf, thislen, &numRead, NULL)) - BAIL_MACRO(errcodeFromWinApi(), -1); - len -= (PHYSFS_uint64) numRead; - totalRead += (PHYSFS_sint64) numRead; - if (numRead != thislen) - break; - } /* while */ - - return totalRead; -} /* __PHYSFS_platformRead */ - - -PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, - PHYSFS_uint64 len) -{ - HANDLE Handle = ((WinApiFile *) opaque)->handle; - PHYSFS_sint64 totalWritten = 0; - - if (!__PHYSFS_ui64FitsAddressSpace(len)) - BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); - - while (len > 0) - { - const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len; - DWORD numWritten = 0; - if (!WriteFile(Handle, buffer, thislen, &numWritten, NULL)) - BAIL_MACRO(errcodeFromWinApi(), -1); - len -= (PHYSFS_uint64) numWritten; - totalWritten += (PHYSFS_sint64) numWritten; - if (numWritten != thislen) - break; - } /* while */ - - return totalWritten; -} /* __PHYSFS_platformWrite */ - - -int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos) -{ - HANDLE Handle = ((WinApiFile *) opaque)->handle; - LONG HighOrderPos; - PLONG pHighOrderPos; - DWORD rc; - - /* Get the high order 32-bits of the position */ - HighOrderPos = HIGHORDER_UINT64(pos); - - /* - * MSDN: "If you do not need the high-order 32 bits, this - * pointer must be set to NULL." - */ - pHighOrderPos = (HighOrderPos) ? &HighOrderPos : NULL; - - /* Move pointer "pos" count from start of file */ - rc = SetFilePointer(Handle, LOWORDER_UINT64(pos), - pHighOrderPos, FILE_BEGIN); - - if ( (rc == PHYSFS_INVALID_SET_FILE_POINTER) && - (GetLastError() != NO_ERROR) ) - { - BAIL_MACRO(errcodeFromWinApi(), 0); - } /* if */ - - return 1; /* No error occured */ -} /* __PHYSFS_platformSeek */ - - -PHYSFS_sint64 __PHYSFS_platformTell(void *opaque) -{ - HANDLE Handle = ((WinApiFile *) opaque)->handle; - LONG HighPos = 0; - DWORD LowPos; - PHYSFS_sint64 retval; - - /* Get current position */ - LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT); - if ( (LowPos == PHYSFS_INVALID_SET_FILE_POINTER) && - (GetLastError() != NO_ERROR) ) - { - BAIL_MACRO(errcodeFromWinApi(), -1); - } /* if */ - else - { - /* Combine the high/low order to create the 64-bit position value */ - retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos; - assert(retval >= 0); - } /* else */ - - return retval; -} /* __PHYSFS_platformTell */ - - -PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) -{ - HANDLE Handle = ((WinApiFile *) opaque)->handle; - DWORD SizeHigh; - DWORD SizeLow; - PHYSFS_sint64 retval; - - SizeLow = GetFileSize(Handle, &SizeHigh); - if ( (SizeLow == PHYSFS_INVALID_SET_FILE_POINTER) && - (GetLastError() != NO_ERROR) ) - { - BAIL_MACRO(errcodeFromWinApi(), -1); - } /* if */ - else - { - /* Combine the high/low order to create the 64-bit position value */ - retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow; - assert(retval >= 0); - } /* else */ - - return retval; -} /* __PHYSFS_platformFileLength */ - - -int __PHYSFS_platformFlush(void *opaque) -{ - WinApiFile *fh = ((WinApiFile *) opaque); - if (!fh->readonly) - BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), errcodeFromWinApi(), 0); - - return 1; -} /* __PHYSFS_platformFlush */ - - -void __PHYSFS_platformClose(void *opaque) -{ - HANDLE Handle = ((WinApiFile *) opaque)->handle; - (void) CloseHandle(Handle); /* ignore errors. You should have flushed! */ - allocator.Free(opaque); -} /* __PHYSFS_platformClose */ - - -static int doPlatformDelete(LPWSTR wpath) -{ - const int isdir = (GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY); - const BOOL rc = (isdir) ? RemoveDirectoryW(wpath) : DeleteFileW(wpath); - BAIL_IF_MACRO(!rc, errcodeFromWinApi(), 0); - return 1; /* if you made it here, it worked. */ -} /* doPlatformDelete */ - - -int __PHYSFS_platformDelete(const char *path) -{ - int retval = 0; - LPWSTR wpath = NULL; - UTF8_TO_UNICODE_STACK_MACRO(wpath, path); - BAIL_IF_MACRO(!wpath, PHYSFS_ERR_OUT_OF_MEMORY, 0); - retval = doPlatformDelete(wpath); - __PHYSFS_smallFree(wpath); - return retval; -} /* __PHYSFS_platformDelete */ - - -void *__PHYSFS_platformCreateMutex(void) -{ - LPCRITICAL_SECTION lpcs; - lpcs = (LPCRITICAL_SECTION) allocator.Malloc(sizeof (CRITICAL_SECTION)); - BAIL_IF_MACRO(!lpcs, PHYSFS_ERR_OUT_OF_MEMORY, NULL); - InitializeCriticalSection(lpcs); - return lpcs; -} /* __PHYSFS_platformCreateMutex */ - - -void __PHYSFS_platformDestroyMutex(void *mutex) -{ - DeleteCriticalSection((LPCRITICAL_SECTION) mutex); - allocator.Free(mutex); -} /* __PHYSFS_platformDestroyMutex */ - - -int __PHYSFS_platformGrabMutex(void *mutex) -{ - EnterCriticalSection((LPCRITICAL_SECTION) mutex); - return 1; -} /* __PHYSFS_platformGrabMutex */ - - -void __PHYSFS_platformReleaseMutex(void *mutex) -{ - LeaveCriticalSection((LPCRITICAL_SECTION) mutex); -} /* __PHYSFS_platformReleaseMutex */ - - -static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft) -{ - SYSTEMTIME st_utc; - SYSTEMTIME st_localtz; - TIME_ZONE_INFORMATION tzi; - DWORD tzid; - PHYSFS_sint64 retval; - struct tm tm; - BOOL rc; - - BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), errcodeFromWinApi(), -1); - tzid = GetTimeZoneInformation(&tzi); - BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, errcodeFromWinApi(), -1); - rc = SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz); - BAIL_IF_MACRO(!rc, errcodeFromWinApi(), -1); - - /* Convert to a format that mktime() can grok... */ - tm.tm_sec = st_localtz.wSecond; - tm.tm_min = st_localtz.wMinute; - tm.tm_hour = st_localtz.wHour; - tm.tm_mday = st_localtz.wDay; - tm.tm_mon = st_localtz.wMonth - 1; - tm.tm_year = st_localtz.wYear - 1900; - tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/; - tm.tm_yday = -1; - tm.tm_isdst = -1; - - /* Convert to a format PhysicsFS can grok... */ - retval = (PHYSFS_sint64) mktime(&tm); - BAIL_IF_MACRO(retval == -1, PHYSFS_ERR_OS_ERROR, -1); - return retval; -} /* FileTimeToPhysfsTime */ - -int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *stat) -{ - WIN32_FILE_ATTRIBUTE_DATA winstat; - WCHAR *wstr = NULL; - DWORD err = 0; - BOOL rc = 0; - - UTF8_TO_UNICODE_STACK_MACRO(wstr, filename); - BAIL_IF_MACRO(!wstr, PHYSFS_ERR_OUT_OF_MEMORY, 0); - rc = GetFileAttributesExW(wstr, GetFileExInfoStandard, &winstat); - err = (!rc) ? GetLastError() : 0; - *exists = ((err != ERROR_FILE_NOT_FOUND) && (err != ERROR_PATH_NOT_FOUND)); - __PHYSFS_smallFree(wstr); - BAIL_IF_MACRO(!rc, errcodeFromWinApiError(err), 0); - - stat->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime); - stat->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime); - stat->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime); - - if(winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - stat->filetype = PHYSFS_FILETYPE_DIRECTORY; - stat->filesize = 0; - } /* if */ - - else if(winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE)) - { - /* !!! FIXME: what are reparse points? */ - stat->filetype = PHYSFS_FILETYPE_OTHER; - /* !!! FIXME: don't rely on this */ - stat->filesize = 0; - } /* else if */ - - /* !!! FIXME: check for symlinks on Vista. */ - - else - { - stat->filetype = PHYSFS_FILETYPE_REGULAR; - stat->filesize = (((PHYSFS_uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow; - } /* else */ - - stat->readonly = ((winstat.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0); - - return 1; -} /* __PHYSFS_platformStat */ - - -/* !!! FIXME: Don't use C runtime for allocators? */ -int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a) -{ - return 0; /* just use malloc() and friends. */ -} /* __PHYSFS_platformSetDefaultAllocator */ - -#endif /* PHYSFS_PLATFORM_WINDOWS */ - -/* end of windows.c ... */ - -