VirtualBox

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

Last change on this file since 4787 was 4372, checked in by vboxsync, 17 years ago

Finally corrected the RTFileRead, RTFileReadAt, RTFileWrite and RTFileWriteAt APIs to size_t. This was long overdue.

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