VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/fileio.cpp@ 46248

Last change on this file since 46248 was 46248, checked in by vboxsync, 12 years ago

build fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.1 KB
Line 
1/* $Id: fileio.cpp 46248 2013-05-23 19:20:58Z vboxsync $ */
2/** @file
3 * IPRT - File I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include <iprt/file.h>
31#include <iprt/alloc.h>
32#include <iprt/assert.h>
33#include <iprt/alloca.h>
34#include <iprt/err.h>
35#include "internal/file.h"
36
37
38/*******************************************************************************
39* Global Variables *
40*******************************************************************************/
41/** Set of forced set open flags for files opened read-only. */
42static unsigned g_fOpenReadSet = 0;
43
44/** Set of forced cleared open flags for files opened read-only. */
45static unsigned g_fOpenReadMask = 0;
46
47/** Set of forced set open flags for files opened write-only. */
48static unsigned g_fOpenWriteSet = 0;
49
50/** Set of forced cleared open flags for files opened write-only. */
51static unsigned g_fOpenWriteMask = 0;
52
53/** Set of forced set open flags for files opened read-write. */
54static unsigned g_fOpenReadWriteSet = 0;
55
56/** Set of forced cleared open flags for files opened read-write. */
57static unsigned g_fOpenReadWriteMask = 0;
58
59
60/**
61 * Force the use of open flags for all files opened after the setting is
62 * changed. The caller is responsible for not causing races with RTFileOpen().
63 *
64 * @returns iprt status code.
65 * @param fOpenForAccess Access mode to which the set/mask settings apply.
66 * @param fSet Open flags to be forced set.
67 * @param fMask Open flags to be masked out.
68 */
69RTR3DECL(int) RTFileSetForceFlags(unsigned fOpenForAccess, unsigned fSet, unsigned fMask)
70{
71 /*
72 * For now allow only RTFILE_O_WRITE_THROUGH. The other flags either
73 * make no sense in this context or are not useful to apply to all files.
74 */
75 if ((fSet | fMask) & ~RTFILE_O_WRITE_THROUGH)
76 return VERR_INVALID_PARAMETER;
77 switch (fOpenForAccess)
78 {
79 case RTFILE_O_READ:
80 g_fOpenReadSet = fSet;
81 g_fOpenReadMask = fMask;
82 break;
83 case RTFILE_O_WRITE:
84 g_fOpenWriteSet = fSet;
85 g_fOpenWriteMask = fMask;
86 break;
87 case RTFILE_O_READWRITE:
88 g_fOpenReadWriteSet = fSet;
89 g_fOpenReadWriteMask = fMask;
90 break;
91 default:
92 AssertMsgFailed(("Invalid access mode %d\n", fOpenForAccess));
93 return VERR_INVALID_PARAMETER;
94 }
95 return VINF_SUCCESS;
96}
97
98
99/**
100 * Adjusts and validates the flags.
101 *
102 * The adjustments are made according to the wishes specified using the RTFileSetForceFlags API.
103 *
104 * @returns IPRT status code.
105 * @param pfOpen Pointer to the user specified flags on input.
106 * Updated on successful return.
107 * @internal
108 */
109int rtFileRecalcAndValidateFlags(uint64_t *pfOpen)
110{
111 /*
112 * Recalc.
113 */
114 uint32_t fOpen = *pfOpen;
115 switch (fOpen & RTFILE_O_ACCESS_MASK)
116 {
117 case RTFILE_O_READ:
118 fOpen |= g_fOpenReadSet;
119 fOpen &= ~g_fOpenReadMask;
120 break;
121 case RTFILE_O_WRITE:
122 fOpen |= g_fOpenWriteSet;
123 fOpen &= ~g_fOpenWriteMask;
124 break;
125 case RTFILE_O_READWRITE:
126 fOpen |= g_fOpenReadWriteSet;
127 fOpen &= ~g_fOpenReadWriteMask;
128 break;
129 default:
130 AssertMsgFailed(("Invalid RW value, fOpen=%#llx\n", fOpen));
131 return VERR_INVALID_PARAMETER;
132 }
133
134 /*
135 * Validate .
136 */
137 AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
138#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
139 AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
140#else
141 AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
142#endif
143 AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
144
145 switch (fOpen & RTFILE_O_ACTION_MASK)
146 {
147 case 0: /* temporarily */
148 AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n"));
149 fOpen |= RTFILE_O_OPEN;
150 break;
151 case RTFILE_O_OPEN:
152 AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
153 case RTFILE_O_OPEN_CREATE:
154 case RTFILE_O_CREATE:
155 case RTFILE_O_CREATE_REPLACE:
156 break;
157 default:
158 AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen));
159 return VERR_INVALID_PARAMETER;
160 }
161
162 switch (fOpen & RTFILE_O_DENY_MASK)
163 {
164 case 0: /* temporarily */
165 AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n"));
166 fOpen |= RTFILE_O_DENY_NONE;
167 break;
168 case RTFILE_O_DENY_NONE:
169 case RTFILE_O_DENY_READ:
170 case RTFILE_O_DENY_WRITE:
171 case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
172 case RTFILE_O_DENY_NOT_DELETE:
173 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ:
174 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE:
175 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
176 break;
177 default:
178 AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen));
179 return VERR_INVALID_PARAMETER;
180 }
181
182 /* done */
183 *pfOpen = fOpen;
184 return VINF_SUCCESS;
185}
186
187
188
189/**
190 * Read bytes from a file at a given offset.
191 * This function may modify the file position.
192 *
193 * @returns iprt status code.
194 * @param File Handle to the file.
195 * @param off Where to read.
196 * @param pvBuf Where to put the bytes we read.
197 * @param cbToRead How much to read.
198 * @param *pcbRead How much we actually read.
199 * If NULL an error will be returned for a partial read.
200 */
201RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
202{
203 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
204 if (RT_SUCCESS(rc))
205 rc = RTFileRead(File, pvBuf, cbToRead, pcbRead);
206 return rc;
207}
208
209
210/**
211 * Read bytes from a file at a given offset into a S/G buffer.
212 * This function may modify the file position.
213 *
214 * @returns iprt status code.
215 * @param hFile Handle to the file.
216 * @param off Where to read.
217 * @param pSgBuf Pointer to the S/G buffer to read into.
218 * @param cbToRead How much to read.
219 * @param pcbRead How much we actually read.
220 * If NULL an error will be returned for a partial read.
221 */
222RTR3DECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
223{
224 int rc = VINF_SUCCESS;
225 size_t cbRead = 0;
226
227 while (cbToRead)
228 {
229 size_t cbThisRead = 0;
230 size_t cbBuf = cbToRead;
231 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
232
233 rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);
234 if (RT_SUCCESS(rc))
235 cbRead += cbThisRead;
236
237 if ( RT_FAILURE(rc)
238 || cbThisRead < cbBuf)
239 break;
240
241 cbToRead -= cbBuf;
242 off += cbBuf;
243 }
244
245 if (pcbRead)
246 *pcbRead = cbRead;
247
248 return rc;
249}
250
251
252/**
253 * Write bytes to a file at a given offset.
254 * This function may modify the file position.
255 *
256 * @returns iprt status code.
257 * @param File Handle to the file.
258 * @param off Where to write.
259 * @param pvBuf What to write.
260 * @param cbToWrite How much to write.
261 * @param *pcbWritten How much we actually wrote.
262 * If NULL an error will be returned for a partial write.
263 */
264RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
265{
266 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
267 if (RT_SUCCESS(rc))
268 rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten);
269 return rc;
270}
271
272
273/**
274 * Write bytes from a S/G buffer to a file at a given offset.
275 * This function may modify the file position.
276 *
277 * @returns iprt status code.
278 * @param hFile Handle to the file.
279 * @param off Where to write.
280 * @param pSgBuf What to write.
281 * @param cbToWrite How much to write.
282 * @param pcbWritten How much we actually wrote.
283 * If NULL an error will be returned for a partial write.
284 */
285RTR3DECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
286{
287 int rc = VINF_SUCCESS;
288 size_t cbWritten = 0;
289
290 while (cbToWrite)
291 {
292 size_t cbThisWritten = 0;
293 size_t cbBuf = cbToWrite;
294 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
295
296 rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);
297 if (RT_SUCCESS(rc))
298 cbWritten += cbThisWritten;
299
300 if ( RT_FAILURE(rc)
301 || cbThisWritten < cbBuf)
302 break;
303
304 cbToWrite -= cbBuf;
305 off += cbBuf;
306 }
307
308 if (pcbWritten)
309 *pcbWritten = cbWritten;
310
311 return rc;
312}
313
314
315/**
316 * Gets the current file position.
317 *
318 * @returns File offset.
319 * @returns ~0UUL on failure.
320 * @param File File handle.
321 */
322RTR3DECL(uint64_t) RTFileTell(RTFILE File)
323{
324 /*
325 * Call the seek api to query the stuff.
326 */
327 uint64_t off = 0;
328 int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);
329 if (RT_SUCCESS(rc))
330 return off;
331 AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));
332 return ~0ULL;
333}
334
335
336/**
337 * Determine the maximum file size.
338 *
339 * @returns The max size of the file.
340 * -1 on failure, the file position is undefined.
341 * @param File Handle to the file.
342 * @see RTFileGetMaxSizeEx.
343 */
344RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)
345{
346 RTFOFF cbMax;
347 int rc = RTFileGetMaxSizeEx(File, &cbMax);
348 return RT_SUCCESS(rc) ? cbMax : -1;
349}
350
351
352/**
353 * Copies a file given the handles to both files.
354 *
355 * @returns VBox Status code.
356 *
357 * @param FileSrc The source file. The file position is unaltered.
358 * @param FileDst The destination file.
359 * On successful returns the file position is at the end of the file.
360 * On failures the file position and size is undefined.
361 */
362RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)
363{
364 return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);
365}
366
367
368/**
369 * Copies a file.
370 *
371 * @returns VERR_ALREADY_EXISTS if the destination file exists.
372 * @returns VBox Status code.
373 *
374 * @param pszSrc The path to the source file.
375 * @param pszDst The path to the destination file.
376 * This file will be created.
377 * @param fFlags Flags, any of the RTFILECOPY_FLAGS_ \#defines.
378 * @param pfnProgress Pointer to callback function for reporting progress.
379 * @param pvUser User argument to pass to pfnProgress along with the completion percentage.
380 */
381RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
382{
383 /*
384 * Validate input.
385 */
386 AssertMsgReturn(VALID_PTR(pszSrc), ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
387 AssertMsgReturn(*pszSrc, ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
388 AssertMsgReturn(VALID_PTR(pszDst), ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
389 AssertMsgReturn(*pszDst, ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
390 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
391 AssertMsgReturn(!(fFlags & ~RTFILECOPY_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
392
393 /*
394 * Open the files.
395 */
396 RTFILE FileSrc;
397 int rc = RTFileOpen(&FileSrc, pszSrc,
398 RTFILE_O_READ | RTFILE_O_OPEN
399 | (fFlags & RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
400 if (RT_SUCCESS(rc))
401 {
402 RTFILE FileDst;
403 rc = RTFileOpen(&FileDst, pszDst,
404 RTFILE_O_WRITE | RTFILE_O_CREATE
405 | (fFlags & RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
406 if (RT_SUCCESS(rc))
407 {
408 /*
409 * Call the ByHandles version and let it do the job.
410 */
411 rc = RTFileCopyByHandlesEx(FileSrc, FileDst, pfnProgress, pvUser);
412
413 /*
414 * Close the files regardless of the result.
415 * Don't bother cleaning up or anything like that.
416 */
417 int rc2 = RTFileClose(FileDst);
418 AssertRC(rc2);
419 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
420 rc = rc2;
421 }
422
423 int rc2 = RTFileClose(FileSrc);
424 AssertRC(rc2);
425 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
426 rc = rc2;
427 }
428 return rc;
429}
430
431
432/**
433 * Copies a file given the handles to both files and
434 * provide progress callbacks.
435 *
436 * @returns VBox Status code.
437 *
438 * @param FileSrc The source file. The file position is unaltered.
439 * @param FileDst The destination file.
440 * On successful returns the file position is at the end of the file.
441 * On failures the file position and size is undefined.
442 * @param pfnProgress Pointer to callback function for reporting progress.
443 * @param pvUser User argument to pass to pfnProgress along with the completion percentage.
444 */
445RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser)
446{
447 /*
448 * Validate input.
449 */
450 AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER);
451 AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER);
452 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
453
454 /*
455 * Save file offset.
456 */
457 RTFOFF offSrcSaved;
458 int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved);
459 if (RT_FAILURE(rc))
460 return rc;
461
462 /*
463 * Get the file size.
464 */
465 RTFOFF cbSrc;
466 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc);
467 if (RT_FAILURE(rc))
468 return rc;
469
470 /*
471 * Allocate buffer.
472 */
473 size_t cbBuf;
474 uint8_t *pbBufFree = NULL;
475 uint8_t *pbBuf;
476 if (cbSrc < _512K)
477 {
478 cbBuf = 8*_1K;
479 pbBuf = (uint8_t *)alloca(cbBuf);
480 }
481 else
482 {
483 cbBuf = _128K;
484 pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf);
485 }
486 if (pbBuf)
487 {
488 /*
489 * Seek to the start of each file
490 * and set the size of the destination file.
491 */
492 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL);
493 if (RT_SUCCESS(rc))
494 {
495 rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL);
496 if (RT_SUCCESS(rc))
497 rc = RTFileSetSize(FileDst, cbSrc);
498 if (RT_SUCCESS(rc) && pfnProgress)
499 rc = pfnProgress(0, pvUser);
500 if (RT_SUCCESS(rc))
501 {
502 /*
503 * Copy loop.
504 */
505 unsigned uPercentage = 0;
506 RTFOFF off = 0;
507 RTFOFF cbPercent = cbSrc / 100;
508 RTFOFF offNextPercent = cbPercent;
509 while (off < cbSrc)
510 {
511 /* copy block */
512 RTFOFF cbLeft = cbSrc - off;
513 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
514 rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL);
515 if (RT_FAILURE(rc))
516 break;
517 rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL);
518 if (RT_FAILURE(rc))
519 break;
520
521 /* advance */
522 off += cbBlock;
523 if (pfnProgress && offNextPercent < off)
524 {
525 while (offNextPercent < off)
526 {
527 uPercentage++;
528 offNextPercent += cbPercent;
529 }
530 rc = pfnProgress(uPercentage, pvUser);
531 if (RT_FAILURE(rc))
532 break;
533 }
534 }
535
536#if 0
537 /*
538 * Copy OS specific data (EAs and stuff).
539 */
540 rtFileCopyOSStuff(FileSrc, FileDst);
541#endif
542
543 /* 100% */
544 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
545 rc = pfnProgress(100, pvUser);
546 }
547 }
548 RTMemTmpFree(pbBufFree);
549 }
550 else
551 rc = VERR_NO_MEMORY;
552
553 /*
554 * Restore source position.
555 */
556 RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL);
557
558 return rc;
559}
560
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