Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/file/file.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * File Functions
4
 *
5
 * Copyright 2015 Thincast Technologies GmbH
6
 * Copyright 2015 Bernhard Miklautz <bernhard.miklautz@thincast.com>
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
#if defined(__FreeBSD_kernel__) && defined(__GLIBC__)
25
#define _GNU_SOURCE
26
#define KFREEBSD
27
#endif
28
29
#include <winpr/wtypes.h>
30
#include <winpr/crt.h>
31
#include <winpr/file.h>
32
33
#ifdef _WIN32
34
35
#include <io.h>
36
37
#else /* _WIN32 */
38
39
#include "../log.h"
40
#define TAG WINPR_TAG("file")
41
42
#include <winpr/wlog.h>
43
#include <winpr/string.h>
44
45
#include "file.h"
46
#include <errno.h>
47
#include <fcntl.h>
48
#include <sys/file.h>
49
#include <sys/stat.h>
50
#include <sys/time.h>
51
52
#ifdef ANDROID
53
#include <sys/vfs.h>
54
#else
55
#include <sys/statvfs.h>
56
#endif
57
58
#ifndef MIN
59
0
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
60
#endif
61
62
static BOOL FileIsHandled(HANDLE handle)
63
0
{
64
0
  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_FILE, FALSE);
65
0
}
66
67
static int FileGetFd(HANDLE handle)
68
0
{
69
0
  WINPR_FILE* file = (WINPR_FILE*)handle;
70
71
0
  if (!FileIsHandled(handle))
72
0
    return -1;
73
74
0
  return fileno(file->fp);
75
0
}
76
77
static BOOL FileCloseHandle(HANDLE handle)
78
0
{
79
0
  WINPR_FILE* file = (WINPR_FILE*)handle;
80
81
0
  if (!FileIsHandled(handle))
82
0
    return FALSE;
83
84
0
  if (file->fp)
85
0
  {
86
    /* Don't close stdin/stdout/stderr */
87
0
    if (fileno(file->fp) > 2)
88
0
    {
89
0
      fclose(file->fp);
90
0
      file->fp = NULL;
91
0
    }
92
0
  }
93
94
0
  free(file->lpFileName);
95
0
  free(file);
96
0
  return TRUE;
97
0
}
98
99
static BOOL FileSetEndOfFile(HANDLE hFile)
100
0
{
101
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
102
0
  INT64 size;
103
104
0
  if (!hFile)
105
0
    return FALSE;
106
107
0
  size = _ftelli64(pFile->fp);
108
109
0
  if (ftruncate(fileno(pFile->fp), size) < 0)
110
0
  {
111
0
    WLog_ERR(TAG, "ftruncate %s failed with %s [0x%08X]", pFile->lpFileName, strerror(errno),
112
0
             errno);
113
0
    SetLastError(map_posix_err(errno));
114
0
    return FALSE;
115
0
  }
116
117
0
  return TRUE;
118
0
}
119
120
static DWORD FileSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
121
                                DWORD dwMoveMethod)
122
0
{
123
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
124
0
  INT64 offset;
125
0
  int whence;
126
127
0
  if (!hFile)
128
0
    return INVALID_SET_FILE_POINTER;
129
130
  /* If there is a high part, the sign is contained in that
131
   * and the low integer must be interpreted as unsigned. */
132
0
  if (lpDistanceToMoveHigh)
133
0
  {
134
0
    offset = (INT64)(((UINT64)*lpDistanceToMoveHigh << 32U) | (UINT64)lDistanceToMove);
135
0
  }
136
0
  else
137
0
    offset = lDistanceToMove;
138
139
0
  switch (dwMoveMethod)
140
0
  {
141
0
    case FILE_BEGIN:
142
0
      whence = SEEK_SET;
143
0
      break;
144
0
    case FILE_END:
145
0
      whence = SEEK_END;
146
0
      break;
147
0
    case FILE_CURRENT:
148
0
      whence = SEEK_CUR;
149
0
      break;
150
0
    default:
151
0
      return INVALID_SET_FILE_POINTER;
152
0
  }
153
154
0
  if (_fseeki64(pFile->fp, offset, whence))
155
0
  {
156
0
    WLog_ERR(TAG, "_fseeki64(%s) failed with %s [0x%08X]", pFile->lpFileName, strerror(errno),
157
0
             errno);
158
0
    return INVALID_SET_FILE_POINTER;
159
0
  }
160
161
0
  return (DWORD)_ftelli64(pFile->fp);
162
0
}
163
164
static BOOL FileSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove,
165
                                 PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
166
0
{
167
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
168
0
  int whence;
169
170
0
  if (!hFile)
171
0
    return FALSE;
172
173
0
  switch (dwMoveMethod)
174
0
  {
175
0
    case FILE_BEGIN:
176
0
      whence = SEEK_SET;
177
0
      break;
178
0
    case FILE_END:
179
0
      whence = SEEK_END;
180
0
      break;
181
0
    case FILE_CURRENT:
182
0
      whence = SEEK_CUR;
183
0
      break;
184
0
    default:
185
0
      return FALSE;
186
0
  }
187
188
0
  if (_fseeki64(pFile->fp, liDistanceToMove.QuadPart, whence))
189
0
  {
190
0
    WLog_ERR(TAG, "_fseeki64(%s) failed with %s [0x%08X]", pFile->lpFileName, strerror(errno),
191
0
             errno);
192
0
    return FALSE;
193
0
  }
194
195
0
  if (lpNewFilePointer)
196
0
    lpNewFilePointer->QuadPart = _ftelli64(pFile->fp);
197
198
0
  return TRUE;
199
0
}
200
201
static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
202
                     LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
203
0
{
204
0
  size_t io_status;
205
0
  WINPR_FILE* file;
206
0
  BOOL status = TRUE;
207
208
0
  if (lpOverlapped)
209
0
  {
210
0
    WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
211
0
    SetLastError(ERROR_NOT_SUPPORTED);
212
0
    return FALSE;
213
0
  }
214
215
0
  if (!Object)
216
0
    return FALSE;
217
218
0
  file = (WINPR_FILE*)Object;
219
0
  clearerr(file->fp);
220
0
  io_status = fread(lpBuffer, 1, nNumberOfBytesToRead, file->fp);
221
222
0
  if (io_status == 0 && ferror(file->fp))
223
0
  {
224
0
    status = FALSE;
225
226
0
    switch (errno)
227
0
    {
228
0
      case EWOULDBLOCK:
229
0
        SetLastError(ERROR_NO_DATA);
230
0
        break;
231
0
      default:
232
0
        SetLastError(map_posix_err(errno));
233
0
    }
234
0
  }
235
236
0
  if (lpNumberOfBytesRead)
237
0
    *lpNumberOfBytesRead = (DWORD)io_status;
238
239
0
  return status;
240
0
}
241
242
static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
243
                      LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
