VirtualBox

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

Last change on this file since 24106 was 23973, checked in by vboxsync, 15 years ago

*,RTFileOpen: Fixing RTFileOpen flag misdesign: The deny, access and action flags are mandatory now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.0 KB
Line 
1/* $Id: fileio.cpp 23973 2009-10-22 12:34:22Z 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.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 * 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 AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n"));
153 fOpen |= RTFILE_O_OPEN;
154 break;
155 case RTFILE_O_OPEN:
156 AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#x\n", fOpen), VERR_INVALID_PARAMETER);
157 case RTFILE_O_OPEN_CREATE:
158 case RTFILE_O_CREATE:
159 case RTFILE_O_CREATE_REPLACE:
160 break;
161 default:
162 AssertMsgFailed(("Invalid action value: fOpen=%#x\n", fOpen));
163 return VERR_INVALID_PARAMETER;
164 }
165
166 switch (fOpen & RTFILE_O_DENY_MASK)
167 {
168 case 0: /* temporarily */
169 AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n"));
170 fOpen |= RTFILE_O_DENY_NONE;
171 break;
172 case RTFILE_O_DENY_NONE:
173 case RTFILE_O_DENY_READ:
174 case RTFILE_O_DENY_WRITE:
175 case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
176 case RTFILE_O_DENY_NOT_DELETE:
177 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ:
178 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE:
179 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
180 break;
181 default:
182 AssertMsgFailed(("Invalid deny value: fOpen=%#x\n", fOpen));
183 return VERR_INVALID_PARAMETER;
184 }
185
186 /* done */
187 *pfOpen = fOpen;
188 return VINF_SUCCESS;
189}
190
191
192
193/**
194 * Read bytes from a file at a given offset.
195 * This function may modify the file position.
196 *
197 * @returns iprt status code.
198 * @param File Handle to the file.
199 * @param off Where to read.
200 * @param pvBuf Where to put the bytes we read.
201 * @param cbToRead How much to read.
202 * @param *pcbRead How much we actually read.
203 * If NULL an error will be returned for a partial read.
204 */
205RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
206{
207 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
208 if (RT_SUCCESS(rc))
209 rc = RTFileRead(File, pvBuf, cbToRead, pcbRead);
210 return rc;
211}
212
213
214/**
215 * Write bytes to a file at a given offset.
216 * This function may modify the file position.
217 *
218 * @returns iprt status code.
219 * @param File Handle to the file.
220 * @param off Where to write.
221 * @param pvBuf What to write.
222 * @param cbToWrite How much to write.
223 * @param *pcbWritten How much we actually wrote.
224 * If NULL an error will be returned for a partial write.
225 */
226RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
227{
228 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
229 if (RT_SUCCESS(rc))
230 rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten);
231 return rc;
232}
233
234
235/**
236 * Gets the current file position.
237 *
238 * @returns File offset.
239 * @returns ~0UUL on failure.
240 * @param File File handle.
241 */
242RTR3DECL(uint64_t) RTFileTell(RTFILE File)
243{
244 /*
245 * Call the seek api to query the stuff.
246 */
247 uint64_t off = 0;
248 int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);
249 if (RT_SUCCESS(rc))
250 return off;
251 AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));
252 return ~0ULL;
253}
254
255
256/**
257 * Determine the maximum file size.
258 *
259 * @returns The max size of the file.
260 * -1 on failure, the file position is undefined.
261 * @param File Handle to the file.
262 * @see RTFileGetMaxSizeEx.
263 */
264RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)
265{
266 RTFOFF cbMax;
267 int rc = RTFileGetMaxSizeEx(File, &cbMax);
268 return RT_SUCCESS(rc) ? cbMax : -1;
269}
270
271
272/**
273 * Copies a file given the handles to both files.
274 *
275 * @returns VBox Status code.
276 *
277 * @param FileSrc The source file. The file position is unaltered.
278 * @param FileDst The destination file.
279 * On successful returns the file position is at the end of the file.
280 * On failures the file position and size is undefined.
281 */
282RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)
283{
284 return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);
285}
286
287
288/**
289 * Copies a file.
290 *
291 * @returns VERR_ALREADY_EXISTS if the destination file exists.
292 * @returns VBox Status code.
293 *
294 * @param pszSrc The path to the source file.
295 * @param pszDst The path to the destination file.
296 * This file will be created.
297 * @param fFlags Flags, any of the RTFILECOPY_FLAGS_ \#defines.
298 * @param pfnProgress Pointer to callback function for reporting progress.
299 * @param pvUser User argument to pass to pfnProgress along with the completion precentage.
300 */
301RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
302{
303 /*
304 * Validate input.
305 */
306 AssertMsgReturn(VALID_PTR(pszSrc), ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
307 AssertMsgReturn(*pszSrc, ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
308 AssertMsgReturn(VALID_PTR(pszDst), ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
309 AssertMsgReturn(*pszDst, ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
310 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
311 AssertMsgReturn(!(fFlags & ~RTFILECOPY_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
312
313 /*
314 * Open the files.
315 */
316 RTFILE FileSrc;
317 int rc = RTFileOpen(&FileSrc, pszSrc,
318 RTFILE_O_READ | RTFILE_O_OPEN
319 | (fFlags & RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
320 if (RT_SUCCESS(rc))
321 {
322 RTFILE FileDst;
323 rc = RTFileOpen(&FileDst, pszDst,
324 RTFILE_O_WRITE | RTFILE_O_CREATE
325 | (fFlags & RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
326 if (RT_SUCCESS(rc))
327 {
328 /*
329 * Call the ByHandles version and let it do the job.
330 */
331 rc = RTFileCopyByHandlesEx(FileSrc, FileDst, pfnProgress, pvUser);
332
333 /*
334 * Close the files regardless of the result.
335 * Don't bother cleaning up or anything like that.
336 */
337 int rc2 = RTFileClose(FileDst);
338 AssertRC(rc2);
339 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
340 rc = rc2;
341 }
342
343 int rc2 = RTFileClose(FileSrc);
344 AssertRC(rc2);
345 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
346 rc = rc2;
347 }
348 return rc;
349}
350
351
352/**
353 * Copies a file given the handles to both files and
354 * provide progress callbacks.
355 *
356 * @returns VBox Status code.
357 *
358 * @param FileSrc The source file. The file position is unaltered.
359 * @param FileDst The destination file.
360 * On successful returns the file position is at the end of the file.
361 * On failures the file position and size is undefined.
362 * @param pfnProgress Pointer to callback function for reporting progress.
363 * @param pvUser User argument to pass to pfnProgress along with the completion precentage.
364 */
365RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser)
366{
367 /*
368 * Validate input.
369 */
370 AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER);
371 AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER);
372 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
373
374 /*
375 * Save file offset.
376 */
377 RTFOFF offSrcSaved;
378 int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved);
379 if (RT_FAILURE(rc))
380 return rc;
381
382 /*
383 * Get the file size.
384 */
385 RTFOFF cbSrc;
386 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc);
387 if (RT_FAILURE(rc))
388 return rc;
389
390 /*
391 * Allocate buffer.
392 */
393 size_t cbBuf;
394 uint8_t *pbBufFree = NULL;
395 uint8_t *pbBuf;
396 if (cbSrc < _512K)
397 {
398 cbBuf = 8*_1K;
399 pbBuf = (uint8_t *)alloca(cbBuf);
400 }
401 else
402 {
403 cbBuf = _128K;
404 pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf);
405 }
406 if (pbBuf)
407 {
408 /*
409 * Seek to the start of each file
410 * and set the size of the destination file.
411 */
412 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL);
413 if (RT_SUCCESS(rc))
414 {
415 rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL);
416 if (RT_SUCCESS(rc))
417 rc = RTFileSetSize(FileDst, cbSrc);
418 if (RT_SUCCESS(rc) && pfnProgress)
419 rc = pfnProgress(0, pvUser);
420 if (RT_SUCCESS(rc))
421 {
422 /*
423 * Copy loop.
424 */
425 unsigned uPercentage = 0;
426 RTFOFF off = 0;
427 RTFOFF cbPercent = cbSrc / 100;
428 RTFOFF offNextPercent = cbPercent;
429 while (off < cbSrc)
430 {
431 /* copy block */
432 RTFOFF cbLeft = cbSrc - off;
433 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
434 rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL);
435 if (RT_FAILURE(rc))
436 break;
437 rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL);
438 if (RT_FAILURE(rc))
439 break;
440
441 /* advance */
442 off += cbBlock;
443 if (pfnProgress && offNextPercent < off)
444 {
445 while (offNextPercent < off)
446 {
447 uPercentage++;
448 offNextPercent += cbPercent;
449 }
450 rc = pfnProgress(uPercentage, pvUser);
451 if (RT_FAILURE(rc))
452 break;
453 }
454 }
455
456#if 0
457 /*
458 * Copy OS specific data (EAs and stuff).
459 */
460 rtFileCopyOSStuff(FileSrc, FileDst);
461#endif
462
463 /* 100% */
464 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
465 rc = pfnProgress(100, pvUser);
466 }
467 }
468 RTMemTmpFree(pbBufFree);
469 }
470 else
471 rc = VERR_NO_MEMORY;
472
473 /*
474 * Restore source position.
475 */
476 RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL);
477
478 return rc;
479}
480
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