VirtualBox

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

Last change on this file since 3672 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

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