FreeRDP
Loading...
Searching...
No Matches
generic.c
1
22#include <winpr/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/wlog.h>
26#include <winpr/string.h>
27#include <winpr/path.h>
28#include <winpr/file.h>
29
30#ifdef WINPR_HAVE_UNISTD_H
31#include <unistd.h>
32#endif
33
34#ifdef WINPR_HAVE_FCNTL_H
35#include <fcntl.h>
36#endif
37
38#include "../log.h"
39#define TAG WINPR_TAG("file")
40
41#ifdef _WIN32
42#include <io.h>
43#include <sys/stat.h>
44#else
45#include <winpr/assert.h>
46#include <pthread.h>
47#include <dirent.h>
48#include <libgen.h>
49#include <errno.h>
50
51#include <sys/un.h>
52#include <sys/stat.h>
53#include <sys/socket.h>
54
55#ifdef WINPR_HAVE_AIO_H
56#undef WINPR_HAVE_AIO_H /* disable for now, incomplete */
57#endif
58
59#ifdef WINPR_HAVE_AIO_H
60#include <aio.h>
61#endif
62
63#ifdef ANDROID
64#include <sys/vfs.h>
65#else
66#include <sys/statvfs.h>
67#endif
68
69#include "../handle/handle.h"
70
71#include "../pipe/pipe.h"
72
73#include "file.h"
74
178static wArrayList* HandleCreators;
179
180static pthread_once_t HandleCreatorsInitialized = PTHREAD_ONCE_INIT;
181
182#include "../comm/comm.h"
183#include "namedPipeClient.h"
184
185static DWORD FileAttributesFromStat(const char* path, const struct stat* fileStat);
186static BOOL FindDataFromStat(const char* path, const struct stat* fileStat,
187 LPWIN32_FIND_DATAA lpFindFileData);
188
189static void HandleCreatorsInit(void)
190{
191 WINPR_ASSERT(HandleCreators == nullptr);
192 HandleCreators = ArrayList_New(TRUE);
193
194 if (!HandleCreators)
195 return;
196
197 /*
198 * Register all file handle creators.
199 */
200 ArrayList_Append(HandleCreators, GetNamedPipeClientHandleCreator());
201 const HANDLE_CREATOR* serial = GetCommHandleCreator();
202 if (serial)
203 ArrayList_Append(HandleCreators, serial);
204 ArrayList_Append(HandleCreators, GetFileHandleCreator());
205}
206
207#ifdef WINPR_HAVE_AIO_H
208
209static BOOL g_AioSignalHandlerInstalled = FALSE;
210
211void AioSignalHandler(int signum, siginfo_t* siginfo, void* arg)
212{
213 WLog_INFO("%d", signum);
214}
215
216int InstallAioSignalHandler()
217{
218 if (!g_AioSignalHandlerInstalled)
219 {
220 struct sigaction action;
221 sigemptyset(&action.sa_mask);
222 sigaddset(&action.sa_mask, SIGIO);
223 action.sa_flags = SA_SIGINFO;
224 action.sa_sigaction = (void*)&AioSignalHandler;
225 sigaction(SIGIO, &action, nullptr);
226 g_AioSignalHandlerInstalled = TRUE;
227 }
228
229 return 0;
230}
231
232#endif /* WINPR_HAVE_AIO_H */
233
234HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
235 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
236 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
237{
238 return winpr_CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
239 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
240}
241
242HANDLE winpr_CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
243 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
244 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
245{
246 if (!lpFileName)
247 return INVALID_HANDLE_VALUE;
248
249 if (pthread_once(&HandleCreatorsInitialized, HandleCreatorsInit) != 0)
250 {
251 SetLastError(ERROR_DLL_INIT_FAILED);
252 return INVALID_HANDLE_VALUE;
253 }
254
255 if (HandleCreators == nullptr)
256 {
257 SetLastError(ERROR_DLL_INIT_FAILED);
258 return INVALID_HANDLE_VALUE;
259 }
260
261 ArrayList_Lock(HandleCreators);
262
263 for (size_t i = 0; i <= ArrayList_Count(HandleCreators); i++)
264 {
265 const HANDLE_CREATOR* creator = ArrayList_GetItem(HandleCreators, i);
266
267 if (creator && creator->IsHandled(lpFileName))
268 {
269 HANDLE newHandle =
270 creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
271 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
272 ArrayList_Unlock(HandleCreators);
273 return newHandle;
274 }
275 }
276
277 ArrayList_Unlock(HandleCreators);
278 return INVALID_HANDLE_VALUE;
279}
280
281HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
282 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
283 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
284{
285 HANDLE hdl = nullptr;
286 if (!lpFileName)
287 return nullptr;
288 char* lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName, nullptr);
289
290 if (!lpFileNameA)
291 {
292 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
293 goto fail;
294 }
295
296 hdl = winpr_CreateFile(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
297 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
298fail:
299 free(lpFileNameA);
300 return hdl;
301}
302
303BOOL DeleteFileA(LPCSTR lpFileName)
304{
305 return winpr_DeleteFile(lpFileName);
306}
307
308BOOL DeleteFileW(LPCWSTR lpFileName)
309{
310 if (!lpFileName)
311 return FALSE;
312 LPSTR lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName, nullptr);
313 BOOL rc = winpr_DeleteFile(lpFileNameA);
314 free(lpFileNameA);
315 return rc;
316}
317
318BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
319 LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
320{
321 ULONG Type = 0;
322 WINPR_HANDLE* handle = nullptr;
323
324 if (hFile == INVALID_HANDLE_VALUE)
325 return FALSE;
326
327 /*
328 * from http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
329 * lpNumberOfBytesRead can be nullptr only when the lpOverlapped parameter is not nullptr.
330 */
331
332 if (!lpNumberOfBytesRead && !lpOverlapped)
333 return FALSE;
334
335 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
336 return FALSE;
337
338 handle = (WINPR_HANDLE*)hFile;
339
340 if (handle->ops->ReadFile)
341 return handle->ops->ReadFile(handle, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
342 lpOverlapped);
343
344 WLog_ERR(TAG, "ReadFile operation not implemented");
345 return FALSE;
346}
347
348BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
349 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
350{
351 ULONG Type = 0;
352 WINPR_HANDLE* handle = nullptr;
353
354 if (hFile == INVALID_HANDLE_VALUE)
355 return FALSE;
356
357 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
358 return FALSE;
359
360 handle = (WINPR_HANDLE*)hFile;
361
362 if (handle->ops->ReadFileEx)
363 return handle->ops->ReadFileEx(handle, lpBuffer, nNumberOfBytesToRead, lpOverlapped,
364 lpCompletionRoutine);
365
366 WLog_ERR(TAG, "ReadFileEx operation not implemented");
367 return FALSE;
368}
369
370BOOL ReadFileScatter(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead,
371 LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
372{
373 ULONG Type = 0;
374 WINPR_HANDLE* handle = nullptr;
375
376 if (hFile == INVALID_HANDLE_VALUE)
377 return FALSE;
378
379 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
380 return FALSE;
381
382 handle = (WINPR_HANDLE*)hFile;
383
384 if (handle->ops->ReadFileScatter)
385 return handle->ops->ReadFileScatter(handle, aSegmentArray, nNumberOfBytesToRead, lpReserved,
386 lpOverlapped);
387
388 WLog_ERR(TAG, "ReadFileScatter operation not implemented");
389 return FALSE;
390}
391
392BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
393 LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
394{
395 ULONG Type = 0;
396 WINPR_HANDLE* handle = nullptr;
397
398 if (hFile == INVALID_HANDLE_VALUE)
399 return FALSE;
400
401 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
402 return FALSE;
403
404 handle = (WINPR_HANDLE*)hFile;
405
406 if (handle->ops->WriteFile)
407 return handle->ops->WriteFile(handle, lpBuffer, nNumberOfBytesToWrite,
408 lpNumberOfBytesWritten, lpOverlapped);
409
410 WLog_ERR(TAG, "WriteFile operation not implemented");
411 return FALSE;
412}
413
414BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
415 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
416{
417 ULONG Type = 0;
418 WINPR_HANDLE* handle = nullptr;
419
420 if (hFile == INVALID_HANDLE_VALUE)
421 return FALSE;
422
423 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
424 return FALSE;
425
426 handle = (WINPR_HANDLE*)hFile;
427
428 if (handle->ops->WriteFileEx)
429 return handle->ops->WriteFileEx(handle, lpBuffer, nNumberOfBytesToWrite, lpOverlapped,
430 lpCompletionRoutine);
431
432 WLog_ERR(TAG, "WriteFileEx operation not implemented");
433 return FALSE;
434}
435
436BOOL WriteFileGather(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[],
437 DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
438{
439 ULONG Type = 0;
440 WINPR_HANDLE* handle = nullptr;
441
442 if (hFile == INVALID_HANDLE_VALUE)
443 return FALSE;
444
445 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
446 return FALSE;
447
448 handle = (WINPR_HANDLE*)hFile;
449
450 if (handle->ops->WriteFileGather)
451 return handle->ops->WriteFileGather(handle, aSegmentArray, nNumberOfBytesToWrite,
452 lpReserved, lpOverlapped);
453
454 WLog_ERR(TAG, "WriteFileGather operation not implemented");
455 return FALSE;
456}
457
458BOOL FlushFileBuffers(HANDLE hFile)
459{
460 ULONG Type = 0;
461 WINPR_HANDLE* handle = nullptr;
462
463 if (hFile == INVALID_HANDLE_VALUE)
464 return FALSE;
465
466 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
467 return FALSE;
468
469 handle = (WINPR_HANDLE*)hFile;
470
471 if (handle->ops->FlushFileBuffers)
472 return handle->ops->FlushFileBuffers(handle);
473
474 WLog_ERR(TAG, "FlushFileBuffers operation not implemented");
475 return FALSE;
476}
477
478BOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,
479 WINPR_ATTR_UNUSED GET_FILEEX_INFO_LEVELS fInfoLevelId,
480 LPVOID lpFileInformation)
481{
482 LPWIN32_FILE_ATTRIBUTE_DATA fd = lpFileInformation;
483 if (!fd)
484 return FALSE;
485
486 struct stat fileStat = WINPR_C_ARRAY_INIT;
487 if (stat(lpFileName, &fileStat) != 0)
488 return FALSE;
489
490 WIN32_FIND_DATAA findFileData = WINPR_C_ARRAY_INIT;
491 if (!FindDataFromStat(lpFileName, &fileStat, &findFileData))
492 return FALSE;
493
494 fd->dwFileAttributes = findFileData.dwFileAttributes;
495 fd->ftCreationTime = findFileData.ftCreationTime;
496 fd->ftLastAccessTime = findFileData.ftLastAccessTime;
497 fd->ftLastWriteTime = findFileData.ftLastWriteTime;
498 fd->nFileSizeHigh = findFileData.nFileSizeHigh;
499 fd->nFileSizeLow = findFileData.nFileSizeLow;
500 return TRUE;
501}
502
503BOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
504 LPVOID lpFileInformation)
505{
506 BOOL ret = 0;
507 if (!lpFileName)
508 return FALSE;
509 LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName, nullptr);
510
511 if (!lpCFileName)
512 {
513 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
514 return FALSE;
515 }
516
517 ret = GetFileAttributesExA(lpCFileName, fInfoLevelId, lpFileInformation);
518 free(lpCFileName);
519 return ret;
520}
521
522DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
523{
524 struct stat fileStat = WINPR_C_ARRAY_INIT;
525 if (stat(lpFileName, &fileStat) != 0)
526 return INVALID_FILE_ATTRIBUTES;
527
528 return FileAttributesFromStat(lpFileName, &fileStat);
529}
530
531DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
532{
533 DWORD ret = 0;
534 if (!lpFileName)
535 return FALSE;
536 LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName, nullptr);
537 if (!lpCFileName)
538 {
539 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
540 return FALSE;
541 }
542
543 ret = GetFileAttributesA(lpCFileName);
544 free(lpCFileName);
545 return ret;
546}
547
548BOOL GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
549{
550 ULONG Type = 0;
551 WINPR_HANDLE* handle = nullptr;
552
553 if (hFile == INVALID_HANDLE_VALUE)
554 return FALSE;
555
556 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
557 return FALSE;
558
559 handle = (WINPR_HANDLE*)hFile;
560
561 if (handle->ops->GetFileInformationByHandle)
562 return handle->ops->GetFileInformationByHandle(handle, lpFileInformation);
563
564 WLog_ERR(TAG, "GetFileInformationByHandle operation not implemented");
565 return 0;
566}
567
568static char* append(char* buffer, size_t size, const char* append)
569{
570 winpr_str_append(append, buffer, size, "|");
571 return buffer;
572}
573
574static const char* flagsToStr(char* buffer, size_t size, DWORD flags)
575{
576 char strflags[32] = WINPR_C_ARRAY_INIT;
577 if (flags & FILE_ATTRIBUTE_READONLY)
578 append(buffer, size, "FILE_ATTRIBUTE_READONLY");
579 if (flags & FILE_ATTRIBUTE_HIDDEN)
580 append(buffer, size, "FILE_ATTRIBUTE_HIDDEN");
581 if (flags & FILE_ATTRIBUTE_SYSTEM)
582 append(buffer, size, "FILE_ATTRIBUTE_SYSTEM");
583 if (flags & FILE_ATTRIBUTE_DIRECTORY)
584 append(buffer, size, "FILE_ATTRIBUTE_DIRECTORY");
585 if (flags & FILE_ATTRIBUTE_ARCHIVE)
586 append(buffer, size, "FILE_ATTRIBUTE_ARCHIVE");
587 if (flags & FILE_ATTRIBUTE_DEVICE)
588 append(buffer, size, "FILE_ATTRIBUTE_DEVICE");
589 if (flags & FILE_ATTRIBUTE_NORMAL)
590 append(buffer, size, "FILE_ATTRIBUTE_NORMAL");
591 if (flags & FILE_ATTRIBUTE_TEMPORARY)
592 append(buffer, size, "FILE_ATTRIBUTE_TEMPORARY");
593 if (flags & FILE_ATTRIBUTE_SPARSE_FILE)
594 append(buffer, size, "FILE_ATTRIBUTE_SPARSE_FILE");
595 if (flags & FILE_ATTRIBUTE_REPARSE_POINT)
596 append(buffer, size, "FILE_ATTRIBUTE_REPARSE_POINT");
597 if (flags & FILE_ATTRIBUTE_COMPRESSED)
598 append(buffer, size, "FILE_ATTRIBUTE_COMPRESSED");
599 if (flags & FILE_ATTRIBUTE_OFFLINE)
600 append(buffer, size, "FILE_ATTRIBUTE_OFFLINE");
601 if (flags & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
602 append(buffer, size, "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED");
603 if (flags & FILE_ATTRIBUTE_ENCRYPTED)
604 append(buffer, size, "FILE_ATTRIBUTE_ENCRYPTED");
605 if (flags & FILE_ATTRIBUTE_VIRTUAL)
606 append(buffer, size, "FILE_ATTRIBUTE_VIRTUAL");
607
608 (void)_snprintf(strflags, sizeof(strflags), " [0x%08" PRIx32 "]", flags);
609 winpr_str_append(strflags, buffer, size, nullptr);
610 return buffer;
611}
612
613BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
614{
615 BOOL rc = FALSE;
616#ifdef WINPR_HAVE_FCNTL_H
617 const uint32_t mask = ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_NORMAL);
618 if (dwFileAttributes & mask)
619 {
620 char buffer[8192] = WINPR_C_ARRAY_INIT;
621 const char* flags = flagsToStr(buffer, sizeof(buffer), dwFileAttributes & mask);
622 WLog_WARN(TAG, "Unsupported flags %s, ignoring!", flags);
623 }
624
625 int fd = open(lpFileName, O_RDONLY);
626 if (fd < 0)
627 return FALSE;
628
629 struct stat st = WINPR_C_ARRAY_INIT;
630 if (fstat(fd, &st) != 0)
631 goto fail;
632
633 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
634 {
635 st.st_mode &= WINPR_ASSERTING_INT_CAST(mode_t, (mode_t)(~(S_IWUSR | S_IWGRP | S_IWOTH)));
636 }
637 else
638 {
639 st.st_mode |= S_IWUSR;
640 }
641
642 if (fchmod(fd, st.st_mode) != 0)
643 goto fail;
644
645 rc = TRUE;
646fail:
647 close(fd);
648#endif
649 return rc;
650}
651
652BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
653{
654 BOOL ret = 0;
655
656 if (!lpFileName)
657 return FALSE;
658
659 char* lpCFileName = ConvertWCharToUtf8Alloc(lpFileName, nullptr);
660 if (!lpCFileName)
661 {
662 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
663 return FALSE;
664 }
665
666 ret = SetFileAttributesA(lpCFileName, dwFileAttributes);
667 free(lpCFileName);
668 return ret;
669}
670
671BOOL SetEndOfFile(HANDLE hFile)
672{
673 ULONG Type = 0;
674 WINPR_HANDLE* handle = nullptr;
675
676 if (hFile == INVALID_HANDLE_VALUE)
677 return FALSE;
678
679 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
680 return FALSE;
681
682 handle = (WINPR_HANDLE*)hFile;
683
684 if (handle->ops->SetEndOfFile)
685 return handle->ops->SetEndOfFile(handle);
686
687 WLog_ERR(TAG, "SetEndOfFile operation not implemented");
688 return FALSE;
689}
690
691DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
692{
693 ULONG Type = 0;
694 WINPR_HANDLE* handle = nullptr;
695
696 if (hFile == INVALID_HANDLE_VALUE)
697 return FALSE;
698
699 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
700 return FALSE;
701
702 handle = (WINPR_HANDLE*)hFile;
703
704 if (handle->ops->GetFileSize)
705 return handle->ops->GetFileSize(handle, lpFileSizeHigh);
706
707 WLog_ERR(TAG, "GetFileSize operation not implemented");
708 return 0;
709}
710
711DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
712 DWORD dwMoveMethod)
713{
714 ULONG Type = 0;
715 WINPR_HANDLE* handle = nullptr;
716
717 if (hFile == INVALID_HANDLE_VALUE)
718 return FALSE;
719
720 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
721 return FALSE;
722
723 handle = (WINPR_HANDLE*)hFile;
724
725 if (handle->ops->SetFilePointer)
726 return handle->ops->SetFilePointer(handle, lDistanceToMove, lpDistanceToMoveHigh,
727 dwMoveMethod);
728
729 WLog_ERR(TAG, "SetFilePointer operation not implemented");
730 return 0;
731}
732
733BOOL SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
734 DWORD dwMoveMethod)
735{
736 ULONG Type = 0;
737 WINPR_HANDLE* handle = nullptr;
738
739 if (hFile == INVALID_HANDLE_VALUE)
740 return FALSE;
741
742 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
743 return FALSE;
744
745 handle = (WINPR_HANDLE*)hFile;
746
747 if (handle->ops->SetFilePointerEx)
748 return handle->ops->SetFilePointerEx(handle, liDistanceToMove, lpNewFilePointer,
749 dwMoveMethod);
750
751 WLog_ERR(TAG, "SetFilePointerEx operation not implemented");
752 return 0;
753}
754
755BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
756 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh)
757{
758 ULONG Type = 0;
759 WINPR_HANDLE* handle = nullptr;
760
761 if (hFile == INVALID_HANDLE_VALUE)
762 return FALSE;
763
764 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
765 return FALSE;
766
767 handle = (WINPR_HANDLE*)hFile;
768
769 if (handle->ops->LockFile)
770 return handle->ops->LockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
771 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
772
773 WLog_ERR(TAG, "LockFile operation not implemented");
774 return FALSE;
775}
776
777BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow,
778 DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped)
779{
780 ULONG Type = 0;
781 WINPR_HANDLE* handle = nullptr;
782
783 if (hFile == INVALID_HANDLE_VALUE)
784 return FALSE;
785
786 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
787 return FALSE;
788
789 handle = (WINPR_HANDLE*)hFile;
790
791 if (handle->ops->LockFileEx)
792 return handle->ops->LockFileEx(handle, dwFlags, dwReserved, nNumberOfBytesToLockLow,
793 nNumberOfBytesToLockHigh, lpOverlapped);
794
795 WLog_ERR(TAG, "LockFileEx operation not implemented");
796 return FALSE;
797}
798
799BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
800 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
801{
802 ULONG Type = 0;
803 WINPR_HANDLE* handle = nullptr;
804
805 if (hFile == INVALID_HANDLE_VALUE)
806 return FALSE;
807
808 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
809 return FALSE;
810
811 handle = (WINPR_HANDLE*)hFile;
812
813 if (handle->ops->UnlockFile)
814 return handle->ops->UnlockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
815 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
816
817 WLog_ERR(TAG, "UnLockFile operation not implemented");
818 return FALSE;
819}
820
821BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow,
822 DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped)
823{
824 ULONG Type = 0;
825 WINPR_HANDLE* handle = nullptr;
826
827 if (hFile == INVALID_HANDLE_VALUE)
828 return FALSE;
829
830 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
831 return FALSE;
832
833 handle = (WINPR_HANDLE*)hFile;
834
835 if (handle->ops->UnlockFileEx)
836 return handle->ops->UnlockFileEx(handle, dwReserved, nNumberOfBytesToUnlockLow,
837 nNumberOfBytesToUnlockHigh, lpOverlapped);
838
839 WLog_ERR(TAG, "UnLockFileEx operation not implemented");
840 return FALSE;
841}
842
843BOOL WINAPI SetFileTime(HANDLE hFile, const FILETIME* lpCreationTime,
844 const FILETIME* lpLastAccessTime, const FILETIME* lpLastWriteTime)
845{
846 ULONG Type = 0;
847 WINPR_HANDLE* handle = nullptr;
848
849 if (hFile == INVALID_HANDLE_VALUE)
850 return FALSE;
851
852 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
853 return FALSE;
854
855 handle = (WINPR_HANDLE*)hFile;
856
857 if (handle->ops->SetFileTime)
858 return handle->ops->SetFileTime(handle, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
859
860 WLog_ERR(TAG, "operation not implemented");
861 return FALSE;
862}
863
864typedef struct
865{
866 char magic[16];
867 LPSTR lpPath;
868 LPSTR lpPattern;
869 DIR* pDir;
870} WIN32_FILE_SEARCH;
871
872static const char file_search_magic[] = "file_srch_magic";
873
874WINPR_ATTR_MALLOC(FindClose, 1)
875static WIN32_FILE_SEARCH* file_search_new(const char* name, size_t namelen, const char* pattern,
876 size_t patternlen)
877{
878 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)calloc(1, sizeof(WIN32_FILE_SEARCH));
879 if (!pFileSearch)
880 return nullptr;
881 WINPR_ASSERT(sizeof(file_search_magic) == sizeof(pFileSearch->magic));
882 memcpy(pFileSearch->magic, file_search_magic, sizeof(pFileSearch->magic));
883
884 pFileSearch->lpPath = strndup(name, namelen);
885 pFileSearch->lpPattern = strndup(pattern, patternlen);
886 if (!pFileSearch->lpPath || !pFileSearch->lpPattern)
887 goto fail;
888
889 pFileSearch->pDir = opendir(pFileSearch->lpPath);
890 if (!pFileSearch->pDir)
891 {
892 /* Work around for android:
893 * parent directories are not accessible, so if we have a directory without pattern
894 * try to open it directly and set pattern to '*'
895 */
896 struct stat fileStat = WINPR_C_ARRAY_INIT;
897 if (stat(name, &fileStat) == 0)
898 {
899 if (S_ISDIR(fileStat.st_mode))
900 {
901 pFileSearch->pDir = opendir(name);
902 if (pFileSearch->pDir)
903 {
904 free(pFileSearch->lpPath);
905 free(pFileSearch->lpPattern);
906 pFileSearch->lpPath = _strdup(name);
907 pFileSearch->lpPattern = _strdup("*");
908 if (!pFileSearch->lpPath || !pFileSearch->lpPattern)
909 {
910 closedir(pFileSearch->pDir);
911 pFileSearch->pDir = nullptr;
912 }
913 }
914 }
915 }
916 else
917 {
918 char buffer[128] = WINPR_C_ARRAY_INIT;
919 const DWORD err = map_posix_err(errno);
920 WLog_DBG(TAG, "stat failed with %s [%d] -> %s",
921 winpr_strerror(errno, buffer, sizeof(buffer)), errno,
922 Win32ErrorCode2Tag(err & 0xFFFF));
923 SetLastError(err);
924 }
925 }
926 if (!pFileSearch->pDir)
927 goto fail;
928
929 return pFileSearch;
930fail:
931 WINPR_PRAGMA_DIAG_PUSH
932 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
933 FindClose(pFileSearch);
934 WINPR_PRAGMA_DIAG_POP
935 return nullptr;
936}
937
938static BOOL is_valid_file_search_handle(HANDLE handle)
939{
940 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)handle;
941 if (!pFileSearch)
942 return FALSE;
943 if (pFileSearch == INVALID_HANDLE_VALUE)
944 return FALSE;
945 if (strncmp(file_search_magic, pFileSearch->magic, sizeof(file_search_magic)) != 0)
946 return FALSE;
947 return TRUE;
948}
949
950static DWORD FileAttributesFromStat(const char* path, const struct stat* fileStat)
951{
952 char* lastSep = nullptr;
953 DWORD dwFileAttributes = 0;
954
955 if (S_ISDIR(fileStat->st_mode))
956 dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
957
958 if (dwFileAttributes == 0)
959 dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
960
961 lastSep = strrchr(path, '/');
962 if (lastSep)
963 {
964 const char* name = lastSep + 1;
965 const size_t namelen = strlen(name);
966
967 if ((namelen > 1) && (name[0] == '.') && (name[1] != '.'))
968 dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
969 }
970
971 if (!(fileStat->st_mode & S_IWUSR))
972 dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
973
974 return dwFileAttributes;
975}
976
977static BOOL FindDataFromStat(const char* path, const struct stat* fileStat,
978 LPWIN32_FIND_DATAA lpFindFileData)
979{
980 UINT64 ft = 0;
981 lpFindFileData->dwFileAttributes = FileAttributesFromStat(path, fileStat);
982
983#ifdef _DARWIN_FEATURE_64_BIT_INODE
984 ft = STAT_TIME_TO_FILETIME(fileStat->st_birthtime);
985#else
986 ft = STAT_TIME_TO_FILETIME(fileStat->st_ctime);
987#endif
988 lpFindFileData->ftCreationTime.dwHighDateTime = (ft) >> 32ULL;
989 lpFindFileData->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
990 ft = STAT_TIME_TO_FILETIME(fileStat->st_mtime);
991 lpFindFileData->ftLastWriteTime.dwHighDateTime = (ft) >> 32ULL;
992 lpFindFileData->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
993 ft = STAT_TIME_TO_FILETIME(fileStat->st_atime);
994 lpFindFileData->ftLastAccessTime.dwHighDateTime = (ft) >> 32ULL;
995 lpFindFileData->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
996 lpFindFileData->nFileSizeHigh = ((UINT64)fileStat->st_size) >> 32ULL;
997 lpFindFileData->nFileSizeLow = fileStat->st_size & 0xFFFFFFFF;
998 return TRUE;
999}
1000
1001HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
1002{
1003 if (!lpFindFileData || !lpFileName)
1004 {
1005 SetLastError(ERROR_BAD_ARGUMENTS);
1006 return INVALID_HANDLE_VALUE;
1007 }
1008
1009 const WIN32_FIND_DATAA empty = WINPR_C_ARRAY_INIT;
1010 *lpFindFileData = empty;
1011
1012 WIN32_FILE_SEARCH* pFileSearch = nullptr;
1013 size_t patternlen = 0;
1014 const size_t flen = strlen(lpFileName);
1015 const char sep = PathGetSeparatorA(PATH_STYLE_NATIVE);
1016 const char* ptr = strrchr(lpFileName, sep);
1017 if (!ptr)
1018 goto fail;
1019 patternlen = strlen(ptr + 1);
1020 if (patternlen == 0)
1021 goto fail;
1022
1023 pFileSearch = file_search_new(lpFileName, flen - patternlen, ptr + 1, patternlen);
1024
1025 if (!pFileSearch)
1026 return INVALID_HANDLE_VALUE;
1027
1028 if (FindNextFileA((HANDLE)pFileSearch, lpFindFileData))
1029 return (HANDLE)pFileSearch;
1030
1031fail:
1032 FindClose(pFileSearch);
1033 return INVALID_HANDLE_VALUE;
1034}
1035
1036static BOOL ConvertFindDataAToW(LPWIN32_FIND_DATAA lpFindFileDataA,
1037 LPWIN32_FIND_DATAW lpFindFileDataW)
1038{
1039 if (!lpFindFileDataA || !lpFindFileDataW)
1040 return FALSE;
1041
1042 lpFindFileDataW->dwFileAttributes = lpFindFileDataA->dwFileAttributes;
1043 lpFindFileDataW->ftCreationTime = lpFindFileDataA->ftCreationTime;
1044 lpFindFileDataW->ftLastAccessTime = lpFindFileDataA->ftLastAccessTime;
1045 lpFindFileDataW->ftLastWriteTime = lpFindFileDataA->ftLastWriteTime;
1046 lpFindFileDataW->nFileSizeHigh = lpFindFileDataA->nFileSizeHigh;
1047 lpFindFileDataW->nFileSizeLow = lpFindFileDataA->nFileSizeLow;
1048 lpFindFileDataW->dwReserved0 = lpFindFileDataA->dwReserved0;
1049 lpFindFileDataW->dwReserved1 = lpFindFileDataA->dwReserved1;
1050
1051 if (ConvertUtf8NToWChar(lpFindFileDataA->cFileName, ARRAYSIZE(lpFindFileDataA->cFileName),
1052 lpFindFileDataW->cFileName, ARRAYSIZE(lpFindFileDataW->cFileName)) < 0)
1053 return FALSE;
1054
1055 return ConvertUtf8NToWChar(lpFindFileDataA->cAlternateFileName,
1056 ARRAYSIZE(lpFindFileDataA->cAlternateFileName),
1057 lpFindFileDataW->cAlternateFileName,
1058 ARRAYSIZE(lpFindFileDataW->cAlternateFileName)) >= 0;
1059}
1060
1061HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData)
1062{
1063 LPSTR utfFileName = nullptr;
1064 HANDLE h = nullptr;
1065 if (!lpFileName)
1066 return INVALID_HANDLE_VALUE;
1067
1069
1070 if (!fd)
1071 {
1072 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1073 return INVALID_HANDLE_VALUE;
1074 }
1075
1076 utfFileName = ConvertWCharToUtf8Alloc(lpFileName, nullptr);
1077 if (!utfFileName)
1078 {
1079 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1080 free(fd);
1081 return INVALID_HANDLE_VALUE;
1082 }
1083
1084 h = FindFirstFileA(utfFileName, fd);
1085 free(utfFileName);
1086
1087 if (h != INVALID_HANDLE_VALUE)
1088 {
1089 if (!ConvertFindDataAToW(fd, lpFindFileData))
1090 {
1091 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1092 FindClose(h);
1093 h = INVALID_HANDLE_VALUE;
1094 goto out;
1095 }
1096 }
1097
1098out:
1099 free(fd);
1100 return h;
1101}
1102
1103HANDLE FindFirstFileExA(WINPR_ATTR_UNUSED LPCSTR lpFileName,
1104 WINPR_ATTR_UNUSED FINDEX_INFO_LEVELS fInfoLevelId,
1105 WINPR_ATTR_UNUSED LPVOID lpFindFileData,
1106 WINPR_ATTR_UNUSED FINDEX_SEARCH_OPS fSearchOp,
1107 WINPR_ATTR_UNUSED LPVOID lpSearchFilter,
1108 WINPR_ATTR_UNUSED DWORD dwAdditionalFlags)
1109{
1110 WLog_ERR("TODO", "TODO: Implement");
1111 return INVALID_HANDLE_VALUE;
1112}
1113
1114HANDLE FindFirstFileExW(WINPR_ATTR_UNUSED LPCWSTR lpFileName,
1115 WINPR_ATTR_UNUSED FINDEX_INFO_LEVELS fInfoLevelId,
1116 WINPR_ATTR_UNUSED LPVOID lpFindFileData,
1117 WINPR_ATTR_UNUSED FINDEX_SEARCH_OPS fSearchOp,
1118 WINPR_ATTR_UNUSED LPVOID lpSearchFilter,
1119 WINPR_ATTR_UNUSED DWORD dwAdditionalFlags)
1120{
1121 WLog_ERR("TODO", "TODO: Implement");
1122 return INVALID_HANDLE_VALUE;
1123}
1124
1125BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
1126{
1127 if (!lpFindFileData)
1128 return FALSE;
1129
1130 const WIN32_FIND_DATAA empty = WINPR_C_ARRAY_INIT;
1131 *lpFindFileData = empty;
1132
1133 if (!is_valid_file_search_handle(hFindFile))
1134 return FALSE;
1135
1136 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1137 struct dirent* pDirent = nullptr;
1138 // NOLINTNEXTLINE(concurrency-mt-unsafe)
1139 while ((pDirent = readdir(pFileSearch->pDir)) != nullptr)
1140 {
1141 if (FilePatternMatchA(pDirent->d_name, pFileSearch->lpPattern))
1142 {
1143 BOOL success = FALSE;
1144
1145 strncpy(lpFindFileData->cFileName, pDirent->d_name, MAX_PATH);
1146 const size_t namelen = strnlen(lpFindFileData->cFileName, MAX_PATH);
1147 size_t pathlen = strlen(pFileSearch->lpPath);
1148 char* fullpath = (char*)malloc(pathlen + namelen + 2);
1149
1150 if (fullpath == nullptr)
1151 {
1152 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1153 return FALSE;
1154 }
1155
1156 memcpy(fullpath, pFileSearch->lpPath, pathlen);
1157 /* Ensure path is terminated with a separator, but prevent
1158 * duplicate separators */
1159 if (fullpath[pathlen - 1] != '/')
1160 fullpath[pathlen++] = '/';
1161 memcpy(fullpath + pathlen, pDirent->d_name, namelen);
1162 fullpath[pathlen + namelen] = 0;
1163
1164 struct stat fileStat = WINPR_C_ARRAY_INIT;
1165 if (stat(fullpath, &fileStat) != 0)
1166 {
1167 free(fullpath);
1168 SetLastError(map_posix_err(errno));
1169 errno = 0;
1170 continue;
1171 }
1172
1173 /* Skip FIFO entries. */
1174 if (S_ISFIFO(fileStat.st_mode))
1175 {
1176 free(fullpath);
1177 continue;
1178 }
1179
1180 success = FindDataFromStat(fullpath, &fileStat, lpFindFileData);
1181 free(fullpath);
1182 return success;
1183 }
1184 }
1185
1186 SetLastError(ERROR_NO_MORE_FILES);
1187 return FALSE;
1188}
1189
1190BOOL FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)
1191{
1193
1194 if (!fd)
1195 {
1196 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1197 return FALSE;
1198 }
1199
1200 if (FindNextFileA(hFindFile, fd))
1201 {
1202 if (!ConvertFindDataAToW(fd, lpFindFileData))
1203 {
1204 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1205 free(fd);
1206 return FALSE;
1207 }
1208
1209 free(fd);
1210 return TRUE;
1211 }
1212
1213 free(fd);
1214 return FALSE;
1215}
1216
1217BOOL FindClose(HANDLE hFindFile)
1218{
1219 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1220 if (!pFileSearch)
1221 return FALSE;
1222
1223 /* Since INVALID_HANDLE_VALUE != nullptr the analyzer guesses that there
1224 * is a initialized HANDLE that is not freed properly.
1225 * Disable this return to stop confusing the analyzer. */
1226#ifndef __clang_analyzer__
1227 if (!is_valid_file_search_handle(hFindFile))
1228 return FALSE;
1229#endif
1230
1231 free(pFileSearch->lpPath);
1232 free(pFileSearch->lpPattern);
1233
1234 if (pFileSearch->pDir)
1235 closedir(pFileSearch->pDir);
1236
1237 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc)
1238 free(pFileSearch);
1239 return TRUE;
1240}
1241
1242BOOL CreateDirectoryA(LPCSTR lpPathName,
1243 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1244{
1245 return mkdir(lpPathName, S_IRUSR | S_IWUSR | S_IXUSR) == 0;
1246}
1247
1248BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1249{
1250 if (!lpPathName)
1251 return FALSE;
1252 char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName, nullptr);
1253 BOOL ret = FALSE;
1254
1255 if (!utfPathName)
1256 {
1257 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1258 goto fail;
1259 }
1260
1261 ret = CreateDirectoryA(utfPathName, lpSecurityAttributes);
1262fail:
1263 free(utfPathName);
1264 return ret;
1265}
1266
1267BOOL RemoveDirectoryA(LPCSTR lpPathName)
1268{
1269 return winpr_RemoveDirectory(lpPathName);
1270}
1271
1272BOOL RemoveDirectoryW(LPCWSTR lpPathName)
1273{
1274 if (!lpPathName)
1275 return FALSE;
1276 char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName, nullptr);
1277 BOOL ret = FALSE;
1278
1279 if (!utfPathName)
1280 {
1281 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1282 goto fail;
1283 }
1284
1285 ret = winpr_RemoveDirectory(utfPathName);
1286fail:
1287 free(utfPathName);
1288 return ret;
1289}
1290
1291BOOL MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
1292{
1293 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, dwFlags);
1294}
1295
1296BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags)
1297{
1298 if (!lpExistingFileName || !lpNewFileName)
1299 return FALSE;
1300
1301 LPSTR lpCExistingFileName = ConvertWCharToUtf8Alloc(lpExistingFileName, nullptr);
1302 LPSTR lpCNewFileName = ConvertWCharToUtf8Alloc(lpNewFileName, nullptr);
1303 BOOL ret = FALSE;
1304
1305 if (!lpCExistingFileName || !lpCNewFileName)
1306 {
1307 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1308 goto fail;
1309 }
1310
1311 ret = winpr_MoveFileEx(lpCExistingFileName, lpCNewFileName, dwFlags);
1312fail:
1313 free(lpCNewFileName);
1314 free(lpCExistingFileName);
1315 return ret;
1316}
1317
1318BOOL MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
1319{
1320 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
1321}
1322
1323BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
1324{
1325 return MoveFileExW(lpExistingFileName, lpNewFileName, 0);
1326}
1327
1328#endif
1329
1330/* Extended API */
1331
1332int UnixChangeFileMode(const char* filename, int flags)
1333{
1334 if (!filename)
1335 return -1;
1336#ifndef _WIN32
1337 mode_t fl = 0;
1338 fl |= (flags & 0x4000) ? S_ISUID : 0;
1339 fl |= (flags & 0x2000) ? S_ISGID : 0;
1340 fl |= (flags & 0x1000) ? S_ISVTX : 0;
1341 fl |= (flags & 0x0400) ? S_IRUSR : 0;
1342 fl |= (flags & 0x0200) ? S_IWUSR : 0;
1343 fl |= (flags & 0x0100) ? S_IXUSR : 0;
1344 fl |= (flags & 0x0040) ? S_IRGRP : 0;
1345 fl |= (flags & 0x0020) ? S_IWGRP : 0;
1346 fl |= (flags & 0x0010) ? S_IXGRP : 0;
1347 fl |= (flags & 0x0004) ? S_IROTH : 0;
1348 fl |= (flags & 0x0002) ? S_IWOTH : 0;
1349 fl |= (flags & 0x0001) ? S_IXOTH : 0;
1350 return chmod(filename, fl);
1351#else
1352 int rc;
1353 WCHAR* wfl = ConvertUtf8ToWCharAlloc(filename, nullptr);
1354
1355 if (!wfl)
1356 return -1;
1357
1358 /* Check for unsupported flags. */
1359 if (flags & ~(_S_IREAD | _S_IWRITE))
1360 WLog_WARN(TAG, "Unsupported file mode %d for _wchmod", flags);
1361
1362 rc = _wchmod(wfl, flags);
1363 free(wfl);
1364 return rc;
1365#endif
1366}
1367
1368#if defined(_WIN32) || defined(_UWP)
1369HANDLE winpr_CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1370 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1371 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1372{
1373 WCHAR* filename = ConvertUtf8ToWCharAlloc(lpFileName, nullptr);
1374 if (!filename)
1375 return nullptr;
1376
1377 HANDLE hdl = CreateFileW(filename, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1378 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1379 free(filename);
1380 return hdl;
1381}
1382#endif