244
0
{
245
0
  size_t io_status;
246
0
  WINPR_FILE* file;
247
248
0
  if (lpOverlapped)
249
0
  {
250
0
    WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
251
0
    SetLastError(ERROR_NOT_SUPPORTED);
252
0
    return FALSE;
253
0
  }
254
255
0
  if (!Object)
256
0
    return FALSE;
257
258
0
  file = (WINPR_FILE*)Object;
259
260
0
  clearerr(file->fp);
261
0
  io_status = fwrite(lpBuffer, 1, nNumberOfBytesToWrite, file->fp);
262
0
  if (io_status == 0 && ferror(file->fp))
263
0
  {
264
0
    SetLastError(map_posix_err(errno));
265
0
    return FALSE;
266
0
  }
267
268
0
  *lpNumberOfBytesWritten = (DWORD)io_status;
269
0
  return TRUE;
270
0
}
271
272
static DWORD FileGetFileSize(HANDLE Object, LPDWORD lpFileSizeHigh)
273
0
{
274
0
  WINPR_FILE* file;
275
0
  INT64 cur, size;
276
277
0
  if (!Object)
278
0
    return 0;
279
280
0
  file = (WINPR_FILE*)Object;
281
282
0
  cur = _ftelli64(file->fp);
283
284
0
  if (cur < 0)
285
0
  {
286
0
    WLog_ERR(TAG, "_ftelli64(%s) failed with %s [0x%08X]", file->lpFileName, strerror(errno),
287
0
             errno);
288
0
    return INVALID_FILE_SIZE;
289
0
  }
290
291
0
  if (_fseeki64(file->fp, 0, SEEK_END) != 0)
292
0
  {
293
0
    WLog_ERR(TAG, "_fseeki64(%s) failed with %s [0x%08X]", file->lpFileName, strerror(errno),
294
0
             errno);
295
0
    return INVALID_FILE_SIZE;
296
0
  }
297
298
0
  size = _ftelli64(file->fp);
299
300
0
  if (size < 0)
301
0
  {
302
0
    WLog_ERR(TAG, "_ftelli64(%s) failed with %s [0x%08X]", file->lpFileName, strerror(errno),
303
0
             errno);
304
0
    return INVALID_FILE_SIZE;
305
0
  }
306
307
0
  if (_fseeki64(file->fp, cur, SEEK_SET) != 0)
308
0
  {
309
0
    WLog_ERR(TAG, "_ftelli64(%s) failed with %s [0x%08X]", file->lpFileName, strerror(errno),
310
0
             errno);
311
0
    return INVALID_FILE_SIZE;
312
0
  }
313
314
0
  if (lpFileSizeHigh)
315
0
    *lpFileSizeHigh = (UINT32)(size >> 32);
316
317
0
  return (UINT32)(size & 0xFFFFFFFF);
318
0
}
319
320
static BOOL FileGetFileInformationByHandle(HANDLE hFile,
321
                                           LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
322
0
{
323
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
324
0
  struct stat st;
325
0
  UINT64 ft;
326
0
  const char* lastSep;
327
328
0
  if (!pFile)
329
0
    return FALSE;
330
0
  if (!lpFileInformation)
331
0
    return FALSE;
332
333
0
  if (fstat(fileno(pFile->fp), &st) == -1)
334
0
  {
335
0
    WLog_ERR(TAG, "fstat failed with %s [%#08X]", errno, strerror(errno));
336
0
    return FALSE;
337
0
  }
338
339
0
  lpFileInformation->dwFileAttributes = 0;
340
341
0
  if (S_ISDIR(st.st_mode))
342
0
    lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
343
344
0
  if (lpFileInformation->dwFileAttributes == 0)
345
0
    lpFileInformation->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
346
347
0
  lastSep = strrchr(pFile->lpFileName, '/');
348
349
0
  if (lastSep)
350
0
  {
351
0
    const char* name = lastSep + 1;
352
0
    const size_t namelen = strlen(name);
353
354
0
    if ((namelen > 1) && (name[0] == '.') && (name[1] != '.'))
355
0
      lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
356
0
  }
357
358
0
  if (!(st.st_mode & S_IWUSR))
359
0
    lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
360
361
#ifdef _DARWIN_FEATURE_64_BIT_INODE
362
  ft = STAT_TIME_TO_FILETIME(st.st_birthtime);
363
#else
364
0
  ft = STAT_TIME_TO_FILETIME(st.st_ctime);
365
0
#endif
366
0
  lpFileInformation->ftCreationTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
367
0
  lpFileInformation->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
368
0
  ft = STAT_TIME_TO_FILETIME(st.st_mtime);
369
0
  lpFileInformation->ftLastWriteTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
370
0
  lpFileInformation->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
371
0
  ft = STAT_TIME_TO_FILETIME(st.st_atime);
372
0
  lpFileInformation->ftLastAccessTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
373
0
  lpFileInformation->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
374
0
  lpFileInformation->nFileSizeHigh = ((UINT64)st.st_size) >> 32ULL;
375
0
  lpFileInformation->nFileSizeLow = st.st_size & 0xFFFFFFFF;
376
0
  lpFileInformation->dwVolumeSerialNumber = st.st_dev;
377
0
  lpFileInformation->nNumberOfLinks = st.st_nlink;
378
0
  lpFileInformation->nFileIndexHigh = (st.st_ino >> 4) & 0xFFFFFFFF;
379
0
  lpFileInformation->nFileIndexLow = st.st_ino & 0xFFFFFFFF;
380
0
  return TRUE;
381
0
}
382
383
static BOOL FileLockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved,
384
                           DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
385
                           LPOVERLAPPED lpOverlapped)
386
0
{
387
#ifdef __sun
388
  struct flock lock;
389
  int lckcmd;
390
#else
391
0
  int lock;
392
0
#endif
393
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
394
395
0
  if (lpOverlapped)
396
0
  {
397
0
    WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
398
0
    SetLastError(ERROR_NOT_SUPPORTED);
399
0
    return FALSE;
400
0
  }
401
402
0
  if (!hFile)
403
0
    return FALSE;
404
405
0
  if (pFile->bLocked)
406
0
  {
407
0
    WLog_ERR(TAG, "File %s already locked!", pFile->lpFileName);
408
0
    return FALSE;
409
0
  }
410
411
#ifdef __sun
412
  lock.l_start = 0;
413
  lock.l_len = 0;
414
  lock.l_whence = SEEK_SET;
415
416
  if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
417
    lock.l_type = F_WRLCK;
418
  else
419
    lock.l_type = F_WRLCK;
420
421
  if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
422
    lckcmd = F_SETLK;
423
  else
424
    lckcmd = F_SETLKW;
425
426
  if (fcntl(fileno(pFile->fp), lckcmd, &lock) == -1)
427
  {
428
    WLog_ERR(TAG, "F_SETLK failed with %s [0x%08X]", strerror(errno), errno);
429
    return FALSE;
430
  }
431
#else
432
0
  if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK)
