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))
60static WINPR_FILE* pStdHandleFile =
nullptr;
62static void GetStdHandle_Uninit(
void) __attribute__((destructor));
64static BOOL FileIsHandled(HANDLE handle)
66 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_FILE, FALSE);
69static int FileGetFd(HANDLE handle)
71 WINPR_FILE* file = (WINPR_FILE*)handle;
73 if (!FileIsHandled(handle))
76 return fileno(file->fp);
79static BOOL FileCloseHandleInt(HANDLE handle, BOOL force)
81 WINPR_FILE* file = (WINPR_FILE*)handle;
83 if (!FileIsHandled(handle))
88 if (handle == pStdHandleFile)
97 if (fileno(file->fp) > 2)
99 (void)fclose(file->fp);
104 free(file->lpFileName);
105 file->lpFileName =
nullptr;
109static BOOL FileCloseHandle(HANDLE handle)
111 return FileCloseHandleInt(handle, FALSE);
114#define log_error(fkt, file) log_error_((fkt), (file), __FILE__, __func__, __LINE__)
115static BOOL log_error_(
const char* name,
const WINPR_FILE* pFile,
const char* file,
const char* fkt,
118 char ebuffer[256] = WINPR_C_ARRAY_INIT;
125 const DWORD level = WLOG_ERROR;
126 static wLog* log =
nullptr;
130 if (WLog_IsLevelActive(log, level))
132 WLog_PrintTextMessage(log, level, line, file, fkt,
"%s %s failed with %s [0x08%x]", name,
133 pFile->lpFileName, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
134 WINPR_CXX_COMPAT_CAST(
unsigned, errno));
136 SetLastError(map_posix_err(errno));
140static BOOL FileSetEndOfFile(HANDLE hFile)
142 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
147 const INT64 size = _ftelli64(pFile->fp);
151 if (ftruncate(fileno(pFile->fp), (off_t)size) < 0)
152 return log_error(
"ftruncate", pFile);
158static DWORD FileSetFilePointer(HANDLE hFile, LONG lDistanceToMove,
159 const PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
162 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
167 return INVALID_SET_FILE_POINTER;
171 if (lpDistanceToMoveHigh)
173 offset = (INT64)(((UINT64)*lpDistanceToMoveHigh << 32U) | (UINT64)lDistanceToMove);
176 offset = lDistanceToMove;
178 switch (dwMoveMethod)
190 return INVALID_SET_FILE_POINTER;
193 if (_fseeki64(pFile->fp, offset, whence))
195 (void)log_error(
"_fseeki64", pFile);
196 return INVALID_SET_FILE_POINTER;
199 return (DWORD)_ftelli64(pFile->fp);
202static BOOL FileSetFilePointerEx(HANDLE hFile,
LARGE_INTEGER liDistanceToMove,
203 PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
205 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
211 switch (dwMoveMethod)
226 if (_fseeki64(pFile->fp, liDistanceToMove.QuadPart, whence))
227 return log_error(
"_fseeki64", pFile);
229 if (lpNewFilePointer)
230 lpNewFilePointer->QuadPart = _ftelli64(pFile->fp);
235static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
238 size_t io_status = 0;
239 WINPR_FILE* file =
nullptr;
244 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
245 SetLastError(ERROR_NOT_SUPPORTED);
252 file = (WINPR_FILE*)Object;
254 io_status = fread(lpBuffer, 1, nNumberOfBytesToRead, file->fp);
256 if (io_status == 0 && ferror(file->fp))
263 SetLastError(ERROR_NO_DATA);
266 SetLastError(map_posix_err(errno));
270 if (lpNumberOfBytesRead)
271 *lpNumberOfBytesRead = (DWORD)io_status;
276static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
277 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
279 size_t io_status = 0;
280 WINPR_FILE* file =
nullptr;
284 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
285 SetLastError(ERROR_NOT_SUPPORTED);
292 file = (WINPR_FILE*)Object;
295 io_status = fwrite(lpBuffer, 1, nNumberOfBytesToWrite, file->fp);
296 if (io_status == 0 && ferror(file->fp))
298 SetLastError(map_posix_err(errno));
302 *lpNumberOfBytesWritten = (DWORD)io_status;
306static DWORD FileGetFileSize(HANDLE Object, LPDWORD lpFileSizeHigh)
308 WINPR_FILE* file =
nullptr;
315 file = (WINPR_FILE*)Object;
317 cur = _ftelli64(file->fp);
321 (void)log_error(
"_ftelli64", file);
322 return INVALID_FILE_SIZE;
325 if (_fseeki64(file->fp, 0, SEEK_END) != 0)
327 (void)log_error(
"_fseeki64", file);
328 return INVALID_FILE_SIZE;
331 size = _ftelli64(file->fp);
335 (void)log_error(
"_ftelli64", file);
336 return INVALID_FILE_SIZE;
339 if (_fseeki64(file->fp, cur, SEEK_SET) != 0)
341 (void)log_error(
"_fseeki64", file);
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 =
nullptr;
387 if (!lpFileInformation)
390 if (fstat(fileno(pFile->fp), &st) == -1)
391 return log_error(
"fstat", pFile);
393 lpFileInformation->dwFileAttributes = 0;
395 if (S_ISDIR(st.st_mode))
396 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
398 if (lpFileInformation->dwFileAttributes == 0)
399 lpFileInformation->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
401 lastSep = strrchr(pFile->lpFileName,
'/');
405 const char* name = lastSep + 1;
406 const size_t namelen = strlen(name);
408 if ((namelen > 1) && (name[0] ==
'.') && (name[1] !=
'.'))
409 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
412 if (!(st.st_mode & S_IWUSR))
413 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
415#ifdef _DARWIN_FEATURE_64_BIT_INODE
416 ft = STAT_TIME_TO_FILETIME(st.st_birthtime);
418 ft = STAT_TIME_TO_FILETIME(st.st_ctime);
420 lpFileInformation->ftCreationTime.dwHighDateTime = (ft) >> 32ULL;
421 lpFileInformation->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
422 ft = STAT_TIME_TO_FILETIME(st.st_mtime);
423 lpFileInformation->ftLastWriteTime.dwHighDateTime = (ft) >> 32ULL;
424 lpFileInformation->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
425 ft = STAT_TIME_TO_FILETIME(st.st_atime);
426 lpFileInformation->ftLastAccessTime.dwHighDateTime = (ft) >> 32ULL;
427 lpFileInformation->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
428 lpFileInformation->nFileSizeHigh = ((UINT64)st.st_size) >> 32ULL;
429 lpFileInformation->nFileSizeLow = st.st_size & 0xFFFFFFFF;
430 lpFileInformation->dwVolumeSerialNumber = (UINT32)st.st_dev;
431 lpFileInformation->nNumberOfLinks = (UINT32)st.st_nlink;
432 lpFileInformation->nFileIndexHigh = (st.st_ino >> 4) & 0xFFFFFFFF;
433 lpFileInformation->nFileIndexLow = st.st_ino & 0xFFFFFFFF;
437static BOOL FileLockFileEx(HANDLE hFile, DWORD dwFlags, WINPR_ATTR_UNUSED DWORD dwReserved,
438 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockLow,
439 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockHigh,
448 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
452 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
453 SetLastError(ERROR_NOT_SUPPORTED);
462 WLog_ERR(TAG,
"File %s already locked!", pFile->lpFileName);
469 lock.l_whence = SEEK_SET;
471 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
472 lock.l_type = F_WRLCK;
474 lock.l_type = F_WRLCK;
476 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
481 if (fcntl(fileno(pFile->fp), lckcmd, &lock) == -1)
483 char ebuffer[256] = WINPR_C_ARRAY_INIT;
484 WLog_ERR(TAG,
"F_SETLK failed with %s [0x%08X]",
485 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
486 SetLastError(map_posix_err(errno));
490 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
495 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
498 if (flock(fileno(pFile->fp), lock) < 0)
499 return log_error(
"flock", pFile);
502 pFile->bLocked = TRUE;
507static BOOL FileUnlockFile(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwFileOffsetLow,
508 WINPR_ATTR_UNUSED DWORD dwFileOffsetHigh,
509 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
510 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh)
512 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
522 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
529 lock.l_whence = SEEK_SET;
530 lock.l_type = F_UNLCK;
531 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
532 return log_error(
"F_GETLK", pFile);
535 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
536 return log_error(
"flock", pFile);
542static BOOL FileUnlockFileEx(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwReserved,
543 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
544 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh,
547 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
554 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
555 SetLastError(ERROR_NOT_SUPPORTED);
564 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
571 lock.l_whence = SEEK_SET;
572 lock.l_type = F_UNLCK;
573 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
574 return log_error(
"F_GETLK", pFile);
576 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
577 return log_error(
"flock", pFile);
583static INT64 FileTimeToUS(
const FILETIME* ft)
585 const INT64 EPOCH_DIFF_US = EPOCH_DIFF * 1000000LL;
586 INT64 tmp = ((INT64)ft->dwHighDateTime) << 32 | ft->dwLowDateTime;
588 tmp -= EPOCH_DIFF_US;
592#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
593static struct timespec filetimeToTimespec(const
FILETIME* ftime)
596 INT64 tmp = FileTimeToUS(ftime);
597 struct timespec ts = WINPR_C_ARRAY_INIT;
598 ts.tv_sec = tmp / 1000000LL;
599 ts.tv_nsec = (tmp % 1000000LL) * 1000LL;
603static BOOL FileSetFileTime(HANDLE hFile, WINPR_ATTR_UNUSED
const FILETIME* lpCreationTime,
606 struct timespec times[2] = { { UTIME_OMIT, UTIME_OMIT },
607 { UTIME_OMIT, UTIME_OMIT } };
608 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
613 if (lpLastAccessTime)
614 times[0] = filetimeToTimespec(lpLastAccessTime);
617 times[1] = filetimeToTimespec(lpLastWriteTime);
620 const int rc = futimens(fileno(pFile->fp), times);
623 char ebuffer[256] = WINPR_C_ARRAY_INIT;
624 WLog_ERR(TAG,
"futimens failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
626 SetLastError(map_posix_err(errno));
632#elif defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) || defined(KFREEBSD)
633static struct timeval filetimeToTimeval(const
FILETIME* ftime)
636 UINT64 tmp = FileTimeToUS(ftime);
637 struct timeval tv = WINPR_C_ARRAY_INIT;
638 tv.tv_sec = tmp / 1000000ULL;
639 tv.tv_usec = tmp % 1000000ULL;
643static struct timeval statToTimeval(const struct stat* sval)
646 struct timeval tv = WINPR_C_ARRAY_INIT;
647#if defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
648 tv.tv_sec = sval->st_atime;
650 TIMESPEC_TO_TIMEVAL(&tv, &sval->st_atim);
652 TIMESPEC_TO_TIMEVAL(&tv, &sval->st_atimespec);
654#elif defined(ANDROID)
655 tv.tv_sec = sval->st_atime;
656 tv.tv_usec = sval->st_atimensec / 1000UL;
661static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
664 struct stat buf = WINPR_C_ARRAY_INIT;
666 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
671 const int rc = fstat(fileno(pFile->fp), &buf);
674 char ebuffer[256] = WINPR_C_ARRAY_INIT;
675 WLog_ERR(TAG,
"fstat failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
677 SetLastError(map_posix_err(errno));
681 struct timeval timevals[2] = { statToTimeval(&buf), statToTimeval(&buf) };
682 if (lpLastAccessTime)
683 timevals[0] = filetimeToTimeval(lpLastAccessTime);
686 timevals[1] = filetimeToTimeval(lpLastWriteTime);
690 const int res = utimes(pFile->lpFileName, timevals);
693 char ebuffer[256] = WINPR_C_ARRAY_INIT;
694 WLog_ERR(TAG,
"utimes failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
696 SetLastError(map_posix_err(errno));
704static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
707 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
712 WLog_WARN(TAG,
"TODO: Creation, Access and Write time can not be handled!");
714 "TODO: Define _POSIX_C_SOURCE >= 200809L or implement a platform specific handler!");
731 FileFlushFileBuffers,
734 FileSetFilePointerEx,
740 FileGetFileInformationByHandle,
764 FileGetFileInformationByHandle,
767static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDisposition, BOOL* create)
769 BOOL writeable = (dwDesiredAccess & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
771 switch (dwCreationDisposition)
775 return (writeable) ?
"wb+" :
"rwb";
784 return (writeable) ?
"rb+" :
"rb";
785 case TRUNCATE_EXISTING:
794UINT32 map_posix_err(
int fs_errno)
810 rc = ERROR_FILE_NOT_FOUND;
816 rc = ERROR_ACCESS_DENIED;
820 rc = ERROR_FILE_NOT_FOUND;
824 rc = ERROR_BUSY_DRIVE;
828 rc = ERROR_FILE_EXISTS;
832 rc = STATUS_FILE_IS_A_DIRECTORY;
836 rc = STATUS_DIRECTORY_NOT_EMPTY;
840 rc = STATUS_TOO_MANY_OPENED_FILES;
845 char ebuffer[256] = WINPR_C_ARRAY_INIT;
846 WLog_ERR(TAG,
"Missing ERRNO mapping %s [%d]",
847 winpr_strerror(fs_errno, ebuffer,
sizeof(ebuffer)), fs_errno);
848 rc = STATUS_UNSUCCESSFUL;
856static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
857 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
858 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
859 HANDLE hTemplateFile)
861 WINPR_FILE* pFile =
nullptr;
863 const char* mode = FileGetMode(dwDesiredAccess, dwCreationDisposition, &create);
872 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
874 WLog_ERR(TAG,
"WinPR does not support the FILE_FLAG_OVERLAPPED flag");
875 SetLastError(ERROR_NOT_SUPPORTED);
876 return INVALID_HANDLE_VALUE;
879 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
882 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
883 return INVALID_HANDLE_VALUE;
886 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
887 pFile->common.ops = &fileOps;
889 pFile->lpFileName = _strdup(lpFileName);
890 if (!pFile->lpFileName)
892 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
894 return INVALID_HANDLE_VALUE;
897 pFile->dwOpenMode = dwDesiredAccess;
898 pFile->dwShareMode = dwShareMode;
899 pFile->dwFlagsAndAttributes = dwFlagsAndAttributes;
900 pFile->lpSecurityAttributes = lpSecurityAttributes;
901 pFile->dwCreationDisposition = dwCreationDisposition;
902 pFile->hTemplateFile = hTemplateFile;
906 if (dwCreationDisposition == CREATE_NEW)
908 if (stat(pFile->lpFileName, &st) == 0)
910 SetLastError(ERROR_FILE_EXISTS);
911 free(pFile->lpFileName);
913 return INVALID_HANDLE_VALUE;
917 fp = winpr_fopen(pFile->lpFileName,
"ab");
920 SetLastError(map_posix_err(errno));
921 free(pFile->lpFileName);
923 return INVALID_HANDLE_VALUE;
926 fp = freopen(pFile->lpFileName, mode, fp);
930 if (stat(pFile->lpFileName, &st) != 0)
932 SetLastError(map_posix_err(errno));
933 free(pFile->lpFileName);
935 return INVALID_HANDLE_VALUE;
941 if (S_ISFIFO(st.st_mode))
943 SetLastError(ERROR_FILE_NOT_FOUND);
944 free(pFile->lpFileName);
946 return INVALID_HANDLE_VALUE;
951 fp = winpr_fopen(pFile->lpFileName, mode);
958 SetLastError(map_posix_err(errno));
959 free(pFile->lpFileName);
961 return INVALID_HANDLE_VALUE;
968 pFile->lpSecurityAttributes && pFile->lpSecurityAttributes->bInheritHandle;
969 if (!winpr_set_cloexec(fileno(fp), !inherit))
971 SetLastError(map_posix_err(errno));
972 FileCloseHandle(pFile);
974 return INVALID_HANDLE_VALUE;
978 (void)setvbuf(fp,
nullptr, _IONBF, 0);
983 lock.l_whence = SEEK_SET;
985 if (dwShareMode & FILE_SHARE_READ)
986 lock.l_type = F_RDLCK;
987 if (dwShareMode & FILE_SHARE_WRITE)
988 lock.l_type = F_RDLCK;
990 if (dwShareMode & FILE_SHARE_READ)
992 if (dwShareMode & FILE_SHARE_WRITE)
996 if (dwShareMode & (FILE_SHARE_READ | FILE_SHARE_WRITE))
999 if (fcntl(fileno(pFile->fp), F_SETLKW, &lock) == -1)
1001 if (flock(fileno(pFile->fp), lock) < 0)
1005 (void)log_error(
"F_SETLKW", pFile);
1007 (void)log_error(
"flock", pFile);
1010 SetLastError(map_posix_err(errno));
1011 FileCloseHandle(pFile);
1013 return INVALID_HANDLE_VALUE;
1016 pFile->bLocked = TRUE;
1019 if (fstat(fileno(pFile->fp), &st) == 0 && dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1021 st.st_mode &= WINPR_ASSERTING_INT_CAST(mode_t, (mode_t)(~(S_IWUSR | S_IWGRP | S_IWOTH)));
1022 if (fchmod(fileno(pFile->fp), st.st_mode) != 0)
1024 SetLastError(map_posix_err(errno));
1025 FileCloseHandle(pFile);
1027 return INVALID_HANDLE_VALUE;
1031 SetLastError(STATUS_SUCCESS);
1035static BOOL IsFileDevice(WINPR_ATTR_UNUSED LPCTSTR lpDeviceName)
1040static const HANDLE_CREATOR FileHandleCreator = { IsFileDevice, FileCreateFileA };
1044 return &FileHandleCreator;
1047static WINPR_FILE* FileHandle_New(FILE* fp)
1049 WINPR_FILE* pFile =
nullptr;
1050 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
1052 (void)_snprintf(name,
sizeof(name),
"device_%d", fileno(fp));
1053 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
1056 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1060 pFile->common.ops = &shmOps;
1061 pFile->lpFileName = _strdup(name);
1063 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
1067void GetStdHandle_Uninit(
void)
1069 FileCloseHandleInt(pStdHandleFile, TRUE);
1070 free(pStdHandleFile);
1073HANDLE GetStdHandle(DWORD nStdHandle)
1079 case STD_INPUT_HANDLE:
1082 case STD_OUTPUT_HANDLE:
1085 case STD_ERROR_HANDLE:
1089 return INVALID_HANDLE_VALUE;
1091 if (!pStdHandleFile)
1092 pStdHandleFile = FileHandle_New(fp);
1094 if (!pStdHandleFile)
1095 return INVALID_HANDLE_VALUE;
1097 return (HANDLE)pStdHandleFile;
1100BOOL SetStdHandle(WINPR_ATTR_UNUSED DWORD nStdHandle, WINPR_ATTR_UNUSED HANDLE hHandle)
1105BOOL SetStdHandleEx(WINPR_ATTR_UNUSED DWORD dwStdHandle, WINPR_ATTR_UNUSED HANDLE hNewHandle,
1106 WINPR_ATTR_UNUSED HANDLE* phOldHandle)
1111BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1112 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1115#define STATVFS statfs
1117#define STATVFS statvfs
1120 struct STATVFS svfst = WINPR_C_ARRAY_INIT;
1121 STATVFS(lpRootPathName, &svfst);
1122 *lpSectorsPerCluster = (UINT32)MIN(svfst.f_frsize, UINT32_MAX);
1123 *lpBytesPerSector = 1;
1124 *lpNumberOfFreeClusters = (UINT32)MIN(svfst.f_bavail, UINT32_MAX);
1125 *lpTotalNumberOfClusters = (UINT32)MIN(svfst.f_blocks, UINT32_MAX);
1129BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1130 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1131 LPDWORD lpTotalNumberOfClusters)
1134 if (!lpRootPathName)
1137 char* rootPathName = ConvertWCharToUtf8Alloc(lpRootPathName,
nullptr);
1140 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1143 ret = GetDiskFreeSpaceA(rootPathName, lpSectorsPerCluster, lpBytesPerSector,
1144 lpNumberOfFreeClusters, lpTotalNumberOfClusters);
1157BOOL ValidFileNameComponent(LPCWSTR lpFileName)
1163 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1164 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1165 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1166 (lpFileName[3] == L
'\0'))
1172 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'P' || lpFileName[0] == L
'p')) &&
1173 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'R' || lpFileName[1] == L
'r')) &&
1174 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1175 (lpFileName[3] == L
'\0'))
1181 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'A' || lpFileName[0] == L
'a')) &&
1182 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1183 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'X' || lpFileName[2] == L
'x')) &&
1184 (lpFileName[3] == L
'\0'))
1190 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'N' || lpFileName[0] == L
'n')) &&
1191 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1192 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'L' || lpFileName[2] == L
'l')) &&
1193 (lpFileName[3] == L
'\0'))
1199 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'L' || lpFileName[0] == L
'l')) &&
1200 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'P' || lpFileName[1] == L
'p')) &&
1201 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'T' || lpFileName[2] == L
't')) &&
1202 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1203 (lpFileName[4] == L
'\0'))
1209 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1210 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1211 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'M' || lpFileName[2] == L
'm')) &&
1212 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1213 (lpFileName[4] == L
'\0'))
1219 for (LPCWSTR c = lpFileName; *c; c++)
1221 if ((*c == L
'<') || (*c == L
'>') || (*c == L
':') || (*c == L
'"') || (*c == L
'/') ||
1222 (*c == L
'\\') || (*c == L
'|') || (*c == L
'?') || (*c == L
'*'))
1233HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1234 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1235 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1238 CREATEFILE2_EXTENDED_PARAMETERS params = WINPR_C_ARRAY_INIT;
1240 params.dwSize =
sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
1242 if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
1243 params.dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
1244 if (dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
1245 params.dwFileFlags |= FILE_FLAG_DELETE_ON_CLOSE;
1246 if (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
1247 params.dwFileFlags |= FILE_FLAG_NO_BUFFERING;
1248 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
1249 params.dwFileFlags |= FILE_FLAG_OPEN_NO_RECALL;
1250 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
1251 params.dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
1252 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REQUIRING_OPLOCK)
1253 params.dwFileFlags |= FILE_FLAG_OPEN_REQUIRING_OPLOCK;
1254 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
1255 params.dwFileFlags |= FILE_FLAG_OVERLAPPED;
1256 if (dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS)
1257 params.dwFileFlags |= FILE_FLAG_POSIX_SEMANTICS;
1258 if (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
1259 params.dwFileFlags |= FILE_FLAG_RANDOM_ACCESS;
1260 if (dwFlagsAndAttributes & FILE_FLAG_SESSION_AWARE)
1261 params.dwFileFlags |= FILE_FLAG_SESSION_AWARE;
1262 if (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
1263 params.dwFileFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
1264 if (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
1265 params.dwFileFlags |= FILE_FLAG_WRITE_THROUGH;
1267 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ARCHIVE)
1268 params.dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1269 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_COMPRESSED)
1270 params.dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
1271 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DEVICE)
1272 params.dwFileAttributes |= FILE_ATTRIBUTE_DEVICE;
1273 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY)
1274 params.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1275 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ENCRYPTED)
1276 params.dwFileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
1277 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_HIDDEN)
1278 params.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1279 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM)
1280 params.dwFileAttributes |= FILE_ATTRIBUTE_INTEGRITY_STREAM;
1281 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NORMAL)
1282 params.dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
1283 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
1284 params.dwFileAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1285 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA)
1286 params.dwFileAttributes |= FILE_ATTRIBUTE_NO_SCRUB_DATA;
1287 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_OFFLINE)
1288 params.dwFileAttributes |= FILE_ATTRIBUTE_OFFLINE;
1289 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1290 params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1291 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1292 params.dwFileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
1293 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SPARSE_FILE)
1294 params.dwFileAttributes |= FILE_ATTRIBUTE_SPARSE_FILE;
1295 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SYSTEM)
1296 params.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
1297 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY)
1298 params.dwFileAttributes |= FILE_ATTRIBUTE_TEMPORARY;
1299 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_VIRTUAL)
1300 params.dwFileAttributes |= FILE_ATTRIBUTE_VIRTUAL;
1302 if (dwFlagsAndAttributes & SECURITY_ANONYMOUS)
1303 params.dwSecurityQosFlags |= SECURITY_ANONYMOUS;
1304 if (dwFlagsAndAttributes & SECURITY_CONTEXT_TRACKING)
1305 params.dwSecurityQosFlags |= SECURITY_CONTEXT_TRACKING;
1306 if (dwFlagsAndAttributes & SECURITY_DELEGATION)
1307 params.dwSecurityQosFlags |= SECURITY_DELEGATION;
1308 if (dwFlagsAndAttributes & SECURITY_EFFECTIVE_ONLY)
1309 params.dwSecurityQosFlags |= SECURITY_EFFECTIVE_ONLY;
1310 if (dwFlagsAndAttributes & SECURITY_IDENTIFICATION)
1311 params.dwSecurityQosFlags |= SECURITY_IDENTIFICATION;
1312 if (dwFlagsAndAttributes & SECURITY_IMPERSONATION)
1313 params.dwSecurityQosFlags |= SECURITY_IMPERSONATION;
1315 params.lpSecurityAttributes = lpSecurityAttributes;
1316 params.hTemplateFile = hTemplateFile;
1318 hFile = CreateFile2(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, ¶ms);
1323HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1324 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1325 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1331 WCHAR* lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
1336 hFile = CreateFileW(lpFileNameW, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1337 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1344DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
1349 if (!lpFileSizeHigh)
1350 return INVALID_FILE_SIZE;
1352 status = GetFileSizeEx(hFile, &fileSize);
1355 return INVALID_FILE_SIZE;
1357 *lpFileSizeHigh = fileSize.HighPart;
1359 return fileSize.LowPart;
1362DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
1369 liDistanceToMove.LowPart = lDistanceToMove;
1371 status = SetFilePointerEx(hFile, liDistanceToMove, &liNewFilePointer, dwMoveMethod);
1374 return INVALID_SET_FILE_POINTER;
1376 if (lpDistanceToMoveHigh)
1377 *lpDistanceToMoveHigh = liNewFilePointer.HighPart;
1379 return liNewFilePointer.LowPart;
1384 return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1390 return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1394DWORD GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart)
1397 WCHAR* lpFileNameW =
nullptr;
1398 WCHAR* lpBufferW =
nullptr;
1399 WCHAR* lpFilePartW =
nullptr;
1400 DWORD nBufferLengthW = nBufferLength *
sizeof(WCHAR);
1402 if (!lpFileName || (nBufferLength < 1))
1405 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
1409 lpBufferW = (WCHAR*)malloc(nBufferLengthW);
1414 dwStatus = GetFullPathNameW(lpFileNameW, nBufferLengthW, lpBufferW, &lpFilePartW);
1416 (void)ConvertWCharNToUtf8(lpBufferW, nBufferLengthW /
sizeof(WCHAR), lpBuffer, nBufferLength);
1419 lpFilePart = lpBuffer + (lpFilePartW - lpBufferW);
1424 return WINPR_ASSERTING_INT_CAST(DWORD, dwStatus *
sizeof(WCHAR));
1427BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1428 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1435 status = GetDiskFreeSpaceExA(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1436 &TotalNumberOfFreeBytes);
1441 *lpBytesPerSector = 1;
1442 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1443 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1444 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1449BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1450 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1451 LPDWORD lpTotalNumberOfClusters)
1458 status = GetDiskFreeSpaceExW(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1459 &TotalNumberOfFreeBytes);
1464 *lpBytesPerSector = 1;
1465 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1466 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1467 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1472DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1474 SetLastError(ERROR_INVALID_FUNCTION);
1478DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1480 SetLastError(ERROR_INVALID_FUNCTION);
1484BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
1502HANDLE GetFileHandleForFileDescriptor(
int fd)
1505 return (HANDLE)_get_osfhandle(fd);
1507 WINPR_FILE* pFile =
nullptr;
1512 if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
1513 return INVALID_HANDLE_VALUE;
1515 flags = fcntl(fd, F_GETFL);
1517 return INVALID_HANDLE_VALUE;
1519 if (flags & O_WRONLY)
1520 fp = fdopen(fd,
"wb");
1522 fp = fdopen(fd,
"rb");
1525 return INVALID_HANDLE_VALUE;
1527 (void)setvbuf(fp,
nullptr, _IONBF, 0);
1530 pFile = FileHandle_New(fp);
1532 return INVALID_HANDLE_VALUE;
1534 return (HANDLE)pFile;
1538FILE* winpr_fopen(
const char* path,
const char* mode)
1541 return fopen(path, mode);
1543 LPWSTR lpPathW =
nullptr;
1544 LPWSTR lpModeW =
nullptr;
1545 FILE* result =
nullptr;
1550 lpPathW = ConvertUtf8ToWCharAlloc(path,
nullptr);
1554 lpModeW = ConvertUtf8ToWCharAlloc(mode,
nullptr);
1558 result = _wfopen(lpPathW, lpModeW);
1567#if !defined(_UWP) && !defined(_WIN32)
1568DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1570 char* buffer =
nullptr;
1571 if (nBufferLength > 0)
1573 buffer = calloc(nBufferLength,
sizeof(
char));
1578 const DWORD rc = GetLogicalDriveStringsA(nBufferLength, buffer);
1580 ConvertMszUtf8NToWChar(buffer, rc, lpBuffer, nBufferLength);
1585DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1591 const char path[] =
"/\0";
1592 const size_t len =
sizeof(path);
1593 if (nBufferLength < len)
1594 return WINPR_ASSERTING_INT_CAST(DWORD, len);
1596 memcpy(lpBuffer, path, len);