Coverage Report

Created: 2026-02-26 06:50

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