433
0
    lock = LOCK_EX;
434
0
  else
435
0
    lock = LOCK_SH;
436
437
0
  if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY)
438
0
    lock |= LOCK_NB;
439
440
0
  if (flock(fileno(pFile->fp), lock) < 0)
441
0
  {
442
0
    WLog_ERR(TAG, "flock failed with %s [0x%08X]", strerror(errno), errno);
443
0
    return FALSE;
444
0
  }
445
0
#endif
446
447
0
  pFile->bLocked = TRUE;
448
449
0
  return TRUE;
450
0
}
451
452
static BOOL FileUnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
453
                           DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
454
0
{
455
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
456
#ifdef __sun
457
  struct flock lock;
458
#endif
459
460
0
  if (!hFile)
461
0
    return FALSE;
462
463
0
  if (!pFile->bLocked)
464
0
  {
465
0
    WLog_ERR(TAG, "File %s is not locked!", pFile->lpFileName);
466
0
    return FALSE;
467
0
  }
468
469
#ifdef __sun
470
  lock.l_start = 0;
471
  lock.l_len = 0;
472
  lock.l_whence = SEEK_SET;
473
  lock.l_type = F_UNLCK;
474
  if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
475
  {
476
    WLog_ERR(TAG, "F_UNLCK on %s failed with %s [0x%08X]", pFile->lpFileName, strerror(errno),
477
             errno);
478
    return FALSE;
479
  }
480
481
#else
482
0
  if (flock(fileno(pFile->fp), LOCK_UN) < 0)
483
0
  {
484
0
    WLog_ERR(TAG, "flock(LOCK_UN) %s failed with %s [0x%08X]", pFile->lpFileName,
485
0
             strerror(errno), errno);
486
0
    return FALSE;
487
0
  }
488
0
#endif
489
490
0
  return TRUE;
491
0
}
492
493
static BOOL FileUnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow,
494
                             DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped)
495
0
{
496
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
497
#ifdef __sun
498
  struct flock lock;
499
#endif
500
501
0
  if (lpOverlapped)
502
0
  {
503
0
    WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
504
0
    SetLastError(ERROR_NOT_SUPPORTED);
505
0
    return FALSE;
506
0
  }
507
508
0
  if (!hFile)
509
0
    return FALSE;
510
511
0
  if (!pFile->bLocked)
512
0
  {
513
0
    WLog_ERR(TAG, "File %s is not locked!", pFile->lpFileName);
514
0
    return FALSE;
515
0
  }
516
517
#ifdef __sun
518
  lock.l_start = 0;
519
  lock.l_len = 0;
520
  lock.l_whence = SEEK_SET;
521
  lock.l_type = F_UNLCK;
522
  if (fcntl(fileno(pFile->fp), F_GETLK, &lock) == -1)
523
  {
524
    WLog_ERR(TAG, "F_UNLCK on %s failed with %s [0x%08X]", pFile->lpFileName, strerror(errno),
525
             errno);
526
    return FALSE;
527
  }
528
#else
529
0
  if (flock(fileno(pFile->fp), LOCK_UN) < 0)
530
0
  {
531
0
    WLog_ERR(TAG, "flock(LOCK_UN) %s failed with %s [0x%08X]", pFile->lpFileName,
532
0
             strerror(errno), errno);
533
0
    return FALSE;
534
0
  }
535
0
#endif
536
537
0
  return TRUE;
538
0
}
539
540
static UINT64 FileTimeToUS(const FILETIME* ft)
541
0
{
542
0
  const UINT64 EPOCH_DIFF_US = EPOCH_DIFF * 1000000ULL;
543
0
  UINT64 tmp = ((UINT64)ft->dwHighDateTime) << 32 | ft->dwLowDateTime;
544
0
  tmp /= 10; /* 100ns steps to 1us step */
545
0
  tmp -= EPOCH_DIFF_US;
546
0
  return tmp;
547
0
}
548
549
static BOOL FileSetFileTime(HANDLE hFile, const FILETIME* lpCreationTime,
550
                            const FILETIME* lpLastAccessTime, const FILETIME* lpLastWriteTime)
