1 /**
2 * WinPR: Windows Portable Runtime
3 * File Functions
4 *
5 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Copyright 2014 Hewlett-Packard Development Company, L.P.
7 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <winpr/crt.h>
27 #include <winpr/path.h>
28 #include <winpr/file.h>
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #ifdef 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 <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 HAVE_AIO_H
56 #undef HAVE_AIO_H /* disable for now, incomplete */
57 #endif
58
59 #ifdef 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
75 /**
76 * api-ms-win-core-file-l1-2-0.dll:
77 *
78 * CreateFileA
79 * CreateFileW
80 * CreateFile2
81 * DeleteFileA
82 * DeleteFileW
83 * CreateDirectoryA
84 * CreateDirectoryW
85 * RemoveDirectoryA
86 * RemoveDirectoryW
87 * CompareFileTime
88 * DefineDosDeviceW
89 * DeleteVolumeMountPointW
90 * FileTimeToLocalFileTime
91 * LocalFileTimeToFileTime
92 * FindClose
93 * FindCloseChangeNotification
94 * FindFirstChangeNotificationA
95 * FindFirstChangeNotificationW
96 * FindFirstFileA
97 * FindFirstFileExA
98 * FindFirstFileExW
99 * FindFirstFileW
100 * FindFirstVolumeW
101 * FindNextChangeNotification
102 * FindNextFileA
103 * FindNextFileW
104 * FindNextVolumeW
105 * FindVolumeClose
106 * GetDiskFreeSpaceA
107 * GetDiskFreeSpaceExA
108 * GetDiskFreeSpaceExW
109 * GetDiskFreeSpaceW
110 * GetDriveTypeA
111 * GetDriveTypeW
112 * GetFileAttributesA
113 * GetFileAttributesExA
114 * GetFileAttributesExW
115 * GetFileAttributesW
116 * GetFileInformationByHandle
117 * GetFileSize
118 * GetFileSizeEx
119 * GetFileTime
120 * GetFileType
121 * GetFinalPathNameByHandleA
122 * GetFinalPathNameByHandleW
123 * GetFullPathNameA
124 * GetFullPathNameW
125 * GetLogicalDrives
126 * GetLogicalDriveStringsW
127 * GetLongPathNameA
128 * GetLongPathNameW
129 * GetShortPathNameW
130 * GetTempFileNameW
131 * GetTempPathW
132 * GetVolumeInformationByHandleW
133 * GetVolumeInformationW
134 * GetVolumeNameForVolumeMountPointW
135 * GetVolumePathNamesForVolumeNameW
136 * GetVolumePathNameW
137 * QueryDosDeviceW
138 * SetFileAttributesA
139 * SetFileAttributesW
140 * SetFileTime
141 * SetFileValidData
142 * SetFileInformationByHandle
143 * ReadFile
144 * ReadFileEx
145 * ReadFileScatter
146 * WriteFile
147 * WriteFileEx
148 * WriteFileGather
149 * FlushFileBuffers
150 * SetEndOfFile
151 * SetFilePointer
152 * SetFilePointerEx
153 * LockFile
154 * LockFileEx
155 * UnlockFile
156 * UnlockFileEx
157 */
158
159 /**
160 * File System Behavior in the Microsoft Windows Environment:
161 * http://download.microsoft.com/download/4/3/8/43889780-8d45-4b2e-9d3a-c696a890309f/File%20System%20Behavior%20Overview.pdf
162 */
163
164 /**
165 * Asynchronous I/O - The GNU C Library:
166 * http://www.gnu.org/software/libc/manual/html_node/Asynchronous-I_002fO.html
167 */
168
169 /**
170 * aio.h - asynchronous input and output:
171 * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/aio.h.html
172 */
173
174 /**
175 * Asynchronous I/O User Guide:
176 * http://code.google.com/p/kernel/wiki/AIOUserGuide
177 */
178
179 #define EPOCH_DIFF 11644473600LL
180 #define STAT_TIME_TO_FILETIME(_t) (((UINT64)(_t) + EPOCH_DIFF) * 10000000LL)
181
182 static wArrayList* _HandleCreators;
183
184 static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT;
185
186 extern HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void);
187
188 #if defined __linux__ && !defined ANDROID
189 extern HANDLE_CREATOR* GetCommHandleCreator(void);
190 #endif /* __linux__ && !defined ANDROID */
191
_HandleCreatorsInit()192 static void _HandleCreatorsInit()
193 {
194 assert(_HandleCreators == NULL);
195 _HandleCreators = ArrayList_New(TRUE);
196
197 if (!_HandleCreators)
198 return;
199
200 /*
201 * Register all file handle creators.
202 */
203 ArrayList_Add(_HandleCreators, GetNamedPipeClientHandleCreator());
204 #if defined __linux__ && !defined ANDROID
205 ArrayList_Add(_HandleCreators, GetCommHandleCreator());
206 #endif /* __linux__ && !defined ANDROID */
207 ArrayList_Add(_HandleCreators, GetFileHandleCreator());
208 }
209
210 #ifdef HAVE_AIO_H
211
212 static BOOL g_AioSignalHandlerInstalled = FALSE;
213
AioSignalHandler(int signum,siginfo_t * siginfo,void * arg)214 void AioSignalHandler(int signum, siginfo_t* siginfo, void* arg)
215 {
216 WLog_INFO("%d", signum);
217 }
218
InstallAioSignalHandler()219 int InstallAioSignalHandler()
220 {
221 if (!g_AioSignalHandlerInstalled)
222 {
223 struct sigaction action;
224 sigemptyset(&action.sa_mask);
225 sigaddset(&action.sa_mask, SIGIO);
226 action.sa_flags = SA_SIGINFO;
227 action.sa_sigaction = (void*)&AioSignalHandler;
228 sigaction(SIGIO, &action, NULL);
229 g_AioSignalHandlerInstalled = TRUE;
230 }
231
232 return 0;
233 }
234
235 #endif /* HAVE_AIO_H */
236
CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)237 HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
238 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
239 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
240 {
241 int i;
242
243 if (!lpFileName)
244 return INVALID_HANDLE_VALUE;
245
246 if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0)
247 {
248 SetLastError(ERROR_DLL_INIT_FAILED);
249 return INVALID_HANDLE_VALUE;
250 }
251
252 if (_HandleCreators == NULL)
253 {
254 SetLastError(ERROR_DLL_INIT_FAILED);
255 return INVALID_HANDLE_VALUE;
256 }
257
258 ArrayList_Lock(_HandleCreators);
259
260 for (i = 0; i <= ArrayList_Count(_HandleCreators); i++)
261 {
262 HANDLE_CREATOR* creator = ArrayList_GetItem(_HandleCreators, i);
263
264 if (creator && creator->IsHandled(lpFileName))
265 {
266 HANDLE newHandle =
267 creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
268 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
269 ArrayList_Unlock(_HandleCreators);
270 return newHandle;
271 }
272 }
273
274 ArrayList_Unlock(_HandleCreators);
275 return INVALID_HANDLE_VALUE;
276 }
277
CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)278 HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
279 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
280 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
281 {
282 LPSTR lpFileNameA = NULL;
283 HANDLE hdl;
284
285 if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL) < 1)
286 return NULL;
287
288 hdl = CreateFileA(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
289 dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
290 free(lpFileNameA);
291 return hdl;
292 }
293
DeleteFileA(LPCSTR lpFileName)294 BOOL DeleteFileA(LPCSTR lpFileName)
295 {
296 int status;
297 status = unlink(lpFileName);
298 return (status != -1) ? TRUE : FALSE;
299 }
300
DeleteFileW(LPCWSTR lpFileName)301 BOOL DeleteFileW(LPCWSTR lpFileName)
302 {
303 LPSTR lpFileNameA = NULL;
304 BOOL rc = FALSE;
305
306 if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL) < 1)
307 return FALSE;
308
309 rc = DeleteFileA(lpFileNameA);
310 free(lpFileNameA);
311 return rc;
312 }
313
ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)314 BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
315 LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
316 {
317 ULONG Type;
318 WINPR_HANDLE* handle;
319
320 if (hFile == INVALID_HANDLE_VALUE)
321 return FALSE;
322
323 /*
324 * from http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
325 * lpNumberOfBytesRead can be NULL only when the lpOverlapped parameter is not NULL.
326 */
327
328 if (!lpNumberOfBytesRead && !lpOverlapped)
329 return FALSE;
330
331 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
332 return FALSE;
333
334 handle = (WINPR_HANDLE*)hFile;
335
336 if (handle->ops->ReadFile)
337 return handle->ops->ReadFile(handle, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
338 lpOverlapped);
339
340 WLog_ERR(TAG, "ReadFile operation not implemented");
341 return FALSE;
342 }
343
ReadFileEx(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)344 BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
345 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
346 {
347 ULONG Type;
348 WINPR_HANDLE* handle;
349
350 if (hFile == INVALID_HANDLE_VALUE)
351 return FALSE;
352
353 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
354 return FALSE;
355
356 handle = (WINPR_HANDLE*)hFile;
357
358 if (handle->ops->ReadFileEx)
359 return handle->ops->ReadFileEx(handle, lpBuffer, nNumberOfBytesToRead, lpOverlapped,
360 lpCompletionRoutine);
361
362 WLog_ERR(TAG, "ReadFileEx operation not implemented");
363 return FALSE;
364 }
365
ReadFileScatter(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToRead,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped)366 BOOL ReadFileScatter(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead,
367 LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
368 {
369 ULONG Type;
370 WINPR_HANDLE* handle;
371
372 if (hFile == INVALID_HANDLE_VALUE)
373 return FALSE;
374
375 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
376 return FALSE;
377
378 handle = (WINPR_HANDLE*)hFile;
379
380 if (handle->ops->ReadFileScatter)
381 return handle->ops->ReadFileScatter(handle, aSegmentArray, nNumberOfBytesToRead, lpReserved,
382 lpOverlapped);
383
384 WLog_ERR(TAG, "ReadFileScatter operation not implemented");
385 return FALSE;
386 }
387
WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)388 BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
389 LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
390 {
391 ULONG Type;
392 WINPR_HANDLE* handle;
393
394 if (hFile == INVALID_HANDLE_VALUE)
395 return FALSE;
396
397 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
398 return FALSE;
399
400 handle = (WINPR_HANDLE*)hFile;
401
402 if (handle->ops->WriteFile)
403 return handle->ops->WriteFile(handle, lpBuffer, nNumberOfBytesToWrite,
404 lpNumberOfBytesWritten, lpOverlapped);
405
406 WLog_ERR(TAG, "WriteFile operation not implemented");
407 return FALSE;
408 }
409
WriteFileEx(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)410 BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
411 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
412 {
413 ULONG Type;
414 WINPR_HANDLE* handle;
415
416 if (hFile == INVALID_HANDLE_VALUE)
417 return FALSE;
418
419 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
420 return FALSE;
421
422 handle = (WINPR_HANDLE*)hFile;
423
424 if (handle->ops->WriteFileEx)
425 return handle->ops->WriteFileEx(handle, lpBuffer, nNumberOfBytesToWrite, lpOverlapped,
426 lpCompletionRoutine);
427
428 WLog_ERR(TAG, "WriteFileEx operation not implemented");
429 return FALSE;
430 }
431
WriteFileGather(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToWrite,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped)432 BOOL WriteFileGather(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[],
433 DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
434 {
435 ULONG Type;
436 WINPR_HANDLE* handle;
437
438 if (hFile == INVALID_HANDLE_VALUE)
439 return FALSE;
440
441 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
442 return FALSE;
443
444 handle = (WINPR_HANDLE*)hFile;
445
446 if (handle->ops->WriteFileGather)
447 return handle->ops->WriteFileGather(handle, aSegmentArray, nNumberOfBytesToWrite,
448 lpReserved, lpOverlapped);
449
450 WLog_ERR(TAG, "WriteFileGather operation not implemented");
451 return FALSE;
452 }
453
FlushFileBuffers(HANDLE hFile)454 BOOL FlushFileBuffers(HANDLE hFile)
455 {
456 ULONG Type;
457 WINPR_HANDLE* handle;
458
459 if (hFile == INVALID_HANDLE_VALUE)
460 return FALSE;
461
462 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
463 return FALSE;
464
465 handle = (WINPR_HANDLE*)hFile;
466
467 if (handle->ops->FlushFileBuffers)
468 return handle->ops->FlushFileBuffers(handle);
469
470 WLog_ERR(TAG, "FlushFileBuffers operation not implemented");
471 return FALSE;
472 }
473
GetFileAttributesExA(LPCSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation)474 BOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
475 LPVOID lpFileInformation)
476 {
477 LPWIN32_FILE_ATTRIBUTE_DATA fd = lpFileInformation;
478 WIN32_FIND_DATAA findFileData;
479 HANDLE hFind;
480
481 if (!fd)
482 return FALSE;
483
484 if ((hFind = FindFirstFileA(lpFileName, &findFileData)) == INVALID_HANDLE_VALUE)
485 return FALSE;
486
487 FindClose(hFind);
488 fd->dwFileAttributes = findFileData.dwFileAttributes;
489 fd->ftCreationTime = findFileData.ftCreationTime;
490 fd->ftLastAccessTime = findFileData.ftLastAccessTime;
491 fd->ftLastWriteTime = findFileData.ftLastWriteTime;
492 fd->nFileSizeHigh = findFileData.nFileSizeHigh;
493 fd->nFileSizeLow = findFileData.nFileSizeLow;
494 return TRUE;
495 }
496
GetFileAttributesExW(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation)497 BOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
498 LPVOID lpFileInformation)
499 {
500 BOOL ret;
501 LPSTR lpCFileName;
502
503 if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL) <= 0)
504 {
505 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
506 return FALSE;
507 }
508
509 ret = GetFileAttributesExA(lpCFileName, fInfoLevelId, lpFileInformation);
510 free(lpCFileName);
511 return ret;
512 }
513
GetFileAttributesA(LPCSTR lpFileName)514 DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
515 {
516 WIN32_FIND_DATAA findFileData;
517 HANDLE hFind;
518
519 if ((hFind = FindFirstFileA(lpFileName, &findFileData)) == INVALID_HANDLE_VALUE)
520 return INVALID_FILE_ATTRIBUTES;
521
522 FindClose(hFind);
523 return findFileData.dwFileAttributes;
524 }
525
GetFileAttributesW(LPCWSTR lpFileName)526 DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
527 {
528 DWORD ret;
529 LPSTR lpCFileName;
530
531 if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL) <= 0)
532 {
533 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
534 return FALSE;
535 }
536
537 ret = GetFileAttributesA(lpCFileName);
538 free(lpCFileName);
539 return ret;
540 }
541
append(char * buffer,size_t size,const char * append)542 static char* append(char* buffer, size_t size, const char* append)
543 {
544 const size_t len = strnlen(buffer, size);
545 if (len == 0)
546 _snprintf(buffer, size, "%s", append);
547 else
548 {
549 strcat(buffer, "|");
550 strcat(buffer, append);
551 }
552
553 return buffer;
554 }
555
flagsToStr(char * buffer,size_t size,DWORD flags)556 static const char* flagsToStr(char* buffer, size_t size, DWORD flags)
557 {
558 char strflags[32] = { 0 };
559 if (flags & FILE_ATTRIBUTE_READONLY)
560 append(buffer, size, "FILE_ATTRIBUTE_READONLY");
561 if (flags & FILE_ATTRIBUTE_HIDDEN)
562 append(buffer, size, "FILE_ATTRIBUTE_HIDDEN");
563 if (flags & FILE_ATTRIBUTE_SYSTEM)
564 append(buffer, size, "FILE_ATTRIBUTE_SYSTEM");
565 if (flags & FILE_ATTRIBUTE_DIRECTORY)
566 append(buffer, size, "FILE_ATTRIBUTE_DIRECTORY");
567 if (flags & FILE_ATTRIBUTE_ARCHIVE)
568 append(buffer, size, "FILE_ATTRIBUTE_ARCHIVE");
569 if (flags & FILE_ATTRIBUTE_DEVICE)
570 append(buffer, size, "FILE_ATTRIBUTE_DEVICE");
571 if (flags & FILE_ATTRIBUTE_NORMAL)
572 append(buffer, size, "FILE_ATTRIBUTE_NORMAL");
573 if (flags & FILE_ATTRIBUTE_TEMPORARY)
574 append(buffer, size, "FILE_ATTRIBUTE_TEMPORARY");
575 if (flags & FILE_ATTRIBUTE_SPARSE_FILE)
576 append(buffer, size, "FILE_ATTRIBUTE_SPARSE_FILE");
577 if (flags & FILE_ATTRIBUTE_REPARSE_POINT)
578 append(buffer, size, "FILE_ATTRIBUTE_REPARSE_POINT");
579 if (flags & FILE_ATTRIBUTE_COMPRESSED)
580 append(buffer, size, "FILE_ATTRIBUTE_COMPRESSED");
581 if (flags & FILE_ATTRIBUTE_OFFLINE)
582 append(buffer, size, "FILE_ATTRIBUTE_OFFLINE");
583 if (flags & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
584 append(buffer, size, "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED");
585 if (flags & FILE_ATTRIBUTE_ENCRYPTED)
586 append(buffer, size, "FILE_ATTRIBUTE_ENCRYPTED");
587 if (flags & FILE_ATTRIBUTE_VIRTUAL)
588 append(buffer, size, "FILE_ATTRIBUTE_VIRTUAL");
589
590 _snprintf(strflags, sizeof(strflags), " [0x%08" PRIx32 "]", flags);
591 strcat(buffer, strflags);
592 return buffer;
593 }
594
SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes)595 BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
596 {
597 struct stat st;
598 int fd;
599 BOOL rc = FALSE;
600
601 if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
602 {
603 char buffer[8192] = { 0 };
604 const char* flags =
605 flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
606 WLog_WARN(TAG, "[%s] Unsupported flags %s, ignoring!", __FUNCTION__, flags);
607 }
608
609 fd = open(lpFileName, O_RDONLY);
610 if (fd < 0)
611 return FALSE;
612
613 if (fstat(fd, &st) != 0)
614 goto fail;
615
616 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
617 {
618 st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
619 }
620 else
621 {
622 st.st_mode |= S_IWUSR;
623 }
624
625 if (fchmod(fd, st.st_mode) != 0)
626 goto fail;
627
628 rc = TRUE;
629 fail:
630 close(fd);
631 return rc;
632 }
633
SetFileAttributesW(LPCWSTR lpFileName,DWORD dwFileAttributes)634 BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
635 {
636 BOOL ret;
637 LPSTR lpCFileName;
638
639 if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
640 {
641 char buffer[8192] = { 0 };
642 const char* flags =
643 flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
644 WLog_WARN(TAG, "[%s] Unsupported flags %s, ignoring!", __FUNCTION__, flags);
645 }
646
647 if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL) <= 0)
648 {
649 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
650 return FALSE;
651 }
652
653 ret = SetFileAttributesA(lpCFileName, dwFileAttributes);
654 free(lpCFileName);
655 return ret;
656 }
657
SetEndOfFile(HANDLE hFile)658 BOOL SetEndOfFile(HANDLE hFile)
659 {
660 ULONG Type;
661 WINPR_HANDLE* handle;
662
663 if (hFile == INVALID_HANDLE_VALUE)
664 return FALSE;
665
666 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
667 return FALSE;
668
669 handle = (WINPR_HANDLE*)hFile;
670
671 if (handle->ops->SetEndOfFile)
672 return handle->ops->SetEndOfFile(handle);
673
674 WLog_ERR(TAG, "SetEndOfFile operation not implemented");
675 return FALSE;
676 }
677
GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh)678 DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
679 {
680 ULONG Type;
681 WINPR_HANDLE* handle;
682
683 if (hFile == INVALID_HANDLE_VALUE)
684 return FALSE;
685
686 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
687 return FALSE;
688
689 handle = (WINPR_HANDLE*)hFile;
690
691 if (handle->ops->GetFileSize)
692 return handle->ops->GetFileSize(handle, lpFileSizeHigh);
693
694 WLog_ERR(TAG, "GetFileSize operation not implemented");
695 return 0;
696 }
697
SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod)698 DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
699 DWORD dwMoveMethod)
700 {
701 ULONG Type;
702 WINPR_HANDLE* handle;
703
704 if (hFile == INVALID_HANDLE_VALUE)
705 return FALSE;
706
707 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
708 return FALSE;
709
710 handle = (WINPR_HANDLE*)hFile;
711
712 if (handle->ops->SetFilePointer)
713 return handle->ops->SetFilePointer(handle, lDistanceToMove, lpDistanceToMoveHigh,
714 dwMoveMethod);
715
716 WLog_ERR(TAG, "SetFilePointer operation not implemented");
717 return 0;
718 }
719
SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod)720 BOOL SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
721 DWORD dwMoveMethod)
722 {
723 ULONG Type;
724 WINPR_HANDLE* handle;
725
726 if (hFile == INVALID_HANDLE_VALUE)
727 return FALSE;
728
729 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
730 return FALSE;
731
732 handle = (WINPR_HANDLE*)hFile;
733
734 if (handle->ops->SetFilePointerEx)
735 return handle->ops->SetFilePointerEx(handle, liDistanceToMove, lpNewFilePointer,
736 dwMoveMethod);
737
738 WLog_ERR(TAG, "SetFilePointerEx operation not implemented");
739 return 0;
740 }
741
LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh)742 BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
743 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh)
744 {
745 ULONG Type;
746 WINPR_HANDLE* handle;
747
748 if (hFile == INVALID_HANDLE_VALUE)
749 return FALSE;
750
751 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
752 return FALSE;
753
754 handle = (WINPR_HANDLE*)hFile;
755
756 if (handle->ops->LockFile)
757 return handle->ops->LockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
758 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
759
760 WLog_ERR(TAG, "LockFile operation not implemented");
761 return FALSE;
762 }
763
LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh,LPOVERLAPPED lpOverlapped)764 BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow,
765 DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped)
766 {
767 ULONG Type;
768 WINPR_HANDLE* handle;
769
770 if (hFile == INVALID_HANDLE_VALUE)
771 return FALSE;
772
773 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
774 return FALSE;
775
776 handle = (WINPR_HANDLE*)hFile;
777
778 if (handle->ops->LockFileEx)
779 return handle->ops->LockFileEx(handle, dwFlags, dwReserved, nNumberOfBytesToLockLow,
780 nNumberOfBytesToLockHigh, lpOverlapped);
781
782 WLog_ERR(TAG, "LockFileEx operation not implemented");
783 return FALSE;
784 }
785
UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh)786 BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
787 DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
788 {
789 ULONG Type;
790 WINPR_HANDLE* handle;
791
792 if (hFile == INVALID_HANDLE_VALUE)
793 return FALSE;
794
795 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
796 return FALSE;
797
798 handle = (WINPR_HANDLE*)hFile;
799
800 if (handle->ops->UnlockFile)
801 return handle->ops->UnlockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
802 nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
803
804 WLog_ERR(TAG, "UnLockFile operation not implemented");
805 return FALSE;
806 }
807
UnlockFileEx(HANDLE hFile,DWORD dwReserved,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh,LPOVERLAPPED lpOverlapped)808 BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow,
809 DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped)
810 {
811 ULONG Type;
812 WINPR_HANDLE* handle;
813
814 if (hFile == INVALID_HANDLE_VALUE)
815 return FALSE;
816
817 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
818 return FALSE;
819
820 handle = (WINPR_HANDLE*)hFile;
821
822 if (handle->ops->UnlockFileEx)
823 return handle->ops->UnlockFileEx(handle, dwReserved, nNumberOfBytesToUnlockLow,
824 nNumberOfBytesToUnlockHigh, lpOverlapped);
825
826 WLog_ERR(TAG, "UnLockFileEx operation not implemented");
827 return FALSE;
828 }
829
SetFileTime(HANDLE hFile,const FILETIME * lpCreationTime,const FILETIME * lpLastAccessTime,const FILETIME * lpLastWriteTime)830 BOOL WINAPI SetFileTime(HANDLE hFile, const FILETIME* lpCreationTime,
831 const FILETIME* lpLastAccessTime, const FILETIME* lpLastWriteTime)
832 {
833 ULONG Type;
834 WINPR_HANDLE* handle;
835
836 if (hFile == INVALID_HANDLE_VALUE)
837 return FALSE;
838
839 if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
840 return FALSE;
841
842 handle = (WINPR_HANDLE*)hFile;
843
844 if (handle->ops->SetFileTime)
845 return handle->ops->SetFileTime(handle, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
846
847 WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__);
848 return FALSE;
849 }
850
851 struct _WIN32_FILE_SEARCH
852 {
853 DIR* pDir;
854 LPSTR lpPath;
855 LPSTR lpPattern;
856 struct dirent* pDirent;
857 };
858 typedef struct _WIN32_FILE_SEARCH WIN32_FILE_SEARCH;
859
FindDataFromStat(const char * path,const struct stat * fileStat,LPWIN32_FIND_DATAA lpFindFileData)860 static BOOL FindDataFromStat(const char* path, const struct stat* fileStat,
861 LPWIN32_FIND_DATAA lpFindFileData)
862 {
863 UINT64 ft;
864 char* lastSep;
865 lpFindFileData->dwFileAttributes = 0;
866
867 if (S_ISDIR(fileStat->st_mode))
868 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
869
870 if (lpFindFileData->dwFileAttributes == 0)
871 lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
872
873 lastSep = strrchr(path, '/');
874
875 if (lastSep)
876 {
877 const char* name = lastSep + 1;
878 const size_t namelen = strlen(name);
879
880 if ((namelen > 1) && (name[0] == '.') && (name[1] != '.'))
881 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
882 }
883
884 if (!(fileStat->st_mode & S_IWUSR))
885 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
886
887 #ifdef _DARWIN_FEATURE_64_BIT_INODE
888 ft = STAT_TIME_TO_FILETIME(fileStat->st_birthtime);
889 #else
890 ft = STAT_TIME_TO_FILETIME(fileStat->st_ctime);
891 #endif
892 lpFindFileData->ftCreationTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
893 lpFindFileData->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
894 ft = STAT_TIME_TO_FILETIME(fileStat->st_mtime);
895 lpFindFileData->ftLastWriteTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
896 lpFindFileData->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
897 ft = STAT_TIME_TO_FILETIME(fileStat->st_atime);
898 lpFindFileData->ftLastAccessTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
899 lpFindFileData->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
900 lpFindFileData->nFileSizeHigh = ((UINT64)fileStat->st_size) >> 32ULL;
901 lpFindFileData->nFileSizeLow = fileStat->st_size & 0xFFFFFFFF;
902 return TRUE;
903 }
904
FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData)905 HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
906 {
907 BOOL isDir = FALSE;
908 struct stat fileStat;
909 WIN32_FILE_SEARCH* pFileSearch;
910
911 if (!lpFindFileData || !lpFileName)
912 {
913 SetLastError(ERROR_BAD_ARGUMENTS);
914 return INVALID_HANDLE_VALUE;
915 }
916
917 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
918 pFileSearch = (WIN32_FILE_SEARCH*)calloc(1, sizeof(WIN32_FILE_SEARCH));
919
920 if (!pFileSearch)
921 {
922 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
923 return INVALID_HANDLE_VALUE;
924 }
925
926 if (stat(lpFileName, &fileStat) >= 0)
927 {
928 isDir = (S_ISDIR(fileStat.st_mode) != 0);
929 }
930 else
931 errno = 0;
932
933 if (isDir)
934 {
935 pFileSearch->lpPath = _strdup(lpFileName);
936 pFileSearch->lpPattern = _strdup(".");
937 }
938 else
939 {
940 LPSTR p;
941 size_t index;
942 size_t length;
943 /* Separate lpFileName into path and pattern components */
944 p = strrchr(lpFileName, '/');
945
946 if (!p)
947 p = strrchr(lpFileName, '\\');
948
949 index = (p - lpFileName);
950 length = (p - lpFileName) + 1;
951 pFileSearch->lpPath = (LPSTR)malloc(length + 1);
952
953 if (!pFileSearch->lpPath)
954 {
955 free(pFileSearch);
956 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
957 return INVALID_HANDLE_VALUE;
958 }
959
960 CopyMemory(pFileSearch->lpPath, lpFileName, length);
961 pFileSearch->lpPath[length] = '\0';
962 length = strlen(lpFileName) - index;
963 pFileSearch->lpPattern = (LPSTR)malloc(length + 1);
964
965 if (!pFileSearch->lpPattern)
966 {
967 free(pFileSearch->lpPath);
968 free(pFileSearch);
969 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
970 return INVALID_HANDLE_VALUE;
971 }
972
973 CopyMemory(pFileSearch->lpPattern, &lpFileName[index + 1], length);
974 pFileSearch->lpPattern[length] = '\0';
975
976 /* Check if the path is a directory */
977
978 if (stat(pFileSearch->lpPath, &fileStat) < 0)
979 {
980 FindClose(pFileSearch);
981 SetLastError(map_posix_err(errno));
982 errno = 0;
983 return INVALID_HANDLE_VALUE; /* stat error */
984 }
985
986 if (S_ISDIR(fileStat.st_mode) == 0)
987 {
988 FindClose(pFileSearch);
989 return INVALID_HANDLE_VALUE; /* not a directory */
990 }
991 }
992
993 /* Open directory for reading */
994 pFileSearch->pDir = opendir(pFileSearch->lpPath);
995
996 if (!pFileSearch->pDir)
997 {
998 FindClose(pFileSearch);
999 SetLastError(map_posix_err(errno));
1000 errno = 0;
1001 return INVALID_HANDLE_VALUE; /* failed to open directory */
1002 }
1003
1004 if (FindNextFileA((HANDLE)pFileSearch, lpFindFileData))
1005 {
1006 if (isDir)
1007 {
1008 const char* name = strrchr(lpFileName, '/');
1009
1010 if (!name)
1011 name = lpFileName;
1012 else
1013 name++;
1014
1015 pFileSearch->lpPattern[0] = '*';
1016 sprintf_s(lpFindFileData->cFileName, ARRAYSIZE(lpFindFileData->cFileName), "%s", name);
1017 }
1018
1019 return (HANDLE)pFileSearch;
1020 }
1021
1022 FindClose(pFileSearch);
1023 return INVALID_HANDLE_VALUE;
1024 }
1025
ConvertFindDataAToW(LPWIN32_FIND_DATAA lpFindFileDataA,LPWIN32_FIND_DATAW lpFindFileDataW)1026 static BOOL ConvertFindDataAToW(LPWIN32_FIND_DATAA lpFindFileDataA,
1027 LPWIN32_FIND_DATAW lpFindFileDataW)
1028 {
1029 size_t length;
1030 WCHAR* unicodeFileName;
1031
1032 if (!lpFindFileDataA || !lpFindFileDataW)
1033 return FALSE;
1034
1035 lpFindFileDataW->dwFileAttributes = lpFindFileDataA->dwFileAttributes;
1036 lpFindFileDataW->ftCreationTime = lpFindFileDataA->ftCreationTime;
1037 lpFindFileDataW->ftLastAccessTime = lpFindFileDataA->ftLastAccessTime;
1038 lpFindFileDataW->ftLastWriteTime = lpFindFileDataA->ftLastWriteTime;
1039 lpFindFileDataW->nFileSizeHigh = lpFindFileDataA->nFileSizeHigh;
1040 lpFindFileDataW->nFileSizeLow = lpFindFileDataA->nFileSizeLow;
1041 lpFindFileDataW->dwReserved0 = lpFindFileDataA->dwReserved0;
1042 lpFindFileDataW->dwReserved1 = lpFindFileDataA->dwReserved1;
1043 unicodeFileName = NULL;
1044 length = ConvertToUnicode(CP_UTF8, 0, lpFindFileDataA->cFileName, -1, &unicodeFileName, 0);
1045
1046 if (length == 0)
1047 return FALSE;
1048
1049 if (length > MAX_PATH)
1050 length = MAX_PATH;
1051
1052 CopyMemory(lpFindFileDataW->cFileName, unicodeFileName, length * sizeof(WCHAR));
1053 free(unicodeFileName);
1054 length =
1055 ConvertToUnicode(CP_UTF8, 0, lpFindFileDataA->cAlternateFileName, -1, &unicodeFileName, 0);
1056
1057 if (length == 0)
1058 return TRUE;
1059
1060 if (length > 14)
1061 length = 14;
1062
1063 CopyMemory(lpFindFileDataW->cAlternateFileName, unicodeFileName, length * sizeof(WCHAR));
1064 free(unicodeFileName);
1065 return TRUE;
1066 }
1067
FindFirstFileW(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData)1068 HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData)
1069 {
1070 LPSTR utfFileName = NULL;
1071 HANDLE h;
1072 LPWIN32_FIND_DATAA fd = (LPWIN32_FIND_DATAA)calloc(1, sizeof(WIN32_FIND_DATAA));
1073
1074 if (!fd)
1075 {
1076 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1077 return INVALID_HANDLE_VALUE;
1078 }
1079
1080 if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &utfFileName, 0, NULL, NULL) <= 0)
1081 {
1082 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1083 free(fd);
1084 return INVALID_HANDLE_VALUE;
1085 }
1086
1087 h = FindFirstFileA(utfFileName, fd);
1088 free(utfFileName);
1089
1090 if (h != INVALID_HANDLE_VALUE)
1091 {
1092 if (!ConvertFindDataAToW(fd, lpFindFileData))
1093 {
1094 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1095 FindClose(h);
1096 h = INVALID_HANDLE_VALUE;
1097 goto out;
1098 }
1099 }
1100
1101 out:
1102 free(fd);
1103 return h;
1104 }
1105
FindFirstFileExA(LPCSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags)1106 HANDLE FindFirstFileExA(LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData,
1107 FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
1108 {
1109 return INVALID_HANDLE_VALUE;
1110 }
1111
FindFirstFileExW(LPCWSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags)1112 HANDLE FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData,
1113 FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
1114 {
1115 return INVALID_HANDLE_VALUE;
1116 }
1117
FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData)1118 BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
1119 {
1120 WIN32_FILE_SEARCH* pFileSearch;
1121 struct stat fileStat;
1122 char* fullpath;
1123 size_t pathlen;
1124 size_t namelen;
1125
1126 if (!hFindFile || !lpFindFileData)
1127 return FALSE;
1128
1129 if (hFindFile == INVALID_HANDLE_VALUE)
1130 return FALSE;
1131
1132 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
1133 pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1134
1135 while ((pFileSearch->pDirent = readdir(pFileSearch->pDir)) != NULL)
1136 {
1137 if (FilePatternMatchA(pFileSearch->pDirent->d_name, pFileSearch->lpPattern))
1138 {
1139 BOOL success;
1140 strncpy(lpFindFileData->cFileName, pFileSearch->pDirent->d_name, MAX_PATH);
1141 namelen = strnlen(lpFindFileData->cFileName, MAX_PATH);
1142 pathlen = strlen(pFileSearch->lpPath);
1143 fullpath = (char*)malloc(pathlen + namelen + 2);
1144
1145 if (fullpath == NULL)
1146 {
1147 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1148 return FALSE;
1149 }
1150
1151 memcpy(fullpath, pFileSearch->lpPath, pathlen);
1152 /* Ensure path is terminated with a separator, but prevent
1153 * duplicate separators */
1154 if (fullpath[pathlen - 1] != '/')
1155 fullpath[pathlen++] = '/';
1156 memcpy(fullpath + pathlen, pFileSearch->pDirent->d_name, namelen);
1157 fullpath[pathlen + namelen] = 0;
1158
1159 if (stat(fullpath, &fileStat) != 0)
1160 {
1161 free(fullpath);
1162 SetLastError(map_posix_err(errno));
1163 errno = 0;
1164 continue;
1165 }
1166
1167 /* Skip FIFO entries. */
1168 if (S_ISFIFO(fileStat.st_mode))
1169 {
1170 free(fullpath);
1171 continue;
1172 }
1173
1174 success = FindDataFromStat(fullpath, &fileStat, lpFindFileData);
1175 free(fullpath);
1176 return success;
1177 }
1178 }
1179
1180 SetLastError(ERROR_NO_MORE_FILES);
1181 return FALSE;
1182 }
1183
FindNextFileW(HANDLE hFindFile,LPWIN32_FIND_DATAW lpFindFileData)1184 BOOL FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)
1185 {
1186 LPWIN32_FIND_DATAA fd = (LPWIN32_FIND_DATAA)calloc(1, sizeof(WIN32_FIND_DATAA));
1187
1188 if (!fd)
1189 {
1190 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1191 return FALSE;
1192 }
1193
1194 if (FindNextFileA(hFindFile, fd))
1195 {
1196 if (!ConvertFindDataAToW(fd, lpFindFileData))
1197 {
1198 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1199 free(fd);
1200 return FALSE;
1201 }
1202
1203 free(fd);
1204 return TRUE;
1205 }
1206
1207 free(fd);
1208 return FALSE;
1209 }
1210
FindClose(HANDLE hFindFile)1211 BOOL FindClose(HANDLE hFindFile)
1212 {
1213 WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
1214
1215 /* Since INVALID_HANDLE_VALUE != NULL the analyzer guesses that there
1216 * is a initialized HANDLE that is not freed properly.
1217 * Disable this return to stop confusing the analyzer. */
1218 #ifndef __clang_analyzer__
1219 if (!pFileSearch || (pFileSearch == INVALID_HANDLE_VALUE))
1220 return FALSE;
1221 #endif
1222
1223 free(pFileSearch->lpPath);
1224 free(pFileSearch->lpPattern);
1225
1226 if (pFileSearch->pDir)
1227 closedir(pFileSearch->pDir);
1228
1229 free(pFileSearch);
1230 return TRUE;
1231 }
1232
CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes)1233 BOOL CreateDirectoryA(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1234 {
1235 if (!mkdir(lpPathName, S_IRUSR | S_IWUSR | S_IXUSR))
1236 return TRUE;
1237
1238 return FALSE;
1239 }
1240
CreateDirectoryW(LPCWSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes)1241 BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
1242 {
1243 char* utfPathName = NULL;
1244 BOOL ret;
1245
1246 if (ConvertFromUnicode(CP_UTF8, 0, lpPathName, -1, &utfPathName, 0, NULL, NULL) <= 0)
1247 {
1248 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1249 return FALSE;
1250 }
1251
1252 ret = CreateDirectoryA(utfPathName, lpSecurityAttributes);
1253 free(utfPathName);
1254 return ret;
1255 }
1256
RemoveDirectoryA(LPCSTR lpPathName)1257 BOOL RemoveDirectoryA(LPCSTR lpPathName)
1258 {
1259 int ret = rmdir(lpPathName);
1260
1261 if (ret != 0)
1262 SetLastError(map_posix_err(errno));
1263 else
1264 SetLastError(STATUS_SUCCESS);
1265
1266 return ret == 0;
1267 }
1268
RemoveDirectoryW(LPCWSTR lpPathName)1269 BOOL RemoveDirectoryW(LPCWSTR lpPathName)
1270 {
1271 char* utfPathName = NULL;
1272 BOOL ret;
1273
1274 if (ConvertFromUnicode(CP_UTF8, 0, lpPathName, -1, &utfPathName, 0, NULL, NULL) <= 0)
1275 {
1276 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1277 return FALSE;
1278 }
1279
1280 ret = RemoveDirectoryA(utfPathName);
1281 free(utfPathName);
1282 return ret;
1283 }
1284
MoveFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags)1285 BOOL MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
1286 {
1287 struct stat st;
1288 int ret;
1289 ret = stat(lpNewFileName, &st);
1290
1291 if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
1292 {
1293 if (ret == 0)
1294 {
1295 SetLastError(ERROR_ALREADY_EXISTS);
1296 return FALSE;
1297 }
1298 }
1299 else
1300 {
1301 if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
1302 {
1303 SetLastError(ERROR_ACCESS_DENIED);
1304 return FALSE;
1305 }
1306 }
1307
1308 ret = rename(lpExistingFileName, lpNewFileName);
1309
1310 if (ret != 0)
1311 SetLastError(map_posix_err(errno));
1312
1313 return ret == 0;
1314 }
1315
MoveFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,DWORD dwFlags)1316 BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags)
1317 {
1318 LPSTR lpCExistingFileName;
1319 LPSTR lpCNewFileName;
1320 BOOL ret;
1321
1322 if (ConvertFromUnicode(CP_UTF8, 0, lpExistingFileName, -1, &lpCExistingFileName, 0, NULL,
1323 NULL) <= 0)
1324 {
1325 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1326 return FALSE;
1327 }
1328
1329 if (ConvertFromUnicode(CP_UTF8, 0, lpNewFileName, -1, &lpCNewFileName, 0, NULL, NULL) <= 0)
1330 {
1331 free(lpCExistingFileName);
1332 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1333 return FALSE;
1334 }
1335
1336 ret = MoveFileExA(lpCExistingFileName, lpCNewFileName, dwFlags);
1337 free(lpCNewFileName);
1338 free(lpCExistingFileName);
1339 return ret;
1340 }
1341
MoveFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName)1342 BOOL MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
1343 {
1344 return MoveFileExA(lpExistingFileName, lpNewFileName, 0);
1345 }
1346
MoveFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName)1347 BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName)
1348 {
1349 return MoveFileExW(lpExistingFileName, lpNewFileName, 0);
1350 }
1351
1352 #endif
1353
1354 /* Extended API */
1355
UnixChangeFileMode(const char * filename,int flags)1356 int UnixChangeFileMode(const char* filename, int flags)
1357 {
1358 #ifndef _WIN32
1359 mode_t fl = 0;
1360 fl |= (flags & 0x4000) ? S_ISUID : 0;
1361 fl |= (flags & 0x2000) ? S_ISGID : 0;
1362 fl |= (flags & 0x1000) ? S_ISVTX : 0;
1363 fl |= (flags & 0x0400) ? S_IRUSR : 0;
1364 fl |= (flags & 0x0200) ? S_IWUSR : 0;
1365 fl |= (flags & 0x0100) ? S_IXUSR : 0;
1366 fl |= (flags & 0x0040) ? S_IRGRP : 0;
1367 fl |= (flags & 0x0020) ? S_IWGRP : 0;
1368 fl |= (flags & 0x0010) ? S_IXGRP : 0;
1369 fl |= (flags & 0x0004) ? S_IROTH : 0;
1370 fl |= (flags & 0x0002) ? S_IWOTH : 0;
1371 fl |= (flags & 0x0001) ? S_IXOTH : 0;
1372 return chmod(filename, fl);
1373 #else
1374 int rc;
1375 WCHAR* wfl = NULL;
1376 int fl = 0;
1377
1378 if (ConvertToUnicode(CP_UTF8, 0, filename, -1, &wfl, 0) <= 0)
1379 return -1;
1380
1381 /* Check for unsupported flags. */
1382 if (flags & ~(_S_IREAD | _S_IWRITE))
1383 WLog_WARN(TAG, "Unsupported file mode %d for _wchmod", flags);
1384
1385 rc = _wchmod(wfl, flags);
1386 free(wfl);
1387 return rc;
1388 #endif
1389 }
1390