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"
194static DWORD FileAttributesFromStat(
const char* path,
const struct stat* fileStat);
197static BOOL FindDataFromStat(
const char* path,
const struct stat* fileStat,
199static void SetDosAttributesToXAttr(
const char* path, DWORD dwFileAttributes);
201static void HandleCreatorsInit(
void)
203 WINPR_ASSERT(HandleCreators ==
nullptr);
204 HandleCreators = ArrayList_New(TRUE);
212 ArrayList_Append(HandleCreators, GetNamedPipeClientHandleCreator());
215 ArrayList_Append(HandleCreators, serial);
216 ArrayList_Append(HandleCreators, GetFileHandleCreator());
219#ifdef WINPR_HAVE_AIO_H
221static BOOL g_AioSignalHandlerInstalled = FALSE;
223void AioSignalHandler(
int signum, siginfo_t* siginfo,
void* arg)
225 WLog_INFO(
"%d", signum);
228int InstallAioSignalHandler()
230 if (!g_AioSignalHandlerInstalled)
232 struct sigaction action;
233 sigemptyset(&action.sa_mask);
234 sigaddset(&action.sa_mask, SIGIO);
235 action.sa_flags = SA_SIGINFO;
236 action.sa_sigaction = (
void*)&AioSignalHandler;
237 sigaction(SIGIO, &action,
nullptr);
238 g_AioSignalHandlerInstalled = TRUE;
246#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
247HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
248 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
249 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
251 return winpr_CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
252 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
256HANDLE winpr_CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
257 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
258 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
261 return INVALID_HANDLE_VALUE;
263 if (pthread_once(&HandleCreatorsInitialized, HandleCreatorsInit) != 0)
265 SetLastError(ERROR_DLL_INIT_FAILED);
266 return INVALID_HANDLE_VALUE;
269 if (HandleCreators ==
nullptr)
271 SetLastError(ERROR_DLL_INIT_FAILED);
272 return INVALID_HANDLE_VALUE;
275 ArrayList_Lock(HandleCreators);
277 for (
size_t i = 0; i <= ArrayList_Count(HandleCreators); i++)
279 const HANDLE_CREATOR* creator = ArrayList_GetItem(HandleCreators, i);
281 if (creator && creator->IsHandled(lpFileName))
284 creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
285 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
286 ArrayList_Unlock(HandleCreators);
291 ArrayList_Unlock(HandleCreators);
292 return INVALID_HANDLE_VALUE;
295HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
296 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
297 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
299 HANDLE hdl =
nullptr;
302 char* lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
306 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
310 hdl = winpr_CreateFile(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
311 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
317#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
318BOOL DeleteFileA(LPCSTR lpFileName)
320 return winpr_DeleteFile(lpFileName);
324BOOL DeleteFileW(LPCWSTR lpFileName)
328 LPSTR lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
329 BOOL rc = winpr_DeleteFile(lpFileNameA);
334BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
340 if (hFile == INVALID_HANDLE_VALUE)
348 if (!lpNumberOfBytesRead && !lpOverlapped)
351 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
356 if (handle->ops->ReadFile)
357 return handle->ops->ReadFile(handle, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
360 WLog_ERR(TAG,
"ReadFile operation not implemented");
364BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
365 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
370 if (hFile == INVALID_HANDLE_VALUE)
373 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
378 if (handle->ops->ReadFileEx)
379 return handle->ops->ReadFileEx(handle, lpBuffer, nNumberOfBytesToRead, lpOverlapped,
380 lpCompletionRoutine);
382 WLog_ERR(TAG,
"ReadFileEx operation not implemented");
386BOOL ReadFileScatter(HANDLE hFile,
FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead,
392 if (hFile == INVALID_HANDLE_VALUE)
395 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
400 if (handle->ops->ReadFileScatter)
401 return handle->ops->ReadFileScatter(handle, aSegmentArray, nNumberOfBytesToRead, lpReserved,
404 WLog_ERR(TAG,
"ReadFileScatter operation not implemented");
408BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
409 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
414 if (hFile == INVALID_HANDLE_VALUE)
417 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
422 if (handle->ops->WriteFile)
423 return handle->ops->WriteFile(handle, lpBuffer, nNumberOfBytesToWrite,
424 lpNumberOfBytesWritten, lpOverlapped);
426 WLog_ERR(TAG,
"WriteFile operation not implemented");
430BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
431 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
436 if (hFile == INVALID_HANDLE_VALUE)
439 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
444 if (handle->ops->WriteFileEx)
445 return handle->ops->WriteFileEx(handle, lpBuffer, nNumberOfBytesToWrite, lpOverlapped,
446 lpCompletionRoutine);
448 WLog_ERR(TAG,
"WriteFileEx operation not implemented");
453 DWORD nNumberOfBytesToWrite, LPDWORD lpReserved,
LPOVERLAPPED lpOverlapped)
458 if (hFile == INVALID_HANDLE_VALUE)
461 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
466 if (handle->ops->WriteFileGather)
467 return handle->ops->WriteFileGather(handle, aSegmentArray, nNumberOfBytesToWrite,
468 lpReserved, lpOverlapped);
470 WLog_ERR(TAG,
"WriteFileGather operation not implemented");
474BOOL FlushFileBuffers(HANDLE hFile)
479 if (hFile == INVALID_HANDLE_VALUE)
482 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
487 if (handle->ops->FlushFileBuffers)
488 return handle->ops->FlushFileBuffers(handle);
490 WLog_ERR(TAG,
"FlushFileBuffers operation not implemented");
494BOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,
495 WINPR_ATTR_UNUSED GET_FILEEX_INFO_LEVELS fInfoLevelId,
496 LPVOID lpFileInformation)
502 struct stat fileStat = WINPR_C_ARRAY_INIT;
503 if (stat(lpFileName, &fileStat) != 0)
507 if (!FindDataFromStat(lpFileName, &fileStat, &findFileData))
510 fd->dwFileAttributes = findFileData.dwFileAttributes;
511 fd->ftCreationTime = findFileData.ftCreationTime;
512 fd->ftLastAccessTime = findFileData.ftLastAccessTime;
513 fd->ftLastWriteTime = findFileData.ftLastWriteTime;
514 fd->nFileSizeHigh = findFileData.nFileSizeHigh;
515 fd->nFileSizeLow = findFileData.nFileSizeLow;
519BOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
520 LPVOID lpFileInformation)
525 LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
529 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
533 ret = GetFileAttributesExA(lpCFileName, fInfoLevelId, lpFileInformation);
538DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
540 struct stat fileStat = WINPR_C_ARRAY_INIT;
541 if (stat(lpFileName, &fileStat) != 0)
542 return INVALID_FILE_ATTRIBUTES;
544 return FileAttributesFromStat(lpFileName, &fileStat);
547DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
552 LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
555 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
559 ret = GetFileAttributesA(lpCFileName);
569 if (hFile == INVALID_HANDLE_VALUE)
572 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
577 if (handle->ops->GetFileInformationByHandle)
578 return handle->ops->GetFileInformationByHandle(handle, lpFileInformation);
580 WLog_ERR(TAG,
"GetFileInformationByHandle operation not implemented");
584static char* append(
char* buffer,
size_t size,
const char* append)
586 (void)winpr_str_append(append, buffer, size,
"|");
591static const char* flagsToStr(
char* buffer,
size_t size, DWORD flags)
593 char strflags[32] = WINPR_C_ARRAY_INIT;
594 if (flags & FILE_ATTRIBUTE_READONLY)
595 append(buffer, size,
"FILE_ATTRIBUTE_READONLY");
596 if (flags & FILE_ATTRIBUTE_HIDDEN)
597 append(buffer, size,
"FILE_ATTRIBUTE_HIDDEN");
598 if (flags & FILE_ATTRIBUTE_SYSTEM)
599 append(buffer, size,
"FILE_ATTRIBUTE_SYSTEM");
600 if (flags & FILE_ATTRIBUTE_DIRECTORY)
601 append(buffer, size,
"FILE_ATTRIBUTE_DIRECTORY");
602 if (flags & FILE_ATTRIBUTE_ARCHIVE)
603 append(buffer, size,
"FILE_ATTRIBUTE_ARCHIVE");
604 if (flags & FILE_ATTRIBUTE_DEVICE)
605 append(buffer, size,
"FILE_ATTRIBUTE_DEVICE");
606 if (flags & FILE_ATTRIBUTE_NORMAL)
607 append(buffer, size,
"FILE_ATTRIBUTE_NORMAL");
608 if (flags & FILE_ATTRIBUTE_TEMPORARY)
609 append(buffer, size,
"FILE_ATTRIBUTE_TEMPORARY");
610 if (flags & FILE_ATTRIBUTE_SPARSE_FILE)
611 append(buffer, size,
"FILE_ATTRIBUTE_SPARSE_FILE");
612 if (flags & FILE_ATTRIBUTE_REPARSE_POINT)
613 append(buffer, size,
"FILE_ATTRIBUTE_REPARSE_POINT");
614 if (flags & FILE_ATTRIBUTE_COMPRESSED)
615 append(buffer, size,
"FILE_ATTRIBUTE_COMPRESSED");
616 if (flags & FILE_ATTRIBUTE_OFFLINE)
617 append(buffer, size,
"FILE_ATTRIBUTE_OFFLINE");
618 if (flags & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
619 append(buffer, size,
"FILE_ATTRIBUTE_NOT_CONTENT_INDEXED");
620 if (flags & FILE_ATTRIBUTE_ENCRYPTED)
621 append(buffer, size,
"FILE_ATTRIBUTE_ENCRYPTED");
622 if (flags & FILE_ATTRIBUTE_VIRTUAL)
623 append(buffer, size,
"FILE_ATTRIBUTE_VIRTUAL");
625 (void)_snprintf(strflags,
sizeof(strflags),
" [0x%08" PRIx32
"]", flags);
626 winpr_str_append(strflags, buffer, size,
nullptr);
630BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
633#ifdef WINPR_HAVE_FCNTL_H
634 const uint32_t mask = ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_NORMAL |
635 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
636 if (dwFileAttributes & mask)
638 char buffer[8192] = WINPR_C_ARRAY_INIT;
639 const char* flags = flagsToStr(buffer,
sizeof(buffer), dwFileAttributes & mask);
640 WLog_WARN(TAG,
"Unsupported flags %s, ignoring!", flags);
643 SetDosAttributesToXAttr(lpFileName, dwFileAttributes);
645 int fd = open(lpFileName, O_RDONLY);
649 struct stat st = WINPR_C_ARRAY_INIT;
650 if (fstat(fd, &st) != 0)
653 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
655 st.st_mode &= WINPR_ASSERTING_INT_CAST(mode_t, (mode_t)(~(S_IWUSR | S_IWGRP | S_IWOTH)));
659 st.st_mode |= S_IWUSR;
662 if (fchmod(fd, st.st_mode) != 0)
666 if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
668 st.st_flags |= UF_HIDDEN;
672 st.st_flags &= ~UF_HIDDEN;
674 if (fchflags(fd, st.st_flags) != 0)
675 if (errno != ENOTSUP && errno != EOPNOTSUPP && errno != EINVAL && errno != ENOTTY)
686BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
693 char* lpCFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
696 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
700 ret = SetFileAttributesA(lpCFileName, dwFileAttributes);
705BOOL SetEndOfFile(HANDLE hFile)
710 if (hFile == INVALID_HANDLE_VALUE)
713 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
718 if (handle->ops->SetEndOfFile)
719 return handle->ops->SetEndOfFile(handle);
721 WLog_ERR(TAG,
"SetEndOfFile operation not implemented");
725DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
730 if (hFile == INVALID_HANDLE_VALUE)
733 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
738 if (handle->ops->GetFileSize)
739 return handle->ops->GetFileSize(handle, lpFileSizeHigh);
741 WLog_ERR(TAG,
"GetFileSize operation not implemented");
745DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
751 if (hFile == INVALID_HANDLE_VALUE)
754 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
759 if (handle->ops->SetFilePointer)
760 return handle->ops->SetFilePointer(handle, lDistanceToMove, lpDistanceToMoveHigh,
763 WLog_ERR(TAG,
"SetFilePointer operation not implemented");
767BOOL SetFilePointerEx(HANDLE hFile,
LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
773 if (hFile == INVALID_HANDLE_VALUE)
776 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
781 if (handle->ops->SetFilePointerEx)
782 return handle->ops->SetFilePointerEx(handle, liDistanceToMove, lpNewFilePointer,
785 WLog_ERR(TAG,
"SetFilePointerEx operation not implemented");
789BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
790 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh)
795 if (hFile == INVALID_HANDLE_VALUE)
798 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
803 if (handle->ops->LockFile)
804 return handle->ops->LockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
805 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
807 WLog_ERR(TAG,
"LockFile operation not implemented");
811BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow,
812 DWORD nNumberOfBytesToLockHigh,
LPOVERLAPPED lpOverlapped)
817 if (hFile == INVALID_HANDLE_VALUE)
820 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
825 if (handle->ops->LockFileEx)
826 return handle->ops->LockFileEx(handle, dwFlags, dwReserved, nNumberOfBytesToLockLow,
827 nNumberOfBytesToLockHigh, lpOverlapped);
829 WLog_ERR(TAG,
"LockFileEx operation not implemented");
833BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
834 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
839 if (hFile == INVALID_HANDLE_VALUE)
842 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
847 if (handle->ops->UnlockFile)
848 return handle->ops->UnlockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
849 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
851 WLog_ERR(TAG,
"UnLockFile operation not implemented");
855BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow,
856 DWORD nNumberOfBytesToUnlockHigh,
LPOVERLAPPED lpOverlapped)
861 if (hFile == INVALID_HANDLE_VALUE)
864 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
869 if (handle->ops->UnlockFileEx)
870 return handle->ops->UnlockFileEx(handle, dwReserved, nNumberOfBytesToUnlockLow,
871 nNumberOfBytesToUnlockHigh, lpOverlapped);
873 WLog_ERR(TAG,
"UnLockFileEx operation not implemented");
877BOOL WINAPI SetFileTime(HANDLE hFile,
const FILETIME* lpCreationTime,
883 if (hFile == INVALID_HANDLE_VALUE)
886 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
891 if (handle->ops->SetFileTime)
892 return handle->ops->SetFileTime(handle, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
894 WLog_ERR(TAG,
"operation not implemented");
906static const char file_search_magic[] =
"file_srch_magic";
908WINPR_ATTR_MALLOC(FindClose, 1)
909static WIN32_FILE_SEARCH* file_search_new(const
char* name,
size_t namelen, const
char* pattern,
912 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)calloc(1,
sizeof(WIN32_FILE_SEARCH));
915 WINPR_ASSERT(
sizeof(file_search_magic) ==
sizeof(pFileSearch->magic));
916 memcpy(pFileSearch->magic, file_search_magic,
sizeof(pFileSearch->magic));
918 pFileSearch->lpPath = strndup(name, namelen);
919 pFileSearch->lpPattern = strndup(pattern, patternlen);
920 if (!pFileSearch->lpPath || !pFileSearch->lpPattern)
923 pFileSearch->pDir = opendir(pFileSearch->lpPath);
924 if (!pFileSearch->pDir)
930 struct stat fileStat = WINPR_C_ARRAY_INIT;
931 if (stat(name, &fileStat) == 0)
933 if (S_ISDIR(fileStat.st_mode))
935 pFileSearch->pDir = opendir(name);
936 if (pFileSearch->pDir)
938 free(pFileSearch->lpPath);
939 free(pFileSearch->lpPattern);
940 pFileSearch->lpPath = _strdup(name);
941 pFileSearch->lpPattern = _strdup(
"*");
942 if (!pFileSearch->lpPath || !pFileSearch->lpPattern)
944 closedir(pFileSearch->pDir);
945 pFileSearch->pDir =
nullptr;
952 char buffer[128] = WINPR_C_ARRAY_INIT;
953 const DWORD err = map_posix_err(errno);
954 WLog_DBG(TAG,
"stat failed with %s [%d] -> %s",
955 winpr_strerror(errno, buffer,
sizeof(buffer)), errno,
956 Win32ErrorCode2Tag(err & 0xFFFF));
960 if (!pFileSearch->pDir)
965 WINPR_PRAGMA_DIAG_PUSH
966 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
967 FindClose(pFileSearch);
968 WINPR_PRAGMA_DIAG_POP
973static BOOL is_valid_file_search_handle(HANDLE handle)
975 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)handle;
978 if (pFileSearch == INVALID_HANDLE_VALUE)
980 if (strncmp(file_search_magic, pFileSearch->magic,
sizeof(file_search_magic)) != 0)
986static DWORD GetDosAttributesFromXAttr(WINPR_ATTR_UNUSED
const char* path)
988#if defined(WINPR_HAVE_SYS_XATTR_H) || defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
989 DWORD dwFileAttributes = 0;
990 uint32_t intAttr = 0;
992 const DWORD supportedMask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
993 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY |
994 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL;
996#if defined(WINPR_HAVE_SYS_XATTR_H)
997 length = getxattr(path,
"system.ntfs_attrib_be", &intAttr,
sizeof(intAttr));
1000 intAttr = ntohl(intAttr);
1001 dwFileAttributes = intAttr;
1005#if defined(WINPR_HAVE_SYS_XATTR_H)
1006 if ((dwFileAttributes & supportedMask) == 0)
1008 length = getxattr(path,
"user.cifs.dosattrib", &intAttr,
sizeof(intAttr));
1010 dwFileAttributes = intAttr;
1014 if ((dwFileAttributes & supportedMask) == 0)
1016#if defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
1017 int fd = open(path, O_RDONLY | O_CLOEXEC);
1020 const int rc = ioctl(fd, FAT_IOCTL_GET_ATTRIBUTES, &intAttr);
1023 char buffer[64] = WINPR_C_ARRAY_INIT;
1024 WLog_DBG(TAG,
"ioctl(%d, FAT_IOCTL_GET_ATTRIBUTES) failed with %s", fd,
1025 winpr_strerror(errno, buffer,
sizeof(buffer)));
1028 dwFileAttributes = intAttr;
1030 const int crc = close(fd);
1033 char buffer[64] = WINPR_C_ARRAY_INIT;
1034 WLog_DBG(TAG,
"close(%d) failed with %s", fd,
1035 winpr_strerror(errno, buffer,
sizeof(buffer)));
1041#if defined(WINPR_HAVE_SYS_XATTR_H)
1042 if ((dwFileAttributes & supportedMask) == 0)
1045 dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1047 char attrValue[11] = WINPR_C_ARRAY_INIT;
1048 length = getxattr(path,
"user.DOSATTRIB", attrValue,
sizeof(attrValue) - 1);
1052 const unsigned long val = strtoul(attrValue,
nullptr, 0);
1054 dwFileAttributes = WINPR_ASSERTING_INT_CAST(DWORD, val);
1058 if ((dwFileAttributes & supportedMask) == 0)
1061 dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1065 return dwFileAttributes;
1071static void SetDosAttributesToXAttr(
const char* path, DWORD dwFileAttributes)
1073#if defined(WINPR_HAVE_SYS_XATTR_H) || defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
1075 dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
1076 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL);
1077 uint32_t intAttrBE = htonl(intAttr);
1079#if defined(WINPR_HAVE_SYS_XATTR_H)
1080 if (setxattr(path,
"system.ntfs_attrib_be", &intAttrBE,
sizeof(intAttrBE), 0) >= 0)
1082 WLog_DBG(TAG,
"Set NTFS attribute xattr for %s", path);
1087 ssize_t length = getxattr(path,
"user.cifs.dosattrib",
nullptr, 0);
1090 if (setxattr(path,
"user.cifs.dosattrib", &intAttrBE,
sizeof(intAttrBE), 0) >= 0)
1092 WLog_DBG(TAG,
"Set CIFS DOS attribute xattr for %s", path);
1099#if defined(WINPR_HAVE_LINUX_MSDOS_FS_H)
1100 int fd = open(path, O_RDONLY | O_CLOEXEC);
1103 if (ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &intAttr) != -1)
1106 WLog_DBG(TAG,
"Set FAT attribute for %s", path);
1113#if defined(WINPR_HAVE_SYS_XATTR_H)
1117 if (intAttr == FILE_ATTRIBUTE_ARCHIVE)
1119 const int rc = removexattr(path,
"user.DOSATTRIB");
1122 char buffer[128] = WINPR_C_ARRAY_INIT;
1123 WLog_DBG(TAG,
"removexattr(%s) failed with %s", path,
1124 winpr_strerror(errno, buffer,
sizeof(buffer)));
1129 char attrValue[11] = WINPR_C_ARRAY_INIT;
1130 const int written = snprintf(attrValue,
sizeof(attrValue),
"0x%x", intAttr);
1134 if (setxattr(path,
"user.DOSATTRIB", attrValue, strlen(attrValue), 0) < 0)
1135 WLog_DBG(TAG,
"Failed to set DOS attribute xattr for %s", path);
1137 WLog_DBG(TAG,
"Set DOS attribute xattr for %s", path);
1143static DWORD FileAttributesFromStat(
const char* path,
const struct stat* fileStat)
1145 DWORD dwFileAttributes = GetDosAttributesFromXAttr(path);
1147 if (S_ISDIR(fileStat->st_mode))
1148 dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1150 if (dwFileAttributes == 0)
1151 dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1153 const char* lastSep = strrchr(path,
'/');
1156 const char* name = lastSep + 1;
1157 const size_t namelen = strlen(name);
1159 if ((namelen > 1) && (name[0] ==
'.') && (name[1] !=
'.'))
1160 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1164 if (fileStat->st_flags & UF_HIDDEN)
1165 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1168 if (!(fileStat->st_mode & S_IWUSR))
1169 dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1171 return dwFileAttributes;
1175static BOOL FindDataFromStat(
const char* path,
const struct stat* fileStat,
1179 lpFindFileData->dwFileAttributes = FileAttributesFromStat(path, fileStat);
1181#ifdef _DARWIN_FEATURE_64_BIT_INODE
1182 ft = STAT_TIME_TO_FILETIME(fileStat->st_birthtime);
1184 ft = STAT_TIME_TO_FILETIME(fileStat->st_ctime);
1186 lpFindFileData->ftCreationTime.dwHighDateTime = (ft) >> 32ULL;
1187 lpFindFileData->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
1188 ft = STAT_TIME_TO_FILETIME(fileStat->st_mtime);
1189 lpFindFileData->ftLastWriteTime.dwHighDateTime = (ft) >> 32ULL;
1190 lpFindFileData->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
1191 ft = STAT_TIME_TO_FILETIME(fileStat->st_atime);
1192 lpFindFileData->ftLastAccessTime.dwHighDateTime = (ft) >> 32ULL;
1193 lpFindFileData->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
1194 lpFindFileData->nFileSizeHigh = ((UINT64)fileStat->st_size) >> 32ULL;
1195 lpFindFileData->nFileSizeLow = fileStat->st_size & 0xFFFFFFFF;
1201 if (!lpFindFileData || !lpFileName)
1203 SetLastError(ERROR_BAD_ARGUMENTS);
1204 return INVALID_HANDLE_VALUE;
1208 *lpFindFileData = empty;
1210 WIN32_FILE_SEARCH* pFileSearch =
nullptr;
1211 size_t patternlen = 0;
1212 const size_t flen = strlen(lpFileName);
1213 const char sep = PathGetSeparatorA(PATH_STYLE_NATIVE);
1214 const char* ptr = strrchr(lpFileName, sep);
1217 patternlen = strlen(ptr + 1);
1218 if (patternlen == 0)
1221 pFileSearch = file_search_new(lpFileName, flen - patternlen, ptr + 1, patternlen);
1224 return INVALID_HANDLE_VALUE;
1226 if (FindNextFileA((HANDLE)pFileSearch, lpFindFileData))
1227 return (HANDLE)pFileSearch;
1230 FindClose(pFileSearch);
1231 return INVALID_HANDLE_VALUE;
1238 if (!lpFindFileDataA || !lpFindFileDataW)
1241 lpFindFileDataW->dwFileAttributes = lpFindFileDataA->dwFileAttributes;
1242 lpFindFileDataW->ftCreationTime = lpFindFileDataA->ftCreationTime;
1243 lpFindFileDataW->ftLastAccessTime = lpFindFileDataA->ftLastAccessTime;
1244 lpFindFileDataW->ftLastWriteTime = lpFindFileDataA->ftLastWriteTime;
1245 lpFindFileDataW->nFileSizeHigh = lpFindFileDataA->nFileSizeHigh;
1246 lpFindFileDataW->nFileSizeLow = lpFindFileDataA->nFileSizeLow;
1247 lpFindFileDataW->dwReserved0 = lpFindFileDataA->dwReserved0;
1248 lpFindFileDataW->dwReserved1 = lpFindFileDataA->dwReserved1;
1250 if (ConvertUtf8NToWChar(lpFindFileDataA->cFileName, ARRAYSIZE(lpFindFileDataA->cFileName),
1251 lpFindFileDataW->cFileName, ARRAYSIZE(lpFindFileDataW->cFileName)) < 0)
1254 return ConvertUtf8NToWChar(lpFindFileDataA->cAlternateFileName,
1255 ARRAYSIZE(lpFindFileDataA->cAlternateFileName),
1256 lpFindFileDataW->cAlternateFileName,
1257 ARRAYSIZE(lpFindFileDataW->cAlternateFileName)) >= 0;
1262 LPSTR utfFileName =
nullptr;
1265 return INVALID_HANDLE_VALUE;
1271 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1272 return INVALID_HANDLE_VALUE;
1275 utfFileName = ConvertWCharToUtf8Alloc(lpFileName,
nullptr);
1278 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1280 return INVALID_HANDLE_VALUE;
1283 h = FindFirstFileA(utfFileName, fd);
1286 if (h != INVALID_HANDLE_VALUE)
1288 if (!ConvertFindDataAToW(fd, lpFindFileData))
1290 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1292 h = INVALID_HANDLE_VALUE;
1302HANDLE FindFirstFileExA(WINPR_ATTR_UNUSED LPCSTR lpFileName,
1303 WINPR_ATTR_UNUSED FINDEX_INFO_LEVELS fInfoLevelId,
1304 WINPR_ATTR_UNUSED LPVOID lpFindFileData,
1305 WINPR_ATTR_UNUSED FINDEX_SEARCH_OPS fSearchOp,
1306 WINPR_ATTR_UNUSED LPVOID lpSearchFilter,
1307 WINPR_ATTR_UNUSED DWORD dwAdditionalFlags)
1309 WLog_ERR(
"TODO",
"TODO: Implement");
1310 return INVALID_HANDLE_VALUE;
1313HANDLE FindFirstFileExW(WINPR_ATTR_UNUSED LPCWSTR lpFileName,
1314 WINPR_ATTR_UNUSED FINDEX_INFO_LEVELS fInfoLevelId,
1315 WINPR_ATTR_UNUSED LPVOID lpFindFileData,
1316 WINPR_ATTR_UNUSED FINDEX_SEARCH_OPS fSearchOp,
1317 WINPR_ATTR_UNUSED LPVOID lpSearchFilter,
1318 WINPR_ATTR_UNUSED DWORD dwAdditionalFlags)
1320 WLog_ERR(
"TODO",
"TODO: Implement");
1321 return INVALID_HANDLE_VALUE;
1326 if (!lpFindFileData)
1330 *lpFindFileData = empty;
1332 if (!is_valid_file_search_handle(hFindFile))
1335 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1336 struct dirent* pDirent =
nullptr;
1338 while ((pDirent = readdir(pFileSearch->pDir)) !=
nullptr)
1340 if (FilePatternMatchA(pDirent->d_name, pFileSearch->lpPattern))
1342 BOOL success = FALSE;
1344 strncpy(lpFindFileData->cFileName, pDirent->d_name, MAX_PATH);
1345 const size_t namelen = strnlen(lpFindFileData->cFileName, MAX_PATH);
1346 size_t pathlen = strlen(pFileSearch->lpPath);
1347 char* fullpath = (
char*)malloc(pathlen + namelen + 2);
1349 if (fullpath ==
nullptr)
1351 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1355 memcpy(fullpath, pFileSearch->lpPath, pathlen);
1358 if (fullpath[pathlen - 1] !=
'/')
1359 fullpath[pathlen++] =
'/';
1360 memcpy(fullpath + pathlen, pDirent->d_name, namelen);
1361 fullpath[pathlen + namelen] = 0;
1363 char* canonical = winpr_PathCanonicalize(fullpath);
1369 struct stat fileStat = WINPR_C_ARRAY_INIT;
1370 if (stat(canonical, &fileStat) != 0)
1373 SetLastError(map_posix_err(errno));
1379 if (S_ISFIFO(fileStat.st_mode))
1385 success = FindDataFromStat(canonical, &fileStat, lpFindFileData);
1391 SetLastError(ERROR_NO_MORE_FILES);
1401 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1405 if (FindNextFileA(hFindFile, fd))
1407 if (!ConvertFindDataAToW(fd, lpFindFileData))
1409 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1422BOOL FindClose(HANDLE hFindFile)
1424 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1431#ifndef __clang_analyzer__
1432 if (!is_valid_file_search_handle(hFindFile))
1436 free(pFileSearch->lpPath);
1437 free(pFileSearch->lpPattern);
1439 if (pFileSearch->pDir)
1440 closedir(pFileSearch->pDir);
1447BOOL CreateDirectoryA(LPCSTR lpPathName,
1448 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1450 return mkdir(lpPathName, S_IRUSR | S_IWUSR | S_IXUSR) == 0;
1453BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1457 char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName,
nullptr);
1462 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1466 ret = CreateDirectoryA(utfPathName, lpSecurityAttributes);
1472#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
1473BOOL RemoveDirectoryA(LPCSTR lpPathName)
1475 return winpr_RemoveDirectory(lpPathName);
1479BOOL RemoveDirectoryW(LPCWSTR lpPathName)
1483 char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName,
nullptr);
1488 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1492 ret = winpr_RemoveDirectory(utfPathName);
1498#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
1499BOOL MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
1501 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, dwFlags);
1505BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags)
1507 if (!lpExistingFileName || !lpNewFileName)
1510 LPSTR lpCExistingFileName = ConvertWCharToUtf8Alloc(lpExistingFileName,
nullptr);
1511 LPSTR lpCNewFileName = ConvertWCharToUtf8Alloc(lpNewFileName,
nullptr);
1514 if (!lpCExistingFileName || !lpCNewFileName)
1516 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1520 ret = winpr_MoveFileEx(lpCExistingFileName, lpCNewFileName, dwFlags);
1522 free(lpCNewFileName);
1523 free(lpCExistingFileName);
1527#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
1528BOOL MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
1530 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
1534BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
1536 return MoveFileExW(lpExistingFileName, lpNewFileName, 0);
1543int UnixChangeFileMode(
const char* filename,
int flags)
1549 fl |= (flags & 0x4000) ? S_ISUID : 0;
1550 fl |= (flags & 0x2000) ? S_ISGID : 0;
1551 fl |= (flags & 0x1000) ? S_ISVTX : 0;
1552 fl |= (flags & 0x0400) ? S_IRUSR : 0;
1553 fl |= (flags & 0x0200) ? S_IWUSR : 0;
1554 fl |= (flags & 0x0100) ? S_IXUSR : 0;
1555 fl |= (flags & 0x0040) ? S_IRGRP : 0;
1556 fl |= (flags & 0x0020) ? S_IWGRP : 0;
1557 fl |= (flags & 0x0010) ? S_IXGRP : 0;
1558 fl |= (flags & 0x0004) ? S_IROTH : 0;
1559 fl |= (flags & 0x0002) ? S_IWOTH : 0;
1560 fl |= (flags & 0x0001) ? S_IXOTH : 0;
1561 return chmod(filename, fl);
1564 WCHAR* wfl = ConvertUtf8ToWCharAlloc(filename,
nullptr);
1570 if (flags & ~(_S_IREAD | _S_IWRITE))
1571 WLog_WARN(TAG,
"Unsupported file mode %d for _wchmod", flags);
1573 rc = _wchmod(wfl, flags);
1579#if defined(_WIN32) || defined(_UWP)
1580HANDLE winpr_CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1581 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1582 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1584 WCHAR* filename = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
1588 HANDLE hdl = CreateFileW(filename, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1589 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);