551
0
{
552
0
  int rc;
553
#if defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) || defined(KFREEBSD)
554
  struct stat buf;
555
  /* OpenBSD, NetBSD and DragonflyBSD support POSIX futimens */
556
  struct timeval timevals[2];
557
#else
558
0
  struct timespec times[2]; /* last access, last modification */
559
0
#endif
560
0
  WINPR_FILE* pFile = (WINPR_FILE*)hFile;
561
562
0
  if (!hFile)
563
0
    return FALSE;
564
565
#if defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) || defined(KFREEBSD)
566
  rc = fstat(fileno(pFile->fp), &buf);
567
568
  if (rc < 0)
569
    return FALSE;
570
571
#endif
572
573
0
  if (!lpLastAccessTime)
574
0
  {
575
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
576
    timevals[0].tv_sec = buf.st_atime;
577
#ifdef _POSIX_SOURCE
578
    TIMESPEC_TO_TIMEVAL(&timevals[0], &buf.st_atim);
579
#else
580
    TIMESPEC_TO_TIMEVAL(&timevals[0], &buf.st_atimespec);
581
#endif
582
#elif defined(ANDROID)
583
    timevals[0].tv_sec = buf.st_atime;
584
    timevals[0].tv_usec = buf.st_atimensec / 1000UL;
585
#else
586
0
    times[0].tv_sec = UTIME_OMIT;
587
0
    times[0].tv_nsec = UTIME_OMIT;
588
0
#endif
589
0
  }
590
0
  else
591
0
  {
592
0
    UINT64 tmp = FileTimeToUS(lpLastAccessTime);
593
#if defined(ANDROID) || defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
594
    timevals[0].tv_sec = tmp / 1000000ULL;
595
    timevals[0].tv_usec = tmp % 1000000ULL;
596
#else
597
0
    times[0].tv_sec = tmp / 1000000ULL;
598
0
    times[0].tv_nsec = (tmp % 1000000ULL) * 1000ULL;
599
0
#endif
600
0
  }
601
602
0
  if (!lpLastWriteTime)
603
0
  {
604
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
605
    timevals[1].tv_sec = buf.st_mtime;
606
#ifdef _POSIX_SOURCE
607
    TIMESPEC_TO_TIMEVAL(&timevals[1], &buf.st_mtim);
608
#else
609
    TIMESPEC_TO_TIMEVAL(&timevals[1], &buf.st_mtimespec);
610
#endif
611
#elif defined(ANDROID)
612
    timevals[1].tv_sec = buf.st_mtime;
613
    timevals[1].tv_usec = buf.st_mtimensec / 1000UL;
614
#else
615
0
    times[1].tv_sec = UTIME_OMIT;
616
0
    times[1].tv_nsec = UTIME_OMIT;
617
0
#endif
618
0
  }
619
0
  else
620
0
  {
621
0
    UINT64 tmp = FileTimeToUS(lpLastWriteTime);
622
#if defined(ANDROID) || defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
623
    timevals[1].tv_sec = tmp / 1000000ULL;
624
    timevals[1].tv_usec = tmp % 1000000ULL;
625
#else
626
0
    times[1].tv_sec = tmp / 1000000ULL;
627
0
    times[1].tv_nsec = (tmp % 1000000ULL) * 1000ULL;
628
0
#endif
629
0
  }
630
631
  // TODO: Creation time can not be handled!
632
#if defined(ANDROID) || defined(__FreeBSD__) || defined(__APPLE__) || defined(KFREEBSD)
633
  rc = utimes(pFile->lpFileName, timevals);
634
#else
635
0
  rc = futimens(fileno(pFile->fp), times);
636
0
#endif
637
638
0
  if (rc != 0)
639
0
    return FALSE;
640
641
0
  return TRUE;
642
0
}
643
644
static HANDLE_OPS fileOps = {
645
  FileIsHandled,
646
  FileCloseHandle,
647
  FileGetFd,
648
  NULL, /* CleanupHandle */
649
  FileRead,
650
  NULL, /* FileReadEx */
651
  NULL, /* FileReadScatter */
652
  FileWrite,
653
  NULL, /* FileWriteEx */
654
  NULL, /* FileWriteGather */
655
  FileGetFileSize,
656
  NULL, /*  FlushFileBuffers */
657
  FileSetEndOfFile,
658
  FileSetFilePointer,
659
  FileSetFilePointerEx,
660
  NULL, /* FileLockFile */
661
  FileLockFileEx,
662
  FileUnlockFile,
663
  FileUnlockFileEx,
664
  FileSetFileTime,
665
  FileGetFileInformationByHandle,
666
};
667
668
static HANDLE_OPS shmOps = {
669
  FileIsHandled,
670
  FileCloseHandle,
671
  FileGetFd,
672
  NULL, /* CleanupHandle */
673
  FileRead,
674
  NULL, /* FileReadEx */
675
  NULL, /* FileReadScatter */
676
  FileWrite,
677
  NULL, /* FileWriteEx */
678
  NULL, /* FileWriteGather */
679
  NULL, /* FileGetFileSize */
680
  NULL, /*  FlushFileBuffers */
681
  NULL, /* FileSetEndOfFile */
682
  NULL, /* FileSetFilePointer */
683
  NULL, /* SetFilePointerEx */
684
  NULL, /* FileLockFile */
685
  NULL, /* FileLockFileEx */
686
  NULL, /* FileUnlockFile */
687
  NULL, /* FileUnlockFileEx */
688
  NULL, /* FileSetFileTime */
689
  FileGetFileInformationByHandle,
690
};
691
692
static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDisposition, BOOL* create)
693
0
{
694
0
  BOOL writeable = (dwDesiredAccess & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
695
696
0
  switch (dwCreationDisposition)
697
0
  {
698
0
    case CREATE_ALWAYS:
699
0
      *create = TRUE;
700
0
      return (writeable) ? "wb+" : "rwb";
701
0
    case CREATE_NEW:
702
0
      *create = TRUE;
703
0
      return "wb+";
704
0
    case OPEN_ALWAYS:
705
0
      *create = TRUE;
706
0
      return "rb+";
707
0
    case OPEN_EXISTING:
708
0
      *create = FALSE;
709
0
      return (writeable) ? "rb+" : "rb";
710
0
    case TRUNCATE_EXISTING:
711
0
      *create = FALSE;
712
0
      return "wb+";
713
0
    default:
714
0
      *create = FALSE;
715
0
      return "";
716
0
  }
717
0
}
718
719
UINT32 map_posix_err(int fs_errno)
720
0
{
721
0
  NTSTATUS rc;
722
723
  /* try to return NTSTATUS version of error code */
724
725
0
  switch (fs_errno)
726
0
  {
727
0
    case 0:
728
0
      rc = STATUS_SUCCESS;
729
0
      break;
730
731
0
    case ENOTCONN:
732
0
    case ENODEV:
733
0
    case ENOTDIR:
734
0
    case ENXIO:
735
0
      rc = ERROR_FILE_NOT_FOUND;
736
0
      break;
737
738
0
    case EROFS:
739
0
    case EPERM:
740
0
    case EACCES:
741
0
      rc = ERROR_ACCESS_DENIED;
742
0
      break;
743
744
0
    case ENOENT:
745
0
      rc = ERROR_FILE_NOT_FOUND;
746
0
      break;
747
748
0
    case EBUSY:
749
0
      rc = ERROR_BUSY_DRIVE;
750
0
      break;
751
752
0
    case EEXIST:
753
0
      rc = ERROR_FILE_EXISTS;
754
0
      break;
755
756
0
    case EISDIR:
757
0
      rc = STATUS_FILE_IS_A_DIRECTORY;
758
0
      break;
759
760
0
    case ENOTEMPTY:
761
0
      rc = STATUS_DIRECTORY_NOT_EMPTY;
762
0
      break;
763
764
0
    case EMFILE:
765
0
      rc = STATUS_TOO_MANY_OPENED_FILES;
766
0
      break;
767
768
0
    default:
769
0
      WLog_ERR(TAG, "Missing ERRNO mapping %s [%d]", strerror(fs_errno), fs_errno);
770
0
      rc = STATUS_UNSUCCESSFUL;
771
0
      break;
772
0
  }
773
774
0
  return (UINT32)rc;
775
0
}
776
777
static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
778
                              LPSECURITY_ATTRIBUTES lpSecurityAttributes,
779
                              DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
780
                              HANDLE hTemplateFile)
