VirtualBox

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

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

IPRT: Return VERR_FILE_TOO_BIG if we exceed the FAT file limit while writing or when calling RTFileSetSize. (The previous IsBeyondLimit() code never ever worked AFAIK.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 41.9 KB
Line 
1/* $Id: fileio-win.cpp 77231 2019-02-08 23:18:13Z 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 return RTErrConvertFromWin32(GetLastError());
553}
554
555
556RTR3DECL(int) RTFileWrite(RTFILE hFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
557{
558 if (cbToWrite <= 0)
559 return VINF_SUCCESS;
560 ULONG const cbToWriteAdj = (ULONG)cbToWrite;
561 AssertReturn(cbToWriteAdj == cbToWrite, VERR_NUMBER_TOO_BIG);
562
563 ULONG cbWritten = 0;
564 if (WriteFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToWriteAdj, &cbWritten, NULL))
565 {
566 if (pcbWritten)
567 /* Caller can handle partial writes. */
568 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
569 else
570 {
571 /* Caller expects everything to be written. */
572 while (cbWritten < cbToWriteAdj)
573 {
574 ULONG cbWrittenPart = 0;
575 if (!WriteFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbWritten,
576 cbToWriteAdj - cbWritten, &cbWrittenPart, NULL))
577 {
578 int rc = RTErrConvertFromWin32(GetLastError());
579 if (rc == VERR_DISK_FULL)
580 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWriteAdj - cbWritten);
581 return rc;
582 }
583 if (cbWrittenPart == 0)
584 return VERR_WRITE_ERROR;
585 cbWritten += cbWrittenPart;
586 }
587 }
588 return VINF_SUCCESS;
589 }
590
591 /*
592 * If it's a console, we might bump into out of memory conditions in the
593 * WriteConsole call.
594 */
595 DWORD dwErr = GetLastError();
596 if (dwErr == ERROR_NOT_ENOUGH_MEMORY)
597 {
598 ULONG cbChunk = cbToWriteAdj / 2;
599 if (cbChunk > _32K)
600 cbChunk = _32K;
601 else
602 cbChunk = RT_ALIGN_32(cbChunk, 256);
603
604 cbWritten = 0;
605 while (cbWritten < cbToWriteAdj)
606 {
607 ULONG cbToWrite = RT_MIN(cbChunk, cbToWriteAdj - cbWritten);
608 ULONG cbWrittenPart = 0;
609 if (!WriteFile((HANDLE)RTFileToNative(hFile), (const char *)pvBuf + cbWritten, cbToWrite, &cbWrittenPart, NULL))
610 {
611 /* If we failed because the buffer is too big, shrink it and
612 try again. */
613 dwErr = GetLastError();
614 if ( dwErr == ERROR_NOT_ENOUGH_MEMORY
615 && cbChunk > 8)
616 {
617 cbChunk /= 2;
618 continue;
619 }
620 int rc = RTErrConvertFromWin32(dwErr);
621 if (rc == VERR_DISK_FULL)
622 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWrite);
623 return rc;
624 }
625 cbWritten += cbWrittenPart;
626
627 /* Return if the caller can handle partial writes, otherwise try
628 write out everything. */
629 if (pcbWritten)
630 {
631 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
632 break;
633 }
634 if (cbWrittenPart == 0)
635 return VERR_WRITE_ERROR;
636 }
637 return VINF_SUCCESS;
638 }
639
640 int rc = RTErrConvertFromWin32(dwErr);
641 if (rc == VERR_DISK_FULL)
642 rc = rtFileWinCheckIfDiskReallyFull(hFile, RTFileTell(hFile) + cbToWriteAdj);
643 return rc;
644}
645
646
647RTDECL(int) RTFileWriteAt(RTFILE hFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
648{
649 ULONG const cbToWriteAdj = (ULONG)cbToWrite;
650 AssertReturn(cbToWriteAdj == cbToWrite, VERR_NUMBER_TOO_BIG);
651
652 OVERLAPPED Overlapped;
653 Overlapped.Offset = (uint32_t)off;
654 Overlapped.OffsetHigh = (uint32_t)(off >> 32);
655 Overlapped.hEvent = NULL;
656 Overlapped.Internal = 0;
657 Overlapped.InternalHigh = 0;
658
659 ULONG cbWritten = 0;
660 if (WriteFile((HANDLE)RTFileToNative(hFile), pvBuf, cbToWriteAdj, &cbWritten, &Overlapped))
661 {
662 if (pcbWritten)
663 /* Caller can handle partial writes. */
664 *pcbWritten = RT_MIN(cbWritten, cbToWriteAdj); /* paranoia^3 */
665 else
666 {
667 /* Caller expects everything to be written. */
668 while (cbWritten < cbToWriteAdj)
669 {
670 Overlapped.Offset = (uint32_t)(off + cbWritten);
671 Overlapped.OffsetHigh = (uint32_t)((off + cbWritten) >> 32);
672 Overlapped.hEvent = NULL;
673 Overlapped.Internal = 0;
674 Overlapped.InternalHigh = 0;
675
676 ULONG cbWrittenPart = 0;
677 if (!WriteFile((HANDLE)RTFileToNative(hFile), (char*)pvBuf + cbWritten,
678 cbToWriteAdj - cbWritten, &cbWrittenPart, &Overlapped))
679 {
680 int rc = RTErrConvertFromWin32(GetLastError());
681 if (rc == VERR_DISK_FULL)
682 rc = rtFileWinCheckIfDiskReallyFull(hFile, off + cbToWriteAdj);
683 return rc;
684 }
685 if (cbWrittenPart == 0)
686 return VERR_WRITE_ERROR;
687 cbWritten += cbWrittenPart;
688 }
689 }
690 return VINF_SUCCESS;
691 }
692
693 int rc = RTErrConvertFromWin32(GetLastError());
694 if (rc == VERR_DISK_FULL)
695 rc = rtFileWinCheckIfDiskReallyFull(hFile, off + cbToWriteAdj);
696 return rc;
697}
698
699
700RTR3DECL(int) RTFileFlush(RTFILE hFile)
701{
702 if (!FlushFileBuffers((HANDLE)RTFileToNative(hFile)))
703 {
704 int rc = GetLastError();
705 Log(("FlushFileBuffers failed with %d\n", rc));
706 return RTErrConvertFromWin32(rc);
707 }
708 return VINF_SUCCESS;
709}
710
711
712RTR3DECL(int) RTFileSetSize(RTFILE hFile, uint64_t cbSize)
713{
714 /*
715 * Get current file pointer.
716 */
717 int rc;
718 uint64_t offCurrent;
719 if (MySetFilePointer(hFile, 0, &offCurrent, FILE_CURRENT))
720 {
721 /*
722 * Set new file pointer.
723 */
724 if (MySetFilePointer(hFile, cbSize, NULL, FILE_BEGIN))
725 {
726 /* set file pointer */
727 if (SetEndOfFile((HANDLE)RTFileToNative(hFile)))
728 {
729 /*
730 * Restore file pointer and return.
731 * If the old pointer was beyond the new file end, ignore failure.
732 */
733 if ( MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN)
734 || offCurrent > cbSize)
735 return VINF_SUCCESS;
736 }
737
738 /*
739 * Failed, try restoring the file pointer.
740 */
741 rc = GetLastError();
742 MySetFilePointer(hFile, offCurrent, NULL, FILE_BEGIN);
743
744 if (rc == ERROR_DISK_FULL)
745 return rtFileWinCheckIfDiskReallyFull(hFile, cbSize);
746 }
747 else
748 rc = GetLastError();
749 }
750 else
751 rc = GetLastError();
752
753 return RTErrConvertFromWin32(rc);
754}
755
756
757RTR3DECL(int) RTFileGetSize(RTFILE hFile, uint64_t *pcbSize)
758{
759 /*
760 * GetFileSize works for most handles.
761 */
762 ULARGE_INTEGER Size;
763 Size.LowPart = GetFileSize((HANDLE)RTFileToNative(hFile), &Size.HighPart);
764 if (Size.LowPart != INVALID_FILE_SIZE)
765 {
766 *pcbSize = Size.QuadPart;
767 return VINF_SUCCESS;
768 }
769 int rc = RTErrConvertFromWin32(GetLastError());
770
771 /*
772 * Could it be a volume or a disk?
773 */
774 DISK_GEOMETRY DriveGeo;
775 DWORD cbDriveGeo;
776 if (DeviceIoControl((HANDLE)RTFileToNative(hFile),
777 IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
778 &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL))
779 {
780 if ( DriveGeo.MediaType == FixedMedia
781 || DriveGeo.MediaType == RemovableMedia)
782 {
783 *pcbSize = DriveGeo.Cylinders.QuadPart
784 * DriveGeo.TracksPerCylinder
785 * DriveGeo.SectorsPerTrack
786 * DriveGeo.BytesPerSector;
787
788 GET_LENGTH_INFORMATION DiskLenInfo;
789 DWORD Ignored;
790 if (DeviceIoControl((HANDLE)RTFileToNative(hFile),
791 IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
792 &DiskLenInfo, sizeof(DiskLenInfo), &Ignored, (LPOVERLAPPED)NULL))
793 {
794 /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */
795 *pcbSize = DiskLenInfo.Length.QuadPart;
796 }
797 return VINF_SUCCESS;
798 }
799 }
800
801 /*
802 * Return the GetFileSize result if not a volume/disk.
803 */
804 return rc;
805}
806
807
808RTR3DECL(int) RTFileGetMaxSizeEx(RTFILE hFile, PRTFOFF pcbMax)
809{
810 /** @todo r=bird:
811 * We might have to make this code OS version specific... In the worse
812 * case, we'll have to try GetVolumeInformationByHandle on vista and fall
813 * back on NtQueryVolumeInformationFile(,,,, FileFsAttributeInformation)
814 * else where, and check for known file system names. (For LAN shares we'll
815 * have to figure out the remote file system.) */
816 RT_NOREF_PV(hFile); RT_NOREF_PV(pcbMax);
817 return VERR_NOT_IMPLEMENTED;
818}
819
820
821RTR3DECL(bool) RTFileIsValid(RTFILE hFile)
822{
823 if (hFile != NIL_RTFILE)
824 {
825 DWORD dwType = GetFileType((HANDLE)RTFileToNative(hFile));
826 switch (dwType)
827 {
828 case FILE_TYPE_CHAR:
829 case FILE_TYPE_DISK:
830 case FILE_TYPE_PIPE:
831 case FILE_TYPE_REMOTE:
832 return true;
833
834 case FILE_TYPE_UNKNOWN:
835 if (GetLastError() == NO_ERROR)
836 return true;
837 break;
838
839 default:
840 break;
841 }
842 }
843 return false;
844}
845
846
847#define LOW_DWORD(u64) ((DWORD)u64)
848#define HIGH_DWORD(u64) (((DWORD *)&u64)[1])
849
850RTR3DECL(int) RTFileLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
851{
852 Assert(offLock >= 0);
853
854 /* Check arguments. */
855 if (fLock & ~RTFILE_LOCK_MASK)
856 {
857 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
858 return VERR_INVALID_PARAMETER;
859 }
860
861 /* Prepare flags. */
862 Assert(RTFILE_LOCK_WRITE);
863 DWORD dwFlags = (fLock & RTFILE_LOCK_WRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0;
864 Assert(RTFILE_LOCK_WAIT);
865 if (!(fLock & RTFILE_LOCK_WAIT))
866 dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
867
868 /* Windows structure. */
869 OVERLAPPED Overlapped;
870 memset(&Overlapped, 0, sizeof(Overlapped));
871 Overlapped.Offset = LOW_DWORD(offLock);
872 Overlapped.OffsetHigh = HIGH_DWORD(offLock);
873
874 /* Note: according to Microsoft, LockFileEx API call is available starting from NT 3.5 */
875 if (LockFileEx((HANDLE)RTFileToNative(hFile), dwFlags, 0, LOW_DWORD(cbLock), HIGH_DWORD(cbLock), &Overlapped))
876 return VINF_SUCCESS;
877
878 return RTErrConvertFromWin32(GetLastError());
879}
880
881
882RTR3DECL(int) RTFileChangeLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
883{
884 Assert(offLock >= 0);
885
886 /* Check arguments. */
887 if (fLock & ~RTFILE_LOCK_MASK)
888 {
889 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
890 return VERR_INVALID_PARAMETER;
891 }
892
893 /* Remove old lock. */
894 int rc = RTFileUnlock(hFile, offLock, cbLock);
895 if (RT_FAILURE(rc))
896 return rc;
897
898 /* Set new lock. */
899 rc = RTFileLock(hFile, fLock, offLock, cbLock);
900 if (RT_SUCCESS(rc))
901 return rc;
902
903 /* Try to restore old lock. */
904 unsigned fLockOld = (fLock & RTFILE_LOCK_WRITE) ? fLock & ~RTFILE_LOCK_WRITE : fLock | RTFILE_LOCK_WRITE;
905 rc = RTFileLock(hFile, fLockOld, offLock, cbLock);
906 if (RT_SUCCESS(rc))
907 return VERR_FILE_LOCK_VIOLATION;
908 else
909 return VERR_FILE_LOCK_LOST;
910}
911
912
913RTR3DECL(int) RTFileUnlock(RTFILE hFile, int64_t offLock, uint64_t cbLock)
914{
915 Assert(offLock >= 0);
916
917 if (UnlockFile((HANDLE)RTFileToNative(hFile),
918 LOW_DWORD(offLock), HIGH_DWORD(offLock),
919 LOW_DWORD(cbLock), HIGH_DWORD(cbLock)))
920 return VINF_SUCCESS;
921
922 return RTErrConvertFromWin32(GetLastError());
923}
924
925
926
927RTR3DECL(int) RTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
928{
929 /*
930 * Validate input.
931 */
932 if (hFile == NIL_RTFILE)
933 {
934 AssertMsgFailed(("Invalid hFile=%RTfile\n", hFile));
935 return VERR_INVALID_PARAMETER;
936 }
937 if (!pObjInfo)
938 {
939 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
940 return VERR_INVALID_PARAMETER;
941 }
942 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
943 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
944 {
945 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
946 return VERR_INVALID_PARAMETER;
947 }
948
949 /*
950 * Query file info.
951 */
952 HANDLE hHandle = (HANDLE)RTFileToNative(hFile);
953#if 1
954 uint64_t auBuf[168 / sizeof(uint64_t)]; /* Missing FILE_ALL_INFORMATION here. */
955 int rc = rtPathNtQueryInfoFromHandle(hFile, auBuf, sizeof(auBuf), pObjInfo, enmAdditionalAttribs, NULL, 0);
956 if (RT_SUCCESS(rc))
957 return rc;
958
959 /*
960 * Console I/O handles make trouble here. On older windows versions they
961 * end up with ERROR_INVALID_HANDLE when handed to the above API, while on
962 * more recent ones they cause different errors to appear.
963 *
964 * Thus, we must ignore the latter and doubly verify invalid handle claims.
965 * We use the undocumented VerifyConsoleIoHandle to do this, falling back on
966 * GetFileType should it not be there.
967 */
968 if ( rc == VERR_INVALID_HANDLE
969 || rc == VERR_ACCESS_DENIED
970 || rc == VERR_UNEXPECTED_FS_OBJ_TYPE)
971 {
972 static PFNVERIFYCONSOLEIOHANDLE s_pfnVerifyConsoleIoHandle = NULL;
973 static bool volatile s_fInitialized = false;
974 PFNVERIFYCONSOLEIOHANDLE pfnVerifyConsoleIoHandle;
975 if (s_fInitialized)
976 pfnVerifyConsoleIoHandle = s_pfnVerifyConsoleIoHandle;
977 else
978 {
979 pfnVerifyConsoleIoHandle = (PFNVERIFYCONSOLEIOHANDLE)RTLdrGetSystemSymbol("kernel32.dll", "VerifyConsoleIoHandle");
980 ASMAtomicWriteBool(&s_fInitialized, true);
981 }
982 if ( pfnVerifyConsoleIoHandle
983 ? !pfnVerifyConsoleIoHandle(hHandle)
984 : GetFileType(hHandle) == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR)
985 return VERR_INVALID_HANDLE;
986 }
987 /*
988 * On Windows 10 and (hopefully) 8.1 we get ERROR_INVALID_FUNCTION with console
989 * I/O handles and null device handles. We must ignore these just like the
990 * above invalid handle error.
991 */
992 else if (rc != VERR_INVALID_FUNCTION && rc != VERR_IO_BAD_COMMAND)
993 return rc;
994
995 RT_ZERO(*pObjInfo);
996 pObjInfo->Attr.enmAdditional = enmAdditionalAttribs;
997 pObjInfo->Attr.fMode = rtFsModeFromDos(RTFS_DOS_NT_DEVICE, "", 0, 0);
998 return VINF_SUCCESS;
999#else
1000
1001 BY_HANDLE_FILE_INFORMATION Data;
1002 if (!GetFileInformationByHandle(hHandle, &Data))
1003 {
1004 /*
1005 * Console I/O handles make trouble here. On older windows versions they
1006 * end up with ERROR_INVALID_HANDLE when handed to the above API, while on
1007 * more recent ones they cause different errors to appear.
1008 *
1009 * Thus, we must ignore the latter and doubly verify invalid handle claims.
1010 * We use the undocumented VerifyConsoleIoHandle to do this, falling back on
1011 * GetFileType should it not be there.
1012 */
1013 DWORD dwErr = GetLastError();
1014 if (dwErr == ERROR_INVALID_HANDLE)
1015 {
1016 static PFNVERIFYCONSOLEIOHANDLE s_pfnVerifyConsoleIoHandle = NULL;
1017 static bool volatile s_fInitialized = false;
1018 PFNVERIFYCONSOLEIOHANDLE pfnVerifyConsoleIoHandle;
1019 if (s_fInitialized)
1020 pfnVerifyConsoleIoHandle = s_pfnVerifyConsoleIoHandle;
1021 else
1022 {
1023 pfnVerifyConsoleIoHandle = (PFNVERIFYCONSOLEIOHANDLE)RTLdrGetSystemSymbol("kernel32.dll", "VerifyConsoleIoHandle");
1024 ASMAtomicWriteBool(&s_fInitialized, true);
1025 }
1026 if ( pfnVerifyConsoleIoHandle
1027 ? !pfnVerifyConsoleIoHandle(hHandle)
1028 : GetFileType(hHandle) == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR)
1029 return VERR_INVALID_HANDLE;
1030 }
1031 /*
1032 * On Windows 10 and (hopefully) 8.1 we get ERROR_INVALID_FUNCTION with console I/O
1033 * handles. We must ignore these just like the above invalid handle error.
1034 */
1035 else if (dwErr != ERROR_INVALID_FUNCTION)
1036 return RTErrConvertFromWin32(dwErr);
1037
1038 RT_ZERO(Data);
1039 Data.dwFileAttributes = RTFS_DOS_NT_DEVICE;
1040 }
1041
1042 /*
1043 * Setup the returned data.
1044 */
1045 pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32)
1046 | (uint64_t)Data.nFileSizeLow;
1047 pObjInfo->cbAllocated = pObjInfo->cbObject;
1048
1049 Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime));
1050 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime);
1051 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime);
1052 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime);
1053 pObjInfo->ChangeTime = pObjInfo->ModificationTime;
1054
1055 pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, "", 0,
1056 RTFSMODE_SYMLINK_REPARSE_TAG /* (symlink or not, doesn't usually matter here) */);
1057
1058 /*
1059 * Requested attributes (we cannot provide anything actually).
1060 */
1061 switch (enmAdditionalAttribs)
1062 {
1063 case RTFSOBJATTRADD_NOTHING:
1064 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
1065 break;
1066
1067 case RTFSOBJATTRADD_UNIX:
1068 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
1069 pObjInfo->Attr.u.Unix.uid = ~0U;
1070 pObjInfo->Attr.u.Unix.gid = ~0U;
1071 pObjInfo->Attr.u.Unix.cHardlinks = Data.nNumberOfLinks ? Data.nNumberOfLinks : 1;
1072 pObjInfo->Attr.u.Unix.INodeIdDevice = Data.dwVolumeSerialNumber;
1073 pObjInfo->Attr.u.Unix.INodeId = RT_MAKE_U64(Data.nFileIndexLow, Data.nFileIndexHigh);
1074 pObjInfo->Attr.u.Unix.fFlags = 0;
1075 pObjInfo->Attr.u.Unix.GenerationId = 0;
1076 pObjInfo->Attr.u.Unix.Device = 0;
1077 break;
1078
1079 case RTFSOBJATTRADD_UNIX_OWNER:
1080 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
1081 pObjInfo->Attr.u.UnixOwner.uid = ~0U;
1082 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
1083 break;
1084
1085 case RTFSOBJATTRADD_UNIX_GROUP:
1086 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
1087 pObjInfo->Attr.u.UnixGroup.gid = ~0U;
1088 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
1089 break;
1090
1091 case RTFSOBJATTRADD_EASIZE:
1092 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
1093 pObjInfo->Attr.u.EASize.cb = 0;
1094 break;
1095
1096 default:
1097 AssertMsgFailed(("Impossible!\n"));
1098 return VERR_INTERNAL_ERROR;
1099 }
1100
1101 return VINF_SUCCESS;
1102#endif
1103}
1104
1105
1106RTR3DECL(int) RTFileSetTimes(RTFILE hFile, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1107 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1108{
1109 RT_NOREF_PV(pChangeTime); /* Not exposed thru the windows API we're using. */
1110
1111 if (!pAccessTime && !pModificationTime && !pBirthTime)
1112 return VINF_SUCCESS; /* NOP */
1113
1114 FILETIME CreationTimeFT;
1115 PFILETIME pCreationTimeFT = NULL;
1116 if (pBirthTime)
1117 pCreationTimeFT = RTTimeSpecGetNtFileTime(pBirthTime, &CreationTimeFT);
1118
1119 FILETIME LastAccessTimeFT;
1120 PFILETIME pLastAccessTimeFT = NULL;
1121 if (pAccessTime)
1122 pLastAccessTimeFT = RTTimeSpecGetNtFileTime(pAccessTime, &LastAccessTimeFT);
1123
1124 FILETIME LastWriteTimeFT;
1125 PFILETIME pLastWriteTimeFT = NULL;
1126 if (pModificationTime)
1127 pLastWriteTimeFT = RTTimeSpecGetNtFileTime(pModificationTime, &LastWriteTimeFT);
1128
1129 int rc = VINF_SUCCESS;
1130 if (!SetFileTime((HANDLE)RTFileToNative(hFile), pCreationTimeFT, pLastAccessTimeFT, pLastWriteTimeFT))
1131 {
1132 DWORD Err = GetLastError();
1133 rc = RTErrConvertFromWin32(Err);
1134 Log(("RTFileSetTimes(%RTfile, %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Rrc)\n",
1135 hFile, pAccessTime, pModificationTime, pChangeTime, pBirthTime, Err, rc));
1136 }
1137 return rc;
1138}
1139
1140
1141#if 0 /* RTFileSetMode is implemented by RTFileSetMode-r3-nt.cpp */
1142/* This comes from a source file with a different set of system headers (DDK)
1143 * so it can't be declared in a common header, like internal/file.h.
1144 */
1145extern int rtFileNativeSetAttributes(HANDLE FileHandle, ULONG FileAttributes);
1146
1147
1148RTR3DECL(int) RTFileSetMode(RTFILE hFile, RTFMODE fMode)
1149{
1150 /*
1151 * Normalize the mode and call the API.
1152 */
1153 fMode = rtFsModeNormalize(fMode, NULL, 0);
1154 if (!rtFsModeIsValid(fMode))
1155 return VERR_INVALID_PARAMETER;
1156
1157 ULONG FileAttributes = (fMode & RTFS_DOS_MASK) >> RTFS_DOS_SHIFT;
1158 int Err = rtFileNativeSetAttributes((HANDLE)hFile, FileAttributes);
1159 if (Err != ERROR_SUCCESS)
1160 {
1161 int rc = RTErrConvertFromWin32(Err);
1162 Log(("RTFileSetMode(%RTfile, %RTfmode): rtFileNativeSetAttributes (0x%08X) failed with err %d (%Rrc)\n",
1163 hFile, fMode, FileAttributes, Err, rc));
1164 return rc;
1165 }
1166 return VINF_SUCCESS;
1167}
1168#endif
1169
1170
1171/* RTFileQueryFsSizes is implemented by ../nt/RTFileQueryFsSizes-nt.cpp */
1172
1173
1174RTR3DECL(int) RTFileDelete(const char *pszFilename)
1175{
1176 PRTUTF16 pwszFilename;
1177 int rc = RTPathWinFromUtf8(&pwszFilename, pszFilename, 0 /*fFlags*/);
1178 if (RT_SUCCESS(rc))
1179 {
1180 if (!DeleteFileW(pwszFilename))
1181 rc = RTErrConvertFromWin32(GetLastError());
1182 RTPathWinFree(pwszFilename);
1183 }
1184
1185 return rc;
1186}
1187
1188
1189RTDECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
1190{
1191 /*
1192 * Validate input.
1193 */
1194 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
1195 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
1196 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
1197
1198 /*
1199 * Hand it on to the worker.
1200 */
1201 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
1202 fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0,
1203 RTFS_TYPE_FILE);
1204
1205 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
1206 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
1207 return rc;
1208
1209}
1210
1211
1212RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove)
1213{
1214 /*
1215 * Validate input.
1216 */
1217 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
1218 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
1219 AssertMsgReturn(!(fMove & ~RTFILEMOVE_FLAGS_REPLACE), ("%#x\n", fMove), VERR_INVALID_PARAMETER);
1220
1221 /*
1222 * Hand it on to the worker.
1223 */
1224 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
1225 fMove & RTFILEMOVE_FLAGS_REPLACE
1226 ? MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING
1227 : MOVEFILE_COPY_ALLOWED,
1228 RTFS_TYPE_FILE);
1229
1230 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
1231 pszSrc, pszSrc, pszDst, pszDst, fMove, rc));
1232 return rc;
1233}
1234
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