VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win32/fileio-win32.cpp@ 1532

Last change on this file since 1532 was 1532, checked in by vboxsync, 18 years ago

Handle EFBIG on Linux correctly (and try to detect the same situation on
Windows). Provide separate runtime error message, because disk full
doesn't describe the problem (file size limit exceeded). Happens mostly
if people store VDIs on FAT32 partitions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.4 KB
Line 
1/* $Id: fileio-win32.cpp 1532 2007-03-16 14:54:40Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - File I/O, native implementation for the Windows host platform.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP RTLOGGROUP_DIR
27#include <Windows.h>
28
29#include <iprt/file.h>
30#include <iprt/path.h>
31#include <iprt/assert.h>
32#include <iprt/string.h>
33#include <iprt/err.h>
34#include <iprt/log.h>
35#include "internal/file.h"
36#include "internal/fs.h"
37#include "internal/path.h"
38
39
40/*******************************************************************************
41* Defined Constants And Macros *
42*******************************************************************************/
43/** @def RT_DONT_CONVERT_FILENAMES
44 * Define this to pass UTF-8 unconverted to the kernel. */
45#ifdef __DOXYGEN__
46# define RT_DONT_CONVERT_FILENAMES 1
47#endif
48
49
50/**
51 * This is wrapper around the ugly SetFilePointer api.
52 *
53 * It's equivalent to SetFilePointerEx which we so unfortunately cannot use because of
54 * it not being present in NT4 GA.
55 *
56 * @returns Success indicator. Extended error information obtainable using GetLastError().
57 * @param File Filehandle.
58 * @param offSeek Offset to seek.
59 * @param poffNew Where to store the new file offset. NULL allowed.
60 * @param uMethod Seek method. (The windows one!)
61 */
62inline bool MySetFilePointer(RTFILE File, uint64_t offSeek, uint64_t *poffNew, unsigned uMethod)
63{
64 LARGE_INTEGER off;
65 off.QuadPart = offSeek;
66#if 1
67 off.LowPart = SetFilePointer((HANDLE)File, off.LowPart, &off.HighPart, uMethod);
68 bool fRc = off.LowPart != INVALID_SET_FILE_POINTER;
69#else
70 bool fRc = SetFilePointerEx((HANDLE)File, off, &off, uMethod);
71#endif
72 if (fRc && poffNew)
73 *poffNew = off.QuadPart;
74 return fRc;
75}
76
77
78/**
79 * This is a helper to check if an attempt is made to grow a file beyond the
80 * limit of the filesystem.
81 *
82 * @returns true for file size limit exceeded.
83 * @param File Filehandle.
84 * @param offSeek Offset to seek.
85 */
86inline bool IsBeyondLimit(RTFILE File, uint64_t offSeek, unsigned uMethod)
87{
88 bool fIsBeyondLimit = false;
89 /*
90 * Get current file pointer.
91 */
92 uint64_t offCurrent;
93 if (MySetFilePointer(File, 0, &offCurrent, FILE_CURRENT))
94 {
95 /*
96 * Set new file pointer.
97 */
98 if (!MySetFilePointer(File, offSeek, NULL, uMethod))
99 {
100 /*
101 * Failed to set new file pointer.
102 */
103 fIsBeyondLimit = (GetLastError() == ERROR_SEEK);
104 }
105 else
106 {
107 /*
108 * Restore file pointer.
109 */
110 MySetFilePointer(File, offCurrent, NULL, FILE_BEGIN);
111 }
112 }
113
114 return fIsBeyondLimit;
115}
116
117
118
119
120RTR3DECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, unsigned fOpen)
121{
122 /*
123 * Validate input.
124 */
125 if (!pFile)
126 {
127 AssertMsgFailed(("Invalid pFile\n"));
128 return VERR_INVALID_PARAMETER;
129 }
130 *pFile = NIL_RTFILE;
131 if (!pszFilename)
132 {
133 AssertMsgFailed(("Invalid pszFilename\n"));
134 return VERR_INVALID_PARAMETER;
135 }
136
137 /*
138 * Merge forced open flags and validate them.
139 */
140 int rc = rtFileRecalcAndValidateFlags(&fOpen);
141 if (RT_FAILURE(rc))
142 return rc;
143
144 /*
145 * Determine disposition, access, share mode, creation flags, and security attributes
146 * for the CreateFile API call.
147 */
148 DWORD dwCreationDisposition;
149 switch (fOpen & RTFILE_O_ACTION_MASK)
150 {
151 case RTFILE_O_OPEN:
152 dwCreationDisposition = fOpen & RTFILE_O_TRUNCATE ? TRUNCATE_EXISTING : OPEN_EXISTING;
153 break;
154 case RTFILE_O_OPEN_CREATE:
155 dwCreationDisposition = OPEN_ALWAYS;
156 break;
157 case RTFILE_O_CREATE:
158 dwCreationDisposition = CREATE_NEW;
159 break;
160 case RTFILE_O_CREATE_REPLACE:
161 dwCreationDisposition = CREATE_ALWAYS;
162 break;
163 default:
164 AssertMsgFailed(("Impossible fOpen=%#x\n", fOpen));
165 return VERR_INVALID_PARAMETER;
166 }
167
168 DWORD dwDesiredAccess;
169 switch (fOpen & RTFILE_O_ACCESS_MASK)
170 {
171 case RTFILE_O_READ: dwDesiredAccess = GENERIC_READ; break;
172 case RTFILE_O_WRITE: dwDesiredAccess = GENERIC_WRITE; break;
173 case RTFILE_O_READWRITE: dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; break;
174 default:
175 AssertMsgFailed(("Impossible fOpen=%#x\n", fOpen));
176 return VERR_INVALID_PARAMETER;
177 }
178
179 DWORD dwShareMode;
180 Assert(RTFILE_O_DENY_READWRITE == RTFILE_O_DENY_ALL && !RTFILE_O_DENY_NONE);
181 switch (fOpen & RTFILE_O_DENY_MASK)
182 {
183 case RTFILE_O_DENY_NONE: dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
184 case RTFILE_O_DENY_READ: dwShareMode = FILE_SHARE_WRITE; break;
185 case RTFILE_O_DENY_WRITE: dwShareMode = FILE_SHARE_READ; break;
186 case RTFILE_O_DENY_READWRITE: dwShareMode = 0; break;
187
188 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_NONE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; break;
189 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_WRITE; break;
190 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ; break;
191 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READWRITE:dwShareMode = FILE_SHARE_DELETE; break;
192 default:
193 AssertMsgFailed(("Impossible fOpen=%#x\n", fOpen));
194 return VERR_INVALID_PARAMETER;
195 }
196
197 SECURITY_ATTRIBUTES SecurityAttributes;
198 PSECURITY_ATTRIBUTES pSecurityAttributes = NULL;
199 if (fOpen & RTFILE_O_INHERIT)
200 {
201 SecurityAttributes.nLength = sizeof(SecurityAttributes);
202 SecurityAttributes.lpSecurityDescriptor = NULL;
203 SecurityAttributes.bInheritHandle = TRUE;
204 pSecurityAttributes = &SecurityAttributes;
205 }
206
207 DWORD dwFlagsAndAttributes;
208 dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
209 if (fOpen & RTFILE_O_WRITE_THROUGH)
210 dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
211
212 /*
213 * Open/Create the file.
214 */
215#ifdef RT_DONT_CONVERT_FILENAMES
216 HANDLE hFile = CreateFile(pszFilename,
217 dwDesiredAccess,
218 dwShareMode,
219 pSecurityAttributes,
220 dwCreationDisposition,
221 dwFlagsAndAttributes,
222 NULL);
223 if (hFile == INVALID_HANDLE_VALUE)
224 return RTErrConvertFromWin32(GetLastError());
225
226#else
227 PRTUCS2 pwszFilename;
228 rc = RTStrToUtf16(pszFilename, &pwszFilename);
229 if (RT_FAILURE(rc))
230 return rc;
231
232 HANDLE hFile = CreateFileW(pwszFilename,
233 dwDesiredAccess,
234 dwShareMode,
235 pSecurityAttributes,
236 dwCreationDisposition,
237 dwFlagsAndAttributes,
238 NULL);
239 if (hFile == INVALID_HANDLE_VALUE)
240 {
241 rc = RTErrConvertFromWin32(GetLastError()); /* get error first! */
242 RTUtf16Free(pwszFilename);
243 return rc;
244 }
245 RTUtf16Free(pwszFilename);
246#endif
247
248 /*
249 * Do we need to truncate the file?
250 */
251 if ( (fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_ACTION_MASK))
252 == (RTFILE_O_TRUNCATE | RTFILE_O_OPEN_CREATE))
253 {
254 if (!SetEndOfFile(hFile))
255 {
256 rc = RTErrConvertFromWin32(GetLastError()); /* get error first! */
257 CloseHandle(hFile);
258 return rc;
259 }
260 }
261
262 *pFile = (RTFILE)hFile;
263 Assert((HANDLE)*pFile == hFile);
264 return VINF_SUCCESS;
265}
266
267
268RTR3DECL(int) RTFileClose(RTFILE File)
269{
270 if (CloseHandle((HANDLE)File))
271 return VINF_SUCCESS;
272 return RTErrConvertFromWin32(GetLastError());
273}
274
275
276RTR3DECL(int) RTFileSeek(RTFILE File, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
277{
278 static ULONG aulSeekRecode[] =
279 {
280 FILE_BEGIN,
281 FILE_CURRENT,
282 FILE_END,
283 };
284
285 /*
286 * Validate input.
287 */
288 if (uMethod > RTFILE_SEEK_END)
289 {
290 AssertMsgFailed(("Invalid uMethod=%d\n", uMethod));
291 return VERR_INVALID_PARAMETER;
292 }
293
294 /*
295 * Execute the seek.
296 */
297 if (MySetFilePointer(File, offSeek, poffActual, aulSeekRecode[uMethod]))
298 return VINF_SUCCESS;
299 return RTErrConvertFromWin32(GetLastError());
300}
301
302
303RTR3DECL(int) RTFileRead(RTFILE File, void *pvBuf, unsigned cbToRead, unsigned *pcbRead)
304{
305 if (cbToRead <= 0)
306 return VINF_SUCCESS;
307
308 ULONG cbRead = 0;
309 if (ReadFile((HANDLE)File, pvBuf, cbToRead, &cbRead, NULL))
310 {
311 if (pcbRead)
312 /* Caller can handle partial reads. */
313 *pcbRead = cbRead;
314 else
315 {
316 /* Caller expects everything to be read. */
317 while (cbToRead > cbRead)
318 {
319 ULONG cbReadPart = 0;
320 if (!ReadFile((HANDLE)File, (char*)pvBuf + cbRead, cbToRead - cbRead, &cbReadPart, NULL))
321 return RTErrConvertFromWin32(GetLastError());
322 if (cbReadPart == 0)
323 return VERR_EOF;
324 cbRead += cbReadPart;
325 }
326 }
327 return VINF_SUCCESS;
328 }
329 return RTErrConvertFromWin32(GetLastError());
330}
331
332
333RTR3DECL(int) RTFileWrite(RTFILE File, const void *pvBuf, unsigned cbToWrite, unsigned *pcbWritten)
334{
335 if (cbToWrite <= 0)
336 return VINF_SUCCESS;
337
338 ULONG cbWritten = 0;
339 if (WriteFile((HANDLE)File, pvBuf, cbToWrite, &cbWritten, NULL))
340 {
341 if (pcbWritten)
342 /* Caller can handle partial writes. */
343 *pcbWritten = cbWritten;
344 else
345 {
346 /* Caller expects everything to be written. */
347 while (cbToWrite > cbWritten)
348 {
349 ULONG cbWrittenPart = 0;
350 if (!WriteFile((HANDLE)File, (char*)pvBuf + cbWritten, cbToWrite - cbWritten, &cbWrittenPart, NULL))
351 {
352 int rc = RTErrConvertFromWin32(GetLastError());
353 if ( rc == VERR_DISK_FULL
354 && IsBeyondLimit(File, cbToWrite - cbWritten, FILE_CURRENT)
355 )
356 rc = VERR_FILE_TOO_BIG;
357 return rc;
358 }
359 if (cbWrittenPart == 0)
360 return VERR_WRITE_ERROR;
361 cbWritten += cbWrittenPart;
362 }
363 }
364 return VINF_SUCCESS;
365 }
366 int rc = RTErrConvertFromWin32(GetLastError());
367 if ( rc == VERR_DISK_FULL
368 && IsBeyondLimit(File, cbToWrite - cbWritten, FILE_CURRENT)
369 )
370 rc = VERR_FILE_TOO_BIG;
371 return rc;
372}
373
374
375RTR3DECL(int) RTFileFlush(RTFILE File)
376{
377 int rc;
378
379 if (FlushFileBuffers((HANDLE)File) == FALSE)
380 {
381 rc = GetLastError();
382 Log(("FlushFileBuffers failed with %d\n", rc));
383 return RTErrConvertFromWin32(rc);
384 }
385 return VINF_SUCCESS;
386}
387
388
389RTR3DECL(int) RTFileSetSize(RTFILE File, uint64_t cbSize)
390{
391 /*
392 * Get current file pointer.
393 */
394 int rc;
395 uint64_t offCurrent;
396 if (MySetFilePointer(File, 0, &offCurrent, FILE_CURRENT))
397 {
398 /*
399 * Set new file pointer.
400 */
401 if (MySetFilePointer(File, cbSize, NULL, FILE_BEGIN))
402 {
403 /* file pointer setted */
404 if (SetEndOfFile((HANDLE)File))
405 {
406 /*
407 * Restore file pointer and return.
408 * If the old pointer was beyond the new file end, ignore failure.
409 */
410 if ( MySetFilePointer(File, offCurrent, NULL, FILE_BEGIN)
411 || offCurrent > cbSize)
412 return VINF_SUCCESS;
413 }
414
415 /*
416 * Failed, try restore file pointer.
417 */
418 rc = GetLastError();
419 MySetFilePointer(File, offCurrent, NULL, FILE_BEGIN);
420 }
421 else
422 rc = GetLastError();
423 }
424 else
425 rc = GetLastError();
426
427 return RTErrConvertFromWin32(rc);
428}
429
430
431RTR3DECL(int) RTFileGetSize(RTFILE File, uint64_t *pcbSize)
432{
433 ULARGE_INTEGER Size;
434 Size.LowPart = GetFileSize((HANDLE)File, &Size.HighPart);
435 if (Size.LowPart != INVALID_FILE_SIZE)
436 {
437 *pcbSize = Size.QuadPart;
438 return VINF_SUCCESS;
439 }
440
441 /* error exit */
442 return RTErrConvertFromWin32(GetLastError());
443}
444
445
446RTR3DECL(bool) RTFileIsValid(RTFILE File)
447{
448 if (File != NIL_RTFILE)
449 {
450 DWORD dwType = GetFileType((HANDLE)File);
451 switch (dwType)
452 {
453 case FILE_TYPE_CHAR:
454 case FILE_TYPE_DISK:
455 case FILE_TYPE_PIPE:
456 case FILE_TYPE_REMOTE:
457 return true;
458
459 case FILE_TYPE_UNKNOWN:
460 if (GetLastError() == NO_ERROR)
461 return true;
462 break;
463 }
464 }
465 return false;
466}
467
468
469#define LOW_DWORD(u64) ((DWORD)u64)
470#define HIGH_DWORD(u64) (((DWORD *)&u64)[1])
471
472RTR3DECL(int) RTFileLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock)
473{
474 Assert(offLock >= 0);
475
476 /* Check arguments. */
477 if (fLock & ~RTFILE_LOCK_MASK)
478 {
479 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
480 return VERR_INVALID_PARAMETER;
481 }
482
483 /* Prepare flags. */
484 Assert(RTFILE_LOCK_WRITE);
485 DWORD dwFlags = (fLock & RTFILE_LOCK_WRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0;
486 Assert(RTFILE_LOCK_WAIT);
487 if (!(fLock & RTFILE_LOCK_WAIT))
488 dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
489
490 /* Windows structure. */
491 OVERLAPPED Overlapped;
492 memset(&Overlapped, 0, sizeof(Overlapped));
493 Overlapped.Offset = LOW_DWORD(offLock);
494 Overlapped.OffsetHigh = HIGH_DWORD(offLock);
495
496 /* Note: according to Microsoft, LockFileEx API call is available starting from NT 3.5 */
497 if (LockFileEx((HANDLE)File, dwFlags, 0, LOW_DWORD(cbLock), HIGH_DWORD(cbLock), &Overlapped))
498 return VINF_SUCCESS;
499
500 return RTErrConvertFromWin32(GetLastError());
501}
502
503
504RTR3DECL(int) RTFileChangeLock(RTFILE File, unsigned fLock, int64_t offLock, uint64_t cbLock)
505{
506 Assert(offLock >= 0);
507
508 /* Check arguments. */
509 if (fLock & ~RTFILE_LOCK_MASK)
510 {
511 AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
512 return VERR_INVALID_PARAMETER;
513 }
514
515 /* Remove old lock. */
516 int rc = RTFileUnlock(File, offLock, cbLock);
517 if (RT_FAILURE(rc))
518 return rc;
519
520 /* Set new lock. */
521 rc = RTFileLock(File, fLock, offLock, cbLock);
522 if (RT_SUCCESS(rc))
523 return rc;
524
525 /* Try to restore old lock. */
526 unsigned fLockOld = (fLock & RTFILE_LOCK_WRITE) ? fLock & ~RTFILE_LOCK_WRITE : fLock | RTFILE_LOCK_WRITE;
527 rc = RTFileLock(File, fLockOld, offLock, cbLock);
528 if (RT_SUCCESS(rc))
529 return VERR_FILE_LOCK_VIOLATION;
530 else
531 return VERR_FILE_LOCK_LOST;
532}
533
534
535RTR3DECL(int) RTFileUnlock(RTFILE File, int64_t offLock, uint64_t cbLock)
536{
537 Assert(offLock >= 0);
538
539 if (UnlockFile((HANDLE)File, LOW_DWORD(offLock), HIGH_DWORD(offLock), LOW_DWORD(cbLock), HIGH_DWORD(cbLock)))
540 return VINF_SUCCESS;
541
542 return RTErrConvertFromWin32(GetLastError());
543}
544
545
546
547RTR3DECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
548{
549 /*
550 * Validate input.
551 */
552 if (File == NIL_RTFILE)
553 {
554 AssertMsgFailed(("Invalid File=%RTfile\n", File));
555 return VERR_INVALID_PARAMETER;
556 }
557 if (!pObjInfo)
558 {
559 AssertMsgFailed(("Invalid pObjInfo=%p\n", pObjInfo));
560 return VERR_INVALID_PARAMETER;
561 }
562 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
563 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
564 {
565 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
566 return VERR_INVALID_PARAMETER;
567 }
568
569 /*
570 * Query file info.
571 */
572 BY_HANDLE_FILE_INFORMATION Data;
573 if (!GetFileInformationByHandle((HANDLE)File, &Data))
574 return RTErrConvertFromWin32(GetLastError());
575
576 /*
577 * Setup the returned data.
578 */
579 pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32)
580 | (uint64_t)Data.nFileSizeLow;
581 pObjInfo->cbAllocated = pObjInfo->cbObject;
582
583 Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime));
584 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime);
585 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime);
586 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime);
587 pObjInfo->ChangeTime = pObjInfo->ModificationTime;
588
589 pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, "", 0);
590
591 /*
592 * Requested attributes (we cannot provide anything actually).
593 */
594 switch (enmAdditionalAttribs)
595 {
596 case RTFSOBJATTRADD_EASIZE:
597 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
598 pObjInfo->Attr.u.EASize.cb = 0;
599 break;
600
601 case RTFSOBJATTRADD_UNIX:
602 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
603 pObjInfo->Attr.u.Unix.uid = ~0U;
604 pObjInfo->Attr.u.Unix.gid = ~0U;
605 pObjInfo->Attr.u.Unix.cHardlinks = Data.nNumberOfLinks ? Data.nNumberOfLinks : 1;
606 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
607 pObjInfo->Attr.u.Unix.INodeId = 0;
608 pObjInfo->Attr.u.Unix.fFlags = 0;
609 pObjInfo->Attr.u.Unix.GenerationId = 0;
610 pObjInfo->Attr.u.Unix.Device = 0;
611 break;
612
613 case RTFSOBJATTRADD_NOTHING:
614 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
615 break;
616
617 default:
618 AssertMsgFailed(("Impossible!\n"));
619 return VERR_INTERNAL_ERROR;
620 }
621
622 return VINF_SUCCESS;
623}
624
625
626RTR3DECL(int) RTFileSetTimes(RTFILE File, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
627 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
628{
629 if (!pAccessTime && !pModificationTime && !pBirthTime)
630 return VINF_SUCCESS; /* NOP */
631
632 FILETIME CreationTimeFT;
633 PFILETIME pCreationTimeFT = NULL;
634 if (pBirthTime)
635 pCreationTimeFT = RTTimeSpecGetNtFileTime(pBirthTime, &CreationTimeFT);
636
637 FILETIME LastAccessTimeFT;
638 PFILETIME pLastAccessTimeFT = NULL;
639 if (pAccessTime)
640 pLastAccessTimeFT = RTTimeSpecGetNtFileTime(pAccessTime, &LastAccessTimeFT);
641
642 FILETIME LastWriteTimeFT;
643 PFILETIME pLastWriteTimeFT = NULL;
644 if (pModificationTime)
645 pLastWriteTimeFT = RTTimeSpecGetNtFileTime(pModificationTime, &LastWriteTimeFT);
646
647 int rc = VINF_SUCCESS;
648 if (!SetFileTime((HANDLE)File, pCreationTimeFT, pLastAccessTimeFT, pLastWriteTimeFT))
649 {
650 DWORD Err = GetLastError();
651 rc = RTErrConvertFromWin32(Err);
652 Log(("RTFileSetTimes(%RTfile, %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Vrc)\n",
653 File, pAccessTime, pModificationTime, pChangeTime, pBirthTime, Err, rc));
654 }
655 return rc;
656}
657
658
659RTR3DECL(int) RTFileSetMode(RTFILE File, RTFMODE fMode)
660{
661 /** @todo darn. this needs a full path; probably must be done if the file is closed
662 * It's quite possible that there is an NT API for this. NtSetInformationFile() for instance. */
663 return VINF_SUCCESS;
664}
665
666
667RTR3DECL(int) RTFileDelete(const char *pszFilename)
668{
669#ifdef RT_DONT_CONVERT_FILENAMES
670 if (DeleteFile(pszFilename))
671 return VINF_SUCCESS;
672 return RTErrConvertFromWin32(GetLastError());
673
674#else
675 PRTUTF16 pwszFilename;
676 int rc = RTStrToUtf16(pszFilename, &pwszFilename);
677 if (RT_SUCCESS(rc))
678 {
679 if (!DeleteFileW(pwszFilename))
680 rc = RTErrConvertFromWin32(GetLastError());
681 RTUtf16Free(pwszFilename);
682 }
683
684 return rc;
685#endif
686}
687
688
689RTDECL(int) RTFileRename(const char *pszSrc, const char *pszDst, unsigned fRename)
690{
691 /*
692 * Validate input.
693 */
694 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
695 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
696 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
697
698 /*
699 * Hand it on to the worker.
700 */
701 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
702 fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0,
703 RTFS_TYPE_FILE);
704
705 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
706 pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
707 return rc;
708
709}
710
711
712RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove)
713{
714 /*
715 * Validate input.
716 */
717 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
718 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
719 AssertMsgReturn(!(fMove & ~RTFILEMOVE_FLAGS_REPLACE), ("%#x\n", fMove), VERR_INVALID_PARAMETER);
720
721 /*
722 * Hand it on to the worker.
723 */
724 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
725 fMove & RTFILEMOVE_FLAGS_REPLACE
726 ? MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING
727 : MOVEFILE_COPY_ALLOWED,
728 RTFS_TYPE_FILE);
729
730 LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
731 pszSrc, pszSrc, pszDst, pszDst, fMove, rc));
732 return rc;
733}
734
Note: See TracBrowser for help on using the repository browser.

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