781
0
{
782
0
  WINPR_FILE* pFile;
783
0
  BOOL create;
784
0
  const char* mode = FileGetMode(dwDesiredAccess, dwCreationDisposition, &create);
785
#ifdef __sun
786
  struct flock lock;
787
#else
788
0
  int lock = 0;
789
0
#endif
790
0
  FILE* fp = NULL;
791
0
  struct stat st;
792
793
0
  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
794
0
  {
795
0
    WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
796
0
    SetLastError(ERROR_NOT_SUPPORTED);
797
0
    return INVALID_HANDLE_VALUE;
798
0
  }
799
800
0
  pFile = (WINPR_FILE*)calloc(1, sizeof(WINPR_FILE));
801
0
  if (!pFile)
802
0
  {
803
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
804
0
    return INVALID_HANDLE_VALUE;
805
0
  }
806
807
0
  WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
808
0
  pFile->common.ops = &fileOps;
809
810
0
  pFile->lpFileName = _strdup(lpFileName);
811
0
  if (!pFile->lpFileName)
812
0
  {
813
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
814
0
    free(pFile);
815
0
    return INVALID_HANDLE_VALUE;
816
0
  }
817
818
0
  pFile->dwOpenMode = dwDesiredAccess;
819
0
  pFile->dwShareMode = dwShareMode;
820
0
  pFile->dwFlagsAndAttributes = dwFlagsAndAttributes;
821
0
  pFile->lpSecurityAttributes = lpSecurityAttributes;
822
0
  pFile->dwCreationDisposition = dwCreationDisposition;
823
0
  pFile->hTemplateFile = hTemplateFile;
824
825
0
  if (create)
826
0
  {
827
0
    if (dwCreationDisposition == CREATE_NEW)
828
0
    {
829
0
      if (stat(pFile->lpFileName, &st) == 0)
830
0
      {
831
0
        SetLastError(ERROR_FILE_EXISTS);
832
0
        free(pFile->lpFileName);
833
0
        free(pFile);
834
0
        return INVALID_HANDLE_VALUE;
835
0
      }
836
0
    }
837
838
0
    fp = winpr_fopen(pFile->lpFileName, "ab");
839
0
    if (!fp)
840
0
    {
841
0
      SetLastError(map_posix_err(errno));
842
0
      free(pFile->lpFileName);
843
0
      free(pFile);
844
0
      return INVALID_HANDLE_VALUE;
845
0
    }
846
847
0
    fp = freopen(pFile->lpFileName, mode, fp);
848
0
  }
849
0
  else
850
0
  {
851
0
    if (stat(pFile->lpFileName, &st) != 0)
852
0
    {
853
0
      SetLastError(map_posix_err(errno));
854
0
      free(pFile->lpFileName);
855
0
      free(pFile);
856
0
      return INVALID_HANDLE_VALUE;
857
0
    }
858
859
    /* FIFO (named pipe) would block the following fopen
860
     * call if not connected. This renders the channel unusable,
861
     * therefore abort early. */
862
0
    if (S_ISFIFO(st.st_mode))
863
0
    {
864
0
      SetLastError(ERROR_FILE_NOT_FOUND);
865
0
      free(pFile->lpFileName);
866
0
      free(pFile);
867
0
      return INVALID_HANDLE_VALUE;
868
0
    }
869
0
  }
870
871
0
  if (NULL == fp)
872
0
    fp = winpr_fopen(pFile->lpFileName, mode);
873
874
0
  pFile->fp = fp;
875
0
  if (!pFile->fp)
876
0
  {
877
    /* This case can occur when trying to open a
878
     * not existing file without create flag. */
879
0
    SetLastError(map_posix_err(errno));
880
0
    free(pFile->lpFileName);
881
0
    free(pFile);
882
0
    return INVALID_HANDLE_VALUE;
883
0
  }
884
885
0
  setvbuf(fp, NULL, _IONBF, 0);
886
887
#ifdef __sun
888
  lock.l_start = 0;
889
  lock.l_len = 0;
890
  lock.l_whence = SEEK_SET;
891
892
  if (dwShareMode & FILE_SHARE_READ)
893
    lock.l_type = F_RDLCK;
894
  if (dwShareMode & FILE_SHARE_WRITE)
895
    lock.l_type = F_RDLCK;
896
#else
897
0
  if (dwShareMode & FILE_SHARE_READ)
898
0
    lock = LOCK_SH;
899
0
  if (dwShareMode & FILE_SHARE_WRITE)
900
0
    lock = LOCK_EX;
901
0
#endif
902
903
0
  if (dwShareMode & (FILE_SHARE_READ | FILE_SHARE_WRITE))
904
0
  {
905
#ifdef __sun
906
    if (fcntl(fileno(pFile->fp), F_SETLKW, &lock) == -1)
907
#else
908
0
    if (flock(fileno(pFile->fp), lock) < 0)
909
0
#endif
910
0
    {
911
#ifdef __sun
912
      WLog_ERR(TAG, "F_SETLKW failed with %s [0x%08X]", strerror(errno), errno);
913
#else
914
0
      WLog_ERR(TAG, "flock failed with %s [0x%08X]", strerror(errno), errno);
915
0
#endif
916
917
0
      SetLastError(map_posix_err(errno));
918
0
      FileCloseHandle(pFile);
919
0
      return INVALID_HANDLE_VALUE;
920
0
    }
921
922
0
    pFile->bLocked = TRUE;
923
0
  }
924
925
0
  if (fstat(fileno(pFile->fp), &st) == 0 && dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
926
0
  {
927
0
    st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
928
0
    fchmod(fileno(pFile->fp), st.st_mode);
929
0
  }
930
931
0
  SetLastError(STATUS_SUCCESS);
932
0
  return pFile;
933
0
}
934
935
static BOOL IsFileDevice(LPCTSTR lpDeviceName)
936
0
{
937
0
  return TRUE;
938
0
}
939
940
static HANDLE_CREATOR _FileHandleCreator = { IsFileDevice, FileCreateFileA };
941
942
HANDLE_CREATOR* GetFileHandleCreator(void)
943
0
{
944
0
  return &_FileHandleCreator;
945
0
}
946
947
static WINPR_FILE* FileHandle_New(FILE* fp)
948
0
{
949
0
  WINPR_FILE* pFile;
950
0
  char name[MAX_PATH] = { 0 };
951
952
0
  _snprintf(name, sizeof(name), "device_%d", fileno(fp));
953
0
  pFile = (WINPR_FILE*)calloc(1, sizeof(WINPR_FILE));
954
0
  if (!pFile)
955
0
  {
956
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
957
0
    return NULL;
958
0
  }
959
0
  pFile->fp = fp;
960
0
  pFile->common.ops = &shmOps;
961
0
  pFile->lpFileName = _strdup(name);
962
963
0
  WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ);
964
0
  return pFile;
965
0
}
966
967
HANDLE GetStdHandle(DWORD nStdHandle)
968
0
{
969
0
  FILE* fp;
970
0
  WINPR_FILE* pFile;
971
972
0
  switch (nStdHandle)
973
0
  {
974
0
    case STD_INPUT_HANDLE:
975
0
      fp = stdin;
976
0
      break;
977
0
    case STD_OUTPUT_HANDLE:
978
0
      fp = stdout;
979
0
      break;
980
0
    case STD_ERROR_HANDLE:
981
0
      fp = stderr;
982
0
      break;
983
0
    default:
984
0
      return INVALID_HANDLE_VALUE;
985
0
  }
986
0
  pFile = FileHandle_New(fp);
987
0
  if (!pFile)
988
0
    return INVALID_HANDLE_VALUE;
989
990
0
  return (HANDLE)pFile;
991
0
}
992
993
BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle)
994
0
{
995
0
  return FALSE;
996
0
}
997
998
BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle)
999
0
{
1000
0
  return FALSE;
1001
0
}
1002
1003
BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1004
                       LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1005
0
{
1006
#if defined(ANDROID)
1007
#define STATVFS statfs
1008
#else
1009
0
#define STATVFS statvfs
1010
0
#endif
1011
1012
0
  struct STATVFS svfst = { 0 };
1013
0
  STATVFS(lpRootPathName, &svfst);
1014
0
  *lpSectorsPerCluster = (UINT32)MIN(svfst.f_frsize, UINT32_MAX);
1015
0
  *lpBytesPerSector = 1;
1016
0
  *lpNumberOfFreeClusters = (UINT32)MIN(svfst.f_bavail, UINT32_MAX);
1017
0
  *lpTotalNumberOfClusters = (UINT32)MIN(svfst.f_blocks, UINT32_MAX);
1018
0
  return TRUE;
1019
0
}
1020
1021
BOOL GetDiskFreeSpaceW(LPCWSTR lpwRootPathName, LPDWORD lpSectorsPerCluster,
1022
                       LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1023
                       LPDWORD lpTotalNumberOfClusters)
1024
0
{
1025
0
  LPSTR lpRootPathName;
1026
0
  BOOL ret;
1027
0
  if (!lpwRootPathName)
1028
0
    return FALSE;
1029
1030
0
  lpRootPathName = ConvertWCharToUtf8Alloc(lpwRootPathName, NULL);
1031
0
  if (!lpRootPathName)
1032
0
  {
1033
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1034
0
    return FALSE;
1035
0
  }
1036
0
  ret = GetDiskFreeSpaceA(lpRootPathName, lpSectorsPerCluster, lpBytesPerSector,
1037
0
                          lpNumberOfFreeClusters, lpTotalNumberOfClusters);
1038
0
  free(lpRootPathName);
1039
0
  return ret;
1040
0
}
1041
1042
#endif /* _WIN32 */
1043
1044
/**
1045
 * Check if a file name component is valid.
1046
 *
1047
 * Some file names are not valid on Windows. See "Naming Files, Paths, and Namespaces":
1048
 * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
1049
 */
1050
BOOL ValidFileNameComponent(LPCWSTR lpFileName)
1051
0
{
1052
0
  LPCWSTR c = NULL;
1053
1054
0
  if (!lpFileName)
1055
0
    return FALSE;
1056
1057
  /* CON */
1058
0
  if ((lpFileName[0] != L'\0' && (lpFileName[0] == L'C' || lpFileName[0] == L'c')) &&
1059
0
      (lpFileName[1] != L'\0' && (lpFileName[1] == L'O' || lpFileName[1] == L'o')) &&
1060
0
      (lpFileName[2] != L'\0' && (lpFileName[2] == L'N' || lpFileName[2] == L'n')) &&
1061
0
      (lpFileName[3] == L'\0'))
1062
0
  {
1063
0
    return FALSE;
1064
0
  }
1065
1066
  /* PRN */
1067
0
  if ((lpFileName[0] != L'\0' && (lpFileName[0] == L'P' || lpFileName[0] == L'p')) &&
1068
0
      (lpFileName[1] != L'\0' && (lpFileName[1] == L'R' || lpFileName[1] == L'r')) &&
1069
0
      (lpFileName[2] != L'\0' && (lpFileName[2] == L'N' || lpFileName[2] == L'n')) &&
1070
0
      (lpFileName[3] == L'\0'))
1071
0
  {
1072
0
    return FALSE;
1073
0
  }
1074
1075
  /* AUX */
1076
0
  if ((lpFileName[0] != L'\0' && (lpFileName[0] == L'A' || lpFileName[0] == L'a')) &&
1077
0
      (lpFileName[1] != L'\0' && (lpFileName[1] == L'U' || lpFileName[1] == L'u')) &&
1078
0
      (lpFileName[2] != L'\0' && (lpFileName[2] == L'X' || lpFileName[2] == L'x')) &&
1079
0
      (lpFileName[3] == L'\0'))
1080
0
  {
1081
0
    return FALSE;
1082
0
  }
1083
1084
  /* NUL */
1085
0
  if ((lpFileName[0] != L'\0' && (lpFileName[0] == L'N' || lpFileName[0] == L'n')) &&
1086
0
      (lpFileName[1] != L'\0' && (lpFileName[1] == L'U' || lpFileName[1] == L'u')) &&
1087
0
      (lpFileName[2] != L'\0' && (lpFileName[2] == L'L' || lpFileName[2] == L'l')) &&
1088
0
      (lpFileName[3] == L'\0'))
1089
0
  {
1090
0
    return FALSE;
1091
0
  }
1092
1093
  /* LPT0-9 */
1094
0
  if ((lpFileName[0] != L'\0' && (lpFileName[0] == L'L' || lpFileName[0] == L'l')) &&
1095
0
      (lpFileName[1] != L'\0' && (lpFileName[1] == L'P' || lpFileName[1] == L'p')) &&
1096
0
      (lpFileName[2] != L'\0' && (lpFileName[2] == L'T' || lpFileName[2] == L't')) &&
1097
0
      (lpFileName[3] != L'\0' && (L'0' <= lpFileName[3] && lpFileName[3] <= L'9')) &&
1098
0
      (lpFileName[4] == L'\0'))
1099
0
  {
1100
0
    return FALSE;
1101
0
  }
1102
1103
  /* COM0-9 */
1104
0
  if ((lpFileName[0] != L'\0' && (lpFileName[0] == L'C' || lpFileName[0] == L'c')) &&
1105
0
      (lpFileName[1] != L'\0' && (lpFileName[1] == L'O' || lpFileName[1] == L'o')) &&
1106
0
      (lpFileName[2] != L'\0' && (lpFileName[2] == L'M' || lpFileName[2] == L'm')) &&
1107
0
      (lpFileName[3] != L'\0' && (L'0' <= lpFileName[3] && lpFileName[3] <= L'9')) &&
1108
0
      (lpFileName[4] == L'\0'))
1109
0
  {
1110
0
    return FALSE;
1111
0
  }
1112
1113
  /* Reserved characters */
1114
0
  for (c = lpFileName; *c; c++)
1115
0
  {
1116
0
    if ((*c == L'<') || (*c == L'>') || (*c == L':') || (*c == L'"') || (*c == L'/') ||
1117
0
        (*c == L'\\') || (*c == L'|') || (*c == L'?') || (*c == L'*'))
1118
0
    {
1119
0
      return FALSE;
1120
0
    }
1121
0
  }
1122
1123
0
  return TRUE;
1124
0
}
1125
1126
#ifdef _UWP
1127
1128
HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1129
                   LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1130
                   DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1131
{
1132
  HANDLE hFile;
1133
  CREATEFILE2_EXTENDED_PARAMETERS params = { 0 };
1134
1135
  params.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
1136
1137
  if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
1138
    params.dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
1139
  if (dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
1140
    params.dwFileFlags |= FILE_FLAG_DELETE_ON_CLOSE;
1141
  if (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
1142
    params.dwFileFlags |= FILE_FLAG_NO_BUFFERING;
1143
  if (dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
1144
    params.dwFileFlags |= FILE_FLAG_OPEN_NO_RECALL;
1145
  if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
1146
    params.dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
1147
  if (dwFlagsAndAttributes & FILE_FLAG_OPEN_REQUIRING_OPLOCK)
1148
    params.dwFileFlags |= FILE_FLAG_OPEN_REQUIRING_OPLOCK;
1149
  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
1150
    params.dwFileFlags |= FILE_FLAG_OVERLAPPED;
1151
  if (dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS)
1152
    params.dwFileFlags |= FILE_FLAG_POSIX_SEMANTICS;
1153
  if (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
1154
    params.dwFileFlags |= FILE_FLAG_RANDOM_ACCESS;
1155
  if (dwFlagsAndAttributes & FILE_FLAG_SESSION_AWARE)
1156
    params.dwFileFlags |= FILE_FLAG_SESSION_AWARE;
1157
  if (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
1158
    params.dwFileFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
1159
  if (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
1160
    params.dwFileFlags |= FILE_FLAG_WRITE_THROUGH;
1161
1162
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ARCHIVE)
1163
    params.dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1164
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_COMPRESSED)
1165
    params.dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
1166
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DEVICE)
1167
    params.dwFileAttributes |= FILE_ATTRIBUTE_DEVICE;
1168
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY)
1169
    params.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1170
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_ENCRYPTED)
1171
    params.dwFileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
1172
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_HIDDEN)
1173
    params.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
1174
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM)
1175
    params.dwFileAttributes |= FILE_ATTRIBUTE_INTEGRITY_STREAM;
1176
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NORMAL)
1177
    params.dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
1178
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
1179
    params.dwFileAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1180
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA)
1181
    params.dwFileAttributes |= FILE_ATTRIBUTE_NO_SCRUB_DATA;
1182
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_OFFLINE)
1183
    params.dwFileAttributes |= FILE_ATTRIBUTE_OFFLINE;
1184
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)
1185
    params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
1186
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1187
    params.dwFileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
1188
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SPARSE_FILE)
1189
    params.dwFileAttributes |= FILE_ATTRIBUTE_SPARSE_FILE;
1190
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_SYSTEM)
1191
    params.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
1192
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY)
1193
    params.dwFileAttributes |= FILE_ATTRIBUTE_TEMPORARY;
1194
  if (dwFlagsAndAttributes & FILE_ATTRIBUTE_VIRTUAL)
1195
    params.dwFileAttributes |= FILE_ATTRIBUTE_VIRTUAL;
1196
1197
  if (dwFlagsAndAttributes & SECURITY_ANONYMOUS)
1198
    params.dwSecurityQosFlags |= SECURITY_ANONYMOUS;
1199
  if (dwFlagsAndAttributes & SECURITY_CONTEXT_TRACKING)
1200
    params.dwSecurityQosFlags |= SECURITY_CONTEXT_TRACKING;
1201
  if (dwFlagsAndAttributes & SECURITY_DELEGATION)
1202
    params.dwSecurityQosFlags |= SECURITY_DELEGATION;
1203
  if (dwFlagsAndAttributes & SECURITY_EFFECTIVE_ONLY)
1204
    params.dwSecurityQosFlags |= SECURITY_EFFECTIVE_ONLY;
1205
  if (dwFlagsAndAttributes & SECURITY_IDENTIFICATION)
1206
    params.dwSecurityQosFlags |= SECURITY_IDENTIFICATION;
1207
  if (dwFlagsAndAttributes & SECURITY_IMPERSONATION)
1208
    params.dwSecurityQosFlags |= SECURITY_IMPERSONATION;
1209
1210
  params.lpSecurityAttributes = lpSecurityAttributes;
1211
  params.hTemplateFile = hTemplateFile;
1212
1213
  hFile = CreateFile2(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, &params);
1214
1215
  return hFile;
1216
}
1217
1218
HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
1219
                   LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
1220
                   DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
1221
{
1222
  HANDLE hFile;
1223
  if (!lpFileName)
1224
    return NULL;
1225
1226
  WCHAR* lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
1227
1228
  if (!lpFileNameW)
1229
    return NULL;
1230
1231
  hFile = CreateFileW(lpFileNameW, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
1232
                      dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1233
1234
  free(lpFileNameW);
1235
1236
  return hFile;
1237
}
1238
1239
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
1240
{
1241
  BOOL status;
1242
  LARGE_INTEGER fileSize = { 0, 0 };
1243
1244
  if (!lpFileSizeHigh)
1245
    return INVALID_FILE_SIZE;
1246
1247
  status = GetFileSizeEx(hFile, &fileSize);
1248
1249
  if (!status)
1250
    return INVALID_FILE_SIZE;
1251
1252
  *lpFileSizeHigh = fileSize.HighPart;
1253
1254
  return fileSize.LowPart;
1255
}
1256
1257
DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
1258
                     DWORD dwMoveMethod)
