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);
113#define log_error(fkt, file) log_error_((fkt), (file), __FILE__, __func__, __LINE__)
114static BOOL log_error_(
const char* name,
const WINPR_FILE* pFile,
const char* file,
const char* fkt,
117 char ebuffer[256] = { 0 };
124 const DWORD level = WLOG_ERROR;
125 static wLog* log = NULL;
129 if (WLog_IsLevelActive(log, level))
131 WLog_PrintTextMessage(log, level, line, file, fkt,
"%s %s failed with %s [0x08%x]", name,
132 pFile->lpFileName, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
133 WINPR_CXX_COMPAT_CAST(
unsigned, errno));
135 SetLastError(map_posix_err(errno));
139static BOOL FileSetEndOfFile(HANDLE hFile)
141 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
146 const INT64 size = _ftelli64(pFile->fp);
150 if (ftruncate(fileno(pFile->fp), (off_t)size) < 0)
151 return log_error(
"ftruncate", pFile);
157static DWORD FileSetFilePointer(HANDLE hFile, LONG lDistanceToMove,
158 const PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
161 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
166 return INVALID_SET_FILE_POINTER;
170 if (lpDistanceToMoveHigh)
172 offset = (INT64)(((UINT64)*lpDistanceToMoveHigh << 32U) | (UINT64)lDistanceToMove);
175 offset = lDistanceToMove;
177 switch (dwMoveMethod)
189 return INVALID_SET_FILE_POINTER;
192 if (_fseeki64(pFile->fp, offset, whence))
194 (void)log_error(
"_fseeki64", pFile);
195 return INVALID_SET_FILE_POINTER;
198 return (DWORD)_ftelli64(pFile->fp);
201static BOOL FileSetFilePointerEx(HANDLE hFile,
LARGE_INTEGER liDistanceToMove,
202 PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
204 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
210 switch (dwMoveMethod)
225 if (_fseeki64(pFile->fp, liDistanceToMove.QuadPart, whence))
226 return log_error(
"_fseeki64", pFile);
228 if (lpNewFilePointer)
229 lpNewFilePointer->QuadPart = _ftelli64(pFile->fp);
234static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
237 size_t io_status = 0;
238 WINPR_FILE* file = NULL;
243 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
244 SetLastError(ERROR_NOT_SUPPORTED);
251 file = (WINPR_FILE*)Object;
253 io_status = fread(lpBuffer, 1, nNumberOfBytesToRead, file->fp);
255 if (io_status == 0 && ferror(file->fp))
262 SetLastError(ERROR_NO_DATA);
265 SetLastError(map_posix_err(errno));
269 if (lpNumberOfBytesRead)
270 *lpNumberOfBytesRead = (DWORD)io_status;
275static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
276 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
278 size_t io_status = 0;
279 WINPR_FILE* file = NULL;
283 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
284 SetLastError(ERROR_NOT_SUPPORTED);
291 file = (WINPR_FILE*)Object;
294 io_status = fwrite(lpBuffer, 1, nNumberOfBytesToWrite, file->fp);
295 if (io_status == 0 && ferror(file->fp))
297 SetLastError(map_posix_err(errno));
301 *lpNumberOfBytesWritten = (DWORD)io_status;
305static DWORD FileGetFileSize(HANDLE Object, LPDWORD lpFileSizeHigh)
307 WINPR_FILE* file = NULL;
314 file = (WINPR_FILE*)Object;
316 cur = _ftelli64(file->fp);
320 (void)log_error(
"_ftelli64", file);
321 return INVALID_FILE_SIZE;
324 if (_fseeki64(file->fp, 0, SEEK_END) != 0)
326 (void)log_error(
"_fseeki64", file);
327 return INVALID_FILE_SIZE;
330 size = _ftelli64(file->fp);
334 (void)log_error(
"_ftelli64", file);
335 return INVALID_FILE_SIZE;
338 if (_fseeki64(file->fp, cur, SEEK_SET) != 0)
340 (void)log_error(
"_fseeki64", file);
341 return INVALID_FILE_SIZE;
345 *lpFileSizeHigh = (UINT32)(size >> 32);
347 return (UINT32)(size & 0xFFFFFFFF);
350static BOOL FileFlushFileBuffers(HANDLE hFile)
352 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
356 SetLastError(ERROR_INVALID_HANDLE);
361 if ((pFile->dwOpenMode & GENERIC_WRITE) == 0)
363 SetLastError(ERROR_ACCESS_DENIED);
367 if (fflush(pFile->fp) != 0)
369 SetLastError(map_posix_err(errno));
376static BOOL FileGetFileInformationByHandle(HANDLE hFile,
379 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
382 const char* lastSep = NULL;
386 if (!lpFileInformation)
389 if (fstat(fileno(pFile->fp), &st) == -1)
390 return log_error(
"fstat", pFile);
392 lpFileInformation->dwFileAttributes = 0;
394 if (S_ISDIR(st.st_mode))
395 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
397 if (lpFileInformation->dwFileAttributes == 0)
398 lpFileInformation->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
400 lastSep = strrchr(pFile->lpFileName,
'/');
404 const char* name = lastSep + 1;
405 const size_t namelen = strlen(name);
407 if ((namelen > 1) && (name[0] ==
'.') && (name[1] !=
'.'))
408 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
411 if (!(st.st_mode & S_IWUSR))
412 lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
414#ifdef _DARWIN_FEATURE_64_BIT_INODE
415 ft = STAT_TIME_TO_FILETIME(st.st_birthtime);
417 ft = STAT_TIME_TO_FILETIME(st.st_ctime);
419 lpFileInformation->ftCreationTime.dwHighDateTime = (ft) >> 32ULL;
420 lpFileInformation->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
421 ft = STAT_TIME_TO_FILETIME(st.st_mtime);
422 lpFileInformation->ftLastWriteTime.dwHighDateTime = (ft) >> 32ULL;
423 lpFileInformation->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
424 ft = STAT_TIME_TO_FILETIME(st.st_atime);
425 lpFileInformation->ftLastAccessTime.dwHighDateTime = (ft) >> 32ULL;
426 lpFileInformation->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
427 lpFileInformation->nFileSizeHigh = ((UINT64)st.st_size) >> 32ULL;
428 lpFileInformation->nFileSizeLow = st.st_size & 0xFFFFFFFF;
429 lpFileInformation->dwVolumeSerialNumber = (UINT32)st.st_dev;
430 lpFileInformation->nNumberOfLinks = (UINT32)st.st_nlink;
431 lpFileInformation->nFileIndexHigh = (st.st_ino >> 4) & 0xFFFFFFFF;
432 lpFileInformation->nFileIndexLow = st.st_ino & 0xFFFFFFFF;
436static BOOL FileLockFileEx(HANDLE hFile, DWORD dwFlags, WINPR_ATTR_UNUSED DWORD dwReserved,
437 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockLow,
438 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToLockHigh,
447 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
451 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
452 SetLastError(ERROR_NOT_SUPPORTED);
461 WLog_ERR(TAG,
"File %s already locked!", pFile->lpFileName);
468 lock.l_whence = SEEK_SET;
470 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
471 lock.l_type = F_WRLCK;
473 lock.l_type = F_WRLCK;
475 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
480 if (fcntl(fileno(pFile->fp), lckcmd, &lock) == -1)
482 char ebuffer[256] = { 0 };
483 WLog_ERR(TAG,
"F_SETLK failed with %s [0x%08X]",
484 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
485 SetLastError(map_posix_err(errno));
489 if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
494 if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
497 if (flock(fileno(pFile->fp), lock) < 0)
498 return log_error(
"flock", pFile);
501 pFile->bLocked = TRUE;
506static BOOL FileUnlockFile(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwFileOffsetLow,
507 WINPR_ATTR_UNUSED DWORD dwFileOffsetHigh,
508 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
509 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh)
511 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
521 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
528 lock.l_whence = SEEK_SET;
529 lock.l_type = F_UNLCK;
530 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
531 return log_error(
"F_GETLK", pFile);
534 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
535 return log_error(
"flock", pFile);
541static BOOL FileUnlockFileEx(HANDLE hFile, WINPR_ATTR_UNUSED DWORD dwReserved,
542 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockLow,
543 WINPR_ATTR_UNUSED DWORD nNumberOfBytesToUnlockHigh,
546 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
553 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
554 SetLastError(ERROR_NOT_SUPPORTED);
563 WLog_ERR(TAG,
"File %s is not locked!", pFile->lpFileName);
570 lock.l_whence = SEEK_SET;
571 lock.l_type = F_UNLCK;
572 if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
573 return log_error(
"F_GETLK", pFile);
575 if (flock(fileno(pFile->fp), LOCK_UN) < 0)
576 return log_error(
"flock", pFile);
582static INT64 FileTimeToUS(
const FILETIME* ft)
584 const INT64 EPOCH_DIFF_US = EPOCH_DIFF * 1000000LL;
585 INT64 tmp = ((INT64)ft->dwHighDateTime) << 32 | ft->dwLowDateTime;
587 tmp -= EPOCH_DIFF_US;
591#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
592static struct timespec filetimeToTimespec(const
FILETIME* ftime)
595 INT64 tmp = FileTimeToUS(ftime);
596 struct timespec ts = { 0 };
597 ts.tv_sec = tmp / 1000000LL;
598 ts.tv_nsec = (tmp % 1000000LL) * 1000LL;
602static BOOL FileSetFileTime(HANDLE hFile, WINPR_ATTR_UNUSED
const FILETIME* lpCreationTime,
605 struct timespec times[2] = { { UTIME_OMIT, UTIME_OMIT },
606 { UTIME_OMIT, UTIME_OMIT } };
607 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
612 if (lpLastAccessTime)
613 times[0] = filetimeToTimespec(lpLastAccessTime);
616 times[1] = filetimeToTimespec(lpLastWriteTime);
619 const int rc = futimens(fileno(pFile->fp), times);
622 char ebuffer[256] = { 0 };
623 WLog_ERR(TAG,
"futimens failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
625 SetLastError(map_posix_err(errno));
631#elif defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) || defined(KFREEBSD)
632static struct timeval filetimeToTimeval(const
FILETIME* ftime)
635 UINT64 tmp = FileTimeToUS(ftime);
636 struct timeval tv = { 0 };
637 tv.tv_sec = tmp / 1000000ULL;
638 tv.tv_usec = tmp % 1000000ULL;
642static struct timeval statToTimeval(const struct stat* sval)
645 struct timeval tv = { 0 };
646#if defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
647 tv.tv_sec = sval->st_atime;
649 TIMESPEC_TO_TIMEVAL(&tv, &sval->st_atim);
651 TIMESPEC_TO_TIMEVAL(&tv, &sval->st_atimespec);
653#elif defined(ANDROID)
654 tv.tv_sec = sval->st_atime;
655 tv.tv_usec = sval->st_atimensec / 1000UL;
660static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
663 struct stat buf = { 0 };
665 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
670 const int rc = fstat(fileno(pFile->fp), &buf);
673 char ebuffer[256] = { 0 };
674 WLog_ERR(TAG,
"fstat failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
676 SetLastError(map_posix_err(errno));
680 struct timeval timevals[2] = { statToTimeval(&buf), statToTimeval(&buf) };
681 if (lpLastAccessTime)
682 timevals[0] = filetimeToTimeval(lpLastAccessTime);
685 timevals[1] = filetimeToTimeval(lpLastWriteTime);
689 const int res = utimes(pFile->lpFileName, timevals);
692 char ebuffer[256] = { 0 };
693 WLog_ERR(TAG,
"utimes failed: %s [%d]", winpr_strerror(errno, ebuffer,
sizeof(ebuffer)),
695 SetLastError(map_posix_err(errno));
703static BOOL FileSetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
706 WINPR_FILE* pFile = (WINPR_FILE*)hFile;
711 WLog_WARN(TAG,
"TODO: Creation, Access and Write time can not be handled!");
713 "TODO: Define _POSIX_C_SOURCE >= 200809L or implement a platform specific handler!");
730 FileFlushFileBuffers,
733 FileSetFilePointerEx,
739 FileGetFileInformationByHandle,
763 FileGetFileInformationByHandle,
766static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDisposition, BOOL* create)
768 BOOL writeable = (dwDesiredAccess & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
770 switch (dwCreationDisposition)
774 return (writeable) ?
"wb+" :
"rwb";
783 return (writeable) ?
"rb+" :
"rb";
784 case TRUNCATE_EXISTING:
793UINT32 map_posix_err(
int fs_errno)
809 rc = ERROR_FILE_NOT_FOUND;
815 rc = ERROR_ACCESS_DENIED;
819 rc = ERROR_FILE_NOT_FOUND;
823 rc = ERROR_BUSY_DRIVE;
827 rc = ERROR_FILE_EXISTS;
831 rc = STATUS_FILE_IS_A_DIRECTORY;
835 rc = STATUS_DIRECTORY_NOT_EMPTY;
839 rc = STATUS_TOO_MANY_OPENED_FILES;
844 char ebuffer[256] = { 0 };
845 WLog_ERR(TAG,
"Missing ERRNO mapping %s [%d]",
846 winpr_strerror(fs_errno, ebuffer,
sizeof(ebuffer)), fs_errno);
847 rc = STATUS_UNSUCCESSFUL;
855static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
856 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
857 DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
858 HANDLE hTemplateFile)
860 WINPR_FILE* pFile = NULL;
862 const char* mode = FileGetMode(dwDesiredAccess, dwCreationDisposition, &create);
871 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
873 WLog_ERR(TAG,
"WinPR does not support the FILE_FLAG_OVERLAPPED flag");
874 SetLastError(ERROR_NOT_SUPPORTED);
875 return INVALID_HANDLE_VALUE;
878 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
881 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
882 return INVALID_HANDLE_VALUE;
885 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
886 pFile->common.ops = &fileOps;
888 pFile->lpFileName = _strdup(lpFileName);
889 if (!pFile->lpFileName)
891 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
893 return INVALID_HANDLE_VALUE;
896 pFile->dwOpenMode = dwDesiredAccess;
897 pFile->dwShareMode = dwShareMode;
898 pFile->dwFlagsAndAttributes = dwFlagsAndAttributes;
899 pFile->lpSecurityAttributes = lpSecurityAttributes;
900 pFile->dwCreationDisposition = dwCreationDisposition;
901 pFile->hTemplateFile = hTemplateFile;
905 if (dwCreationDisposition == CREATE_NEW)
907 if (stat(pFile->lpFileName, &st) == 0)
909 SetLastError(ERROR_FILE_EXISTS);
910 free(pFile->lpFileName);
912 return INVALID_HANDLE_VALUE;
916 fp = winpr_fopen(pFile->lpFileName,
"ab");
919 SetLastError(map_posix_err(errno));
920 free(pFile->lpFileName);
922 return INVALID_HANDLE_VALUE;
925 fp = freopen(pFile->lpFileName, mode, fp);
929 if (stat(pFile->lpFileName, &st) != 0)
931 SetLastError(map_posix_err(errno));
932 free(pFile->lpFileName);
934 return INVALID_HANDLE_VALUE;
940 if (S_ISFIFO(st.st_mode))
942 SetLastError(ERROR_FILE_NOT_FOUND);
943 free(pFile->lpFileName);
945 return INVALID_HANDLE_VALUE;
950 fp = winpr_fopen(pFile->lpFileName, mode);
957 SetLastError(map_posix_err(errno));
958 free(pFile->lpFileName);
960 return INVALID_HANDLE_VALUE;
963 (void)setvbuf(fp, NULL, _IONBF, 0);
968 lock.l_whence = SEEK_SET;
970 if (dwShareMode & FILE_SHARE_READ)
971 lock.l_type = F_RDLCK;
972 if (dwShareMode & FILE_SHARE_WRITE)
973 lock.l_type = F_RDLCK;
975 if (dwShareMode & FILE_SHARE_READ)
977 if (dwShareMode & FILE_SHARE_WRITE)
981 if (dwShareMode & (FILE_SHARE_READ | FILE_SHARE_WRITE))
984 if (fcntl(fileno(pFile->fp), F_SETLKW, &lock) == -1)
986 if (flock(fileno(pFile->fp), lock) < 0)
990 (void)log_error(
"F_SETLKW", pFile);
992 (void)log_error(
"flock", pFile);
995 SetLastError(map_posix_err(errno));
996 FileCloseHandle(pFile);
997 return INVALID_HANDLE_VALUE;
1000 pFile->bLocked = TRUE;
1003 if (fstat(fileno(pFile->fp), &st) == 0 && dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1005 st.st_mode &= WINPR_ASSERTING_INT_CAST(mode_t, (mode_t)(~(S_IWUSR | S_IWGRP | S_IWOTH)));
1006 if (fchmod(fileno(pFile->fp), st.st_mode) != 0)
1008 SetLastError(map_posix_err(errno));
1009 FileCloseHandle(pFile);
1010 return INVALID_HANDLE_VALUE;
1014 SetLastError(STATUS_SUCCESS);
1018static BOOL IsFileDevice(WINPR_ATTR_UNUSED LPCTSTR lpDeviceName)
1023static const HANDLE_CREATOR FileHandleCreator = { IsFileDevice, FileCreateFileA };
1027 return &FileHandleCreator;
1030static WINPR_FILE* FileHandle_New(FILE* fp)
1032 WINPR_FILE* pFile = NULL;
1033 char name[MAX_PATH] = { 0 };
1035 (void)_snprintf(name,
sizeof(name),
"device_%d", fileno(fp));
1036 pFile = (WINPR_FILE*)calloc(1,
sizeof(WINPR_FILE));
1039 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1043 pFile->common.ops = &shmOps;
1044 pFile->lpFileName = _strdup(name);
1046 WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
1050void GetStdHandle_Uninit(
void)
1052 FileCloseHandleInt(pStdHandleFile, TRUE);
1055HANDLE GetStdHandle(DWORD nStdHandle)
1061 case STD_INPUT_HANDLE:
1064 case STD_OUTPUT_HANDLE:
1067 case STD_ERROR_HANDLE:
1071 return INVALID_HANDLE_VALUE;
1073 if (!pStdHandleFile)
1074 pStdHandleFile = FileHandle_New(fp);
1076 if (!pStdHandleFile)
1077 return INVALID_HANDLE_VALUE;
1079 return (HANDLE)pStdHandleFile;
1082BOOL SetStdHandle(WINPR_ATTR_UNUSED DWORD nStdHandle, WINPR_ATTR_UNUSED HANDLE hHandle)
1087BOOL SetStdHandleEx(WINPR_ATTR_UNUSED DWORD dwStdHandle, WINPR_ATTR_UNUSED HANDLE hNewHandle,
1088 WINPR_ATTR_UNUSED HANDLE* phOldHandle)
1093BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1094 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1097#define STATVFS statfs
1099#define STATVFS statvfs
1102 struct STATVFS svfst = { 0 };
1103 STATVFS(lpRootPathName, &svfst);
1104 *lpSectorsPerCluster = (UINT32)MIN(svfst.f_frsize, UINT32_MAX);
1105 *lpBytesPerSector = 1;
1106 *lpNumberOfFreeClusters = (UINT32)MIN(svfst.f_bavail, UINT32_MAX);
1107 *lpTotalNumberOfClusters = (UINT32)MIN(svfst.f_blocks, UINT32_MAX);
1111BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1112 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1113 LPDWORD lpTotalNumberOfClusters)
1116 if (!lpRootPathName)
1119 char* rootPathName = ConvertWCharToUtf8Alloc(lpRootPathName, NULL);
1122 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1125 ret = GetDiskFreeSpaceA(rootPathName, lpSectorsPerCluster, lpBytesPerSector,
1126 lpNumberOfFreeClusters, lpTotalNumberOfClusters);
1139BOOL ValidFileNameComponent(LPCWSTR lpFileName)
1145 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1146 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1147 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1148 (lpFileName[3] == L
'\0'))
1154 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'P' || lpFileName[0] == L
'p')) &&
1155 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'R' || lpFileName[1] == L
'r')) &&
1156 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'N' || lpFileName[2] == L
'n')) &&
1157 (lpFileName[3] == L
'\0'))
1163 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'A' || lpFileName[0] == L
'a')) &&
1164 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1165 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'X' || lpFileName[2] == L
'x')) &&
1166 (lpFileName[3] == L
'\0'))
1172 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'N' || lpFileName[0] == L
'n')) &&
1173 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'U' || lpFileName[1] == L
'u')) &&
1174 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'L' || lpFileName[2] == L
'l')) &&
1175 (lpFileName[3] == L
'\0'))
1181 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'L' || lpFileName[0] == L
'l')) &&
1182 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'P' || lpFileName[1] == L
'p')) &&
1183 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'T' || lpFileName[2] == L
't')) &&
1184 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1185 (lpFileName[4] == L
'\0'))
1191 if ((lpFileName[0] != L
'\0' && (lpFileName[0] == L
'C' || lpFileName[0] == L
'c')) &&
1192 (lpFileName[1] != L
'\0' && (lpFileName[1] == L
'O' || lpFileName[1] == L
'o')) &&
1193 (lpFileName[2] != L
'\0' && (lpFileName[2] == L
'M' || lpFileName[2] == L
'm')) &&
1194 (lpFileName[3] != L
'\0' && (L
'0' <= lpFileName[3] && lpFileName[3] <= L
'9')) &&
1195 (lpFileName[4] == L
'\0'))
1201 for (LPCWSTR c = lpFileName; *c; c++)
1203 if ((*c == L
'<') || (*c == L
'>') || (*c == L
':') || (*c == L
'"') || (*c == L
'/') ||
1204 (*c == L
'\\') || (*c == L
'|') || (*c == L
'?') || (*c == L
'*'))
1215HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1216 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1217 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1220 CREATEFILE2_EXTENDED_PARAMETERS params = { 0 };
1222 params.dwSize =
sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
1224 if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
1225 params.dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
1226 if (dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
1227 params.dwFileFlags |= FILE_FLAG_DELETE_ON_CLOSE;
1228 if (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
1229 params.dwFileFlags |= FILE_FLAG_NO_BUFFERING;
1230 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
1231 params.dwFileFlags |= FILE_FLAG_OPEN_NO_RECALL;
1232 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
1233 params.dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
1234 if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REQUIRING_OPLOCK)
1235 params.dwFileFlags |= FILE_FLAG_OPEN_REQUIRING_OPLOCK;
1236 if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
1237 params.dwFileFlags |= FILE_FLAG_OVERLAPPED;
1238 if (dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS)
1239 params.dwFileFlags |= FILE_FLAG_POSIX_SEMANTICS;
1240 if (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
1241 params.dwFileFlags |= FILE_FLAG_RANDOM_ACCESS;
1242 if (dwFlagsAndAttributes & FILE_FLAG_SESSION_AWARE)
1243 params.dwFileFlags |= FILE_FLAG_SESSION_AWARE;
1244 if (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
1245 params.dwFileFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
1246 if (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
1247 params.dwFileFlags |= FILE_FLAG_WRITE_THROUGH;
1249 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ARCHIVE)
1250 params.dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1251 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_COMPRESSED)
1252 params.dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
1253 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DEVICE)
1254 params.dwFileAttributes |= FILE_ATTRIBUTE_DEVICE;
1255 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY)
1256 params.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1257 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ENCRYPTED)
1258 params.dwFileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
1259 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_HIDDEN)
1260 params.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1261 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM)
1262 params.dwFileAttributes |= FILE_ATTRIBUTE_INTEGRITY_STREAM;
1263 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NORMAL)
1264 params.dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
1265 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
1266 params.dwFileAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1267 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA)
1268 params.dwFileAttributes |= FILE_ATTRIBUTE_NO_SCRUB_DATA;
1269 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_OFFLINE)
1270 params.dwFileAttributes |= FILE_ATTRIBUTE_OFFLINE;
1271 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1272 params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1273 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1274 params.dwFileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
1275 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SPARSE_FILE)
1276 params.dwFileAttributes |= FILE_ATTRIBUTE_SPARSE_FILE;
1277 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SYSTEM)
1278 params.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
1279 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY)
1280 params.dwFileAttributes |= FILE_ATTRIBUTE_TEMPORARY;
1281 if (dwFlagsAndAttributes & FILE_ATTRIBUTE_VIRTUAL)
1282 params.dwFileAttributes |= FILE_ATTRIBUTE_VIRTUAL;
1284 if (dwFlagsAndAttributes & SECURITY_ANONYMOUS)
1285 params.dwSecurityQosFlags |= SECURITY_ANONYMOUS;
1286 if (dwFlagsAndAttributes & SECURITY_CONTEXT_TRACKING)
1287 params.dwSecurityQosFlags |= SECURITY_CONTEXT_TRACKING;
1288 if (dwFlagsAndAttributes & SECURITY_DELEGATION)
1289 params.dwSecurityQosFlags |= SECURITY_DELEGATION;
1290 if (dwFlagsAndAttributes & SECURITY_EFFECTIVE_ONLY)
1291 params.dwSecurityQosFlags |= SECURITY_EFFECTIVE_ONLY;
1292 if (dwFlagsAndAttributes & SECURITY_IDENTIFICATION)
1293 params.dwSecurityQosFlags |= SECURITY_IDENTIFICATION;
1294 if (dwFlagsAndAttributes & SECURITY_IMPERSONATION)
1295 params.dwSecurityQosFlags |= SECURITY_IMPERSONATION;
1297 params.lpSecurityAttributes = lpSecurityAttributes;
1298 params.hTemplateFile = hTemplateFile;
1300 hFile = CreateFile2(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, ¶ms);
1305HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1306 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1307 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1313 WCHAR* lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
1318 hFile = CreateFileW(lpFileNameW, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1319 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1326DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
1331 if (!lpFileSizeHigh)
1332 return INVALID_FILE_SIZE;
1334 status = GetFileSizeEx(hFile, &fileSize);
1337 return INVALID_FILE_SIZE;
1339 *lpFileSizeHigh = fileSize.HighPart;
1341 return fileSize.LowPart;
1344DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
1351 liDistanceToMove.LowPart = lDistanceToMove;
1353 status = SetFilePointerEx(hFile, liDistanceToMove, &liNewFilePointer, dwMoveMethod);
1356 return INVALID_SET_FILE_POINTER;
1358 if (lpDistanceToMoveHigh)
1359 *lpDistanceToMoveHigh = liNewFilePointer.HighPart;
1361 return liNewFilePointer.LowPart;
1366 return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1372 return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1376DWORD GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart)
1379 WCHAR* lpFileNameW = NULL;
1380 WCHAR* lpBufferW = NULL;
1381 WCHAR* lpFilePartW = NULL;
1382 DWORD nBufferLengthW = nBufferLength *
sizeof(WCHAR);
1384 if (!lpFileName || (nBufferLength < 1))
1387 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
1391 lpBufferW = (WCHAR*)malloc(nBufferLengthW);
1396 dwStatus = GetFullPathNameW(lpFileNameW, nBufferLengthW, lpBufferW, &lpFilePartW);
1398 (void)ConvertWCharNToUtf8(lpBufferW, nBufferLengthW /
sizeof(WCHAR), lpBuffer, nBufferLength);
1401 lpFilePart = lpBuffer + (lpFilePartW - lpBufferW);
1406 return dwStatus * 2;
1409BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1410 LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1417 status = GetDiskFreeSpaceExA(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1418 &TotalNumberOfFreeBytes);
1423 *lpBytesPerSector = 1;
1424 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1425 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1426 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1431BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1432 LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1433 LPDWORD lpTotalNumberOfClusters)
1440 status = GetDiskFreeSpaceExW(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1441 &TotalNumberOfFreeBytes);
1446 *lpBytesPerSector = 1;
1447 *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1448 *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1449 *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1454DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1456 SetLastError(ERROR_INVALID_FUNCTION);
1460DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1462 SetLastError(ERROR_INVALID_FUNCTION);
1466BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
1484HANDLE GetFileHandleForFileDescriptor(
int fd)
1487 return (HANDLE)_get_osfhandle(fd);
1489 WINPR_FILE* pFile = NULL;
1494 if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
1495 return INVALID_HANDLE_VALUE;
1497 flags = fcntl(fd, F_GETFL);
1499 return INVALID_HANDLE_VALUE;
1501 if (flags & O_WRONLY)
1502 fp = fdopen(fd,
"wb");
1504 fp = fdopen(fd,
"rb");
1507 return INVALID_HANDLE_VALUE;
1509 (void)setvbuf(fp, NULL, _IONBF, 0);
1512 pFile = FileHandle_New(fp);
1514 return INVALID_HANDLE_VALUE;
1516 return (HANDLE)pFile;
1520FILE* winpr_fopen(
const char* path,
const char* mode)
1523 return fopen(path, mode);
1525 LPWSTR lpPathW = NULL;
1526 LPWSTR lpModeW = NULL;
1527 FILE* result = NULL;
1532 lpPathW = ConvertUtf8ToWCharAlloc(path, NULL);
1536 lpModeW = ConvertUtf8ToWCharAlloc(mode, NULL);
1540 result = _wfopen(lpPathW, lpModeW);
1549#if !defined(_UWP) && !defined(_WIN32)
1550DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1552 char* buffer = NULL;
1553 if (nBufferLength > 0)
1555 buffer = calloc(nBufferLength,
sizeof(
char));
1560 const DWORD rc = GetLogicalDriveStringsA(nBufferLength, buffer);
1562 ConvertMszUtf8NToWChar(buffer, rc, lpBuffer, nBufferLength);
1567DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1573 const char path[] =
"/\0";
1574 const size_t len =
sizeof(path);
1575 if (nBufferLength < len)
1576 return WINPR_ASSERTING_INT_CAST(DWORD, len);
1578 memcpy(lpBuffer, path, len);