VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/fileio-win.cpp@ 77681

Last change on this file since 77681 was 77681, checked in by vboxsync, 6 years ago

IPRT: Adding an extended file open API that returns the action taken (opened, created, replaced, truncated) for addressing tickref:9276. Windows implementation only thus far.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 44.0 KB
Line 
1/* $Id: fileio-win.cpp 77681 2019-03-13 15:26:52Z vboxsync $ */
2/** @file
3 * IPRT - File I/O, native implementation for the Windows host platform.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_DIR
32#ifndef _WIN32_WINNT
33# define _WIN32_WINNT 0x0500
34#endif
35#include <iprt/nt/nt-and-windows.h>
36
37#include <iprt/file.h>
38
39#include <iprt/asm.h>
40#include <iprt/assert.h>
41#include <iprt/path.h>
42#include <iprt/string.h>
43#include <iprt/err.h>
44#include <iprt/ldr.h>
45#include <iprt/log.h>
46#include "internal/file.h"
47#include "internal/fs.h"
48#include "internal/path.h"
49#include "internal-r3-win.h" /* For g_enmWinVer + kRTWinOSType_XXX */
50
51
52/*********************************************************************************************************************************
53* Defined Constants And Macros *
54*********************************************************************************************************************************/
55typedef BOOL WINAPI FNVERIFYCONSOLEIOHANDLE(HANDLE);
56typedef FNVERIFYCONSOLEIOHANDLE *PFNVERIFYCONSOLEIOHANDLE; /* No, nobody fell on the keyboard, really! */
57
58/**
59 * This is wrapper around the ugly SetFilePointer api.
60 *
61 * It's equivalent to SetFilePointerEx which we so unfortunately cannot use because of
62 * it not being present in NT4 GA.
63 *
64 * @returns Success indicator. Extended error information obtainable using GetLastError().
65 * @param hFile Filehandle.
66 * @param offSeek Offset to seek.
67 * @param poffNew Where to store the new file offset. NULL allowed.
68 * @param uMethod Seek method. (The windows one!)
69 */
70DECLINLINE(bool) MySetFilePointer(RTFILE hFile, uint64_t offSeek, uint64_t *poffNew, unsigned uMethod)
71{
72 bool fRc;
73 LARGE_INTEGER off;
74
75 off.QuadPart = offSeek;
76#if 1
77 if (off.LowPart != INVALID_SET_FILE_POINTER)
78 {
79 off.LowPart = SetFilePointer((HANDLE)RTFileToNative(hFile), off.LowPart, &off.HighPart, uMethod);
80 fRc = off.LowPart != INVALID_SET_FILE_POINTER;
81 }
82 else
83 {
84 SetLastError(NO_ERROR);
85 off.LowPart = SetFilePointer((HANDLE)RTFileToNative(hFile), off.LowPart, &off.HighPart, uMethod);
86 fRc = GetLastError() == NO_ERROR;
87 }
88#else
89 fRc = SetFilePointerEx((HANDLE)RTFileToNative(hFile), off, &off, uMethod);
90#endif
91 if (fRc && poffNew)
92 *poffNew = off.QuadPart;
93 return fRc;
94}
95
96
97/**
98 * Helper for checking if a VERR_DISK_FULL isn't a VERR_FILE_TOO_BIG.
99 * @returns VERR_DISK_FULL or VERR_FILE_TOO_BIG.
100 */
101static int rtFileWinCheckIfDiskReallyFull(RTFILE hFile, uint64_t cbDesired)
102{
103 /*
104 * Windows doesn't appear to have a way to query the file size limit of a
105 * file system, so we have to deduce the limit from the file system driver name.
106 * This means it will only work for known file systems.
107 */
108 if (cbDesired >= _2G - 1)
109 {
110 uint64_t cbMaxFile = UINT64_MAX;
111 RTFSTYPE enmFsType;
112 int rc = rtNtQueryFsType((HANDLE)RTFileToNative(hFile), &enmFsType);
113 if (RT_SUCCESS(rc))
114 switch (enmFsType)
115 {
116 case RTFSTYPE_NTFS:
117 case RTFSTYPE_EXFAT:
118 case RTFSTYPE_UDF:
119 cbMaxFile = UINT64_C(0xffffffffffffffff); /* (May be limited by IFS.) */
120 break;
121
122 case RTFSTYPE_ISO9660:
123 cbMaxFile = 8 *_1T;
124 break;
125
126 case RTFSTYPE_FAT:
127 cbMaxFile = _4G;
128 break;
129
130 case RTFSTYPE_HPFS:
131 cbMaxFile = _2G;
132 break;
133
134 default:
135 break;
136 }
137 if (cbDesired >= cbMaxFile)
138 return VERR_FILE_TOO_BIG;
139 }
140 return VERR_DISK_FULL;
141}
142
143
144RTR3DECL(int) RTFileFromNative(PRTFILE pFile, RTHCINTPTR uNative)
145{
146 HANDLE h = (HANDLE)uNative;
147 AssertCompile(sizeof(h) == sizeof(uNative));
148 if (h == INVALID_HANDLE_VALUE)
149 {
150 AssertMsgFailed(("%p\n", uNative));
151 *pFile = NIL_RTFILE;
152 return VERR_INVALID_HANDLE;
153 }
154 *pFile = (RTFILE)h;
155 return VINF_SUCCESS;
156}
157
158
159RTR3DECL(RTHCINTPTR) RTFileToNative(RTFILE hFile)
160{
161 AssertReturn(hFile != NIL_RTFILE, (RTHCINTPTR)INVALID_HANDLE_VALUE);
162 return (RTHCINTPTR)hFile;
163}
164
165
166RTR3DECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, uint64_t fOpen)
167{
168 return RTFileOpenEx(pszFilename, fOpen, pFile, NULL);
169}
170
171
172RTDECL(int) RTFileOpenEx(const char *pszFilename, uint64_t fOpen, PRTFILE phFile, PRTFILEACTION penmActionTaken)
173{
174 /*
175 * Validate input.
176 */
177 AssertReturn(phFile, VERR_INVALID_PARAMETER);
178 *phFile = NIL_RTFILE;
179 if (penmActionTaken)
180 *penmActionTaken = RTFILEACTION_INVALID;
181 AssertReturn(pszFilename, VERR_INVALID_PARAMETER);
182
183 /*
184 * Merge forced open flags and validate them.
185 */
186 int rc = rtFileRecalcAndValidateFlags(&fOpen);
187 if (RT_FAILURE(rc))
188 return rc;
189
190 /*
191 * Determine disposition, access, share mode, creation flags, and security attributes
192 * for the CreateFile API call.
193 */
194 DWORD dwCreationDisposition;
195 switch (fOpen & RTFILE_O_ACTION_MASK)
196 {
197 case RTFILE_O_OPEN:
198 dwCreationDisposition = fOpen & RTFILE_O_TRUNCATE ? TRUNCATE_EXISTING : OPEN_EXISTING;
199 break;
200 case RTFILE_O_OPEN_CREATE:
201 dwCreationDisposition = OPEN_ALWAYS;
202 break;
203 case RTFILE_O_CREATE:
204 dwCreationDisposition = CREATE_NEW;
205 break;
206 case RTFILE_O_CREATE_REPLACE:
207 dwCreationDisposition = CREATE_ALWAYS;
208 break;
209 default:
210 AssertMsgFailedReturn(("Impossible fOpen=%#llx\n", fOpen), VERR_INVALID_FLAGS);
211 }
212
213 DWORD dwDesiredAccess;
214 switch (fOpen & RTFILE_O_ACCESS_MASK)
215 {
216 case RTFILE_O_READ:
217 dwDesiredAccess = FILE_GENERIC_READ; /* RTFILE_O_APPEND is ignored. */
218 break;
219 case RTFILE_O_WRITE:
220 dwDesiredAccess = fOpen & RTFILE_O_APPEND
221 ? FILE_GENERIC_WRITE & ~FILE_WRITE_DATA
222 : FILE_GENERIC_WRITE;
223 break;
224 case RTFILE_O_READWRITE:
225 dwDesiredAccess = fOpen & RTFILE_O_APPEND
226 ? FILE_GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA)
227 : FILE_GENERIC_READ | FILE_GENERIC_WRITE;
228 break;
229 case RTFILE_O_ATTR_ONLY:
230 if (fOpen & RTFILE_O_ACCESS_ATTR_MASK)
231 {
232 dwDesiredAccess = 0;
233 break;
234 }
235 RT_FALL_THRU();
236 default:
237 AssertMsgFailedReturn(("Impossible fOpen=%#llx\n", fOpen), VERR_INVALID_FLAGS);
238 }
239 if (dwCreationDisposition == TRUNCATE_EXISTING)
240 /* Required for truncating the file (see MSDN), it is *NOT* part of FILE_GENERIC_WRITE. */
241 dwDesiredAccess |= GENERIC_WRITE;
242
243 /* RTFileSetMode needs following rights as well. */
244 switch (fOpen & RTFILE_O_ACCESS_ATTR_MASK)
245 {
246 case RTFILE_O_ACCESS_ATTR_READ: dwDesiredAccess |= FILE_READ_ATTRIBUTES | SYNCHRONIZE; break;
247 case RTFILE_O_ACCESS_ATTR_WRITE: dwDesiredAccess |= FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
248 case RTFILE_O_ACCESS_ATTR_READWRITE: dwDesiredAccess |= FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
249 default:
250 /* Attributes access is the same as the file access. */
251 switch (fOpen & RTFILE_O_ACCESS_MASK)
252 {
253 case RTFILE_O_READ: dwDesiredAccess |= FILE_READ_ATTRIBUTES | SYNCHRONIZE; break;
254 case RTFILE_O_WRITE: dwDesiredAccess |= FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
255 case RTFILE_O_READWRITE: dwDesiredAccess |= FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
256 default:
257 AssertMsgFailedReturn(("Impossible fOpen=%#llx\n", fOpen), VERR_INVALID_FLAGS);
258 }
259 }
260
261 DWORD dwShareMode;
262 switch (fOpen & RTFILE_O_DENY_MASK)
263 {
264 case RTFILE_O_DENY_NONE: dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
265 case RTFILE_O_DENY_READ: dwShareMode = FILE_SHARE_WRITE; break;
266 case RTFILE_O_DENY_WRITE: dwShareMode = FILE_SHARE_READ; break;
267 case RTFILE_O_DENY_READWRITE: dwShareMode = 0; break;
268
269 case RTFILE_O_DENY_NOT_DELETE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; break;
270 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_WRITE; break;
271 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ; break;
272 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READWRITE:dwShareMode = FILE_SHARE_DELETE; break;
273 default:
274 AssertMsgFailedReturn(("Impossible fOpen=%#llx\n", fOpen), VERR_INVALID_FLAGS);
275 }
276
277 SECURITY_ATTRIBUTES SecurityAttributes;
278 PSECURITY_ATTRIBUTES pSecurityAttributes = NULL;
279 if (fOpen & RTFILE_O_INHERIT)
280 {
281 SecurityAttributes.nLength = sizeof(SecurityAttributes);
282 SecurityAttributes.lpSecurityDescriptor = NULL;
283 SecurityAttributes.bInheritHandle = TRUE;
284 pSecurityAttributes = &SecurityAttributes;
285 }
286
287 DWORD dwFlagsAndAttributes;
288 dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
289 if (fOpen & RTFILE_O_WRITE_THROUGH)
290 dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
291 if (fOpen & RTFILE_O_ASYNC_IO)
292 dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
293 if (fOpen & RTFILE_O_NO_CACHE)
294 {
295 dwFlagsAndAttributes |= FILE_FLAG_NO_BUFFERING;
296 dwDesiredAccess &= ~FILE_APPEND_DATA;
297 }
298
299 /*
300 * Open/Create the file.
301 */
302 PRTUTF16 pwszFilename;
303 rc = RTPathWinFromUtf8(&pwszFilename, pszFilename, 0 /*fFlags*/);
304 if (RT_SUCCESS(rc))
305 {
306 HANDLE hFile = CreateFileW(pwszFilename,
307 dwDesiredAccess,
308 dwShareMode,
309 pSecurityAttributes,
310 dwCreationDisposition,
311 dwFlagsAndAttributes,
312 NULL);
313 DWORD const dwErr = GetLastError();
314 if (hFile != INVALID_HANDLE_VALUE)
315 {
316 /*
317 * Calculate the action taken value.
318 */
319 RTFILEACTION enmActionTaken;
320 switch (dwCreationDisposition)
321 {
322 case CREATE_NEW:
323 enmActionTaken = RTFILEACTION_CREATED;
324 break;
325 case CREATE_ALWAYS:
326 AssertMsg(dwErr == ERROR_ALREADY_EXISTS || dwErr == NO_ERROR, ("%u\n", dwErr));
327 enmActionTaken = dwErr == ERROR_ALREADY_EXISTS ? RTFILEACTION_REPLACED : RTFILEACTION_CREATED;
328 break;
329 case OPEN_EXISTING:
330 enmActionTaken = RTFILEACTION_OPENED;
331 break;
332 case OPEN_ALWAYS:
333 AssertMsg(dwErr == ERROR_ALREADY_EXISTS || dwErr == NO_ERROR, ("%u\n", dwErr));
334 enmActionTaken = dwErr == ERROR_ALREADY_EXISTS ? RTFILEACTION_OPENED : RTFILEACTION_CREATED;
335 break;
336 case TRUNCATE_EXISTING:
337 enmActionTaken = RTFILEACTION_TRUNCATED;
338 break;
339 default:
340 AssertMsgFailed(("%d %#x\n", dwCreationDisposition, dwCreationDisposition));
341 enmActionTaken = RTFILEACTION_INVALID;
342 break;
343 }
344
345 /*
346 * Turn off indexing of directory through Windows Indexing Service if
347 * we created a new file or replaced an existing one.
348 */
349 if ( (fOpen & RTFILE_O_NOT_CONTENT_INDEXED)
350 && ( enmActionTaken == RTFILEACTION_CREATED
351 || enmActionTaken == RTFILEACTION_REPLACED) )
352 {
353 /** @todo there must be a way to do this via the handle! */
354 if (!SetFileAttributesW(pwszFilename, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED))
355 rc = RTErrConvertFromWin32(GetLastError());
356 }
357 /*
358 * If RTFILEACTION_OPENED, we may need to truncate the file.
359 */
360 else if ( (fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_ACTION_MASK)) == (RTFILE_O_TRUNCATE | RTFILE_O_OPEN_CREATE)
361 && enmActionTaken == RTFILEACTION_OPENED)
362 {
363 if (SetEndOfFile(hFile))
364 enmActionTaken = RTFILEACTION_TRUNCATED;
365 else
366 rc = RTErrConvertFromWin32(GetLastError());
367 }
368 if (penmActionTaken)
369 *penmActionTaken = enmActionTaken;
370 if (RT_SUCCESS(rc))
371 {
372 *phFile = (RTFILE)hFile;
373 Assert((HANDLE)*phFile == hFile);
374 RTPathWinFree(pwszFilename);
375 return VINF_SUCCESS;
376 }
377
378 CloseHandle(hFile);
379 }
380 else
381 {
382 if ( penmActionTaken
383 && dwCreationDisposition == CREATE_NEW
384 && dwErr == ERROR_FILE_EXISTS)
385 *penmActionTaken = RTFILEACTION_ALREADY_EXISTS;
386 rc = RTErrConvertFromWin32(dwErr);
387 }
388 RTPathWinFree(pwszFilename);
389 }
390 return rc;
391}
392
393
394RTR3DECL(int) RTFileOpenBitBucket(PRTFILE phFile, uint64_t fAccess)
395{
396 AssertReturn( fAccess == RTFILE_O_READ
397 || fAccess == RTFILE_O_WRITE
398 || fAccess == RTFILE_O_READWRITE,
399 VERR_INVALID_PARAMETER);
400 return RTFileOpen(phFile, "NUL", fAccess | RTFILE_O_DENY_NONE | RTFILE_O_OPEN);
401}
402
403
404RTR3DECL(int) RTFileClose(RTFILE hFile)
405{
406 if (hFile == NIL_RTFILE)
407 return VINF_SUCCESS;
408 if (CloseHandle((HANDLE)RTFileToNative(hFile)))
409 return VINF_SUCCESS;
410 return RTErrConvertFromWin32(GetLastError());
411}
412
413
414RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle)
415{
416 DWORD dwStdHandle;
417 switch (enmStdHandle)
418 {
419 case RTHANDLESTD_INPUT: dwStdHandle = STD_INPUT_HANDLE; break;
420 case RTHANDLESTD_OUTPUT: dwStdHandle = STD_OUTPUT_HANDLE; break;
421 case RTHANDLESTD_ERROR: dwStdHandle = STD_ERROR_HANDLE; break;
422 default:
423 AssertFailedReturn(NIL_RTFILE);
424 }
425
426 HANDLE hNative = GetStdHandle(dwStdHandle);
427 if (hNative == INVALID_HANDLE_VALUE)
428 return NIL_RTFILE;
429
430 RTFILE hFile = (RTFILE)(uintptr_t)hNative;
431 AssertReturn((HANDLE)(uintptr_t)hFile == hNative, NIL_RTFILE);
432 return hFile;
433}
434
435
436RTR3DECL(int) RTFileSeek(RTFILE hFile, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
437{
438 static ULONG aulSeekRecode[] =
439 {
440 FILE_BEGIN,
441 FILE_CURRENT,
442 FILE_END,
443 };
444
445 /*
446 * Validate input.
447 */
448 if (uMethod > RTFILE_SEEK_END)
449 {
450 AssertMsgFailed(("Invalid uMethod=%d\n", uMethod));
451 return VERR_INVALID_PARAMETER;
452 }
453
454 /*
455 * Execute the seek.
456 */
457 if (MySetFilePointer(hFile, offSeek, poffActual, aulSeekRecode[uMethod]))
458 return VINF_SUCCESS;
459 return RTErrConvertFromWin32(GetLastError());
460}
461
462
463RTR3DECL(int) RTFileRead(RTFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
464{
465 if (cbToRead <= 0)
466 {
467 if (pcbRead)
468 *pcbRead = 0;
469 return VINF_SUCCESS;
470 }
471 ULONG cbToReadAdj = (ULONG)cbToRead;
472 AssertReturn(cbToReadAdj == cbToRead, VERR_NUMBER_TOO_BIG);
473
474 ULONG cbRead = 0;
475 if (ReadFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToReadAdj, &cbRead, NULL))
476 {
477 if (pcbRead)
478 /* Caller can handle partial reads. */
479 *pcbRead = cbRead;
480 else
481 {
482 /* Caller expects everything to be read. */
483 while (cbToReadAdj > cbRead)
484 {
485 ULONG cbReadPart = 0;
486 if (!ReadFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbRead, cbToReadAdj - cbRead, &cbReadPart, NULL))
487 return RTErrConvertFromWin32(GetLastError());
488 if (cbReadPart == 0)
489 return VERR_EOF;
490 cbRead += cbReadPart;
491 }
492 }
493 return VINF_SUCCESS;
494 }
495
496 /*
497 * If it's a console, we might bump into out of memory conditions in the
498 * ReadConsole call.
499 */
500 DWORD dwErr = GetLastError();
501 if (dwErr == ERROR_NOT_ENOUGH_MEMORY)
502 {
503 ULONG cbChunk = cbToReadAdj / 2;
504 if (cbChunk > 16*_1K)
505 cbChunk = 16*_1K;
506 else
507 cbChunk = RT_ALIGN_32(cbChunk, 256);
508
509 cbRead = 0;
510 while (cbToReadAdj > cbRead)
511 {
512 ULONG cbToRead = RT_MIN(cbChunk, cbToReadAdj - cbRead);
513 ULONG cbReadPart = 0;
514 if (!ReadFile((HANDLE)RTFileToNative(hFile), (char *)pvBuf + cbRead, cbToRead, &cbReadPart, NULL))
515 {
516 /* If we failed because the buffer is too big, shrink it and
517 try again. */
518 dwErr = GetLastError();
519 if ( dwErr == ERROR_NOT_ENOUGH_MEMORY
520 && cbChunk > 8)
521 {
522 cbChunk /= 2;
523 continue;
524 }
525 return RTErrConvertFromWin32(dwErr);
526 }
527 cbRead += cbReadPart;
528
529 /* Return if the caller can handle partial reads, otherwise try
530 fill the buffer all the way up. */
531 if (pcbRead)
532 {
533 *pcbRead = cbRead;
534 break;
535 }
536 if (cbReadPart == 0)
537 return VERR_EOF;
538 }
539 return VINF_SUCCESS;
540 }
541
542 return RTErrConvertFromWin32(dwErr);
543}
544
545
546RTDECL(int) RTFileReadAt(RTFILE hFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
547{
548 ULONG cbToReadAdj = (ULONG)cbToRead;
549 AssertReturn(cbToReadAdj == cbToRead, VERR_NUMBER_TOO_BIG);
550
551 OVERLAPPED Overlapped;
552 Overlapped.Offset = (uint32_t)off;
553 Overlapped.OffsetHigh = (uint32_t)(off >> 32);
554 Overlapped.hEvent = NULL;
555 Overlapped.Internal = 0;
556 Overlapped.InternalHigh = 0;
557
558 ULONG cbRead = 0;
559 if (ReadFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToReadAdj, &cbRead, &Overlapped))
560 {
561 if (pcbRead)
562 /* Caller can handle partial reads. */
563 *pcbRead = cbRead;
564 else
565 {
566 /* Caller expects everything to be read. */
567 while (cbToReadAdj > cbRead)
568 {
569 Overlapped.Offset = (uint32_t)(off + cbRead);
570 Overlapped.OffsetHigh = (uint32_t)((off + cbRead) >> 32);
571 Overlapped.hEvent = NULL;
572 Overlapped.Internal = 0;
573 Overlapped.InternalHigh = 0;
574
575 ULONG cbReadPart = 0;
576 if (!ReadFile((HANDLE)RTFileToNative(hFile), (char *)pvBuf + cbRead, cbToReadAdj - cbRead,
577 &cbReadPart, &Overlapped))
578 return RTErrConvertFromWin32(GetLastError());
579 if (cbReadPart == 0)
580 return VERR_EOF;
581 cbRead += cbReadPart;
582 }
583 }
584 return VINF_SUCCESS;
585 }
586
587 /* We will get an EOF error when using overlapped I/O. So, make sure we don't
588 return it when pcbhRead is not NULL. */
589 DWORD dwErr = GetLastError();
590 if (pcbRead && dwErr == ERROR_HANDLE_EOF)
591 {
592 *pcbRead = 0;
593 return VINF_SUCCESS;
594 }
595 return RTErrConvertFromWin32(dwErr);
596}
597
598
599RTR3DECL(int) RTFileWrite(RTFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
600{
601 if (cbToWrite <= 0)
602 return VINF_SUCCESS;
603 ULONG const cbToWriteAdj = (ULONG)cbToWrite;
604 AssertReturn(cbToWriteAdj == cbToWrite, VERR_NUMBER_TOO_BIG);
605
606 ULONG cbWritten = 0;
607 if (WriteFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToWriteAdj, &cbWritten, NULL))
608 {
609 if (pcbWritten)
610 /* Caller can handle partial writes. */
611 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
612 else
613 {
614 /* Caller expects everything to be written. */
615 while (cbWritten < cbToWriteAdj)
616 {
617 ULONG cbWrittenPart = 0;
618 if (!WriteFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbWritten,
619 cbToWriteAdj - cbWritten, &cbWrittenPart, NULL))
620 {
621 int rc = RTErrConvertFromWin32(GetLastError());
622 if (rc == VERR_DISK_FULL)
623 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWriteAdj - cbWritten);
624 return rc;
625 }
626 if (cbWrittenPart == 0)
627 return VERR_WRITE_ERROR;
628 cbWritten += cbWrittenPart;
629 }
630 }
631 return VINF_SUCCESS;
632 }
633
634 /*
635 * If it's a console, we might bump into out of memory conditions in the
636 * WriteConsole call.
637 */
638 DWORD dwErr = GetLastError();
639 if (dwErr == ERROR_NOT_ENOUGH_MEMORY)
640 {
641 ULONG cbChunk = cbToWriteAdj / 2;
642 if (cbChunk > _32K)
643 cbChunk = _32K;
644 else
645 cbChunk = RT_ALIGN_32(cbChunk, 256);
646
647 cbWritten = 0;
648 while (cbWritten < cbToWriteAdj)
649 {
650 ULONG cbToWrite = RT_MIN(cbChunk, cbToWriteAdj - cbWritten);
651 ULONG cbWrittenPart = 0;
652 if (!WriteFile((HANDLE)RTFileToNative(hFile), (const char *)pvBuf + cbWritten, cbToWrite, &cbWrittenPart, NULL))
653 {
654 /* If we failed because the buffer is too big, shrink it and
655 try again. */
656 dwErr = GetLastError();
657 if ( dwErr == ERROR_NOT_ENOUGH_MEMORY
658 && cbChunk > 8)
659 {
660 cbChunk /= 2;
661 continue;
662 }
663 int rc = RTErrConvertFromWin32(dwErr);
664 if (rc == VERR_DISK_FULL)
665 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWrite);
666 return rc;
667 }
668 cbWritten += cbWrittenPart;
669
670 /* Return if the caller can handle partial writes, otherwise try
671 write out everything. */
672 if (pcbWritten)
673 {
674 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
675 break;
676 }
677 if (cbWrittenPart == 0)
678 return VERR_WRITE_ERROR;
679 }
680 return VINF_SUCCESS;
681 }
682
683 int rc = RTErrConvertFromWin32(dwErr);
684 if (rc == VERR_DISK_FULL)
685 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWriteAdj);
686 return rc;
687}
688
689
690RTDECL(int) RTFileWriteAt(RTFILE hFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
691{
692 ULONG const cbToWriteAdj = (ULONG)cbToWrite;
693 AssertReturn(cbToWriteAdj == cbToWrite, VERR_NUMBER_TOO_BIG);
694
695 OVERLAPPED Overlapped;
696 Overlapped.Offset = (uint32_t)off;
697 Overlapped.OffsetHigh = (uint32_t)(off >> 32);
698 Overlapped.hEvent = NULL;
699 Overlapped.Internal = 0;
700 Overlapped.InternalHigh = 0;
701
702 ULONG cbWritten = 0;
703 if (WriteFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToWriteAdj, &cbWritten, &Overlapped))
704 {
705 if (pcbWritten)
706 /* Caller can handle partial writes. */
707 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
708 else
709 {
710 /* Caller expects everything to be written. */
711 while (cbWritten < cbToWriteAdj)
712 {
713 Overlapped.Offset = (uint32_t)(off + cbWritten);
714 Overlapped.OffsetHigh = (uint32_t)((off + cbWritten) >> 32);
715 Overlapped.hEvent = NULL;
716 Overlapped.Internal = 0;
717 Overlapped.InternalHigh = 0;
718
719 ULONG cbWrittenPart = 0;
720 if (!WriteFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbWritten,
721 cbToWriteAdj - cbWritten, &cbWrittenPart, &Overlapped))
722 {
723 int rc = RTErrConvertFromWin32(GetLastError());
724 if (rc == VERR_DISK_FULL)
725 rc = rtFileWinCheckIfDiskReallyFull(hFile, off + cbToWriteAdj);
726 return rc;
727 }
728 if (cbWrittenPart == 0)
729 return VERR_WRITE_ERROR;
730 cbWritten += cbWrittenPart;
731 }
732 }
733 return VINF_SUCCESS;
734 }
735
736 int rc = RTErrConvertFromWin32(GetLastError());
737 if (rc == VERR_DISK_FULL)
738 rc = rtFileWinCheckIfDiskReallyFull(hFile, off + cbToWriteAdj);
739 return rc;
740}
741
742
743RTR3DECL(int) RTFileFlush(RTFILE hFile)
744{
745 if (!FlushFileBuffers((HANDLE)RTFileToNative(hFile)))
746 {
747 int rc = GetLastError();
748 Log(("FlushFileBuffers failed with %d\n", rc));
749 return RTErrConvertFromWin32(rc);
750 }
751 return VINF_SUCCESS;
752}
753
754
755RTR3DECL(int) RTFileSetSize(RTFILE hFile, uint64_t cbSize)
756{
757 /*
758 * Get current file pointer.
759 */
760 int rc;
761 uint64_t offCurrent;
762 if (MySetFilePointer(hFile, 0, &offCurrent, FILE_CURRENT))
763 {
764 /*
765 * Set new file pointer.
766 */
767 if (MySetFilePointer(hFile, cbSize, NULL, FILE_BEGIN))
768 {
769 /* set file pointer */
770 if (SetEndOfFile((HANDLE)RTFileToNative(hFile)))
771 {
772 /*
773 * Restore file pointer and return.
774 * If the old pointer was beyond the new file end, ignore failure.
775 */
776 if ( MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN)
777 || offCurrent > cbSize)
778 return VINF_SUCCESS;
779 }
780
781 /*
782 * Failed, try restoring the file pointer.
783 */
784 rc = GetLastError();
785 MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN);
786
787 if (rc == ERROR_DISK_FULL)
788 return rtFileWinCheckIfDiskReallyFull(hFile, cbSize);
789 }
790 else
791 rc = GetLastError();
792 }
793 else
794 rc = GetLastError();
795
796 return RTErrConvertFromWin32(rc);
797}
798
799
800RTR3DECL(int) RTFileGetSize(RTFILE hFile, uint64_t *pcbSize)
801{
802 /*
803 * GetFileSize works for most handles.
804 */
805 ULARGE_INTEGER Size;
806 Size.LowPart = GetFileSize((HANDLE)RTFileToNative(hFile), &Size.HighPart);
807 if (Size.LowPart != INVALID_FILE_SIZE)
808 {
809 *pcbSize = Size.QuadPart;
810 return VINF_SUCCESS;
811 }
812 int rc = RTErrConvertFromWin32(GetLastError());
813
814 /*
815 * Could it be a volume or a disk?
816 */
817 DISK_GEOMETRY DriveGeo;
818 DWORD cbDriveGeo;
819 if (DeviceIoControl((HANDLE)RTFileToNative(hFile),
820 IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
821 &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL))
822 {
823 if ( DriveGeo.MediaType == FixedMedia
824 || DriveGeo.MediaType == RemovableMedia)
825 {
826 *pcbSize = DriveGeo.Cylinders.QuadPart
827 * DriveGeo.TracksPerCylinder
828 * DriveGeo.SectorsPerTrack
829 * DriveGeo.BytesPerSector;
830
831 GET_LENGTH_INFORMATION DiskLenInfo;
832 DWORD Ignored;
833 if (DeviceIoControl((HANDLE)RTFileToNative(hFile),
834 IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
835 &DiskLenInfo, sizeof(DiskLenInfo), &Ignored, (LPOVERLAPPED)NULL))
836 {
837 /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */
838 *pcbSize = DiskLenInfo.Length.QuadPart;
839 }
840 return VINF_SUCCESS;
841 }
842 }
843
844 /*
845 * Return the GetFileSize result if not a volume/disk.
846 */
847 return rc;
848}
849
850
851RTR3DECL(int) RTFileGetMaxSizeEx(RTFILE hFile, PRTFOFF pcbMax)
852{
853 /** @todo r=bird:
854 * We might have to make this code OS version specific... In the worse
855 * case, we'll have to try GetVolumeInformationByHandle on vista and fall
856 * back on NtQueryVolumeInformationFile(,,,, FileFsAttributeInformation)
857 * else where, and check for known file system names. (For LAN shares we'll
858 * have to figure out the remote file system.) */
859 RT_NOREF_PV(hFile); RT_NOREF_PV(pcbMax);
860 return VERR_NOT_IMPLEMENTED;
861}
862
863
864RTR3DECL(bool) RTFileIsValid(RTFILE hFile)
865{
866 if (hFile != NIL_RTFILE)
867 {
868 DWORD dwType = GetFileType((HANDLE)RTFileToNative(hFile));
869 switch (dwType)
870 {
871 case FILE_TYPE_CHAR:
872 case FILE_TYPE_DISK:
873 case FILE_TYPE_PIPE:
874 case FILE_TYPE_REMOTE:
875 return true;
876
877 case FILE_TYPE_UNKNOWN:
878 if (GetLastError() == NO_ERROR)
879 return true;
880 break;
881
882 default:
883 break;
884 }
885 }
886 return false;
887}
888
889
890#define LOW_DWORD(u64) ((DWORD)u64)
891#define HIGH_DWORD(u64) (((DWORD *)&u64)[1])
892
893RTR3DECL(int) RTFileLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
894{
895 Assert(offLock >= 0);
896
897 /* Check arguments. */
898 if (fLock & ~RTFILE_LOCK_MASK)
899 {
900 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
901 return VERR_INVALID_PARAMETER;
902 }
903
904 /* Prepare flags. */
905 Assert(RTFILE_LOCK_WRITE);
906 DWORD dwFlags = (fLock & RTFILE_LOCK_WRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0;
907 Assert(RTFILE_LOCK_WAIT);
908 if (!(fLock & RTFILE_LOCK_WAIT))
909 dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
910
911 /* Windows structure. */
912 OVERLAPPED Overlapped;
913 memset(&Overlapped, 0, sizeof(Overlapped));
914 Overlapped.Offset = LOW_DWORD(offLock);
915 Overlapped.OffsetHigh = HIGH_DWORD(offLock);
916
917 /* Note: according to Microsoft, LockFileEx API call is available starting from NT 3.5 */
918 if (LockFileEx((HANDLE)RTFileToNative(hFile), dwFlags, 0, LOW_DWORD(cbLock), HIGH_DWORD(cbLock), &Overlapped))
919 return VINF_SUCCESS;
920
921 return RTErrConvertFromWin32(GetLastError());
922}
923
924
925RTR3DECL(int) RTFileChangeLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
926{
927 Assert(offLock >= 0);
928
929 /* Check arguments. */
930 if (fLock & ~RTFILE_LOCK_MASK)
931 {
932 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
933 return VERR_INVALID_PARAMETER;
934 }
935
936 /* Remove old lock. */
937 int rc = RTFileUnlock(hFile, offLock, cbLock);
938 if (RT_FAILURE(rc))
939 return rc;
940
941 /* Set new lock. */
942 rc = RTFileLock(hFile, fLock, offLock, cbLock);
943 if (RT_SUCCESS(rc))
944 return rc;
945
946 /* Try to restore old lock. */
947 unsigned fLockOld = (fLock & RTFILE_LOCK_WRITE) ? fLock & ~RTFILE_LOCK_WRITE : fLock | RTFILE_LOCK_WRITE;
948 rc = RTFileLock(hFile, fLockOld, offLock, cbLock);
949 if (RT_SUCCESS(rc))
950 return VERR_FILE_LOCK_VIOLATION;
951 else
952 return VERR_FILE_LOCK_LOST;
953}
954
955
956RTR3DECL(int) RTFileUnlock(RTFILE hFile, int64_t offLock, uint64_t cbLock)
957{
958 Assert(offLock >= 0);
959
960 if (UnlockFile((HANDLE)RTFileToNative(hFile),
961 LOW_DWORD(offLock), HIGH_DWORD(offLock),
962 LOW_DWORD(cbLock), HIGH_DWORD(cbLock)))
963 return VINF_SUCCESS;
964
965 return RTErrConvertFromWin32(GetLastError());
966}
967
968
969
970RTR3DECL(int) RTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
971{
972 /*
973 * Validate input.
974 */
975 if (hFile == NIL_RTFILE)
976 {
977 AssertMsgFailed(("Invalid hFile=%RTfile\n", hFile));
978 return VERR_INVALID_PARAMETER;
979 }
980 if (!pObjInfo)
981 {
982 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
983 return VERR_INVALID_PARAMETER;
984 }
985 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
986 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
987 {
988 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
989 return VERR_INVALID_PARAMETER;
990 }
991
992 /*
993 * Query file info.
994 */
995 HANDLE hHandle = (HANDLE)RTFileToNative(hFile);
996#if 1
997 uint64_t auBuf[168 / sizeof(uint64_t)]; /* Missing FILE_ALL_INFORMATION here. */
998 int rc = rtPathNtQueryInfoFromHandle(hFile, auBuf, sizeof(auBuf), pObjInfo, enmAdditionalAttribs, NULL, 0);
999 if (RT_SUCCESS(rc))
1000 return rc;
1001
1002 /*
1003 * Console I/O handles make trouble here. On older windows versions they
1004 * end up with ERROR_INVALID_HANDLE when handed to the above API, while on
1005 * more recent ones they cause different errors to appear.
1006 *
1007 * Thus, we must ignore the latter and doubly verify invalid handle claims.
1008 * We use the undocumented VerifyConsoleIoHandle to do this, falling back on
1009 * GetFileType should it not be there.
1010 */
1011 if ( rc == VERR_INVALID_HANDLE
1012 || rc == VERR_ACCESS_DENIED
1013 || rc == VERR_UNEXPECTED_FS_OBJ_TYPE)
1014 {
1015 static PFNVERIFYCONSOLEIOHANDLE s_pfnVerifyConsoleIoHandle = NULL;
1016 static bool volatile s_fInitialized = false;
1017 PFNVERIFYCONSOLEIOHANDLE pfnVerifyConsoleIoHandle;
1018 if (s_fInitialized)
1019 pfnVerifyConsoleIoHandle = s_pfnVerifyConsoleIoHandle;
1020 else
1021 {
1022 pfnVerifyConsoleIoHandle = (PFNVERIFYCONSOLEIOHANDLE)RTLdrGetSystemSymbol("kernel32.dll", "VerifyConsoleIoHandle");
1023 ASMAtomicWriteBool(&s_fInitialized, true);
1024 }
1025 if ( pfnVerifyConsoleIoHandle
1026 ? !pfnVerifyConsoleIoHandle(hHandle)
1027 : GetFileType(hHandle) == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR)
1028 return VERR_INVALID_HANDLE;
1029 }
1030 /*
1031 * On Windows 10 and (hopefully) 8.1 we get ERROR_INVALID_FUNCTION with console
1032 * I/O handles and null device handles. We must ignore these just like the
1033 * above invalid handle error.
1034 */
1035 else if (rc != VERR_INVALID_FUNCTION && rc != VERR_IO_BAD_COMMAND)
1036 return rc;
1037
1038 RT_ZERO(*pObjInfo);
1039 pObjInfo->Attr.enmAdditional = enmAdditionalAttribs;
1040 pObjInfo->Attr.fMode = rtFsModeFromDos(RTFS_DOS_NT_DEVICE, "", 0, 0);
1041 return VINF_SUCCESS;
1042#else
1043
1044 BY_HANDLE_FILE_INFORMATION Data;
1045 if (!GetFileInformationByHandle(hHandle, &Data))
1046 {
1047 /*
1048 * Console I/O handles make trouble here. On older windows versions they
1049 * end up with ERROR_INVALID_HANDLE when handed to the above API, while on
1050 * more recent ones they cause different errors to appear.
1051 *
1052 * Thus, we must ignore the latter and doubly verify invalid handle claims.
1053 * We use the undocumented VerifyConsoleIoHandle to do this, falling back on
1054 * GetFileType should it not be there.
1055 */
1056 DWORD dwErr = GetLastError();
1057 if (dwErr == ERROR_INVALID_HANDLE)
1058 {
1059 static PFNVERIFYCONSOLEIOHANDLE s_pfnVerifyConsoleIoHandle = NULL;
1060 static bool volatile s_fInitialized = false;
1061 PFNVERIFYCONSOLEIOHANDLE pfnVerifyConsoleIoHandle;
1062 if (s_fInitialized)
1063 pfnVerifyConsoleIoHandle = s_pfnVerifyConsoleIoHandle;
1064 else
1065 {
1066 pfnVerifyConsoleIoHandle = (PFNVERIFYCONSOLEIOHANDLE)RTLdrGetSystemSymbol("kernel32.dll", "VerifyConsoleIoHandle");
1067 ASMAtomicWriteBool(&s_fInitialized, true);
1068 }
1069 if ( pfnVerifyConsoleIoHandle
1070 ? !pfnVerifyConsoleIoHandle(hHandle)
1071 : GetFileType(hHandle) == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR)
1072 return VERR_INVALID_HANDLE;
1073 }
1074 /*
1075 * On Windows 10 and (hopefully) 8.1 we get ERROR_INVALID_FUNCTION with console I/O
1076 * handles. We must ignore these just like the above invalid handle error.
1077 */
1078 else if (dwErr != ERROR_INVALID_FUNCTION)
1079 return RTErrConvertFromWin32(dwErr);
1080
1081 RT_ZERO(Data);
1082 Data.dwFileAttributes = RTFS_DOS_NT_DEVICE;
1083 }
1084
1085 /*
1086 * Setup the returned data.
1087 */
1088 pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32)
1089 | (uint64_t)Data.nFileSizeLow;
1090 pObjInfo->cbAllocated = pObjInfo->cbObject;
1091
1092 Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime));
1093 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime);
1094 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime);
1095 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime);
1096 pObjInfo->ChangeTime = pObjInfo->ModificationTime;
1097
1098 pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, "", 0,
1099 RTFSMODE_SYMLINK_REPARSE_TAG /* (symlink or not, doesn't usually matter here) */);
1100
1101 /*
1102 * Requested attributes (we cannot provide anything actually).
1103 */
1104 switch (enmAdditionalAttribs)
1105 {
1106 case RTFSOBJATTRADD_NOTHING:
1107 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
1108 break;
1109
1110 case RTFSOBJATTRADD_UNIX:
1111 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
1112 pObjInfo->Attr.u.Unix.uid = ~0U;
1113 pObjInfo->Attr.u.Unix.gid = ~0U;
1114 pObjInfo->Attr.u.Unix.cHardlinks = Data.nNumberOfLinks ? Data.nNumberOfLinks : 1;
1115 pObjInfo->Attr.u.Unix.INodeIdDevice = Data.dwVolumeSerialNumber;
1116 pObjInfo->Attr.u.Unix.INodeId = RT_MAKE_U64(Data.nFileIndexLow, Data.nFileIndexHigh);
1117 pObjInfo->Attr.u.Unix.fFlags = 0;
1118 pObjInfo->Attr.u.Unix.GenerationId = 0;
1119 pObjInfo->Attr.u.Unix.Device = 0;
1120 break;
1121
1122 case RTFSOBJATTRADD_UNIX_OWNER:
1123 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
1124 pObjInfo->Attr.u.UnixOwner.uid = ~0U;
1125 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
1126 break;
1127
1128 case RTFSOBJATTRADD_UNIX_GROUP:
1129 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
1130 pObjInfo->Attr.u.UnixGroup.gid = ~0U;
1131 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
1132 break;
1133
1134 case RTFSOBJATTRADD_EASIZE:
1135 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
1136 pObjInfo->Attr.u.EASize.cb = 0;
1137 break;
1138
1139 default:
1140 AssertMsgFailed(("Impossible!\n"));
1141 return VERR_INTERNAL_ERROR;
1142 }
1143
1144 return VINF_SUCCESS;
1145#endif
1146}
1147
1148
1149RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1150 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1151{
1152 RT_NOREF_PV(pChangeTime); /* Not exposed thru the windows API we're using. */
1153
1154 if (!pAccessTime && !pModificationTime && !pBirthTime)
1155 return VINF_SUCCESS; /* NOP */
1156
1157 FILETIME CreationTimeFT;
1158 PFILETIME pCreationTimeFT = NULL;
1159 if (pBirthTime)
1160 pCreationTimeFT = RTTimeSpecGetNtFileTime(pBirthTime, &CreationTimeFT);
1161
1162 FILETIME LastAccessTimeFT;
1163 PFILETIME pLastAccessTimeFT = NULL;
1164 if (pAccessTime)
1165 pLastAccessTimeFT = RTTimeSpecGetNtFileTime(pAccessTime, &LastAccessTimeFT);
1166
1167 FILETIME LastWriteTimeFT;
1168 PFILETIME pLastWriteTimeFT = NULL;
1169 if (pModificationTime)
1170 pLastWriteTimeFT = RTTimeSpecGetNtFileTime(pModificationTime, &LastWriteTimeFT);
1171
1172 int rc = VINF_SUCCESS;
1173 if (!SetFileTime((HANDLE)RTFileToNative(hFile), pCreationTimeFT, pLastAccessTimeFT, pLastWriteTimeFT))
1174 {
1175 DWORD Err = GetLastError();
1176 rc = RTErrConvertFromWin32(Err);
1177 Log(("RTFileSetTimes(%RTfile, %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Rrc)\n",
1178 hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime, Err, rc));
1179 }
1180 return rc;
1181}
1182
1183
1184#if 0 /* RTFileSetMode is implemented by RTFileSetMode-r3-nt.cpp */
1185/* This comes from a source file with a different set of system headers (DDK)
1186 * so it can't be declared in a common header, like internal/file.h.
1187 */
1188extern int rtFileNativeSetAttributes(HANDLE FileHandle, ULONG FileAttributes);
1189
1190
1191RTR3DECL(int) RTFileSetMode(RTFILE hFile, RTFMODE fMode)
1192{
1193 /*
1194 * Normalize the mode and call the API.
1195 */
1196 fMode = rtFsModeNormalize(fMode, NULL, 0);
1197 if (!rtFsModeIsValid(fMode))
1198 return VERR_INVALID_PARAMETER;
1199
1200 ULONG FileAttributes = (fMode & RTFS_DOS_MASK) >> RTFS_DOS_SHIFT;
1201 int Err = rtFileNativeSetAttributes((HANDLE)hFile, FileAttributes);
1202 if (Err != ERROR_SUCCESS)
1203 {
1204 int rc = RTErrConvertFromWin32(Err);
1205 Log(("RTFileSetMode(%RTfile, %RTfmode): rtFileNativeSetAttributes (0x%08X) failed with err %d (%Rrc)\n",
1206 hFile, fMode, FileAttributes, Err, rc));
1207 return rc;
1208 }
1209 return VINF_SUCCESS;
1210}
1211#endif
1212
1213
1214/* RTFileQueryFsSizes is implemented by ../nt/RTFileQueryFsSizes-nt.cpp */
1215
1216
1217RTR3DECL(int) RTFileDelete(const char *pszFilename)
1218{
1219 PRTUTF16 pwszFilename;
1220 int rc = RTPathWinFromUtf8(&pwszFilename, pszFilename, 0 /*fFlags*/);
1221 if (RT_SUCCESS(rc))
1222 {
1223 if (!DeleteFileW(pwszFilename))
1224 rc = RTErrConvertFromWin32(GetLastError());
1225 RTPathWinFree(pwszFilename);
1226 }
1227
1228 return rc;
1229}
1230
1231
1232RTDECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
1233{
1234 /*
1235 * Validate input.
1236 */
1237 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
1238 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
1239 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
1240
1241 /*
1242 * Hand it on to the worker.
1243 */
1244 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
1245 fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0,
1246 RTFS_TYPE_FILE);
1247
1248 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
1249 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
1250 return rc;
1251
1252}
1253
1254
1255RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove)
1256{
1257 /*
1258 * Validate input.
1259 */
1260 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
1261 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
1262 AssertMsgReturn(!(fMove & ~RTFILEMOVE_FLAGS_REPLACE), ("%#x\n", fMove), VERR_INVALID_PARAMETER);
1263
1264 /*
1265 * Hand it on to the worker.
1266 */
1267 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
1268 fMove & RTFILEMOVE_FLAGS_REPLACE
1269 ? MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING
1270 : MOVEFILE_COPY_ALLOWED,
1271 RTFS_TYPE_FILE);
1272
1273 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
1274 pszSrc, pszSrc, pszDst, pszDst, fMove, rc));
1275 return rc;
1276}
1277
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette