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