PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname) { PHYSFS_sint64 retval = -1; WIN32_FILE_ATTRIBUTE_DATA attr; int rc = 0; memset(&attr, '\0', sizeof(attr)); /* GetFileAttributesEx didn't show up until Win98 and NT4. */ if ((pGetFileAttributesExW != NULL) || (pGetFileAttributesExA != NULL)) { WCHAR *wstr; UTF8_TO_UNICODE_STACK_MACRO(wstr, fname); if (wstr != NULL) /* if NULL, maybe the fallback will work. */ { if (pGetFileAttributesExW != NULL) /* NT/XP/Vista/etc system. */ rc = pGetFileAttributesExW(wstr, GetFileExInfoStandard, &attr); else /* Win98/ME system */ { const int len = (int)(wStrLen(wstr) + 1); char *cp = (char *)__PHYSFS_smallAlloc(len); if (cp != NULL) { WideCharToMultiByte(CP_ACP, 0, wstr, len, cp, len, 0, 0); rc = pGetFileAttributesExA(cp, GetFileExInfoStandard, &attr); __PHYSFS_smallFree(cp); } /* if */ } /* else */ __PHYSFS_smallFree(wstr); } /* if */ } /* if */ if (rc) /* had API entry point and it worked. */ { /* 0 return value indicates an error or not supported */ if ((attr.ftLastWriteTime.dwHighDateTime != 0) || (attr.ftLastWriteTime.dwLowDateTime != 0)) { retval = FileTimeToPhysfsTime(&attr.ftLastWriteTime); } /* if */ } /* if */ /* GetFileTime() has been in the Win32 API since the start. */ if (retval == -1) /* try a fallback... */ { FILETIME ft; BOOL rc; const char *err; WinApiFile *f = (WinApiFile *)__PHYSFS_platformOpenRead(fname); BAIL_IF_MACRO(f == NULL, NULL, -1) rc = GetFileTime(f->handle, NULL, NULL, &ft); err = winApiStrError(); CloseHandle(f->handle); allocator.Free(f); BAIL_IF_MACRO(!rc, err, -1); retval = FileTimeToPhysfsTime(&ft); } /* if */ return(retval); } /* __PHYSFS_platformGetLastModTime */
static BOOL WINAPI fallbackDeleteFileW(LPCWSTR fname) { BOOL retval = 0; const int buflen = (int)(wStrLen(fname) + 1); char *cpstr = (char *)__PHYSFS_smallAlloc(buflen); WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL); retval = DeleteFileA(cpstr); __PHYSFS_smallFree(cpstr); return(retval); } /* fallbackDeleteFileW */
static BOOL WINAPI fallbackGetUserNameW(LPWSTR buf, LPDWORD len) { const DWORD cplen = *len; char *cpstr = __PHYSFS_smallAlloc(cplen); BOOL retval = GetUserNameA(cpstr, len); if (buf != NULL) MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpstr, cplen, buf, *len); __PHYSFS_smallFree(cpstr); return(retval); } /* fallbackGetUserNameW */
static BOOL WINAPI fallbackRemoveDirectoryW(LPCWSTR dname) { BOOL retval = 0; const int buflen = (int)(wStrLen(dname) + 1); char *cpstr = (char *)__PHYSFS_smallAlloc(buflen); WideCharToMultiByte(CP_ACP, 0, dname, buflen, cpstr, buflen, NULL, NULL); retval = RemoveDirectoryA(cpstr); __PHYSFS_smallFree(cpstr); return(retval); } /* fallbackRemoveDirectoryW */
static DWORD WINAPI fallbackGetFileAttributesW(LPCWSTR fname) { DWORD retval = 0; const int buflen = (int) (wStrLen(fname) + 1); char *cpstr = (char *) __PHYSFS_smallAlloc(buflen); WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL); retval = GetFileAttributesA(cpstr); __PHYSFS_smallFree(cpstr); return(retval); } /* fallbackGetFileAttributesW */
static DWORD WINAPI fallbackGetModuleFileNameW(HMODULE hMod, LPWCH lpBuf, DWORD nSize) { char *cpbuf = (char *)__PHYSFS_smallAlloc(nSize); DWORD retval = GetModuleFileNameA(hMod, cpbuf, nSize); if (retval > 0) MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpbuf, retval, lpBuf, nSize); __PHYSFS_smallFree(cpbuf); return(retval); } /* fallbackGetModuleFileNameW */
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 */
/* * Try to make use of GetUserProfileDirectoryW(), which isn't available on * some common variants of Win32. If we can't use this, we just punt and * use the physfs base dir for the user dir, too. * * On success, module-scope variable (userDir) will have a pointer to * a malloc()'d string of the user's profile dir, and a non-zero value is * returned. If we can't determine the profile dir, (userDir) will * be NULL, and zero is returned. */ static int determineUserDir(void) { if (userDir != NULL) return(1); /* already good to go. */ /* * GetUserProfileDirectoryW() is only available on NT 4.0 and later. * This means Win95/98/ME (and CE?) users have to do without, so for * them, we'll default to the base directory when we can't get the * function pointer. Since this is originally an NT API, we don't * offer a non-Unicode fallback. */ if (pGetUserProfileDirectoryW != NULL) { HANDLE accessToken = NULL; /* Security handle to process */ HANDLE processHandle = GetCurrentProcess(); if (OpenProcessToken(processHandle, TOKEN_QUERY, &accessToken)) { 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 = pGetUserProfileDirectoryW(accessToken, &dummy, &psize); assert(!rc); /* !!! FIXME: handle this gracefully. */ (void)rc; /* Allocate memory for the profile directory */ wstr = (LPWSTR) __PHYSFS_smallAlloc(psize * sizeof (WCHAR)); if (wstr != NULL) { if (pGetUserProfileDirectoryW(accessToken, wstr, &psize)) userDir = unicodeToUtf8Heap(wstr); __PHYSFS_smallFree(wstr); } /* else */ } /* if */ CloseHandle(accessToken); } /* if */ if (userDir == NULL) /* couldn't get profile for some reason. */ { /* Might just be a non-NT system; resort to the basedir. */ userDir = getExePath(); BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* STILL failed?! */ } /* if */ return(1); /* We made it: hit the showers. */ } /* determineUserDir */
/* * Moved to seperate function so we can use alloca then immediately throw * away the allocated stack space... */ static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata, const char *odir, const char *str, PHYSFS_sint32 ln) { char *newstr = __PHYSFS_smallAlloc(ln + 1); if (newstr == NULL) return; memcpy(newstr, str, ln); newstr[ln] = '\0'; cb(callbackdata, odir, newstr); __PHYSFS_smallFree(newstr); } /* doEnumCallback */
static DWORD WINAPI fallbackFormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLangId, LPWSTR lpBuf, DWORD nSize, va_list *Arguments) { char *cpbuf = (char *)__PHYSFS_smallAlloc(nSize); DWORD retval = FormatMessageA(dwFlags, lpSource, dwMessageId, dwLangId, cpbuf, nSize, Arguments); if (retval > 0) MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpbuf, retval, lpBuf, nSize); __PHYSFS_smallFree(cpbuf); return(retval); } /* fallbackFormatMessageW */
static DWORD WINAPI fallbackGetCurrentDirectoryW(DWORD buflen, LPWSTR buf) { DWORD retval = 0; char *cpbuf = NULL; if (buf != NULL) cpbuf = (char *) __PHYSFS_smallAlloc(buflen); retval = GetCurrentDirectoryA(buflen, cpbuf); if (cpbuf != NULL) { MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,cpbuf,retval,buf,buflen); __PHYSFS_smallFree(cpbuf); } /* if */ return(retval); } /* fallbackGetCurrentDirectoryW */
static HANDLE WINAPI fallbackCreateFileW(LPCWSTR fname, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttrs, DWORD dwCreationDisposition, DWORD dwFlagsAndAttrs, HANDLE hTemplFile) { HANDLE retval; const int buflen = (int)(wStrLen(fname) + 1); char *cpstr = (char *)__PHYSFS_smallAlloc(buflen); WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL); //retval = CreateFileA(cpstr, dwDesiredAccess, dwShareMode, lpSecurityAttrs, dwCreationDisposition, dwFlagsAndAttrs, hTemplFile); retval = CreateFile2(fname, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); __PHYSFS_smallFree(cpstr); return(retval); } /* fallbackCreateFileW */
static char *codepageToUtf8Heap(const char *cpstr) { char *retval = NULL; if (cpstr != NULL) { const int len = (int)(strlen(cpstr) + 1); WCHAR *wbuf = (WCHAR *)__PHYSFS_smallAlloc(len * sizeof(WCHAR)); BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpstr, len, wbuf, len); retval = (char *)allocator.Malloc(len * 4); if (retval == NULL) __PHYSFS_setError(ERR_OUT_OF_MEMORY); else PHYSFS_utf8FromUcs2((const PHYSFS_uint16*)wbuf, retval, len * 4); __PHYSFS_smallFree(wbuf); } /* if */ return(retval); } /* codepageToUtf8Heap */
char *__PHYSFS_platformGetUserName(void) { DWORD bufsize = 0; char *retval = NULL; if (pGetUserNameW(NULL, &bufsize) == 0) /* This SHOULD fail. */ { LPWSTR wbuf = (LPWSTR)__PHYSFS_smallAlloc(bufsize * sizeof(WCHAR)); BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL); if (pGetUserNameW(wbuf, &bufsize) == 0) /* ?! */ __PHYSFS_setError(winApiStrError()); else retval = unicodeToUtf8Heap(wbuf); __PHYSFS_smallFree(wbuf); } /* if */ return(retval); } /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformCurrentDir(void) { char *retval = NULL; WCHAR *wbuf = NULL; DWORD buflen = 0; buflen = pGetCurrentDirectoryW(buflen, NULL); wbuf = (WCHAR *) __PHYSFS_smallAlloc((buflen + 2) * sizeof (WCHAR)); BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL); pGetCurrentDirectoryW(buflen, wbuf); if (wbuf[buflen - 2] == '\\') wbuf[buflen-1] = '\0'; /* just in case... */ else { wbuf[buflen - 1] = '\\'; wbuf[buflen] = '\0'; } /* else */ retval = unicodeToUtf8Heap(wbuf); __PHYSFS_smallFree(wbuf); return(retval); } /* __PHYSFS_platformCurrentDir */
void __PHYSFS_platformEnumerateFiles(const char *dirname, 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); dir = FindFirstFileExW(wSearchPath, FindExInfoStandard, &entw, FindExSearchNameMatch, NULL, 0); __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; utf8 = unicodeToUtf8Heap(fn); if (utf8 != NULL) { callback(callbackdata, origdir, utf8); allocator.Free(utf8); } /* if */ } while (FindNextFileW(dir, &entw) != 0); FindClose(dir); } /* __PHYSFS_platformEnumerateFiles */
char *__PHYSFS_platformCalcBaseDir(const char *argv0) { char *retval = NULL; const char *envr = NULL; /* Try to avoid using argv0 unless forced to. Try system-specific stuff. */ #if PHYSFS_PLATFORM_FREEBSD { char fullpath[PATH_MAX]; size_t buflen = sizeof (fullpath); int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1) retval = __PHYSFS_strdup(fullpath); } #elif PHYSFS_PLATFORM_SOLARIS { const char *path = getexecname(); if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */ retval = __PHYSFS_strdup(path); } #endif if (retval) return retval; /* already got it. */ /* If there's a Linux-like /proc filesystem, you can get the full path to * the current process from a symlink in there. */ if (access("/proc", F_OK) == 0) { retval = readSymLink("/proc/self/exe"); if (!retval) retval = readSymLink("/proc/curproc/file"); if (!retval) retval = readSymLink("/proc/curproc/exe"); if (retval == NULL) { /* older kernels don't have /proc/self ... try PID version... */ const unsigned long long pid = (unsigned long long) getpid(); char path[64]; const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid); if ( (rc > 0) && (rc < sizeof(path)) ) retval = readSymLink(path); } /* if */ } /* if */ if (retval != NULL) /* chop off filename. */ { char *ptr = strrchr(retval, '/'); if (ptr != NULL) *(ptr+1) = '\0'; else /* shouldn't happen, but just in case... */ { physfs_alloc.Free(retval); retval = NULL; } /* else */ } /* if */ /* No /proc/self/exe, etc, but we have an argv[0] we can parse? */ if ((retval == NULL) && (argv0 != NULL)) { /* fast path: default behaviour can handle this. */ if (strchr(argv0, '/') != NULL) return NULL; /* higher level parses out real path from argv0. */ /* If there's no dirsep on argv0, then look through $PATH for it. */ envr = getenv("PATH"); if (envr != NULL) { char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1); BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL); strcpy(path, envr); retval = findBinaryInPath(argv0, path); __PHYSFS_smallFree(path); } /* if */ } /* if */ if (retval != NULL) { /* try to shrink buffer... */ char *ptr = (char *) physfs_alloc.Realloc(retval, strlen(retval) + 1); if (ptr != NULL) retval = ptr; /* oh well if it failed. */ } /* if */ return retval; } /* __PHYSFS_platformCalcBaseDir */
void __PHYSFS_platformEnumerateFiles(const char *dirname, int omitSymLinks, PHYSFS_EnumFilesCallback callback, const char *origdir, void *callbackdata) { const int unicode = (pFindFirstFileW != NULL) && (pFindNextFileW != NULL); HANDLE dir = INVALID_HANDLE_VALUE; WIN32_FIND_DATA ent; WIN32_FIND_DATAW entw; size_t len = strlen(dirname); char *searchPath = NULL; WCHAR *wSearchPath = NULL; char *utf8 = 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 == NULL) return; /* oh well. */ if (unicode) dir = pFindFirstFileW(wSearchPath, &entw); else { const int len = (int)(wStrLen(wSearchPath) + 1); char *cp = (char *)__PHYSFS_smallAlloc(len); if (cp != NULL) { WideCharToMultiByte(CP_ACP, 0, wSearchPath, len, cp, len, 0, 0); //dir = FindFirstFileA(cp, &ent); dir = FindFirstFileExA(cp, FindExInfoStandard, &ent, FindExSearchNameMatch, NULL, 0); __PHYSFS_smallFree(cp); } /* if */ } /* else */ __PHYSFS_smallFree(wSearchPath); __PHYSFS_smallFree(searchPath); if (dir == INVALID_HANDLE_VALUE) return; if (unicode) { do { const DWORD attr = entw.dwFileAttributes; const DWORD tag = entw.dwReserved0; const WCHAR *fn = entw.cFileName; 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 (pFindNextFileW(dir, &entw) != 0); } /* if */ else /* ANSI fallback. */ { do { const DWORD attr = ent.dwFileAttributes; const DWORD tag = ent.dwReserved0; const char *fn = ent.cFileName; if ((fn[0] == '.') && (fn[1] == '\0')) continue; if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0')) continue; if ((omitSymLinks) && (isSymlinkAttrs(attr, tag))) continue; utf8 = codepageToUtf8Heap(fn); if (utf8 != NULL) { callback(callbackdata, origdir, utf8); allocator.Free(utf8); } /* if */ } while (FindNextFileA(dir, &ent) != 0); } /* else */ FindClose(dir); } /* __PHYSFS_platformEnumerateFiles */