VirtualBox

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

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

IPRT: Specialized RTFileWriteAt and RTFileReadAt for windows. bugref:9172

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