VirtualBox

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

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

IPRT/fileio-win.cpp: Corrected RTFileReadAt so it does not return VERR_EOF when pcbRead is non-NULL, preserving the previous behavior and unixy host behaviour of the function. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 42.2 KB
Line 
1/* $Id: fileio-win.cpp 77641 2019-03-11 01:28:09Z 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.215389.xyz. 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 /*
169 * Validate input.
170 */
171 if (!pFile)
172 {
173 AssertMsgFailed(("Invalid pFile\n"));
174 return VERR_INVALID_PARAMETER;
175 }
176 *pFile = NIL_RTFILE;
177 if (!pszFilename)
178 {
179 AssertMsgFailed(("Invalid pszFilename\n"));
180 return VERR_INVALID_PARAMETER;
181 }
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 AssertMsgFailed(("Impossible fOpen=%#llx\n", fOpen));
211 return VERR_INVALID_PARAMETER;
212 }
213
214 DWORD dwDesiredAccess;
215 switch (fOpen & RTFILE_O_ACCESS_MASK)
216 {
217 case RTFILE_O_READ:
218 dwDesiredAccess = FILE_GENERIC_READ; /* RTFILE_O_APPEND is ignored. */
219 break;
220 case RTFILE_O_WRITE:
221 dwDesiredAccess = fOpen & RTFILE_O_APPEND
222 ? FILE_GENERIC_WRITE & ~FILE_WRITE_DATA
223 : FILE_GENERIC_WRITE;
224 break;
225 case RTFILE_O_READWRITE:
226 dwDesiredAccess = fOpen & RTFILE_O_APPEND
227 ? FILE_GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA)
228 : FILE_GENERIC_READ | FILE_GENERIC_WRITE;
229 break;
230 case RTFILE_O_ATTR_ONLY:
231 if (fOpen & RTFILE_O_ACCESS_ATTR_MASK)
232 {
233 dwDesiredAccess = 0;
234 break;
235 }
236 RT_FALL_THRU();
237 default:
238 AssertMsgFailed(("Impossible fOpen=%#llx\n", fOpen));
239 return VERR_INVALID_PARAMETER;
240 }
241 if (dwCreationDisposition == TRUNCATE_EXISTING)
242 /* Required for truncating the file (see MSDN), it is *NOT* part of FILE_GENERIC_WRITE. */
243 dwDesiredAccess |= GENERIC_WRITE;
244
245 /* RTFileSetMode needs following rights as well. */
246 switch (fOpen & RTFILE_O_ACCESS_ATTR_MASK)
247 {
248 case RTFILE_O_ACCESS_ATTR_READ: dwDesiredAccess |= FILE_READ_ATTRIBUTES | SYNCHRONIZE; break;
249 case RTFILE_O_ACCESS_ATTR_WRITE: dwDesiredAccess |= FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
250 case RTFILE_O_ACCESS_ATTR_READWRITE: dwDesiredAccess |= FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
251 default:
252 /* Attributes access is the same as the file access. */
253 switch (fOpen & RTFILE_O_ACCESS_MASK)
254 {
255 case RTFILE_O_READ: dwDesiredAccess |= FILE_READ_ATTRIBUTES | SYNCHRONIZE; break;
256 case RTFILE_O_WRITE: dwDesiredAccess |= FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
257 case RTFILE_O_READWRITE: dwDesiredAccess |= FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE; break;
258 default:
259 AssertMsgFailed(("Impossible fOpen=%#llx\n", fOpen));
260 return VERR_INVALID_PARAMETER;
261 }
262 }
263
264 DWORD dwShareMode;
265 switch (fOpen & RTFILE_O_DENY_MASK)
266 {
267 case RTFILE_O_DENY_NONE: dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
268 case RTFILE_O_DENY_READ: dwShareMode = FILE_SHARE_WRITE; break;
269 case RTFILE_O_DENY_WRITE: dwShareMode = FILE_SHARE_READ; break;
270 case RTFILE_O_DENY_READWRITE: dwShareMode = 0; break;
271
272 case RTFILE_O_DENY_NOT_DELETE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; break;
273 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_WRITE; break;
274 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ; break;
275 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READWRITE:dwShareMode = FILE_SHARE_DELETE; break;
276 default:
277 AssertMsgFailed(("Impossible fOpen=%#llx\n", fOpen));
278 return VERR_INVALID_PARAMETER;
279 }
280
281 SECURITY_ATTRIBUTES SecurityAttributes;
282 PSECURITY_ATTRIBUTES pSecurityAttributes = NULL;
283 if (fOpen & RTFILE_O_INHERIT)
284 {
285 SecurityAttributes.nLength = sizeof(SecurityAttributes);
286 SecurityAttributes.lpSecurityDescriptor = NULL;
287 SecurityAttributes.bInheritHandle = TRUE;
288 pSecurityAttributes = &SecurityAttributes;
289 }
290
291 DWORD dwFlagsAndAttributes;
292 dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
293 if (fOpen & RTFILE_O_WRITE_THROUGH)
294 dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
295 if (fOpen & RTFILE_O_ASYNC_IO)
296 dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
297 if (fOpen & RTFILE_O_NO_CACHE)
298 {
299 dwFlagsAndAttributes |= FILE_FLAG_NO_BUFFERING;
300 dwDesiredAccess &= ~FILE_APPEND_DATA;
301 }
302
303 /*
304 * Open/Create the file.
305 */
306 PRTUTF16 pwszFilename;
307 rc = RTPathWinFromUtf8(&pwszFilename, pszFilename, 0 /*fFlags*/);
308 if (RT_SUCCESS(rc))
309 {
310 HANDLE hFile = CreateFileW(pwszFilename,
311 dwDesiredAccess,
312 dwShareMode,
313 pSecurityAttributes,
314 dwCreationDisposition,
315 dwFlagsAndAttributes,
316 NULL);
317 if (hFile != INVALID_HANDLE_VALUE)
318 {
319 bool fCreated = dwCreationDisposition == CREATE_ALWAYS
320 || dwCreationDisposition == CREATE_NEW
321 || (dwCreationDisposition == OPEN_ALWAYS && GetLastError() == 0);
322
323 /*
324 * Turn off indexing of directory through Windows Indexing Service.
325 */
326 if ( fCreated
327 && (fOpen & RTFILE_O_NOT_CONTENT_INDEXED))
328 {
329 if (!SetFileAttributesW(pwszFilename, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED))
330 rc = RTErrConvertFromWin32(GetLastError());
331 }
332 /*
333 * Do we need to truncate the file?
334 */
335 else if ( !fCreated
336 && (fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_ACTION_MASK))
337 == (RTFILE_O_TRUNCATE | RTFILE_O_OPEN_CREATE))
338 {
339 if (!SetEndOfFile(hFile))
340 rc = RTErrConvertFromWin32(GetLastError());
341 }
342 if (RT_SUCCESS(rc))
343 {
344 *pFile = (RTFILE)hFile;
345 Assert((HANDLE)*pFile == hFile);
346 RTPathWinFree(pwszFilename);
347 return VINF_SUCCESS;
348 }
349
350 CloseHandle(hFile);
351 }
352 else
353 rc = RTErrConvertFromWin32(GetLastError());
354 RTPathWinFree(pwszFilename);
355 }
356 return rc;
357}
358
359
360RTR3DECL(int) RTFileOpenBitBucket(PRTFILE phFile, uint64_t fAccess)
361{
362 AssertReturn( fAccess == RTFILE_O_READ
363 || fAccess == RTFILE_O_WRITE
364 || fAccess == RTFILE_O_READWRITE,
365 VERR_INVALID_PARAMETER);
366 return RTFileOpen(phFile, "NUL", fAccess | RTFILE_O_DENY_NONE | RTFILE_O_OPEN);
367}
368
369
370RTR3DECL(int) RTFileClose(RTFILE hFile)
371{
372 if (hFile == NIL_RTFILE)
373 return VINF_SUCCESS;
374 if (CloseHandle((HANDLE)RTFileToNative(hFile)))
375 return VINF_SUCCESS;
376 return RTErrConvertFromWin32(GetLastError());
377}
378
379
380RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle)
381{
382 DWORD dwStdHandle;
383 switch (enmStdHandle)
384 {
385 case RTHANDLESTD_INPUT: dwStdHandle = STD_INPUT_HANDLE; break;
386 case RTHANDLESTD_OUTPUT: dwStdHandle = STD_OUTPUT_HANDLE; break;
387 case RTHANDLESTD_ERROR: dwStdHandle = STD_ERROR_HANDLE; break;
388 default:
389 AssertFailedReturn(NIL_RTFILE);
390 }
391
392 HANDLE hNative = GetStdHandle(dwStdHandle);
393 if (hNative == INVALID_HANDLE_VALUE)
394 return NIL_RTFILE;
395
396 RTFILE hFile = (RTFILE)(uintptr_t)hNative;
397 AssertReturn((HANDLE)(uintptr_t)hFile == hNative, NIL_RTFILE);
398 return hFile;
399}
400
401
402RTR3DECL(int) RTFileSeek(RTFILE hFile, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
403{
404 static ULONG aulSeekRecode[] =
405 {
406 FILE_BEGIN,
407 FILE_CURRENT,
408 FILE_END,
409 };
410
411 /*
412 * Validate input.
413 */
414 if (uMethod > RTFILE_SEEK_END)
415 {
416 AssertMsgFailed(("Invalid uMethod=%d\n", uMethod));
417 return VERR_INVALID_PARAMETER;
418 }
419
420 /*
421 * Execute the seek.
422 */
423 if (MySetFilePointer(hFile, offSeek, poffActual, aulSeekRecode[uMethod]))
424 return VINF_SUCCESS;
425 return RTErrConvertFromWin32(GetLastError());
426}
427
428
429RTR3DECL(int) RTFileRead(RTFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
430{
431 if (cbToRead <= 0)
432 {
433 if (pcbRead)
434 *pcbRead = 0;
435 return VINF_SUCCESS;
436 }
437 ULONG cbToReadAdj = (ULONG)cbToRead;
438 AssertReturn(cbToReadAdj == cbToRead, VERR_NUMBER_TOO_BIG);
439
440 ULONG cbRead = 0;
441 if (ReadFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToReadAdj, &cbRead, NULL))
442 {
443 if (pcbRead)
444 /* Caller can handle partial reads. */
445 *pcbRead = cbRead;
446 else
447 {
448 /* Caller expects everything to be read. */
449 while (cbToReadAdj > cbRead)
450 {
451 ULONG cbReadPart = 0;
452 if (!ReadFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbRead, cbToReadAdj - cbRead, &cbReadPart, NULL))
453 return RTErrConvertFromWin32(GetLastError());
454 if (cbReadPart == 0)
455 return VERR_EOF;
456 cbRead += cbReadPart;
457 }
458 }
459 return VINF_SUCCESS;
460 }
461
462 /*
463 * If it's a console, we might bump into out of memory conditions in the
464 * ReadConsole call.
465 */
466 DWORD dwErr = GetLastError();
467 if (dwErr == ERROR_NOT_ENOUGH_MEMORY)
468 {
469 ULONG cbChunk = cbToReadAdj / 2;
470 if (cbChunk > 16*_1K)
471 cbChunk = 16*_1K;
472 else
473 cbChunk = RT_ALIGN_32(cbChunk, 256);
474
475 cbRead = 0;
476 while (cbToReadAdj > cbRead)
477 {
478 ULONG cbToRead = RT_MIN(cbChunk, cbToReadAdj - cbRead);
479 ULONG cbReadPart = 0;
480 if (!ReadFile((HANDLE)RTFileToNative(hFile), (char *)pvBuf + cbRead, cbToRead, &cbReadPart, NULL))
481 {
482 /* If we failed because the buffer is too big, shrink it and
483 try again. */
484 dwErr = GetLastError();
485 if ( dwErr == ERROR_NOT_ENOUGH_MEMORY
486 && cbChunk > 8)
487 {
488 cbChunk /= 2;
489 continue;
490 }
491 return RTErrConvertFromWin32(dwErr);
492 }
493 cbRead += cbReadPart;
494
495 /* Return if the caller can handle partial reads, otherwise try
496 fill the buffer all the way up. */
497 if (pcbRead)
498 {
499 *pcbRead = cbRead;
500 break;
501 }
502 if (cbReadPart == 0)
503 return VERR_EOF;
504 }
505 return VINF_SUCCESS;
506 }
507
508 return RTErrConvertFromWin32(dwErr);
509}
510
511
512RTDECL(int) RTFileReadAt(RTFILE hFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
513{
514 ULONG cbToReadAdj = (ULONG)cbToRead;
515 AssertReturn(cbToReadAdj == cbToRead, VERR_NUMBER_TOO_BIG);
516
517 OVERLAPPED Overlapped;
518 Overlapped.Offset = (uint32_t)off;
519 Overlapped.OffsetHigh = (uint32_t)(off >> 32);
520 Overlapped.hEvent = NULL;
521 Overlapped.Internal = 0;
522 Overlapped.InternalHigh = 0;
523
524 ULONG cbRead = 0;
525 if (ReadFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToReadAdj, &cbRead, &Overlapped))
526 {
527 if (pcbRead)
528 /* Caller can handle partial reads. */
529 *pcbRead = cbRead;
530 else
531 {
532 /* Caller expects everything to be read. */
533 while (cbToReadAdj > cbRead)
534 {
535 Overlapped.Offset = (uint32_t)(off + cbRead);
536 Overlapped.OffsetHigh = (uint32_t)((off + cbRead) >> 32);
537 Overlapped.hEvent = NULL;
538 Overlapped.Internal = 0;
539 Overlapped.InternalHigh = 0;
540
541 ULONG cbReadPart = 0;
542 if (!ReadFile((HANDLE)RTFileToNative(hFile), (char *)pvBuf + cbRead, cbToReadAdj - cbRead,
543 &cbReadPart, &Overlapped))
544 return RTErrConvertFromWin32(GetLastError());
545 if (cbReadPart == 0)
546 return VERR_EOF;
547 cbRead += cbReadPart;
548 }
549 }
550 return VINF_SUCCESS;
551 }
552
553 /* We will get an EOF error when using overlapped I/O. So, make sure we don't
554 return it when pcbhRead is not NULL. */
555 DWORD dwErr = GetLastError();
556 if (pcbRead && dwErr == ERROR_HANDLE_EOF)
557 {
558 *pcbRead = 0;
559 return VINF_SUCCESS;
560 }
561 return RTErrConvertFromWin32(dwErr);
562}
563
564
565RTR3DECL(int) RTFileWrite(RTFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
566{
567 if (cbToWrite <= 0)
568 return VINF_SUCCESS;
569 ULONG const cbToWriteAdj = (ULONG)cbToWrite;
570 AssertReturn(cbToWriteAdj == cbToWrite, VERR_NUMBER_TOO_BIG);
571
572 ULONG cbWritten = 0;
573 if (WriteFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToWriteAdj, &cbWritten, NULL))
574 {
575 if (pcbWritten)
576 /* Caller can handle partial writes. */
577 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
578 else
579 {
580 /* Caller expects everything to be written. */
581 while (cbWritten < cbToWriteAdj)
582 {
583 ULONG cbWrittenPart = 0;
584 if (!WriteFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbWritten,
585 cbToWriteAdj - cbWritten, &cbWrittenPart, NULL))
586 {
587 int rc = RTErrConvertFromWin32(GetLastError());
588 if (rc == VERR_DISK_FULL)
589 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWriteAdj - cbWritten);
590 return rc;
591 }
592 if (cbWrittenPart == 0)
593 return VERR_WRITE_ERROR;
594 cbWritten += cbWrittenPart;
595 }
596 }
597 return VINF_SUCCESS;
598 }
599
600 /*
601 * If it's a console, we might bump into out of memory conditions in the
602 * WriteConsole call.
603 */
604 DWORD dwErr = GetLastError();
605 if (dwErr == ERROR_NOT_ENOUGH_MEMORY)
606 {
607 ULONG cbChunk = cbToWriteAdj / 2;
608 if (cbChunk > _32K)
609 cbChunk = _32K;
610 else
611 cbChunk = RT_ALIGN_32(cbChunk, 256);
612
613 cbWritten = 0;
614 while (cbWritten < cbToWriteAdj)
615 {
616 ULONG cbToWrite = RT_MIN(cbChunk, cbToWriteAdj - cbWritten);
617 ULONG cbWrittenPart = 0;
618 if (!WriteFile((HANDLE)RTFileToNative(hFile), (const char *)pvBuf + cbWritten, cbToWrite, &cbWrittenPart, NULL))
619 {
620 /* If we failed because the buffer is too big, shrink it and
621 try again. */
622 dwErr = GetLastError();
623 if ( dwErr == ERROR_NOT_ENOUGH_MEMORY
624 && cbChunk > 8)
625 {
626 cbChunk /= 2;
627 continue;
628 }
629 int rc = RTErrConvertFromWin32(dwErr);
630 if (rc == VERR_DISK_FULL)
631 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWrite);
632 return rc;
633 }
634 cbWritten += cbWrittenPart;
635
636 /* Return if the caller can handle partial writes, otherwise try
637 write out everything. */
638 if (pcbWritten)
639 {
640 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
641 break;
642 }
643 if (cbWrittenPart == 0)
644 return VERR_WRITE_ERROR;
645 }
646 return VINF_SUCCESS;
647 }
648
649 int rc = RTErrConvertFromWin32(dwErr);
650 if (rc == VERR_DISK_FULL)
651 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWriteAdj);
652 return rc;
653}
654
655
656RTDECL(int) RTFileWriteAt(RTFILE hFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
657{
658 ULONG const cbToWriteAdj = (ULONG)cbToWrite;
659 AssertReturn(cbToWriteAdj == cbToWrite, VERR_NUMBER_TOO_BIG);
660
661 OVERLAPPED Overlapped;
662 Overlapped.Offset = (uint32_t)off;
663 Overlapped.OffsetHigh = (uint32_t)(off >> 32);
664 Overlapped.hEvent = NULL;
665 Overlapped.Internal = 0;
666 Overlapped.InternalHigh = 0;
667
668 ULONG cbWritten = 0;
669 if (WriteFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToWriteAdj, &cbWritten, &Overlapped))
670 {
671 if (pcbWritten)
672 /* Caller can handle partial writes. */
673 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
674 else
675 {
676 /* Caller expects everything to be written. */
677 while (cbWritten < cbToWriteAdj)
678 {
679 Overlapped.Offset = (uint32_t)(off + cbWritten);
680 Overlapped.OffsetHigh = (uint32_t)((off + cbWritten) >> 32);
681 Overlapped.hEvent = NULL;
682 Overlapped.Internal = 0;
683 Overlapped.InternalHigh = 0;
684
685 ULONG cbWrittenPart = 0;
686 if (!WriteFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbWritten,
687 cbToWriteAdj - cbWritten, &cbWrittenPart, &Overlapped))
688 {
689 int rc = RTErrConvertFromWin32(GetLastError());
690 if (rc == VERR_DISK_FULL)
691 rc = rtFileWinCheckIfDiskReallyFull(hFile, off + cbToWriteAdj);
692 return rc;
693 }
694 if (cbWrittenPart == 0)
695 return VERR_WRITE_ERROR;
696 cbWritten += cbWrittenPart;
697 }
698 }
699 return VINF_SUCCESS;
700 }
701
702 int rc = RTErrConvertFromWin32(GetLastError());
703 if (rc == VERR_DISK_FULL)
704 rc = rtFileWinCheckIfDiskReallyFull(hFile, off + cbToWriteAdj);
705 return rc;
706}
707
708
709RTR3DECL(int) RTFileFlush(RTFILE hFile)
710{
711 if (!FlushFileBuffers((HANDLE)RTFileToNative(hFile)))
712 {
713 int rc = GetLastError();
714 Log(("FlushFileBuffers failed with %d\n", rc));
715 return RTErrConvertFromWin32(rc);
716 }
717 return VINF_SUCCESS;
718}
719
720
721RTR3DECL(int) RTFileSetSize(RTFILE hFile, uint64_t cbSize)
722{
723 /*
724 * Get current file pointer.
725 */
726 int rc;
727 uint64_t offCurrent;
728 if (MySetFilePointer(hFile, 0, &offCurrent, FILE_CURRENT))
729 {
730 /*
731 * Set new file pointer.
732 */
733 if (MySetFilePointer(hFile, cbSize, NULL, FILE_BEGIN))
734 {
735 /* set file pointer */
736 if (SetEndOfFile((HANDLE)RTFileToNative(hFile)))
737 {
738 /*
739 * Restore file pointer and return.
740 * If the old pointer was beyond the new file end, ignore failure.
741 */
742 if ( MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN)
743 || offCurrent > cbSize)
744 return VINF_SUCCESS;
745 }
746
747 /*
748 * Failed, try restoring the file pointer.
749 */
750 rc = GetLastError();
751 MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN);
752
753 if (rc == ERROR_DISK_FULL)
754 return rtFileWinCheckIfDiskReallyFull(hFile, cbSize);
755 }
756 else
757 rc = GetLastError();
758 }
759 else
760 rc = GetLastError();
761
762 return RTErrConvertFromWin32(rc);
763}
764
765
766RTR3DECL(int) RTFileGetSize(RTFILE hFile, uint64_t *pcbSize)
767{
768 /*
769 * GetFileSize works for most handles.
770 */
771 ULARGE_INTEGER Size;
772 Size.LowPart = GetFileSize((HANDLE)RTFileToNative(hFile), &Size.HighPart);
773 if (Size.LowPart != INVALID_FILE_SIZE)
774 {
775 *pcbSize = Size.QuadPart;
776 return VINF_SUCCESS;
777 }
778 int rc = RTErrConvertFromWin32(GetLastError());
779
780 /*
781 * Could it be a volume or a disk?
782 */
783 DISK_GEOMETRY DriveGeo;
784 DWORD cbDriveGeo;
785 if (DeviceIoControl((HANDLE)RTFileToNative(hFile),
786 IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
787 &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL))
788 {
789 if ( DriveGeo.MediaType == FixedMedia
790 || DriveGeo.MediaType == RemovableMedia)
791 {
792 *pcbSize = DriveGeo.Cylinders.QuadPart
793 * DriveGeo.TracksPerCylinder
794 * DriveGeo.SectorsPerTrack
795 * DriveGeo.BytesPerSector;
796
797 GET_LENGTH_INFORMATION DiskLenInfo;
798 DWORD Ignored;
799 if (DeviceIoControl((HANDLE)RTFileToNative(hFile),
800 IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
801 &DiskLenInfo, sizeof(DiskLenInfo), &Ignored, (LPOVERLAPPED)NULL))
802 {
803 /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */
804 *pcbSize = DiskLenInfo.Length.QuadPart;
805 }
806 return VINF_SUCCESS;
807 }
808 }
809
810 /*
811 * Return the GetFileSize result if not a volume/disk.
812 */
813 return rc;
814}
815
816
817RTR3DECL(int) RTFileGetMaxSizeEx(RTFILE hFile, PRTFOFF pcbMax)
818{
819 /** @todo r=bird:
820 * We might have to make this code OS version specific... In the worse
821 * case, we'll have to try GetVolumeInformationByHandle on vista and fall
822 * back on NtQueryVolumeInformationFile(,,,, FileFsAttributeInformation)
823 * else where, and check for known file system names. (For LAN shares we'll
824 * have to figure out the remote file system.) */
825 RT_NOREF_PV(hFile); RT_NOREF_PV(pcbMax);
826 return VERR_NOT_IMPLEMENTED;
827}
828
829
830RTR3DECL(bool) RTFileIsValid(RTFILE hFile)
831{
832 if (hFile != NIL_RTFILE)
833 {
834 DWORD dwType = GetFileType((HANDLE)RTFileToNative(hFile));
835 switch (dwType)
836 {
837 case FILE_TYPE_CHAR:
838 case FILE_TYPE_DISK:
839 case FILE_TYPE_PIPE:
840 case FILE_TYPE_REMOTE:
841 return true;
842
843 case FILE_TYPE_UNKNOWN:
844 if (GetLastError() == NO_ERROR)
845 return true;
846 break;
847
848 default:
849 break;
850 }
851 }
852 return false;
853}
854
855
856#define LOW_DWORD(u64) ((DWORD)u64)
857#define HIGH_DWORD(u64) (((DWORD *)&u64)[1])
858
859RTR3DECL(int) RTFileLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
860{
861 Assert(offLock >= 0);
862
863 /* Check arguments. */
864 if (fLock & ~RTFILE_LOCK_MASK)
865 {
866 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
867 return VERR_INVALID_PARAMETER;
868 }
869
870 /* Prepare flags. */
871 Assert(RTFILE_LOCK_WRITE);
872 DWORD dwFlags = (fLock & RTFILE_LOCK_WRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0;
873 Assert(RTFILE_LOCK_WAIT);
874 if (!(fLock & RTFILE_LOCK_WAIT))
875 dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
876
877 /* Windows structure. */
878 OVERLAPPED Overlapped;
879 memset(&Overlapped, 0, sizeof(Overlapped));
880 Overlapped.Offset = LOW_DWORD(offLock);
881 Overlapped.OffsetHigh = HIGH_DWORD(offLock);
882
883 /* Note: according to Microsoft, LockFileEx API call is available starting from NT 3.5 */
884 if (LockFileEx((HANDLE)RTFileToNative(hFile), dwFlags, 0, LOW_DWORD(cbLock), HIGH_DWORD(cbLock), &Overlapped))
885 return VINF_SUCCESS;
886
887 return RTErrConvertFromWin32(GetLastError());
888}
889
890
891RTR3DECL(int) RTFileChangeLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
892{
893 Assert(offLock >= 0);
894
895 /* Check arguments. */
896 if (fLock & ~RTFILE_LOCK_MASK)
897 {
898 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
899 return VERR_INVALID_PARAMETER;
900 }
901
902 /* Remove old lock. */
903 int rc = RTFileUnlock(hFile, offLock, cbLock);
904 if (RT_FAILURE(rc))
905 return rc;
906
907 /* Set new lock. */
908 rc = RTFileLock(hFile, fLock, offLock, cbLock);
909 if (RT_SUCCESS(rc))
910 return rc;
911
912 /* Try to restore old lock. */
913 unsigned fLockOld = (fLock & RTFILE_LOCK_WRITE) ? fLock & ~RTFILE_LOCK_WRITE : fLock | RTFILE_LOCK_WRITE;
914 rc = RTFileLock(hFile, fLockOld, offLock, cbLock);
915 if (RT_SUCCESS(rc))
916 return VERR_FILE_LOCK_VIOLATION;
917 else
918 return VERR_FILE_LOCK_LOST;
919}
920
921
922RTR3DECL(int) RTFileUnlock(RTFILE hFile, int64_t offLock, uint64_t cbLock)
923{
924 Assert(offLock >= 0);
925
926 if (UnlockFile((HANDLE)RTFileToNative(hFile),
927 LOW_DWORD(offLock), HIGH_DWORD(offLock),
928 LOW_DWORD(cbLock), HIGH_DWORD(cbLock)))
929 return VINF_SUCCESS;
930
931 return RTErrConvertFromWin32(GetLastError());
932}
933
934
935
936RTR3DECL(int) RTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
937{
938 /*
939 * Validate input.
940 */
941 if (hFile == NIL_RTFILE)
942 {
943 AssertMsgFailed(("Invalid hFile=%RTfile\n", hFile));
944 return VERR_INVALID_PARAMETER;
945 }
946 if (!pObjInfo)
947 {
948 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
949 return VERR_INVALID_PARAMETER;
950 }
951 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
952 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
953 {
954 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
955 return VERR_INVALID_PARAMETER;
956 }
957
958 /*
959 * Query file info.
960 */
961 HANDLE hHandle = (HANDLE)RTFileToNative(hFile);
962#if 1
963 uint64_t auBuf[168 / sizeof(uint64_t)]; /* Missing FILE_ALL_INFORMATION here. */
964 int rc = rtPathNtQueryInfoFromHandle(hFile, auBuf, sizeof(auBuf), pObjInfo, enmAdditionalAttribs, NULL, 0);
965 if (RT_SUCCESS(rc))
966 return rc;
967
968 /*
969 * Console I/O handles make trouble here. On older windows versions they
970 * end up with ERROR_INVALID_HANDLE when handed to the above API, while on
971 * more recent ones they cause different errors to appear.
972 *
973 * Thus, we must ignore the latter and doubly verify invalid handle claims.
974 * We use the undocumented VerifyConsoleIoHandle to do this, falling back on
975 * GetFileType should it not be there.
976 */
977 if ( rc == VERR_INVALID_HANDLE
978 || rc == VERR_ACCESS_DENIED
979 || rc == VERR_UNEXPECTED_FS_OBJ_TYPE)
980 {
981 static PFNVERIFYCONSOLEIOHANDLE s_pfnVerifyConsoleIoHandle = NULL;
982 static bool volatile s_fInitialized = false;
983 PFNVERIFYCONSOLEIOHANDLE pfnVerifyConsoleIoHandle;
984 if (s_fInitialized)
985 pfnVerifyConsoleIoHandle = s_pfnVerifyConsoleIoHandle;
986 else
987 {
988 pfnVerifyConsoleIoHandle = (PFNVERIFYCONSOLEIOHANDLE)RTLdrGetSystemSymbol("kernel32.dll", "VerifyConsoleIoHandle");
989 ASMAtomicWriteBool(&s_fInitialized, true);
990 }
991 if ( pfnVerifyConsoleIoHandle
992 ? !pfnVerifyConsoleIoHandle(hHandle)
993 : GetFileType(hHandle) == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR)
994 return VERR_INVALID_HANDLE;
995 }
996 /*
997 * On Windows 10 and (hopefully) 8.1 we get ERROR_INVALID_FUNCTION with console
998 * I/O handles and null device handles. We must ignore these just like the
999 * above invalid handle error.
1000 */
1001 else if (rc != VERR_INVALID_FUNCTION && rc != VERR_IO_BAD_COMMAND)
1002 return rc;
1003
1004 RT_ZERO(*pObjInfo);
1005 pObjInfo->Attr.enmAdditional = enmAdditionalAttribs;
1006 pObjInfo->Attr.fMode = rtFsModeFromDos(RTFS_DOS_NT_DEVICE, "", 0, 0);
1007 return VINF_SUCCESS;
1008#else
1009
1010 BY_HANDLE_FILE_INFORMATION Data;
1011 if (!GetFileInformationByHandle(hHandle, &Data))
1012 {
1013 /*
1014 * Console I/O handles make trouble here. On older windows versions they
1015 * end up with ERROR_INVALID_HANDLE when handed to the above API, while on
1016 * more recent ones they cause different errors to appear.
1017 *
1018 * Thus, we must ignore the latter and doubly verify invalid handle claims.
1019 * We use the undocumented VerifyConsoleIoHandle to do this, falling back on
1020 * GetFileType should it not be there.
1021 */
1022 DWORD dwErr = GetLastError();
1023 if (dwErr == ERROR_INVALID_HANDLE)
1024 {
1025 static PFNVERIFYCONSOLEIOHANDLE s_pfnVerifyConsoleIoHandle = NULL;
1026 static bool volatile s_fInitialized = false;
1027 PFNVERIFYCONSOLEIOHANDLE pfnVerifyConsoleIoHandle;
1028 if (s_fInitialized)
1029 pfnVerifyConsoleIoHandle = s_pfnVerifyConsoleIoHandle;
1030 else
1031 {
1032 pfnVerifyConsoleIoHandle = (PFNVERIFYCONSOLEIOHANDLE)RTLdrGetSystemSymbol("kernel32.dll", "VerifyConsoleIoHandle");
1033 ASMAtomicWriteBool(&s_fInitialized, true);
1034 }
1035 if ( pfnVerifyConsoleIoHandle
1036 ? !pfnVerifyConsoleIoHandle(hHandle)
1037 : GetFileType(hHandle) == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR)
1038 return VERR_INVALID_HANDLE;
1039 }
1040 /*
1041 * On Windows 10 and (hopefully) 8.1 we get ERROR_INVALID_FUNCTION with console I/O
1042 * handles. We must ignore these just like the above invalid handle error.
1043 */
1044 else if (dwErr != ERROR_INVALID_FUNCTION)
1045 return RTErrConvertFromWin32(dwErr);
1046
1047 RT_ZERO(Data);
1048 Data.dwFileAttributes = RTFS_DOS_NT_DEVICE;
1049 }
1050
1051 /*
1052 * Setup the returned data.
1053 */
1054 pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32)
1055 | (uint64_t)Data.nFileSizeLow;
1056 pObjInfo->cbAllocated = pObjInfo->cbObject;
1057
1058 Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime));
1059 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime);
1060 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime);
1061 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime);
1062 pObjInfo->ChangeTime = pObjInfo->ModificationTime;
1063
1064 pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, "", 0,
1065 RTFSMODE_SYMLINK_REPARSE_TAG /* (symlink or not, doesn't usually matter here) */);
1066
1067 /*
1068 * Requested attributes (we cannot provide anything actually).
1069 */
1070 switch (enmAdditionalAttribs)
1071 {
1072 case RTFSOBJATTRADD_NOTHING:
1073 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
1074 break;
1075
1076 case RTFSOBJATTRADD_UNIX:
1077 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
1078 pObjInfo->Attr.u.Unix.uid = ~0U;
1079 pObjInfo->Attr.u.Unix.gid = ~0U;
1080 pObjInfo->Attr.u.Unix.cHardlinks = Data.nNumberOfLinks ? Data.nNumberOfLinks : 1;
1081 pObjInfo->Attr.u.Unix.INodeIdDevice = Data.dwVolumeSerialNumber;
1082 pObjInfo->Attr.u.Unix.INodeId = RT_MAKE_U64(Data.nFileIndexLow, Data.nFileIndexHigh);
1083 pObjInfo->Attr.u.Unix.fFlags = 0;
1084 pObjInfo->Attr.u.Unix.GenerationId = 0;
1085 pObjInfo->Attr.u.Unix.Device = 0;
1086 break;
1087
1088 case RTFSOBJATTRADD_UNIX_OWNER:
1089 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
1090 pObjInfo->Attr.u.UnixOwner.uid = ~0U;
1091 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
1092 break;
1093
1094 case RTFSOBJATTRADD_UNIX_GROUP:
1095 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
1096 pObjInfo->Attr.u.UnixGroup.gid = ~0U;
1097 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
1098 break;
1099
1100 case RTFSOBJATTRADD_EASIZE:
1101 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
1102 pObjInfo->Attr.u.EASize.cb = 0;
1103 break;
1104
1105 default:
1106 AssertMsgFailed(("Impossible!\n"));
1107 return VERR_INTERNAL_ERROR;
1108 }
1109
1110 return VINF_SUCCESS;
1111#endif
1112}
1113
1114
1115RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1116 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1117{
1118 RT_NOREF_PV(pChangeTime); /* Not exposed thru the windows API we're using. */
1119
1120 if (!pAccessTime && !pModificationTime && !pBirthTime)
1121 return VINF_SUCCESS; /* NOP */
1122
1123 FILETIME CreationTimeFT;
1124 PFILETIME pCreationTimeFT = NULL;
1125 if (pBirthTime)
1126 pCreationTimeFT = RTTimeSpecGetNtFileTime(pBirthTime, &CreationTimeFT);
1127
1128 FILETIME LastAccessTimeFT;
1129 PFILETIME pLastAccessTimeFT = NULL;
1130 if (pAccessTime)
1131 pLastAccessTimeFT = RTTimeSpecGetNtFileTime(pAccessTime, &LastAccessTimeFT);
1132
1133 FILETIME LastWriteTimeFT;
1134 PFILETIME pLastWriteTimeFT = NULL;
1135 if (pModificationTime)
1136 pLastWriteTimeFT = RTTimeSpecGetNtFileTime(pModificationTime, &LastWriteTimeFT);
1137
1138 int rc = VINF_SUCCESS;
1139 if (!SetFileTime((HANDLE)RTFileToNative(hFile), pCreationTimeFT, pLastAccessTimeFT, pLastWriteTimeFT))
1140 {
1141 DWORD Err = GetLastError();
1142 rc = RTErrConvertFromWin32(Err);
1143 Log(("RTFileSetTimes(%RTfile, %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Rrc)\n",
1144 hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime, Err, rc));
1145 }
1146 return rc;
1147}
1148
1149
1150#if 0 /* RTFileSetMode is implemented by RTFileSetMode-r3-nt.cpp */
1151/* This comes from a source file with a different set of system headers (DDK)
1152 * so it can't be declared in a common header, like internal/file.h.
1153 */
1154extern int rtFileNativeSetAttributes(HANDLE FileHandle, ULONG FileAttributes);
1155
1156
1157RTR3DECL(int) RTFileSetMode(RTFILE hFile, RTFMODE fMode)
1158{
1159 /*
1160 * Normalize the mode and call the API.
1161 */
1162 fMode = rtFsModeNormalize(fMode, NULL, 0);
1163 if (!rtFsModeIsValid(fMode))
1164 return VERR_INVALID_PARAMETER;
1165
1166 ULONG FileAttributes = (fMode & RTFS_DOS_MASK) >> RTFS_DOS_SHIFT;
1167 int Err = rtFileNativeSetAttributes((HANDLE)hFile, FileAttributes);
1168 if (Err != ERROR_SUCCESS)
1169 {
1170 int rc = RTErrConvertFromWin32(Err);
1171 Log(("RTFileSetMode(%RTfile, %RTfmode): rtFileNativeSetAttributes (0x%08X) failed with err %d (%Rrc)\n",
1172 hFile, fMode, FileAttributes, Err, rc));
1173 return rc;
1174 }
1175 return VINF_SUCCESS;
1176}
1177#endif
1178
1179
1180/* RTFileQueryFsSizes is implemented by ../nt/RTFileQueryFsSizes-nt.cpp */
1181
1182
1183RTR3DECL(int) RTFileDelete(const char *pszFilename)
1184{
1185 PRTUTF16 pwszFilename;
1186 int rc = RTPathWinFromUtf8(&pwszFilename, pszFilename, 0 /*fFlags*/);
1187 if (RT_SUCCESS(rc))
1188 {
1189 if (!DeleteFileW(pwszFilename))
1190 rc = RTErrConvertFromWin32(GetLastError());
1191 RTPathWinFree(pwszFilename);
1192 }
1193
1194 return rc;
1195}
1196
1197
1198RTDECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
1199{
1200 /*
1201 * Validate input.
1202 */
1203 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
1204 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
1205 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
1206
1207 /*
1208 * Hand it on to the worker.
1209 */
1210 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
1211 fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0,
1212 RTFS_TYPE_FILE);
1213
1214 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
1215 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
1216 return rc;
1217
1218}
1219
1220
1221RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove)
1222{
1223 /*
1224 * Validate input.
1225 */
1226 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
1227 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
1228 AssertMsgReturn(!(fMove & ~RTFILEMOVE_FLAGS_REPLACE), ("%#x\n", fMove), VERR_INVALID_PARAMETER);
1229
1230 /*
1231 * Hand it on to the worker.
1232 */
1233 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
1234 fMove & RTFILEMOVE_FLAGS_REPLACE
1235 ? MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING
1236 : MOVEFILE_COPY_ALLOWED,
1237 RTFS_TYPE_FILE);
1238
1239 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
1240 pszSrc, pszSrc, pszDst, pszDst, fMove, rc));
1241 return rc;
1242}
1243
Note: See TracBrowser for help on using the repository browser.

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