1259
{
1260
  BOOL status;
1261
  LARGE_INTEGER liDistanceToMove = { 0, 0 };
1262
  LARGE_INTEGER liNewFilePointer = { 0, 0 };
1263
1264
  liDistanceToMove.LowPart = lDistanceToMove;
1265
1266
  status = SetFilePointerEx(hFile, liDistanceToMove, &liNewFilePointer, dwMoveMethod);
1267
1268
  if (!status)
1269
    return INVALID_SET_FILE_POINTER;
1270
1271
  if (lpDistanceToMoveHigh)
1272
    *lpDistanceToMoveHigh = liNewFilePointer.HighPart;
1273
1274
  return liNewFilePointer.LowPart;
1275
}
1276
1277
HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
1278
{
1279
  return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1280
                          NULL, 0);
1281
}
1282
1283
HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData)
1284
{
1285
  return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch,
1286
                          NULL, 0);
1287
}
1288
1289
DWORD GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart)
1290
{
1291
  DWORD dwStatus;
1292
  WCHAR* lpFileNameW = NULL;
1293
  WCHAR* lpBufferW = NULL;
1294
  WCHAR* lpFilePartW = NULL;
1295
  DWORD nBufferLengthW = nBufferLength * sizeof(WCHAR);
1296
1297
  if (!lpFileName || (nBufferLength < 1))
1298
    return 0;
1299
1300
  lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
1301
  if (!lpFileNameW)
1302
    return 0;
1303
1304
  lpBufferW = (WCHAR*)malloc(nBufferLengthW);
1305
1306
  if (!lpBufferW)
1307
    return 0;
1308
1309
  dwStatus = GetFullPathNameW(lpFileNameW, nBufferLengthW, lpBufferW, &lpFilePartW);
1310
1311
  ConvertWCharNToUtf8(lpBufferW, nBufferLengthW / sizeof(WCHAR), lpBuffer, nBufferLength);
1312
1313
  if (lpFilePart)
1314
    lpFilePart = lpBuffer + (lpFilePartW - lpBufferW);
1315
1316
  free(lpFileNameW);
1317
  free(lpBufferW);
1318
1319
  return dwStatus * 2;
1320
}
1321
1322
BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
1323
                       LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
1324
{
1325
  BOOL status;
1326
  ULARGE_INTEGER FreeBytesAvailableToCaller = { 0, 0 };
1327
  ULARGE_INTEGER TotalNumberOfBytes = { 0, 0 };
1328
  ULARGE_INTEGER TotalNumberOfFreeBytes = { 0, 0 };
1329
1330
  status = GetDiskFreeSpaceExA(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1331
                               &TotalNumberOfFreeBytes);
1332
1333
  if (!status)
1334
    return FALSE;
1335
1336
  *lpBytesPerSector = 1;
1337
  *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1338
  *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1339
  *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1340
1341
  return TRUE;
1342
}
1343
1344
BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
1345
                       LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters,
1346
                       LPDWORD lpTotalNumberOfClusters)
1347
{
1348
  BOOL status;
1349
  ULARGE_INTEGER FreeBytesAvailableToCaller = { 0, 0 };
1350
  ULARGE_INTEGER TotalNumberOfBytes = { 0, 0 };
1351
  ULARGE_INTEGER TotalNumberOfFreeBytes = { 0, 0 };
1352
1353
  status = GetDiskFreeSpaceExW(lpRootPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
1354
                               &TotalNumberOfFreeBytes);
1355
1356
  if (!status)
1357
    return FALSE;
1358
1359
  *lpBytesPerSector = 1;
1360
  *lpSectorsPerCluster = TotalNumberOfBytes.LowPart;
1361
  *lpNumberOfFreeClusters = FreeBytesAvailableToCaller.LowPart;
1362
  *lpTotalNumberOfClusters = TotalNumberOfFreeBytes.LowPart;
1363
1364
  return TRUE;
1365
}
1366
1367
DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
1368
{
1369
  SetLastError(ERROR_INVALID_FUNCTION);
1370
  return 0;
1371
}
1372
1373
DWORD GetLogicalDriveStringsW(DWORD nBufferLength, LPWSTR lpBuffer)
1374
{
1375
  SetLastError(ERROR_INVALID_FUNCTION);
1376
  return 0;
1377
}
1378
1379
BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
1380
{
1381
  return FALSE;
1382
}
1383
1384
UINT GetACP(void)
1385
{
1386
  return CP_UTF8;
1387
}
1388
1389
#endif
1390
1391
/* Extended API */
1392
1393
#ifdef _WIN32
1394
#include <io.h>
1395
#endif
1396
1397
HANDLE GetFileHandleForFileDescriptor(int fd)
1398
0
{
1399
#ifdef _WIN32
1400
  return (HANDLE)_get_osfhandle(fd);
1401
#else  /* _WIN32 */
1402
0
  WINPR_FILE* pFile;
1403
0
  FILE* fp;
1404
0
  int flags;
1405
1406
  /* Make sure it's a valid fd */
1407
0
  if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
1408
0
    return INVALID_HANDLE_VALUE;
1409
1410
0
  flags = fcntl(fd, F_GETFL);
1411
0
  if (flags == -1)
1412
0
    return INVALID_HANDLE_VALUE;
1413
1414
0
  if (flags & O_WRONLY)
1415
0
    fp = fdopen(fd, "wb");
1416
0
  else
1417
0
    fp = fdopen(fd, "rb");
1418
1419
0
  if (!fp)
1420
0
    return INVALID_HANDLE_VALUE;
1421
1422
0
  setvbuf(fp, NULL, _IONBF, 0);
1423
1424
0
  pFile = FileHandle_New(fp);
1425
0
  if (!pFile)
1426
0
    return INVALID_HANDLE_VALUE;
1427
1428
0
  return (HANDLE)pFile;
1429
0
#endif /* _WIN32 */
1430
0
}
1431
1432
FILE* winpr_fopen(const char* path, const char* mode)
1433
0
{
1434
0
#ifndef _WIN32
1435
0
  return fopen(path, mode);
1436
#else
1437
  LPWSTR lpPathW = NULL;
1438
  LPWSTR lpModeW = NULL;
1439
  FILE* result = NULL;
1440
1441
  if (!path || !mode)
1442
    return NULL;
1443
1444
  lpPathW = ConvertUtf8ToWCharAlloc(path, NULL);
1445
  if (!lpPathW)
1446
    goto cleanup;
1447
1448
  lpModeW = ConvertUtf8ToWCharAlloc(mode, NULL);
1449
  if (!lpModeW)
1450
    goto cleanup;
1451
1452
  result = _wfopen(lpPathW, lpModeW);
1453
1454
cleanup:
1455
  free(lpPathW);
1456
  free(lpModeW);
1457
  return result;
1458
#endif
1459
0
}