Coverage Report

Created: 2024-05-20 06:11

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