Coverage Report

Created: 2024-09-08 06:18

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