VirtualBox

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

Last change on this file since 24650 was 24650, checked in by vboxsync, 16 years ago

Disabling asserts preventing ISO image mounts

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