Coverage Report

Created: 2025-07-01 06:46

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