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