22#include <winpr/config.h>
25#include <winpr/wlog.h>
26#include <winpr/string.h>
27#include <winpr/path.h>
28#include <winpr/file.h>
30#ifdef WINPR_HAVE_UNISTD_H
34#ifdef WINPR_HAVE_FCNTL_H
39#define TAG WINPR_TAG("file")
45#include <winpr/assert.h>
54#include <sys/socket.h>
55#if defined(WINPR_HAVE_SYS_XATTR_H)
58#if defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
59#include <linux/msdos_fs.h>
62#ifdef WINPR_HAVE_AIO_H
63#undef WINPR_HAVE_AIO_H
66#ifdef WINPR_HAVE_AIO_H
73#include <sys/statvfs.h>
76#include "../handle/handle.h"
78#include "../pipe/pipe.h"
79#include "../path/path.h"
186static wArrayList* HandleCreators;
188static pthread_once_t HandleCreatorsInitialized = PTHREAD_ONCE_INIT;
190#include "../comm/comm.h"
191#include "namedPipeClient.h"
193static DWORD FileAttributesFromStat(
const char* path,
const struct stat* fileStat);
194static BOOL FindDataFromStat(
const char* path,
const struct stat* fileStat,
196static void SetDosAttributesToXAttr(
const char* path, DWORD dwFileAttributes);
198static void HandleCreatorsInit(
void)
200 WINPR_ASSERT(HandleCreators ==
nullptr);
201 HandleCreators = ArrayList_New(TRUE);
209 ArrayList_Append(HandleCreators, GetNamedPipeClientHandleCreator());
212 ArrayList_Append(HandleCreators, serial);
213 ArrayList_Append(HandleCreators, GetFileHandleCreator());
216#ifdef WINPR_HAVE_AIO_H
218static BOOL g_AioSignalHandlerInstalled = FALSE;
220void AioSignalHandler(
int signum, siginfo_t* siginfo,
void* arg)
222 WLog_INFO(
"%d", signum);
225int InstallAioSignalHandler()
227 if (!g_AioSignalHandlerInstalled)
229 struct sigaction action;
230 sigemptyset(&action.sa_mask);
231 sigaddset(&action.sa_mask, SIGIO);
232 action.sa_flags = SA_SIGINFO;
233 action.sa_sigaction = (
void*)&AioSignalHandler;
234 sigaction(SIGIO, &action,
nullptr);
235 g_AioSignalHandlerInstalled = TRUE;
243#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
244HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
245 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
246 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
248 return winpr_CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
249 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
253HANDLE winpr_CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
254 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
255 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
258 return INVALID_HANDLE_VALUE;
260 if (pthread_once(&HandleCreatorsInitialized, HandleCreatorsInit) != 0)
262 SetLastError(ERROR_DLL_INIT_FAILED);
263 return INVALID_HANDLE_VALUE;
266 if (HandleCreators ==
nullptr)
268 SetLastError(ERROR_DLL_INIT_FAILED);
269 return INVALID_HANDLE_VALUE;
272 ArrayList_Lock(HandleCreators);
274 for (
size_t i = 0; i <= ArrayList_Count(HandleCreators); i++)
276 const HANDLE_CREATOR* creator = ArrayList_GetItem(HandleCreators, i);
278 if (creator && creator->IsHandled(lpFileName))
281 creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
282 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
283 ArrayList_Unlock(HandleCreators);
288 ArrayList_Unlock(HandleCreators);
289 return INVALID_HANDLE_VALUE;
292HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
293 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
294 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
296 HANDLE hdl =
nullptr;
299 char* lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
303 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
307 hdl = winpr_CreateFile(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
308 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
314#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
315BOOL DeleteFileA(LPCSTR lpFileName)
317 return winpr_DeleteFile(lpFileName);
321BOOL DeleteFileW(LPCWSTR lpFileName)
325 LPSTR lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
326 BOOL rc = winpr_DeleteFile(lpFileNameA);
331BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
337 if (hFile == INVALID_HANDLE_VALUE)
345 if (!lpNumberOfBytesRead && !lpOverlapped)
348 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
353 if (handle->ops->ReadFile)
354 return handle->ops->ReadFile(handle, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
357 WLog_ERR(TAG,
"ReadFile operation not implemented");
361BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
362 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
367 if (hFile == INVALID_HANDLE_VALUE)
370 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
375 if (handle->ops->ReadFileEx)
376 return handle->ops->ReadFileEx(handle, lpBuffer, nNumberOfBytesToRead, lpOverlapped,
377 lpCompletionRoutine);
379 WLog_ERR(TAG,
"ReadFileEx operation not implemented");
383BOOL ReadFileScatter(HANDLE hFile,
FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead,
389 if (hFile == INVALID_HANDLE_VALUE)
392 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
397 if (handle->ops->ReadFileScatter)
398 return handle->ops->ReadFileScatter(handle, aSegmentArray, nNumberOfBytesToRead, lpReserved,
401 WLog_ERR(TAG,
"ReadFileScatter operation not implemented");
405BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
406 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
411 if (hFile == INVALID_HANDLE_VALUE)
414 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
419 if (handle->ops->WriteFile)
420 return handle->ops->WriteFile(handle, lpBuffer, nNumberOfBytesToWrite,
421 lpNumberOfBytesWritten, lpOverlapped);
423 WLog_ERR(TAG,
"WriteFile operation not implemented");
427BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
428 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
433 if (hFile == INVALID_HANDLE_VALUE)
436 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
441 if (handle->ops->WriteFileEx)
442 return handle->ops->WriteFileEx(handle, lpBuffer, nNumberOfBytesToWrite, lpOverlapped,
443 lpCompletionRoutine);
445 WLog_ERR(TAG,
"WriteFileEx operation not implemented");
450 DWORD nNumberOfBytesToWrite, LPDWORD lpReserved,
LPOVERLAPPED lpOverlapped)
455 if (hFile == INVALID_HANDLE_VALUE)
458 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
463 if (handle->ops->WriteFileGather)
464 return handle->ops->WriteFileGather(handle, aSegmentArray, nNumberOfBytesToWrite,
465 lpReserved, lpOverlapped);
467 WLog_ERR(TAG,
"WriteFileGather operation not implemented");
471BOOL FlushFileBuffers(HANDLE hFile)
476 if (hFile == INVALID_HANDLE_VALUE)
479 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
484 if (handle->ops->FlushFileBuffers)
485 return handle->ops->FlushFileBuffers(handle);
487 WLog_ERR(TAG,
"FlushFileBuffers operation not implemented");
491BOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,
492 WINPR_ATTR_UNUSED GET_FILEEX_INFO_LEVELS fInfoLevelId,
493 LPVOID lpFileInformation)
499 struct stat fileStat = WINPR_C_ARRAY_INIT;
500 if (stat(lpFileName, &fileStat) != 0)
504 if (!FindDataFromStat(lpFileName, &fileStat, &findFileData))
507 fd->dwFileAttributes = findFileData.dwFileAttributes;
508 fd->ftCreationTime = findFileData.ftCreationTime;
509 fd->ftLastAccessTime = findFileData.ftLastAccessTime;
510 fd->ftLastWriteTime = findFileData.ftLastWriteTime;
511 fd->nFileSizeHigh = findFileData.nFileSizeHigh;
512 fd->nFileSizeLow = findFileData.nFileSizeLow;
516BOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
517 LPVOID lpFileInformation)
522 LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
526 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
530 ret = GetFileAttributesExA(lpCFileName, fInfoLevelId, lpFileInformation);
535DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
537 struct stat fileStat = WINPR_C_ARRAY_INIT;
538 if (stat(lpFileName, &fileStat) != 0)
539 return INVALID_FILE_ATTRIBUTES;
541 return FileAttributesFromStat(lpFileName, &fileStat);
544DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
549 LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
552 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
556 ret = GetFileAttributesA(lpCFileName);
566 if (hFile == INVALID_HANDLE_VALUE)
569 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
574 if (handle->ops->GetFileInformationByHandle)
575 return handle->ops->GetFileInformationByHandle(handle, lpFileInformation);
577 WLog_ERR(TAG,
"GetFileInformationByHandle operation not implemented");
581static char* append(
char* buffer,
size_t size,
const char* append)
583 winpr_str_append(append, buffer, size,
"|");
587static const char* flagsToStr(
char* buffer,
size_t size, DWORD flags)
589 char strflags[32] = WINPR_C_ARRAY_INIT;
590 if (flags & FILE_ATTRIBUTE_READONLY)
591 append(buffer, size,
"FILE_ATTRIBUTE_READONLY");
592 if (flags & FILE_ATTRIBUTE_HIDDEN)
593 append(buffer, size,
"FILE_ATTRIBUTE_HIDDEN");
594 if (flags & FILE_ATTRIBUTE_SYSTEM)
595 append(buffer, size,
"FILE_ATTRIBUTE_SYSTEM");
596 if (flags & FILE_ATTRIBUTE_DIRECTORY)
597 append(buffer, size,
"FILE_ATTRIBUTE_DIRECTORY");
598 if (flags & FILE_ATTRIBUTE_ARCHIVE)
599 append(buffer, size,
"FILE_ATTRIBUTE_ARCHIVE");
600 if (flags & FILE_ATTRIBUTE_DEVICE)
601 append(buffer, size,
"FILE_ATTRIBUTE_DEVICE");
602 if (flags & FILE_ATTRIBUTE_NORMAL)
603 append(buffer, size,
"FILE_ATTRIBUTE_NORMAL");
604 if (flags & FILE_ATTRIBUTE_TEMPORARY)
605 append(buffer, size,
"FILE_ATTRIBUTE_TEMPORARY");
606 if (flags & FILE_ATTRIBUTE_SPARSE_FILE)
607 append(buffer, size,
"FILE_ATTRIBUTE_SPARSE_FILE");
608 if (flags & FILE_ATTRIBUTE_REPARSE_POINT)
609 append(buffer, size,
"FILE_ATTRIBUTE_REPARSE_POINT");
610 if (flags & FILE_ATTRIBUTE_COMPRESSED)
611 append(buffer, size,
"FILE_ATTRIBUTE_COMPRESSED");
612 if (flags & FILE_ATTRIBUTE_OFFLINE)
613 append(buffer, size,
"FILE_ATTRIBUTE_OFFLINE");
614 if (flags & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
615 append(buffer, size,
"FILE_ATTRIBUTE_NOT_CONTENT_INDEXED");
616 if (flags & FILE_ATTRIBUTE_ENCRYPTED)
617 append(buffer, size,
"FILE_ATTRIBUTE_ENCRYPTED");
618 if (flags & FILE_ATTRIBUTE_VIRTUAL)
619 append(buffer, size,
"FILE_ATTRIBUTE_VIRTUAL");
621 (void)_snprintf(strflags,
sizeof(strflags),
" [0x%08" PRIx32
"]", flags);
622 winpr_str_append(strflags, buffer, size,
nullptr);
626BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
629#ifdef WINPR_HAVE_FCNTL_H
630 const uint32_t mask = ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_NORMAL |
631 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
632 if (dwFileAttributes & mask)
634 char buffer[8192] = WINPR_C_ARRAY_INIT;
635 const char* flags = flagsToStr(buffer,
sizeof(buffer), dwFileAttributes & mask);
636 WLog_WARN(TAG,
"Unsupported flags %s, ignoring!", flags);
639 SetDosAttributesToXAttr(lpFileName, dwFileAttributes);
641 int fd = open(lpFileName, O_RDONLY);
645 struct stat st = WINPR_C_ARRAY_INIT;
646 if (fstat(fd, &st) != 0)
649 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
651 st.st_mode &= WINPR_ASSERTING_INT_CAST(mode_t, (mode_t)(~(S_IWUSR | S_IWGRP | S_IWOTH)));
655 st.st_mode |= S_IWUSR;
658 if (fchmod(fd, st.st_mode) != 0)
668BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
675 char* lpCFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
678 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
682 ret = SetFileAttributesA(lpCFileName, dwFileAttributes);
687BOOL SetEndOfFile(HANDLE hFile)
692 if (hFile == INVALID_HANDLE_VALUE)
695 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
700 if (handle->ops->SetEndOfFile)
701 return handle->ops->SetEndOfFile(handle);
703 WLog_ERR(TAG,
"SetEndOfFile operation not implemented");
707DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
712 if (hFile == INVALID_HANDLE_VALUE)
715 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
720 if (handle->ops->GetFileSize)
721 return handle->ops->GetFileSize(handle, lpFileSizeHigh);
723 WLog_ERR(TAG,
"GetFileSize operation not implemented");
727DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
733 if (hFile == INVALID_HANDLE_VALUE)
736 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
741 if (handle->ops->SetFilePointer)
742 return handle->ops->SetFilePointer(handle, lDistanceToMove, lpDistanceToMoveHigh,
745 WLog_ERR(TAG,
"SetFilePointer operation not implemented");
749BOOL SetFilePointerEx(HANDLE hFile,
LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
755 if (hFile == INVALID_HANDLE_VALUE)
758 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
763 if (handle->ops->SetFilePointerEx)
764 return handle->ops->SetFilePointerEx(handle, liDistanceToMove, lpNewFilePointer,
767 WLog_ERR(TAG,
"SetFilePointerEx operation not implemented");
771BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
772 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh)
777 if (hFile == INVALID_HANDLE_VALUE)
780 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
785 if (handle->ops->LockFile)
786 return handle->ops->LockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
787 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
789 WLog_ERR(TAG,
"LockFile operation not implemented");
793BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow,
794 DWORD nNumberOfBytesToLockHigh,
LPOVERLAPPED lpOverlapped)
799 if (hFile == INVALID_HANDLE_VALUE)
802 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
807 if (handle->ops->LockFileEx)
808 return handle->ops->LockFileEx(handle, dwFlags, dwReserved, nNumberOfBytesToLockLow,
809 nNumberOfBytesToLockHigh, lpOverlapped);
811 WLog_ERR(TAG,
"LockFileEx operation not implemented");
815BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
816 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
821 if (hFile == INVALID_HANDLE_VALUE)
824 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
829 if (handle->ops->UnlockFile)
830 return handle->ops->UnlockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
831 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
833 WLog_ERR(TAG,
"UnLockFile operation not implemented");
837BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow,
838 DWORD nNumberOfBytesToUnlockHigh,
LPOVERLAPPED lpOverlapped)
843 if (hFile == INVALID_HANDLE_VALUE)
846 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
851 if (handle->ops->UnlockFileEx)
852 return handle->ops->UnlockFileEx(handle, dwReserved, nNumberOfBytesToUnlockLow,
853 nNumberOfBytesToUnlockHigh, lpOverlapped);
855 WLog_ERR(TAG,
"UnLockFileEx operation not implemented");
859BOOL WINAPI SetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
865 if (hFile == INVALID_HANDLE_VALUE)
868 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
873 if (handle->ops->SetFileTime)
874 return handle->ops->SetFileTime(handle, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
876 WLog_ERR(TAG,
"operation not implemented");
888static const char file_search_magic[] =
"file_srch_magic";
890WINPR_ATTR_MALLOC(FindClose, 1)
891static WIN32_FILE_SEARCH* file_search_new(const
char* name,
size_t namelen, const
char* pattern,
894 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)calloc(1,
sizeof(WIN32_FILE_SEARCH));
897 WINPR_ASSERT(
sizeof(file_search_magic) ==
sizeof(pFileSearch->magic));
898 memcpy(pFileSearch->magic, file_search_magic,
sizeof(pFileSearch->magic));
900 pFileSearch->lpPath = strndup(name, namelen);
901 pFileSearch->lpPattern = strndup(pattern, patternlen);
902 if (!pFileSearch->lpPath || !pFileSearch->lpPattern)
905 pFileSearch->pDir = opendir(pFileSearch->lpPath);
906 if (!pFileSearch->pDir)
912 struct stat fileStat = WINPR_C_ARRAY_INIT;
913 if (stat(name, &fileStat) == 0)
915 if (S_ISDIR(fileStat.st_mode))
917 pFileSearch->pDir = opendir(name);
918 if (pFileSearch->pDir)
920 free(pFileSearch->lpPath);
921 free(pFileSearch->lpPattern);
922 pFileSearch->lpPath = _strdup(name);
923 pFileSearch->lpPattern = _strdup(
"*");
924 if (!pFileSearch->lpPath || !pFileSearch->lpPattern)
926 closedir(pFileSearch->pDir);
927 pFileSearch->pDir =
nullptr;
934 char buffer[128] = WINPR_C_ARRAY_INIT;
935 const DWORD err = map_posix_err(errno);
936 WLog_DBG(TAG,
"stat failed with %s [%d] -> %s",
937 winpr_strerror(errno, buffer,
sizeof(buffer)), errno,
938 Win32ErrorCode2Tag(err & 0xFFFF));
942 if (!pFileSearch->pDir)
947 WINPR_PRAGMA_DIAG_PUSH
948 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
949 FindClose(pFileSearch);
950 WINPR_PRAGMA_DIAG_POP
954static BOOL is_valid_file_search_handle(HANDLE handle)
956 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)handle;
959 if (pFileSearch == INVALID_HANDLE_VALUE)
961 if (strncmp(file_search_magic, pFileSearch->magic,
sizeof(file_search_magic)) != 0)
966static DWORD GetDosAttributesFromXAttr(WINPR_ATTR_UNUSED
const char* path)
968#if defined(WINPR_HAVE_SYS_XATTR_H) || defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
969 DWORD dwFileAttributes = 0;
970 uint32_t intAttr = 0;
972 const DWORD supportedMask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
973 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY |
974 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL;
976#if defined(WINPR_HAVE_SYS_XATTR_H)
977 length = getxattr(path,
"system.ntfs_attrib_be", &intAttr,
sizeof(intAttr));
980 intAttr = ntohl(intAttr);
981 dwFileAttributes = intAttr;
985#if defined(WINPR_HAVE_SYS_XATTR_H)
986 if ((dwFileAttributes & supportedMask) == 0)
988 length = getxattr(path,
"user.cifs.dosattrib", &intAttr,
sizeof(intAttr));
990 dwFileAttributes = intAttr;
994 if ((dwFileAttributes & supportedMask) == 0)
996#if defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
997 int fd = open(path, O_RDONLY | O_CLOEXEC);
1000 const int rc = ioctl(fd, FAT_IOCTL_GET_ATTRIBUTES, &intAttr);
1003 char buffer[64] = WINPR_C_ARRAY_INIT;
1004 WLog_WARN(TAG,
"ioctl(%d, FAT_IOCTL_GET_ATTRIBUTES) failed with %s", fd,
1005 winpr_strerror(errno, buffer,
sizeof(buffer)));
1008 dwFileAttributes = intAttr;
1010 const int crc = close(fd);
1013 char buffer[64] = WINPR_C_ARRAY_INIT;
1014 WLog_WARN(TAG,
"close(%d) failed with %s", fd,
1015 winpr_strerror(errno, buffer,
sizeof(buffer)));
1021#if defined(WINPR_HAVE_SYS_XATTR_H)
1022 if ((dwFileAttributes & supportedMask) == 0)
1025 dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1027 char attrValue[11] = WINPR_C_ARRAY_INIT;
1028 length = getxattr(path,
"user.DOSATTRIB", attrValue,
sizeof(attrValue) - 1);
1032 const unsigned long val = strtoul(attrValue,
nullptr, 0);
1034 dwFileAttributes = WINPR_ASSERTING_INT_CAST(DWORD, val);
1038 if ((dwFileAttributes & supportedMask) == 0)
1041 dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1045 return dwFileAttributes;
1051static void SetDosAttributesToXAttr(
const char* path, DWORD dwFileAttributes)
1053#if defined(WINPR_HAVE_SYS_XATTR_H) || defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
1055 dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
1056 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL);
1057 uint32_t intAttrBE = htonl(intAttr);
1059#if defined(WINPR_HAVE_SYS_XATTR_H)
1060 if (setxattr(path,
"system.ntfs_attrib_be", &intAttrBE,
sizeof(intAttrBE), 0) >= 0)
1062 WLog_INFO(TAG,
"Set NTFS attribute xattr for %s", path);
1067 ssize_t length = getxattr(path,
"user.cifs.dosattrib",
nullptr, 0);
1070 if (setxattr(path,
"user.cifs.dosattrib", &intAttrBE,
sizeof(intAttrBE), 0) >= 0)
1072 WLog_INFO(TAG,
"Set CIFS DOS attribute xattr for %s", path);
1079#if defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
1080 int fd = open(path, O_RDONLY | O_CLOEXEC);
1083 if (ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &intAttr) != -1)
1086 WLog_INFO(TAG,
"Set FAT attribute for %s", path);
1093#if defined(WINPR_HAVE_SYS_XATTR_H)
1097 if (intAttr == FILE_ATTRIBUTE_ARCHIVE)
1099 const int rc = removexattr(path,
"user.DOSATTRIB");
1102 char buffer[128] = WINPR_C_ARRAY_INIT;
1103 WLog_WARN(TAG,
"removexattr(%s) failed with %s", path,
1104 winpr_strerror(errno, buffer,
sizeof(buffer)));
1109 char attrValue[11] = WINPR_C_ARRAY_INIT;
1110 const int written = snprintf(attrValue,
sizeof(attrValue),
"0x%x", intAttr);
1114 if (setxattr(path,
"user.DOSATTRIB", attrValue, strlen(attrValue), 0) < 0)
1115 WLog_WARN(TAG,
"Failed to set DOS attribute xattr for %s", path);
1117 WLog_INFO(TAG,
"Set DOS attribute xattr for %s", path);
1122static DWORD FileAttributesFromStat(
const char* path,
const struct stat* fileStat)
1124 DWORD dwFileAttributes = GetDosAttributesFromXAttr(path);
1126 if (S_ISDIR(fileStat->st_mode))
1127 dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1129 if (dwFileAttributes == 0)
1130 dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1132 const char* lastSep = strrchr(path,
'/');
1135 const char* name = lastSep + 1;
1136 const size_t namelen = strlen(name);
1138 if ((namelen > 1) && (name[0] ==
'.') && (name[1] !=
'.'))
1139 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1142 if (!(fileStat->st_mode & S_IWUSR))
1143 dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1145 return dwFileAttributes;
1148static BOOL FindDataFromStat(
const char* path,
const struct stat* fileStat,
1152 lpFindFileData->dwFileAttributes = FileAttributesFromStat(path, fileStat);
1154#ifdef _DARWIN_FEATURE_64_BIT_INODE
1155 ft = STAT_TIME_TO_FILETIME(fileStat->st_birthtime);
1157 ft = STAT_TIME_TO_FILETIME(fileStat->st_ctime);
1159 lpFindFileData->ftCreationTime.dwHighDateTime = (ft) >> 32ULL;
1160 lpFindFileData->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
1161 ft = STAT_TIME_TO_FILETIME(fileStat->st_mtime);
1162 lpFindFileData->ftLastWriteTime.dwHighDateTime = (ft) >> 32ULL;
1163 lpFindFileData->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
1164 ft = STAT_TIME_TO_FILETIME(fileStat->st_atime);
1165 lpFindFileData->ftLastAccessTime.dwHighDateTime = (ft) >> 32ULL;
1166 lpFindFileData->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
1167 lpFindFileData->nFileSizeHigh = ((UINT64)fileStat->st_size) >> 32ULL;
1168 lpFindFileData->nFileSizeLow = fileStat->st_size & 0xFFFFFFFF;
1174 if (!lpFindFileData || !lpFileName)
1176 SetLastError(ERROR_BAD_ARGUMENTS);
1177 return INVALID_HANDLE_VALUE;
1181 *lpFindFileData = empty;
1183 WIN32_FILE_SEARCH* pFileSearch =
nullptr;
1184 size_t patternlen = 0;
1185 const size_t flen = strlen(lpFileName);
1186 const char sep = PathGetSeparatorA(PATH_STYLE_NATIVE);
1187 const char* ptr = strrchr(lpFileName, sep);
1190 patternlen = strlen(ptr + 1);
1191 if (patternlen == 0)
1194 pFileSearch = file_search_new(lpFileName, flen - patternlen, ptr + 1, patternlen);
1197 return INVALID_HANDLE_VALUE;
1199 if (FindNextFileA((HANDLE)pFileSearch, lpFindFileData))
1200 return (HANDLE)pFileSearch;
1203 FindClose(pFileSearch);
1204 return INVALID_HANDLE_VALUE;
1210 if (!lpFindFileDataA || !lpFindFileDataW)
1213 lpFindFileDataW->dwFileAttributes = lpFindFileDataA->dwFileAttributes;
1214 lpFindFileDataW->ftCreationTime = lpFindFileDataA->ftCreationTime;
1215 lpFindFileDataW->ftLastAccessTime = lpFindFileDataA->ftLastAccessTime;
1216 lpFindFileDataW->ftLastWriteTime = lpFindFileDataA->ftLastWriteTime;
1217 lpFindFileDataW->nFileSizeHigh = lpFindFileDataA->nFileSizeHigh;
1218 lpFindFileDataW->nFileSizeLow = lpFindFileDataA->nFileSizeLow;
1219 lpFindFileDataW->dwReserved0 = lpFindFileDataA->dwReserved0;
1220 lpFindFileDataW->dwReserved1 = lpFindFileDataA->dwReserved1;
1222 if (ConvertUtf8NToWChar(lpFindFileDataA->cFileName, ARRAYSIZE(lpFindFileDataA->cFileName),
1223 lpFindFileDataW->cFileName, ARRAYSIZE(lpFindFileDataW->cFileName)) < 0)
1226 return ConvertUtf8NToWChar(lpFindFileDataA->cAlternateFileName,
1227 ARRAYSIZE(lpFindFileDataA->cAlternateFileName),
1228 lpFindFileDataW->cAlternateFileName,
1229 ARRAYSIZE(lpFindFileDataW->cAlternateFileName)) >= 0;
1234 LPSTR utfFileName =
nullptr;
1237 return INVALID_HANDLE_VALUE;
1243 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1244 return INVALID_HANDLE_VALUE;
1247 utfFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
1250 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1252 return INVALID_HANDLE_VALUE;
1255 h = FindFirstFileA(utfFileName, fd);
1258 if (h != INVALID_HANDLE_VALUE)
1260 if (!ConvertFindDataAToW(fd, lpFindFileData))
1262 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1264 h = INVALID_HANDLE_VALUE;
1274HANDLE FindFirstFileExA(WINPR_ATTR_UNUSED LPCSTR lpFileName,
1275 WINPR_ATTR_UNUSED FINDEX_INFO_LEVELS fInfoLevelId,
1276 WINPR_ATTR_UNUSED LPVOID lpFindFileData,
1277 WINPR_ATTR_UNUSED FINDEX_SEARCH_OPS fSearchOp,
1278 WINPR_ATTR_UNUSED LPVOID lpSearchFilter,
1279 WINPR_ATTR_UNUSED DWORD dwAdditionalFlags)
1281 WLog_ERR(
"TODO",
"TODO: Implement");
1282 return INVALID_HANDLE_VALUE;
1285HANDLE FindFirstFileExW(WINPR_ATTR_UNUSED LPCWSTR lpFileName,
1286 WINPR_ATTR_UNUSED FINDEX_INFO_LEVELS fInfoLevelId,
1287 WINPR_ATTR_UNUSED LPVOID lpFindFileData,
1288 WINPR_ATTR_UNUSED FINDEX_SEARCH_OPS fSearchOp,
1289 WINPR_ATTR_UNUSED LPVOID lpSearchFilter,
1290 WINPR_ATTR_UNUSED DWORD dwAdditionalFlags)
1292 WLog_ERR(
"TODO",
"TODO: Implement");
1293 return INVALID_HANDLE_VALUE;
1298 if (!lpFindFileData)
1302 *lpFindFileData = empty;
1304 if (!is_valid_file_search_handle(hFindFile))
1307 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1308 struct dirent* pDirent =
nullptr;
1310 while ((pDirent = readdir(pFileSearch->pDir)) !=
nullptr)
1312 if (FilePatternMatchA(pDirent->d_name, pFileSearch->lpPattern))
1314 BOOL success = FALSE;
1316 strncpy(lpFindFileData->cFileName, pDirent->d_name, MAX_PATH);
1317 const size_t namelen = strnlen(lpFindFileData->cFileName, MAX_PATH);
1318 size_t pathlen = strlen(pFileSearch->lpPath);
1319 char* fullpath = (
char*)malloc(pathlen + namelen + 2);
1321 if (fullpath ==
nullptr)
1323 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1327 memcpy(fullpath, pFileSearch->lpPath, pathlen);
1330 if (fullpath[pathlen - 1] !=
'/')
1331 fullpath[pathlen++] =
'/';
1332 memcpy(fullpath + pathlen, pDirent->d_name, namelen);
1333 fullpath[pathlen + namelen] = 0;
1335 char* canonical = winpr_PathCanonicalize(fullpath);
1341 struct stat fileStat = WINPR_C_ARRAY_INIT;
1342 if (stat(canonical, &fileStat) != 0)
1345 SetLastError(map_posix_err(errno));
1351 if (S_ISFIFO(fileStat.st_mode))
1357 success = FindDataFromStat(canonical, &fileStat, lpFindFileData);
1363 SetLastError(ERROR_NO_MORE_FILES);
1373 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1377 if (FindNextFileA(hFindFile, fd))
1379 if (!ConvertFindDataAToW(fd, lpFindFileData))
1381 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1394BOOL FindClose(HANDLE hFindFile)
1396 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1403#ifndef __clang_analyzer__
1404 if (!is_valid_file_search_handle(hFindFile))
1408 free(pFileSearch->lpPath);
1409 free(pFileSearch->lpPattern);
1411 if (pFileSearch->pDir)
1412 closedir(pFileSearch->pDir);
1419BOOL CreateDirectoryA(LPCSTR lpPathName,
1420 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1422 return mkdir(lpPathName, S_IRUSR | S_IWUSR | S_IXUSR) == 0;
1425BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1429 char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName,
nullptr);
1434 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1438 ret = CreateDirectoryA(utfPathName, lpSecurityAttributes);
1444#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
1445BOOL RemoveDirectoryA(LPCSTR lpPathName)
1447 return winpr_RemoveDirectory(lpPathName);
1451BOOL RemoveDirectoryW(LPCWSTR lpPathName)
1455 char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName,
nullptr);
1460 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1464 ret = winpr_RemoveDirectory(utfPathName);
1470#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
1471BOOL MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
1473 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, dwFlags);
1477BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags)
1479 if (!lpExistingFileName || !lpNewFileName)
1482 LPSTR lpCExistingFileName = ConvertWCharToUtf8Alloc(lpExistingFileName,
nullptr);
1483 LPSTR lpCNewFileName = ConvertWCharToUtf8Alloc(lpNewFileName,
nullptr);
1486 if (!lpCExistingFileName || !lpCNewFileName)
1488 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1492 ret = winpr_MoveFileEx(lpCExistingFileName, lpCNewFileName, dwFlags);
1494 free(lpCNewFileName);
1495 free(lpCExistingFileName);
1499#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
1500BOOL MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
1502 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
1506BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
1508 return MoveFileExW(lpExistingFileName, lpNewFileName, 0);
1515int UnixChangeFileMode(
const char* filename,
int flags)
1521 fl |= (flags & 0x4000) ? S_ISUID : 0;
1522 fl |= (flags & 0x2000) ? S_ISGID : 0;
1523 fl |= (flags & 0x1000) ? S_ISVTX : 0;
1524 fl |= (flags & 0x0400) ? S_IRUSR : 0;
1525 fl |= (flags & 0x0200) ? S_IWUSR : 0;
1526 fl |= (flags & 0x0100) ? S_IXUSR : 0;
1527 fl |= (flags & 0x0040) ? S_IRGRP : 0;
1528 fl |= (flags & 0x0020) ? S_IWGRP : 0;
1529 fl |= (flags & 0x0010) ? S_IXGRP : 0;
1530 fl |= (flags & 0x0004) ? S_IROTH : 0;
1531 fl |= (flags & 0x0002) ? S_IWOTH : 0;
1532 fl |= (flags & 0x0001) ? S_IXOTH : 0;
1533 return chmod(filename, fl);
1536 WCHAR* wfl = ConvertUtf8ToWCharAlloc(filename,
nullptr);
1542 if (flags & ~(_S_IREAD | _S_IWRITE))
1543 WLog_WARN(TAG,
"Unsupported file mode %d for _wchmod", flags);
1545 rc = _wchmod(wfl, flags);
1551#if defined(_WIN32) || defined(_UWP)
1552HANDLE winpr_CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1553 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1554 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1556 WCHAR* filename = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
1560 HANDLE hdl = CreateFileW(filename, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1561 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);