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>
52#include <sys/statvfs.h>
56#define MIN(x, y) (((x) < (y)) ? (x) : (y))
59static WINPR_FILE* pStdHandleFile = NULL;
61static void GetStdHandle_Uninit(
void) __attribute__((destructor));
63static BOOL FileIsHandled(HANDLE handle)
65 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_FILE, FALSE);
68static int FileGetFd(HANDLE handle)
70 WINPR_FILE* file = (WINPR_FILE*)handle;
72 if (!FileIsHandled(handle))
75 return fileno(file->fp);
78static BOOL FileCloseHandleInt(HANDLE handle, BOOL force)
80 WINPR_FILE* file = (WINPR_FILE*)handle;
82 if (!FileIsHandled(handle))
87 if (handle == pStdHandleFile)
96 if (fileno(file->fp) > 2)
98 (void)fclose(file->fp);
103 free(file->lpFileName);
108static BOOL FileCloseHandle(HANDLE handle)
110 return FileCloseHandleInt(handle, FALSE);
113static BOOL FileSetEndOfFile(HANDLE hFile)
115 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
120 const INT64 size = _ftelli64(pFile->fp);
124 if (ftruncate(fileno(pFile->fp), (off_t)size) < 0)
126 char ebuffer[256] = { 0 };
127 WLog_ERR(TAG,
"ftruncate %s failed with %s [0x%08X]", pFile->lpFileName,
128 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
129 SetLastError(map_posix_err(errno));
137static DWORD FileSetFilePointer(HANDLE hFile, LONG lDistanceToMove,
138 const PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
141 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
146 return INVALID_SET_FILE_POINTER;
150 if (lpDistanceToMoveHigh)
152 offset = (INT64)(((UINT64)*lpDistanceToMoveHigh << 32U) | (UINT64)lDistanceToMove);
155 offset = lDistanceToMove;
157 switch (dwMoveMethod)
169 return INVALID_SET_FILE_POINTER;
172 if (_fseeki64(pFile->fp, offset, whence))
174 char ebuffer[256] = { 0 };
175 WLog_ERR(TAG,
"_fseeki64(%s) failed with %s [0x%08X]", pFile->lpFileName,
176 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
177 SetLastError(map_posix_err(errno));
178 return INVALID_SET_FILE_POINTER;
181 return (DWORD)_ftelli64(pFile->fp);
184static BOOL FileSetFilePointerEx(HANDLE hFile,
LARGE_INTEGER liDistanceToMove,
185 PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
187 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
193 switch (dwMoveMethod)
208 if (_fseeki64(pFile->fp, liDistanceToMove.QuadPart, whence))
210 char ebuffer[256] = { 0 };
211 WLog_ERR(TAG,
"_fseeki64(%s) failed with %s [0x%08X]", pFile->lpFileName,
212 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
213 SetLastError(map_posix_err(errno));
217 if (lpNewFilePointer)
218 lpNewFilePointer->QuadPart = _ftelli64(pFile->fp);
223static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
226 size_t io_status = 0;
227 WINPR_FILE* file = NULL;
232 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
233 SetLastError(ERROR_NOT_SUPPORTED);
240 file = (WINPR_FILE*)Object;
242 io_status = fread(lpBuffer, 1, nNumberOfBytesToRead, file->fp);
244 if (io_status == 0 && ferror(file->fp))
251 SetLastError(ERROR_NO_DATA);
254 SetLastError(map_posix_err(errno));
258 if (lpNumberOfBytesRead)
259 *lpNumberOfBytesRead = (DWORD)io_status;
264static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
265 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
267 size_t io_status = 0;
268 WINPR_FILE* file = NULL;
272 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
273 SetLastError(ERROR_NOT_SUPPORTED);
280 file = (WINPR_FILE*)Object;
283 io_status = fwrite(lpBuffer, 1, nNumberOfBytesToWrite, file->fp);
284 if (io_status == 0 && ferror(file->fp))
286 SetLastError(map_posix_err(errno));
290 *lpNumberOfBytesWritten = (DWORD)io_status;
294static DWORD FileGetFileSize(HANDLE Object, LPDWORD lpFileSizeHigh)
296 WINPR_FILE* file = NULL;
303 file = (WINPR_FILE*)Object;
305 cur = _ftelli64(file->fp);
309 char ebuffer[256] = { 0 };
310 WLog_ERR(TAG,
"_ftelli64(%s) failed with %s [0x%08X]", file->lpFileName,
311 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
312 SetLastError(map_posix_err(errno));
313 return INVALID_FILE_SIZE;
316 if (_fseeki64(file->fp, 0, SEEK_END) != 0)
318 char ebuffer[256] = { 0 };
319 WLog_ERR(TAG,
"_fseeki64(%s) failed with %s [0x%08X]", file->lpFileName,
320 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
321 SetLastError(map_posix_err(errno));
322 return INVALID_FILE_SIZE;
325 size = _ftelli64(file->fp);
329 char ebuffer[256] = { 0 };
330 WLog_ERR(TAG,
"_ftelli64(%s) failed with %s [0x%08X]", file->lpFileName,
331 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
332 SetLastError(map_posix_err(errno));
333 return INVALID_FILE_SIZE;
336 if (_fseeki64(file->fp, cur, SEEK_SET) != 0)
338 char ebuffer[256] = { 0 };
339 WLog_ERR(TAG,
"_ftelli64(%s) failed with %s [0x%08X]", file->lpFileName,
340 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
341 SetLastError(map_posix_err(errno));
342 return INVALID_FILE_SIZE;
346 *lpFileSizeHigh = (UINT32)(size >> 32);
348 return (UINT32)(size & 0xFFFFFFFF);
351static BOOL FileFlushFileBuffers(HANDLE hFile)
353 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
357 SetLastError(ERROR_INVALID_HANDLE);
362 if ((pFile->dwOpenMode & GENERIC_WRITE) == 0)
364 SetLastError(ERROR_ACCESS_DENIED);
368 if (fflush(pFile->fp) != 0)
370 SetLastError(map_posix_err(errno));
377static BOOL FileGetFileInformationByHandle(HANDLE hFile,
380 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
383 const char* lastSep = NULL;
387 if (!lpFileInformation)
390 if (fstat(fileno(pFile->fp), &st) == -1)
392 char ebuffer[256] = { 0 };
393 WLog_ERR(TAG,
"fstat failed with %s [%#08X]", errno,
394 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
395 SetLastError(map_posix_err(errno));
399 lpFileInformation->dwFileAttributes = 0;
401 if (S_ISDIR(st.st_mode))
402 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
404 if (lpFileInformation->dwFileAttributes == 0)
405 lpFileInformation->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
407 lastSep = strrchr(pFile->lpFileName,
'/');
411 const char* name = lastSep + 1;
412 const size_t namelen = strlen(name);
414 if ((namelen > 1) && (name[0] ==
'.') && (name[1] !=
'.'))
415 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
418 if (!(st.st_mode & S_IWUSR))
419 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
421#ifdef _DARWIN_FEATURE_64_BIT_INODE
422 ft = STAT_TIME_TO_FILETIME(st.st_birthtime);
424 ft = STAT_TIME_TO_FILETIME(st.st_ctime);
426 lpFileInformation->ftCreationTime.dwHighDateTime = (ft) >> 32ULL;
427 lpFileInformation->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
428 ft = STAT_TIME_TO_FILETIME(st.st_mtime);
429 lpFileInformation->ftLastWriteTime.dwHighDateTime = (ft) >> 32ULL;
430 lpFileInformation->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
431 ft = STAT_TIME_TO_FILETIME(st.st_atime);
432 lpFileInformation->ftLastAccessTime.dwHighDateTime = (ft) >> 32ULL;
433 lpFileInformation->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
434 lpFileInformation->nFileSizeHigh = ((UINT64)st.st_size) >> 32ULL;
435 lpFileInformation->nFileSizeLow = st.st_size & 0xFFFFFFFF;
436 lpFileInformation->dwVolumeSerialNumber = (UINT32)st.st_dev;
437 lpFileInformation->nNumberOfLinks = (UINT32)st.st_nlink;
438 lpFileInformation->nFileIndexHigh = (st.st_ino >> 4) & 0xFFFFFFFF;
439 lpFileInformation->nFileIndexLow = st.st_ino & 0xFFFFFFFF;
443static BOOL FileLockFileEx(HANDLE hFile, DWORD dwFlags, WINPR_ATTR_UNUSED DWORD dwReserved,
444 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockLow,
445 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockHigh,
454 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
458 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
459 SetLastError(ERROR_NOT_SUPPORTED);
468 WLog_ERR(TAG,
"File %s already locked!", pFile->lpFileName);
475 lock.l_whence = SEEK_SET;
477 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
478 lock.l_type = F_WRLCK;
480 lock.l_type = F_WRLCK;
482 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
487 if (fcntl(fileno(pFile->fp), lckcmd, &lock) == -1)
489 char ebuffer[256] = { 0 };
490 WLog_ERR(TAG,
"F_SETLK failed with %s [0x%08X]",
491 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
492 SetLastError(map_posix_err(errno));
496 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
501 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
504 if (flock(fileno(pFile->fp), lock) < 0)
506 char ebuffer[256] = { 0 };
507 WLog_ERR(TAG,
"flock failed with %s [0x%08X]",
508 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
509 SetLastError(map_posix_err(errno));
514 pFile->bLocked = TRUE;
519static BOOL FileUnlockFile(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwFileOffsetLow,
520 WINPR_ATTR_UNUSED DWORD dwFileOffsetHigh,
521 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
522 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh)
524 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
534 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
541 lock.l_whence = SEEK_SET;
542 lock.l_type = F_UNLCK;
543 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
545 char ebuffer[256] = { 0 };
546 WLog_ERR(TAG,
"F_UNLCK on %s failed with %s [0x%08X]", pFile->lpFileName,
547 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
548 SetLastError(map_posix_err(errno));
553 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
555 char ebuffer[256] = { 0 };
556 WLog_ERR(TAG,
"flock(LOCK_UN) %s failed with %s [0x%08X]", pFile->lpFileName,
557 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
558 SetLastError(map_posix_err(errno));
566static BOOL FileUnlockFileEx(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwReserved,
567 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
568 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh,
571 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
578 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
579 SetLastError(ERROR_NOT_SUPPORTED);
588 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
595 lock.l_whence = SEEK_SET;
596 lock.l_type = F_UNLCK;
597 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
599 char ebuffer[256] = { 0 };
600 WLog_ERR(TAG,
"F_UNLCK on %s failed with %s [0x%08X]", pFile->lpFileName,
601 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
602 SetLastError(map_posix_err(errno));
606 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
608 char ebuffer[256] = { 0 };
609 WLog_ERR(TAG,
"flock(LOCK_UN) %s failed with %s [0x%08X]", pFile->lpFileName,
610 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
611 SetLastError(map_posix_err(errno));
619static INT64 FileTimeToUS(
const FILETIME* ft)
621 const INT64 EPOCH_DIFF_US = EPOCH_DIFF * 1000000LL;
622 INT64 tmp = ((INT64)ft->dwHighDateTime) << 32 | ft->dwLowDateTime;
624 tmp -= EPOCH_DIFF_US;
628#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
629static struct timespec filetimeToTimespec(const
FILETIME* ftime)
632 INT64 tmp = FileTimeToUS(ftime);
633 struct timespec ts = { 0 };
634 ts.tv_sec = tmp / 1000000LL;
635 ts.tv_nsec = (tmp % 1000000LL) * 1000LL;
639static BOOL FileSetFileTime(HANDLE hFile, WINPR_ATTR_UNUSED
const FILETIME* lpCreationTime,
642 struct timespec times[2] = { { UTIME_OMIT, UTIME_OMIT },
643 { UTIME_OMIT, UTIME_OMIT } };
644 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
649 if (lpLastAccessTime)
650 times[0] = filetimeToTimespec(lpLastAccessTime);
653 times[1] = filetimeToTimespec(lpLastWriteTime);
656 const int rc = futimens(fileno(pFile->fp), times);
659 char ebuffer[256] = { 0 };
660 WLog_ERR(TAG,
"futimens failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
662 SetLastError(map_posix_err(errno));
668#elif defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) || defined(KFREEBSD)
669static struct timeval filetimeToTimeval(const
FILETIME* ftime)
672 UINT64 tmp = FileTimeToUS(ftime);
673 struct timeval tv = { 0 };
674 tv.tv_sec = tmp / 1000000ULL;
675 tv.tv_usec = tmp % 1000000ULL;
679static struct timeval statToTimeval(const struct stat* sval)
682 struct timeval tv = { 0 };
683#if defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
684 tv.tv_sec = sval->st_atime;
686 TIMESPEC_TO_TIMEVAL(&tv, &sval->st_atim);
688 TIMESPEC_TO_TIMEVAL(&tv, &sval->st_atimespec);
690#elif defined(ANDROID)
691 tv.tv_sec = sval->st_atime;
692 tv.tv_usec = sval->st_atimensec / 1000UL;
697static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
700 struct stat buf = { 0 };
702 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
707 const int rc = fstat(fileno(pFile->fp), &buf);
710 char ebuffer[256] = { 0 };
711 WLog_ERR(TAG,
"fstat failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
713 SetLastError(map_posix_err(errno));
717 struct timeval timevals[2] = { statToTimeval(&buf), statToTimeval(&buf) };
718 if (lpLastAccessTime)
719 timevals[0] = filetimeToTimeval(lpLastAccessTime);
722 timevals[1] = filetimeToTimeval(lpLastWriteTime);
726 const int res = utimes(pFile->lpFileName, timevals);
729 char ebuffer[256] = { 0 };
730 WLog_ERR(TAG,
"utimes failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
732 SetLastError(map_posix_err(errno));
740static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
743 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
748 WLog_WARN(TAG,
"TODO: Creation, Access and Write time can not be handled!");
750 "TODO: Define _POSIX_C_SOURCE >= 200809L or implement a platform specific handler!");
767 FileFlushFileBuffers,
770 FileSetFilePointerEx,
776 FileGetFileInformationByHandle,
800 FileGetFileInformationByHandle,
803static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDisposition, BOOL* create)
805 BOOL writeable = (dwDesiredAccess & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
807 switch (dwCreationDisposition)
811 return (writeable) ?
"wb+" :
"rwb";
820 return (writeable) ?
"rb+" :
"rb";
821 case TRUNCATE_EXISTING:
830UINT32 map_posix_err(
int fs_errno)
846 rc = ERROR_FILE_NOT_FOUND;
852 rc = ERROR_ACCESS_DENIED;
856 rc = ERROR_FILE_NOT_FOUND;
860 rc = ERROR_BUSY_DRIVE;
864 rc = ERROR_FILE_EXISTS;
868 rc = STATUS_FILE_IS_A_DIRECTORY;
872 rc = STATUS_DIRECTORY_NOT_EMPTY;
876 rc = STATUS_TOO_MANY_OPENED_FILES;
881 char ebuffer[256] = { 0 };
882 WLog_ERR(TAG,
"Missing ERRNO mapping %s [%d]",
883 winpr_strerror(fs_errno, ebuffer,
sizeof(ebuffer)), fs_errno);
884 rc = STATUS_UNSUCCESSFUL;
892static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
893 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
894 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
895 HANDLE hTemplateFile)
897 WINPR_FILE* pFile = NULL;
899 const char* mode = FileGetMode(dwDesiredAccess, dwCreationDisposition, &create);
908 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
910 WLog_ERR(TAG,
"WinPR does not support the FILE_FLAG_OVERLAPPED flag");
911 SetLastError(ERROR_NOT_SUPPORTED);
912 return INVALID_HANDLE_VALUE;
915 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
918 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
919 return INVALID_HANDLE_VALUE;
922 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
923 pFile->common.ops = &fileOps;
925 pFile->lpFileName = _strdup(lpFileName);
926 if (!pFile->lpFileName)
928 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
930 return INVALID_HANDLE_VALUE;
933 pFile->dwOpenMode = dwDesiredAccess;
934 pFile->dwShareMode = dwShareMode;
935 pFile->dwFlagsAndAttributes = dwFlagsAndAttributes;
936 pFile->lpSecurityAttributes = lpSecurityAttributes;
937 pFile->dwCreationDisposition = dwCreationDisposition;
938 pFile->hTemplateFile = hTemplateFile;
942 if (dwCreationDisposition == CREATE_NEW)
944 if (stat(pFile->lpFileName, &st) == 0)
946 SetLastError(ERROR_FILE_EXISTS);
947 free(pFile->lpFileName);
949 return INVALID_HANDLE_VALUE;
953 fp = winpr_fopen(pFile->lpFileName,
"ab");
956 SetLastError(map_posix_err(errno));
957 free(pFile->lpFileName);
959 return INVALID_HANDLE_VALUE;
962 fp = freopen(pFile->lpFileName, mode, fp);
966 if (stat(pFile->lpFileName, &st) != 0)
968 SetLastError(map_posix_err(errno));
969 free(pFile->lpFileName);
971 return INVALID_HANDLE_VALUE;
977 if (S_ISFIFO(st.st_mode))
979 SetLastError(ERROR_FILE_NOT_FOUND);
980 free(pFile->lpFileName);
982 return INVALID_HANDLE_VALUE;
987 fp = winpr_fopen(pFile->lpFileName, mode);
994 SetLastError(map_posix_err(errno));
995 free(pFile->lpFileName);
997 return INVALID_HANDLE_VALUE;
1000 (void)setvbuf(fp, NULL, _IONBF, 0);
1005 lock.l_whence = SEEK_SET;
1007 if (dwShareMode & FILE_SHARE_READ)
1008 lock.l_type = F_RDLCK;
1009 if (dwShareMode & FILE_SHARE_WRITE)
1010 lock.l_type = F_RDLCK;
1012 if (dwShareMode & FILE_SHARE_READ)
1014 if (dwShareMode & FILE_SHARE_WRITE)
1018 if (dwShareMode & (FILE_SHARE_READ | FILE_SHARE_WRITE))
1021 if (fcntl(fileno(pFile->fp), F_SETLKW, &lock) == -1)
1023 if (flock(fileno(pFile->fp), lock) < 0)
1026 char ebuffer[256] = { 0 };
1028 WLog_ERR(TAG,
"F_SETLKW failed with %s [0x%08X]",
1029 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1031 WLog_ERR(TAG,
"flock failed with %s [0x%08X]",
1032 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1035 SetLastError(map_posix_err(errno));
1036 FileCloseHandle(pFile);
1037 return INVALID_HANDLE_VALUE;
1040 pFile->bLocked = TRUE;
1043 if (fstat(fileno(pFile->fp), &st) == 0 && dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1045 st.st_mode &= WINPR_ASSERTING_INT_CAST(mode_t, (mode_t)(~(S_IWUSR | S_IWGRP | S_IWOTH)));
1046 if (fchmod(fileno(pFile->fp), st.st_mode) != 0)
1048 SetLastError(map_posix_err(errno));
1049 FileCloseHandle(pFile);
1050 return INVALID_HANDLE_VALUE;
1054 SetLastError(STATUS_SUCCESS);
1058static BOOL IsFileDevice(WINPR_ATTR_UNUSED LPCTSTR lpDeviceName)
1063static const HANDLE_CREATOR FileHandleCreator = { IsFileDevice, FileCreateFileA };
1067 return &FileHandleCreator;
1070static WINPR_FILE* FileHandle_New(FILE* fp)
1072 WINPR_FILE* pFile = NULL;
1073 char name[MAX_PATH] = { 0 };
1075 (void)_snprintf(name,
sizeof(name),
"device_%d", fileno(fp));
1076 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
1079 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1083 pFile->common.ops = &shmOps;
1084 pFile->lpFileName = _strdup(name);
1086 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
1090void GetStdHandle_Uninit(
void)
1092 FileCloseHandleInt(pStdHandleFile, TRUE);
1095HANDLE GetStdHandle(DWORD nStdHandle)
1101 case STD_INPUT_HANDLE:
1104 case STD_OUTPUT_HANDLE:
1107 case STD_ERROR_HANDLE:
1111 return INVALID_HANDLE_VALUE;
1113 if (!pStdHandleFile)
1114 pStdHandleFile = FileHandle_New(fp);
1116 if (!pStdHandleFile)
1117 return INVALID_HANDLE_VALUE;
1119 return (HANDLE)pStdHandleFile;
1122BOOL SetStdHandle(WINPR_ATTR_UNUSED DWORD nStdHandle, WINPR_ATTR_UNUSED HANDLE hHandle)
1127BOOL SetStdHandleEx(WINPR_ATTR_UNUSED DWORD dwStdHandle, WINPR_ATTR_UNUSED HANDLE hNewHandle,
1128 WINPR_ATTR_UNUSED HANDLE* phOldHandle)
1133BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1134 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1137#define STATVFS statfs
1139#define STATVFS statvfs
1142 struct STATVFS svfst = { 0 };
1143 STATVFS(lpRootPathName, &svfst);
1144 *lpSectorsPerCluster = (UINT32)MIN(svfst.f_frsize, UINT32_MAX);
1145 *lpBytesPerSector = 1;
1146 *lpNumberOfFreeClusters = (UINT32)MIN(svfst.f_bavail, UINT32_MAX);
1147 *lpTotalNumberOfClusters = (UINT32)MIN(svfst.f_blocks, UINT32_MAX);
1151BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1152 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1153 LPDWORD lpTotalNumberOfClusters)
1156 if (!lpRootPathName)
1159 char* rootPathName = ConvertWCharToUtf8Alloc(lpRootPathName, NULL);
1162 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1165 ret = GetDiskFreeSpaceA(rootPathName, lpSectorsPerCluster, lpBytesPerSector,
1166 lpNumberOfFreeClusters, lpTotalNumberOfClusters);
1179BOOL ValidFileNameComponent(LPCWSTR lpFileName)
1185 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1186 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1187 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1188 (lpFileName[3] == L
'\0'))
1194 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'P' || lpFileName[0] == L
'p')) &&
1195 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'R' || lpFileName[1] == L
'r')) &&
1196 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1197 (lpFileName[3] == L
'\0'))
1203 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'A' || lpFileName[0] == L
'a')) &&
1204 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1205 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'X' || lpFileName[2] == L
'x')) &&
1206 (lpFileName[3] == L
'\0'))
1212 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'N' || lpFileName[0] == L
'n')) &&
1213 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1214 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'L' || lpFileName[2] == L
'l')) &&
1215 (lpFileName[3] == L
'\0'))
1221 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'L' || lpFileName[0] == L
'l')) &&
1222 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'P' || lpFileName[1] == L
'p')) &&
1223 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'T' || lpFileName[2] == L
't')) &&
1224 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1225 (lpFileName[4] == L
'\0'))
1231 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1232 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1233 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'M' || lpFileName[2] == L
'm')) &&
1234 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1235 (lpFileName[4] == L
'\0'))
1241 for (LPCWSTR c = lpFileName; *c; c++)
1243 if ((*c == L
'<') || (*c == L
'>') || (*c == L
':') || (*c == L
'"') || (*c == L
'/') ||
1244 (*c == L
'\\') || (*c == L
'|') || (*c == L
'?') || (*c == L
'*'))
1255HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1256 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1257 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1260 CREATEFILE2_EXTENDED_PARAMETERS params = { 0 };
1262 params.dwSize =
sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
1264 if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
1265 params.dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
1266 if (dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
1267 params.dwFileFlags |= FILE_FLAG_DELETE_ON_CLOSE;
1268 if (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
1269 params.dwFileFlags |= FILE_FLAG_NO_BUFFERING;
1270 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
1271 params.dwFileFlags |= FILE_FLAG_OPEN_NO_RECALL;
1272 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
1273 params.dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
1274 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REQUIRING_OPLOCK)
1275 params.dwFileFlags |= FILE_FLAG_OPEN_REQUIRING_OPLOCK;
1276 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
1277 params.dwFileFlags |= FILE_FLAG_OVERLAPPED;
1278 if (dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS)
1279 params.dwFileFlags |= FILE_FLAG_POSIX_SEMANTICS;
1280 if (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
1281 params.dwFileFlags |= FILE_FLAG_RANDOM_ACCESS;
1282 if (dwFlagsAndAttributes & FILE_FLAG_SESSION_AWARE)
1283 params.dwFileFlags |= FILE_FLAG_SESSION_AWARE;
1284 if (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
1285 params.dwFileFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
1286 if (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
1287 params.dwFileFlags |= FILE_FLAG_WRITE_THROUGH;
1289 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ARCHIVE)
1290 params.dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1291 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_COMPRESSED)
1292 params.dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
1293 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DEVICE)
1294 params.dwFileAttributes |= FILE_ATTRIBUTE_DEVICE;
1295 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY)
1296 params.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1297 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ENCRYPTED)
1298 params.dwFileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
1299 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_HIDDEN)
1300 params.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1301 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM)
1302 params.dwFileAttributes |= FILE_ATTRIBUTE_INTEGRITY_STREAM;
1303 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NORMAL)
1304 params.dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
1305 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
1306 params.dwFileAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1307 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA)
1308 params.dwFileAttributes |= FILE_ATTRIBUTE_NO_SCRUB_DATA;
1309 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_OFFLINE)
1310 params.dwFileAttributes |= FILE_ATTRIBUTE_OFFLINE;
1311 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1312 params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1313 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1314 params.dwFileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
1315 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SPARSE_FILE)
1316 params.dwFileAttributes |= FILE_ATTRIBUTE_SPARSE_FILE;
1317 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SYSTEM)
1318 params.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
1319 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY)
1320 params.dwFileAttributes |= FILE_ATTRIBUTE_TEMPORARY;
1321 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_VIRTUAL)
1322 params.dwFileAttributes |= FILE_ATTRIBUTE_VIRTUAL;
1324 if (dwFlagsAndAttributes & SECURITY_ANONYMOUS)
1325 params.dwSecurityQosFlags |= SECURITY_ANONYMOUS;
1326 if (dwFlagsAndAttributes & SECURITY_CONTEXT_TRACKING)
1327 params.dwSecurityQosFlags |= SECURITY_CONTEXT_TRACKING;
1328 if (dwFlagsAndAttributes & SECURITY_DELEGATION)
1329 params.dwSecurityQosFlags |= SECURITY_DELEGATION;
1330 if (dwFlagsAndAttributes & SECURITY_EFFECTIVE_ONLY)
1331 params.dwSecurityQosFlags |= SECURITY_EFFECTIVE_ONLY;
1332 if (dwFlagsAndAttributes & SECURITY_IDENTIFICATION)
1333 params.dwSecurityQosFlags |= SECURITY_IDENTIFICATION;
1334 if (dwFlagsAndAttributes & SECURITY_IMPERSONATION)
1335 params.dwSecurityQosFlags |= SECURITY_IMPERSONATION;
1337 params.lpSecurityAttributes = lpSecurityAttributes;
1338 params.hTemplateFile = hTemplateFile;
1340 hFile = CreateFile2(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, ¶ms);
1345HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1346 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1347 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1353 WCHAR* lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
1358 hFile = CreateFileW(lpFileNameW, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1359 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1366DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
1371 if (!lpFileSizeHigh)
1372 return INVALID_FILE_SIZE;
1374 status = GetFileSizeEx(hFile, &fileSize);
1377 return INVALID_FILE_SIZE;
1379 *lpFileSizeHigh = fileSize.HighPart;
1381 return fileSize.LowPart;
1384DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
1391 liDistanceToMove.LowPart = lDistanceToMove;
1393 status = SetFilePointerEx(hFile, liDistanceToMove, &liNewFilePointer, dwMoveMethod);
1396 return INVALID_SET_FILE_POINTER;
1398 if (lpDistanceToMoveHigh)
1399 *lpDistanceToMoveHigh = liNewFilePointer.HighPart;
1401 return liNewFilePointer.LowPart;
1406 return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1412 return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1416DWORD GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart)
1419 WCHAR* lpFileNameW = NULL;
1420 WCHAR* lpBufferW = NULL;
1421 WCHAR* lpFilePartW = NULL;
1422 DWORD nBufferLengthW = nBufferLength *
sizeof(WCHAR);
1424 if (!lpFileName || (nBufferLength < 1))
1427 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
1431 lpBufferW = (WCHAR*)malloc(nBufferLengthW);
1436 dwStatus = GetFullPathNameW(lpFileNameW, nBufferLengthW, lpBufferW, &lpFilePartW);
1438 (void)ConvertWCharNToUtf8(lpBufferW, nBufferLengthW /
sizeof(WCHAR), lpBuffer, nBufferLength);
1441 lpFilePart = lpBuffer + (lpFilePartW - lpBufferW);
1446 return dwStatus * 2;
1449BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1450 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1457 status = GetDiskFreeSpaceExA(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1458 &TotalNumberOfFreeBytes);
1463 *lpBytesPerSector = 1;
1464 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1465 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1466 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1471BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1472 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1473 LPDWORD lpTotalNumberOfClusters)
1480 status = GetDiskFreeSpaceExW(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1481 &TotalNumberOfFreeBytes);
1486 *lpBytesPerSector = 1;
1487 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1488 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1489 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1494DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1496 SetLastError(ERROR_INVALID_FUNCTION);
1500DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1502 SetLastError(ERROR_INVALID_FUNCTION);
1506BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
1524HANDLE GetFileHandleForFileDescriptor(
int fd)
1527 return (HANDLE)_get_osfhandle(fd);
1529 WINPR_FILE* pFile = NULL;
1534 if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
1535 return INVALID_HANDLE_VALUE;
1537 flags = fcntl(fd, F_GETFL);
1539 return INVALID_HANDLE_VALUE;
1541 if (flags & O_WRONLY)
1542 fp = fdopen(fd,
"wb");
1544 fp = fdopen(fd,
"rb");
1547 return INVALID_HANDLE_VALUE;
1549 (void)setvbuf(fp, NULL, _IONBF, 0);
1552 pFile = FileHandle_New(fp);
1554 return INVALID_HANDLE_VALUE;
1556 return (HANDLE)pFile;
1560FILE* winpr_fopen(
const char* path,
const char* mode)
1563 return fopen(path, mode);
1565 LPWSTR lpPathW = NULL;
1566 LPWSTR lpModeW = NULL;
1567 FILE* result = NULL;
1572 lpPathW = ConvertUtf8ToWCharAlloc(path, NULL);
1576 lpModeW = ConvertUtf8ToWCharAlloc(mode, NULL);
1580 result = _wfopen(lpPathW, lpModeW);
1589#if !defined(_UWP) && !defined(_WIN32)
1590DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1592 char* buffer = NULL;
1593 if (nBufferLength > 0)
1595 buffer = calloc(nBufferLength,
sizeof(
char));
1600 const DWORD rc = GetLogicalDriveStringsA(nBufferLength, buffer);
1602 ConvertMszUtf8NToWChar(buffer, rc, lpBuffer, nBufferLength);
1607DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1613 const char path[] =
"/\0";
1614 const size_t len =
sizeof(path);
1615 if (nBufferLength < len)
1616 return WINPR_ASSERTING_INT_CAST(DWORD, len);
1618 memcpy(lpBuffer, path, len);