22#include <winpr/config.h>
23#include <winpr/debug.h>
24#include <winpr/assert.h>
26#include <winpr/wtypes.h>
28#include <winpr/file.h>
37#define TAG WINPR_TAG("file")
39#include <winpr/wlog.h>
40#include <winpr/string.h>
43#include "../handle/handle.h"
53#include <sys/statvfs.h>
57#define MIN(x, y) (((x) < (y)) ? (x) : (y))
61static WINPR_FILE* pStdHandleFiles[3] = WINPR_C_ARRAY_INIT;
64WINPR_PRAGMA_DIAG(
"-Wglobal-constructors")
65static
void GetStdHandle_Uninit(
void) __attribute__((destructor));
68static BOOL FileIsStdHandle(HANDLE handle)
70 for (
size_t x = 0; x < ARRAYSIZE(pStdHandleFiles); x++)
72 if (handle == pStdHandleFiles[x])
78static BOOL FileIsHandled(HANDLE handle)
80 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_FILE, FALSE);
83static int FileGetFd(HANDLE handle)
85 WINPR_FILE* file = (WINPR_FILE*)handle;
87 if (!FileIsHandled(handle))
90 return fileno(file->fp);
93static BOOL FileCloseHandleInt(HANDLE handle, BOOL force)
95 WINPR_FILE* file = (WINPR_FILE*)handle;
97 if (!FileIsHandled(handle))
102 if (FileIsStdHandle(handle))
111 if (fileno(file->fp) > 2)
113 (void)fclose(file->fp);
118 free(file->lpFileName);
119 file->lpFileName =
nullptr;
123static BOOL FileCloseHandle(HANDLE handle)
125 return FileCloseHandleInt(handle, FALSE);
128#define log_error(fkt, file) log_error_((fkt), (file), __FILE__, __func__, __LINE__)
129static BOOL log_error_(
const char* name,
const WINPR_FILE* pFile,
const char* file,
const char* fkt,
132 char ebuffer[256] = WINPR_C_ARRAY_INIT;
139 const DWORD level = WLOG_ERROR;
140 static wLog* log =
nullptr;
144 if (WLog_IsLevelActive(log, level))
146 WLog_PrintTextMessage(log, level, line, file, fkt,
"%s %s failed with %s [0x%08x]", name,
147 pFile->lpFileName, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
148 WINPR_CXX_COMPAT_CAST(
unsigned, errno));
150 SetLastError(map_posix_err(errno));
154static BOOL FileSetEndOfFile(HANDLE hFile)
156 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
161 const INT64 size = _ftelli64(pFile->fp);
165 if (ftruncate(fileno(pFile->fp), (off_t)size) < 0)
166 return log_error(
"ftruncate", pFile);
172static DWORD FileSetFilePointer(HANDLE hFile, LONG lDistanceToMove,
173 const PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
176 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
181 return INVALID_SET_FILE_POINTER;
185 if (lpDistanceToMoveHigh)
187 offset = (INT64)(((UINT64)*lpDistanceToMoveHigh << 32U) | (UINT64)lDistanceToMove);
190 offset = lDistanceToMove;
192 switch (dwMoveMethod)
204 return INVALID_SET_FILE_POINTER;
207 if (_fseeki64(pFile->fp, offset, whence))
209 (void)log_error(
"_fseeki64", pFile);
210 return INVALID_SET_FILE_POINTER;
213 return (DWORD)_ftelli64(pFile->fp);
216static BOOL FileSetFilePointerEx(HANDLE hFile,
LARGE_INTEGER liDistanceToMove,
217 PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
219 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
225 switch (dwMoveMethod)
240 if (_fseeki64(pFile->fp, liDistanceToMove.QuadPart, whence))
241 return log_error(
"_fseeki64", pFile);
243 if (lpNewFilePointer)
244 lpNewFilePointer->QuadPart = _ftelli64(pFile->fp);
249static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
252 size_t io_status = 0;
253 WINPR_FILE* file =
nullptr;
258 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
259 SetLastError(ERROR_NOT_SUPPORTED);
266 file = (WINPR_FILE*)Object;
268 io_status = fread(lpBuffer, 1, nNumberOfBytesToRead, file->fp);
270 if (io_status == 0 && ferror(file->fp))
277 SetLastError(ERROR_NO_DATA);
280 SetLastError(map_posix_err(errno));
284 if (lpNumberOfBytesRead)
285 *lpNumberOfBytesRead = (DWORD)io_status;
290static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
291 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
293 size_t io_status = 0;
294 WINPR_FILE* file =
nullptr;
298 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
299 SetLastError(ERROR_NOT_SUPPORTED);
306 file = (WINPR_FILE*)Object;
309 io_status = fwrite(lpBuffer, 1, nNumberOfBytesToWrite, file->fp);
310 if (io_status == 0 && ferror(file->fp))
312 SetLastError(map_posix_err(errno));
316 *lpNumberOfBytesWritten = (DWORD)io_status;
320static DWORD FileGetFileSize(HANDLE Object, LPDWORD lpFileSizeHigh)
322 WINPR_FILE* file =
nullptr;
329 file = (WINPR_FILE*)Object;
331 cur = _ftelli64(file->fp);
335 (void)log_error(
"_ftelli64", file);
336 return INVALID_FILE_SIZE;
339 if (_fseeki64(file->fp, 0, SEEK_END) != 0)
341 (void)log_error(
"_fseeki64", file);
342 return INVALID_FILE_SIZE;
345 size = _ftelli64(file->fp);
349 (void)log_error(
"_ftelli64", file);
350 return INVALID_FILE_SIZE;
353 if (_fseeki64(file->fp, cur, SEEK_SET) != 0)
355 (void)log_error(
"_fseeki64", file);
356 return INVALID_FILE_SIZE;
360 *lpFileSizeHigh = (UINT32)(size >> 32);
362 return (UINT32)(size & 0xFFFFFFFF);
365static BOOL FileFlushFileBuffers(HANDLE hFile)
367 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
371 SetLastError(ERROR_INVALID_HANDLE);
376 if ((pFile->dwOpenMode & GENERIC_WRITE) == 0)
378 SetLastError(ERROR_ACCESS_DENIED);
382 if (fflush(pFile->fp) != 0)
384 SetLastError(map_posix_err(errno));
391static BOOL FileGetFileInformationByHandle(HANDLE hFile,
394 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
397 const char* lastSep =
nullptr;
401 if (!lpFileInformation)
404 if (fstat(fileno(pFile->fp), &st) == -1)
405 return log_error(
"fstat", pFile);
407 lpFileInformation->dwFileAttributes = 0;
409 if (S_ISDIR(st.st_mode))
410 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
412 if (lpFileInformation->dwFileAttributes == 0)
413 lpFileInformation->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
415 lastSep = strrchr(pFile->lpFileName,
'/');
419 const char* name = lastSep + 1;
420 const size_t namelen = strlen(name);
422 if ((namelen > 1) && (name[0] ==
'.') && (name[1] !=
'.'))
423 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
426 if (!(st.st_mode & S_IWUSR))
427 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
429#ifdef _DARWIN_FEATURE_64_BIT_INODE
430 ft = STAT_TIME_TO_FILETIME(st.st_birthtime);
432 ft = STAT_TIME_TO_FILETIME(st.st_ctime);
434 lpFileInformation->ftCreationTime.dwHighDateTime = (ft) >> 32ULL;
435 lpFileInformation->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
436 ft = STAT_TIME_TO_FILETIME(st.st_mtime);
437 lpFileInformation->ftLastWriteTime.dwHighDateTime = (ft) >> 32ULL;
438 lpFileInformation->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
439 ft = STAT_TIME_TO_FILETIME(st.st_atime);
440 lpFileInformation->ftLastAccessTime.dwHighDateTime = (ft) >> 32ULL;
441 lpFileInformation->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
442 lpFileInformation->nFileSizeHigh = ((UINT64)st.st_size) >> 32ULL;
443 lpFileInformation->nFileSizeLow = st.st_size & 0xFFFFFFFF;
444 lpFileInformation->dwVolumeSerialNumber = (UINT32)st.st_dev;
445 lpFileInformation->nNumberOfLinks = (UINT32)st.st_nlink;
446 lpFileInformation->nFileIndexHigh = (st.st_ino >> 4) & 0xFFFFFFFF;
447 lpFileInformation->nFileIndexLow = st.st_ino & 0xFFFFFFFF;
451static BOOL FileLockFileEx(HANDLE hFile, DWORD dwFlags, WINPR_ATTR_UNUSED DWORD dwReserved,
452 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockLow,
453 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockHigh,
462 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
466 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
467 SetLastError(ERROR_NOT_SUPPORTED);
476 WLog_ERR(TAG,
"File %s already locked!", pFile->lpFileName);
483 lock.l_whence = SEEK_SET;
485 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
486 lock.l_type = F_WRLCK;
488 lock.l_type = F_WRLCK;
490 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
495 if (fcntl(fileno(pFile->fp), lckcmd, &lock) == -1)
497 char ebuffer[256] = WINPR_C_ARRAY_INIT;
498 WLog_ERR(TAG,
"F_SETLK failed with %s [0x%08X]",
499 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
500 SetLastError(map_posix_err(errno));
504 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
509 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
512 if (flock(fileno(pFile->fp), lock) < 0)
513 return log_error(
"flock", pFile);
516 pFile->bLocked = TRUE;
521static BOOL FileUnlockFile(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwFileOffsetLow,
522 WINPR_ATTR_UNUSED DWORD dwFileOffsetHigh,
523 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
524 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh)
526 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
536 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
543 lock.l_whence = SEEK_SET;
544 lock.l_type = F_UNLCK;
545 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
546 return log_error(
"F_GETLK", pFile);
549 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
550 return log_error(
"flock", pFile);
556static BOOL FileUnlockFileEx(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwReserved,
557 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
558 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh,
561 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
568 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
569 SetLastError(ERROR_NOT_SUPPORTED);
578 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
585 lock.l_whence = SEEK_SET;
586 lock.l_type = F_UNLCK;
587 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
588 return log_error(
"F_GETLK", pFile);
590 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
591 return log_error(
"flock", pFile);
597static INT64 FileTimeToUS(
const FILETIME* ft)
599 const INT64 EPOCH_DIFF_US = EPOCH_DIFF * 1000000LL;
600 INT64 tmp = ((INT64)ft->dwHighDateTime) << 32 | ft->dwLowDateTime;
602 tmp -= EPOCH_DIFF_US;
606#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
607static struct timespec filetimeToTimespec(const
FILETIME* ftime)
610 INT64 tmp = FileTimeToUS(ftime);
611 struct timespec ts = WINPR_C_ARRAY_INIT;
612 ts.tv_sec = tmp / 1000000LL;
613 ts.tv_nsec = (tmp % 1000000LL) * 1000LL;
617static BOOL FileSetFileTime(HANDLE hFile, WINPR_ATTR_UNUSED
const FILETIME* lpCreationTime,
620 struct timespec times[2] = { { UTIME_OMIT, UTIME_OMIT },
621 { UTIME_OMIT, UTIME_OMIT } };
622 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
627 if (lpLastAccessTime)
628 times[0] = filetimeToTimespec(lpLastAccessTime);
631 times[1] = filetimeToTimespec(lpLastWriteTime);
634 const int rc = futimens(fileno(pFile->fp), times);
637 char ebuffer[256] = WINPR_C_ARRAY_INIT;
638 WLog_ERR(TAG,
"futimens failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
640 SetLastError(map_posix_err(errno));
646#elif defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) || defined(KFREEBSD)
647static struct timeval filetimeToTimeval(const
FILETIME* ftime)
650 UINT64 tmp = FileTimeToUS(ftime);
651 struct timeval tv = WINPR_C_ARRAY_INIT;
652 tv.tv_sec = tmp / 1000000ULL;
653 tv.tv_usec = tmp % 1000000ULL;
657static struct timeval statToTimeval(const struct stat* sval, BOOL modification)
660 struct timeval tv = WINPR_C_ARRAY_INIT;
661#if defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
663 TIMESPEC_TO_TIMEVAL(&tv, modification ? &sval->st_mtim : &sval->st_atim);
665 TIMESPEC_TO_TIMEVAL(&tv, modification ? &sval->st_mtimespec : &sval->st_atimespec);
667#elif defined(ANDROID)
668 tv.tv_sec = modification ? sval->st_mtime : sval->st_atime;
669 tv.tv_usec = (modification ? sval->st_mtimensec : sval->st_atimensec) / 1000UL;
674static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
677 struct stat buf = WINPR_C_ARRAY_INIT;
679 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
684 const int rc = fstat(fileno(pFile->fp), &buf);
687 char ebuffer[256] = WINPR_C_ARRAY_INIT;
688 WLog_ERR(TAG,
"fstat failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
690 SetLastError(map_posix_err(errno));
695 struct timeval timevals[2] = { statToTimeval(&buf, FALSE), statToTimeval(&buf, TRUE) };
696 if (lpLastAccessTime)
697 timevals[0] = filetimeToTimeval(lpLastAccessTime);
700 timevals[1] = filetimeToTimeval(lpLastWriteTime);
704 const int res = utimes(pFile->lpFileName, timevals);
707 char ebuffer[256] = WINPR_C_ARRAY_INIT;
708 WLog_ERR(TAG,
"utimes failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
710 SetLastError(map_posix_err(errno));
718static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
721 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
726 WLog_WARN(TAG,
"TODO: Creation, Access and Write time can not be handled!");
728 "TODO: Define _POSIX_C_SOURCE >= 200809L or implement a platform specific handler!");
745 FileFlushFileBuffers,
748 FileSetFilePointerEx,
754 FileGetFileInformationByHandle,
778 FileGetFileInformationByHandle,
781static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDisposition, BOOL* create)
783 BOOL writeable = (dwDesiredAccess & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
785 switch (dwCreationDisposition)
789 return (writeable) ?
"wb+" :
"rwb";
798 return (writeable) ?
"rb+" :
"rb";
799 case TRUNCATE_EXISTING:
808UINT32 map_posix_err(
int fs_errno)
824 rc = ERROR_FILE_NOT_FOUND;
830 rc = ERROR_ACCESS_DENIED;
834 rc = ERROR_FILE_NOT_FOUND;
838 rc = ERROR_BUSY_DRIVE;
842 rc = ERROR_FILE_EXISTS;
846 rc = STATUS_FILE_IS_A_DIRECTORY;
850 rc = STATUS_DIRECTORY_NOT_EMPTY;
854 rc = STATUS_TOO_MANY_OPENED_FILES;
859 char ebuffer[256] = WINPR_C_ARRAY_INIT;
860 WLog_ERR(TAG,
"Missing ERRNO mapping %s [%d]",
861 winpr_strerror(fs_errno, ebuffer,
sizeof(ebuffer)), fs_errno);
862 rc = STATUS_UNSUCCESSFUL;
870static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
871 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
872 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
873 HANDLE hTemplateFile)
875 WINPR_FILE* pFile =
nullptr;
877 const char* mode = FileGetMode(dwDesiredAccess, dwCreationDisposition, &create);
886 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
888 WLog_ERR(TAG,
"WinPR does not support the FILE_FLAG_OVERLAPPED flag");
889 SetLastError(ERROR_NOT_SUPPORTED);
890 return INVALID_HANDLE_VALUE;
893 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
896 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
897 return INVALID_HANDLE_VALUE;
900 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
901 pFile->common.ops = &fileOps;
903 pFile->lpFileName = _strdup(lpFileName);
904 if (!pFile->lpFileName)
906 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
908 return INVALID_HANDLE_VALUE;
911 pFile->dwOpenMode = dwDesiredAccess;
912 pFile->dwShareMode = dwShareMode;
913 pFile->dwFlagsAndAttributes = dwFlagsAndAttributes;
914 pFile->lpSecurityAttributes = lpSecurityAttributes;
915 pFile->dwCreationDisposition = dwCreationDisposition;
916 pFile->hTemplateFile = hTemplateFile;
920 if (dwCreationDisposition == CREATE_NEW)
922 if (stat(pFile->lpFileName, &st) == 0)
924 SetLastError(ERROR_FILE_EXISTS);
925 free(pFile->lpFileName);
927 return INVALID_HANDLE_VALUE;
931 fp = winpr_fopen(pFile->lpFileName,
"ab");
934 SetLastError(map_posix_err(errno));
935 free(pFile->lpFileName);
937 return INVALID_HANDLE_VALUE;
940 fp = freopen(pFile->lpFileName, mode, fp);
944 if (stat(pFile->lpFileName, &st) != 0)
946 SetLastError(map_posix_err(errno));
947 free(pFile->lpFileName);
949 return INVALID_HANDLE_VALUE;
955 if (S_ISFIFO(st.st_mode))
957 SetLastError(ERROR_FILE_NOT_FOUND);
958 free(pFile->lpFileName);
960 return INVALID_HANDLE_VALUE;
965 fp = winpr_fopen(pFile->lpFileName, mode);
972 SetLastError(map_posix_err(errno));
973 free(pFile->lpFileName);
975 return INVALID_HANDLE_VALUE;
982 pFile->lpSecurityAttributes && pFile->lpSecurityAttributes->bInheritHandle;
983 if (!winpr_set_cloexec(fileno(fp), !inherit))
985 SetLastError(map_posix_err(errno));
986 FileCloseHandle(pFile);
988 return INVALID_HANDLE_VALUE;
992 (void)setvbuf(fp,
nullptr, _IONBF, 0);
997 lock.l_whence = SEEK_SET;
999 if (dwShareMode & FILE_SHARE_READ)
1000 lock.l_type = F_RDLCK;
1001 if (dwShareMode & FILE_SHARE_WRITE)
1002 lock.l_type = F_RDLCK;
1004 if (dwShareMode & FILE_SHARE_READ)
1006 if (dwShareMode & FILE_SHARE_WRITE)
1010 if (dwShareMode & (FILE_SHARE_READ | FILE_SHARE_WRITE))
1013 if (fcntl(fileno(pFile->fp), F_SETLKW, &lock) == -1)
1015 if (flock(fileno(pFile->fp), lock) < 0)
1019 (void)log_error(
"F_SETLKW", pFile);
1021 (void)log_error(
"flock", pFile);
1024 SetLastError(map_posix_err(errno));
1025 FileCloseHandle(pFile);
1027 return INVALID_HANDLE_VALUE;
1030 pFile->bLocked = TRUE;
1033 if (fstat(fileno(pFile->fp), &st) == 0 && dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1035 st.st_mode &= WINPR_ASSERTING_INT_CAST(mode_t, (mode_t)(~(S_IWUSR | S_IWGRP | S_IWOTH)));
1036 if (fchmod(fileno(pFile->fp), st.st_mode) != 0)
1038 SetLastError(map_posix_err(errno));
1039 FileCloseHandle(pFile);
1041 return INVALID_HANDLE_VALUE;
1045 SetLastError(STATUS_SUCCESS);
1049static BOOL IsFileDevice(WINPR_ATTR_UNUSED LPCTSTR lpDeviceName)
1054static const HANDLE_CREATOR FileHandleCreator = { IsFileDevice, FileCreateFileA };
1058 return &FileHandleCreator;
1061static WINPR_FILE* FileHandle_New(FILE* fp)
1063 WINPR_FILE* pFile =
nullptr;
1064 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
1066 (void)_snprintf(name,
sizeof(name),
"device_%d", fileno(fp));
1067 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
1070 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1074 pFile->common.ops = &shmOps;
1075 pFile->lpFileName = _strdup(name);
1077 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
1081void GetStdHandle_Uninit(
void)
1083 for (
size_t x = 0; x < ARRAYSIZE(pStdHandleFiles); x++)
1085 (void)FileCloseHandleInt(pStdHandleFiles[x], TRUE);
1086 free(pStdHandleFiles[x]);
1087 pStdHandleFiles[x] =
nullptr;
1091HANDLE GetStdHandle(DWORD nStdHandle)
1098 case STD_INPUT_HANDLE:
1102 case STD_OUTPUT_HANDLE:
1106 case STD_ERROR_HANDLE:
1111 return INVALID_HANDLE_VALUE;
1114 if (!pStdHandleFiles[idx])
1115 pStdHandleFiles[idx] = FileHandle_New(fp);
1117 if (!pStdHandleFiles[idx])
1118 return INVALID_HANDLE_VALUE;
1120 return (HANDLE)pStdHandleFiles[idx];
1123BOOL SetStdHandle(WINPR_ATTR_UNUSED DWORD nStdHandle, WINPR_ATTR_UNUSED HANDLE hHandle)
1128BOOL SetStdHandleEx(WINPR_ATTR_UNUSED DWORD dwStdHandle, WINPR_ATTR_UNUSED HANDLE hNewHandle,
1129 WINPR_ATTR_UNUSED HANDLE* phOldHandle)
1134BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1135 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1138#define STATVFS statfs
1140#define STATVFS statvfs
1143 struct STATVFS svfst = WINPR_C_ARRAY_INIT;
1144 STATVFS(lpRootPathName, &svfst);
1145 *lpSectorsPerCluster = (UINT32)MIN(svfst.f_frsize, UINT32_MAX);
1146 *lpBytesPerSector = 1;
1147 *lpNumberOfFreeClusters = (UINT32)MIN(svfst.f_bavail, UINT32_MAX);
1148 *lpTotalNumberOfClusters = (UINT32)MIN(svfst.f_blocks, UINT32_MAX);
1152BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1153 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1154 LPDWORD lpTotalNumberOfClusters)
1157 if (!lpRootPathName)
1160 char* rootPathName = ConvertWCharToUtf8Alloc(lpRootPathName,
nullptr);
1163 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1166 ret = GetDiskFreeSpaceA(rootPathName, lpSectorsPerCluster, lpBytesPerSector,
1167 lpNumberOfFreeClusters, lpTotalNumberOfClusters);
1180BOOL ValidFileNameComponent(LPCWSTR lpFileName)
1186 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1187 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1188 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1189 (lpFileName[3] == L
'\0'))
1195 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'P' || lpFileName[0] == L
'p')) &&
1196 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'R' || lpFileName[1] == L
'r')) &&
1197 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1198 (lpFileName[3] == L
'\0'))
1204 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'A' || lpFileName[0] == L
'a')) &&
1205 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1206 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'X' || lpFileName[2] == L
'x')) &&
1207 (lpFileName[3] == L
'\0'))
1213 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'N' || lpFileName[0] == L
'n')) &&
1214 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1215 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'L' || lpFileName[2] == L
'l')) &&
1216 (lpFileName[3] == L
'\0'))
1222 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'L' || lpFileName[0] == L
'l')) &&
1223 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'P' || lpFileName[1] == L
'p')) &&
1224 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'T' || lpFileName[2] == L
't')) &&
1225 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1226 (lpFileName[4] == L
'\0'))
1232 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1233 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1234 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'M' || lpFileName[2] == L
'm')) &&
1235 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1236 (lpFileName[4] == L
'\0'))
1242 for (LPCWSTR c = lpFileName; *c; c++)
1244 if ((*c == L
'<') || (*c == L
'>') || (*c == L
':') || (*c == L
'"') || (*c == L
'/') ||
1245 (*c == L
'\\') || (*c == L
'|') || (*c == L
'?') || (*c == L
'*'))
1256HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1257 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1258 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1261 CREATEFILE2_EXTENDED_PARAMETERS params = WINPR_C_ARRAY_INIT;
1263 params.dwSize =
sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
1265 if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
1266 params.dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
1267 if (dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
1268 params.dwFileFlags |= FILE_FLAG_DELETE_ON_CLOSE;
1269 if (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
1270 params.dwFileFlags |= FILE_FLAG_NO_BUFFERING;
1271 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
1272 params.dwFileFlags |= FILE_FLAG_OPEN_NO_RECALL;
1273 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
1274 params.dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
1275 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REQUIRING_OPLOCK)
1276 params.dwFileFlags |= FILE_FLAG_OPEN_REQUIRING_OPLOCK;
1277 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
1278 params.dwFileFlags |= FILE_FLAG_OVERLAPPED;
1279 if (dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS)
1280 params.dwFileFlags |= FILE_FLAG_POSIX_SEMANTICS;
1281 if (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
1282 params.dwFileFlags |= FILE_FLAG_RANDOM_ACCESS;
1283 if (dwFlagsAndAttributes & FILE_FLAG_SESSION_AWARE)
1284 params.dwFileFlags |= FILE_FLAG_SESSION_AWARE;
1285 if (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
1286 params.dwFileFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
1287 if (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
1288 params.dwFileFlags |= FILE_FLAG_WRITE_THROUGH;
1290 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ARCHIVE)
1291 params.dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1292 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_COMPRESSED)
1293 params.dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
1294 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DEVICE)
1295 params.dwFileAttributes |= FILE_ATTRIBUTE_DEVICE;
1296 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY)
1297 params.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1298 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ENCRYPTED)
1299 params.dwFileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
1300 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_HIDDEN)
1301 params.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1302 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM)
1303 params.dwFileAttributes |= FILE_ATTRIBUTE_INTEGRITY_STREAM;
1304 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NORMAL)
1305 params.dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
1306 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
1307 params.dwFileAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1308 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA)
1309 params.dwFileAttributes |= FILE_ATTRIBUTE_NO_SCRUB_DATA;
1310 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_OFFLINE)
1311 params.dwFileAttributes |= FILE_ATTRIBUTE_OFFLINE;
1312 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1313 params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1314 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1315 params.dwFileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
1316 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SPARSE_FILE)
1317 params.dwFileAttributes |= FILE_ATTRIBUTE_SPARSE_FILE;
1318 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SYSTEM)
1319 params.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
1320 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY)
1321 params.dwFileAttributes |= FILE_ATTRIBUTE_TEMPORARY;
1322 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_VIRTUAL)
1323 params.dwFileAttributes |= FILE_ATTRIBUTE_VIRTUAL;
1325 if (dwFlagsAndAttributes & SECURITY_ANONYMOUS)
1326 params.dwSecurityQosFlags |= SECURITY_ANONYMOUS;
1327 if (dwFlagsAndAttributes & SECURITY_CONTEXT_TRACKING)
1328 params.dwSecurityQosFlags |= SECURITY_CONTEXT_TRACKING;
1329 if (dwFlagsAndAttributes & SECURITY_DELEGATION)
1330 params.dwSecurityQosFlags |= SECURITY_DELEGATION;
1331 if (dwFlagsAndAttributes & SECURITY_EFFECTIVE_ONLY)
1332 params.dwSecurityQosFlags |= SECURITY_EFFECTIVE_ONLY;
1333 if (dwFlagsAndAttributes & SECURITY_IDENTIFICATION)
1334 params.dwSecurityQosFlags |= SECURITY_IDENTIFICATION;
1335 if (dwFlagsAndAttributes & SECURITY_IMPERSONATION)
1336 params.dwSecurityQosFlags |= SECURITY_IMPERSONATION;
1338 params.lpSecurityAttributes = lpSecurityAttributes;
1339 params.hTemplateFile = hTemplateFile;
1341 hFile = CreateFile2(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, ¶ms);
1346HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1347 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1348 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1354 WCHAR* lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
1359 hFile = CreateFileW(lpFileNameW, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1360 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1367DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
1372 if (!lpFileSizeHigh)
1373 return INVALID_FILE_SIZE;
1375 status = GetFileSizeEx(hFile, &fileSize);
1378 return INVALID_FILE_SIZE;
1380 *lpFileSizeHigh = fileSize.HighPart;
1382 return fileSize.LowPart;
1385DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
1392 liDistanceToMove.LowPart = lDistanceToMove;
1394 status = SetFilePointerEx(hFile, liDistanceToMove, &liNewFilePointer, dwMoveMethod);
1397 return INVALID_SET_FILE_POINTER;
1399 if (lpDistanceToMoveHigh)
1400 *lpDistanceToMoveHigh = liNewFilePointer.HighPart;
1402 return liNewFilePointer.LowPart;
1407 return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1413 return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1417DWORD GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart)
1420 WCHAR* lpFileNameW =
nullptr;
1421 WCHAR* lpBufferW =
nullptr;
1422 WCHAR* lpFilePartW =
nullptr;
1423 DWORD nBufferLengthW = nBufferLength *
sizeof(WCHAR);
1425 if (!lpFileName || (nBufferLength < 1))
1428 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
1432 lpBufferW = (WCHAR*)malloc(nBufferLengthW);
1437 dwStatus = GetFullPathNameW(lpFileNameW, nBufferLengthW, lpBufferW, &lpFilePartW);
1439 (void)ConvertWCharNToUtf8(lpBufferW, nBufferLengthW /
sizeof(WCHAR), lpBuffer, nBufferLength);
1442 lpFilePart = lpBuffer + (lpFilePartW - lpBufferW);
1447 return WINPR_ASSERTING_INT_CAST(DWORD, dwStatus *
sizeof(WCHAR));
1450BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1451 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1458 status = GetDiskFreeSpaceExA(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1459 &TotalNumberOfFreeBytes);
1464 *lpBytesPerSector = 1;
1465 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1466 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1467 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1472BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1473 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1474 LPDWORD lpTotalNumberOfClusters)
1481 status = GetDiskFreeSpaceExW(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1482 &TotalNumberOfFreeBytes);
1487 *lpBytesPerSector = 1;
1488 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1489 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1490 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1495DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1497 SetLastError(ERROR_INVALID_FUNCTION);
1501DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1503 SetLastError(ERROR_INVALID_FUNCTION);
1507BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
1525HANDLE GetFileHandleForFileDescriptor(
int fd)
1528 return (HANDLE)_get_osfhandle(fd);
1530 WINPR_FILE* pFile =
nullptr;
1535 if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
1536 return INVALID_HANDLE_VALUE;
1538 flags = fcntl(fd, F_GETFL);
1540 return INVALID_HANDLE_VALUE;
1542 if (flags & O_WRONLY)
1543 fp = fdopen(fd,
"wb");
1545 fp = fdopen(fd,
"rb");
1548 return INVALID_HANDLE_VALUE;
1550 (void)setvbuf(fp,
nullptr, _IONBF, 0);
1553 pFile = FileHandle_New(fp);
1555 return INVALID_HANDLE_VALUE;
1557 return (HANDLE)pFile;
1561FILE* winpr_fopen(
const char* path,
const char* mode)
1564 return fopen(path, mode);
1566 LPWSTR lpPathW =
nullptr;
1567 LPWSTR lpModeW =
nullptr;
1568 FILE* result =
nullptr;
1573 lpPathW = ConvertUtf8ToWCharAlloc(path,
nullptr);
1577 lpModeW = ConvertUtf8ToWCharAlloc(mode,
nullptr);
1581 result = _wfopen(lpPathW, lpModeW);
1590#if !defined(_UWP) && !defined(_WIN32)
1591DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1593 char* buffer =
nullptr;
1594 if (nBufferLength > 0)
1596 buffer = calloc(nBufferLength,
sizeof(
char));
1601 const DWORD rc = GetLogicalDriveStringsA(nBufferLength, buffer);
1603 ConvertMszUtf8NToWChar(buffer, rc, lpBuffer, nBufferLength);
1608DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1614 const char path[] =
"/\0";
1615 const size_t len =
sizeof(path);
1616 if (nBufferLength < len)
1617 return WINPR_ASSERTING_INT_CAST(DWORD, len);
1619 memcpy(lpBuffer, path, len);