VirtualBox

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

Last change on this file since 57016 was 56290, checked in by vboxsync, 10 years ago

IPRT: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.4 KB
Line 
1/* $Id: fileio.cpp 56290 2015-06-09 14:01:31Z vboxsync $ */
2/** @file
3 * IPRT - File I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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 "internal/iprt.h"
31#include <iprt/file.h>
32
33#include <iprt/mem.h>
34#include <iprt/assert.h>
35#include <iprt/alloca.h>
36#include <iprt/string.h>
37#include <iprt/err.h>
38#include "internal/file.h"
39
40
41/*******************************************************************************
42* Global Variables *
43*******************************************************************************/
44/** Set of forced set open flags for files opened read-only. */
45static unsigned g_fOpenReadSet = 0;
46
47/** Set of forced cleared open flags for files opened read-only. */
48static unsigned g_fOpenReadMask = 0;
49
50/** Set of forced set open flags for files opened write-only. */
51static unsigned g_fOpenWriteSet = 0;
52
53/** Set of forced cleared open flags for files opened write-only. */
54static unsigned g_fOpenWriteMask = 0;
55
56/** Set of forced set open flags for files opened read-write. */
57static unsigned g_fOpenReadWriteSet = 0;
58
59/** Set of forced cleared open flags for files opened read-write. */
60static unsigned g_fOpenReadWriteMask = 0;
61
62
63/**
64 * Force the use of open flags for all files opened after the setting is
65 * changed. The caller is responsible for not causing races with RTFileOpen().
66 *
67 * @returns iprt status code.
68 * @param fOpenForAccess Access mode to which the set/mask settings apply.
69 * @param fSet Open flags to be forced set.
70 * @param fMask Open flags to be masked out.
71 */
72RTR3DECL(int) RTFileSetForceFlags(unsigned fOpenForAccess, unsigned fSet, unsigned fMask)
73{
74 /*
75 * For now allow only RTFILE_O_WRITE_THROUGH. The other flags either
76 * make no sense in this context or are not useful to apply to all files.
77 */
78 if ((fSet | fMask) & ~RTFILE_O_WRITE_THROUGH)
79 return VERR_INVALID_PARAMETER;
80 switch (fOpenForAccess)
81 {
82 case RTFILE_O_READ:
83 g_fOpenReadSet = fSet;
84 g_fOpenReadMask = fMask;
85 break;
86 case RTFILE_O_WRITE:
87 g_fOpenWriteSet = fSet;
88 g_fOpenWriteMask = fMask;
89 break;
90 case RTFILE_O_READWRITE:
91 g_fOpenReadWriteSet = fSet;
92 g_fOpenReadWriteMask = fMask;
93 break;
94 default:
95 AssertMsgFailed(("Invalid access mode %d\n", fOpenForAccess));
96 return VERR_INVALID_PARAMETER;
97 }
98 return VINF_SUCCESS;
99}
100
101
102/**
103 * Adjusts and validates the flags.
104 *
105 * The adjustments are made according to the wishes specified using the RTFileSetForceFlags API.
106 *
107 * @returns IPRT status code.
108 * @param pfOpen Pointer to the user specified flags on input.
109 * Updated on successful return.
110 * @internal
111 */
112int rtFileRecalcAndValidateFlags(uint64_t *pfOpen)
113{
114 /*
115 * Recalc.
116 */
117 uint32_t fOpen = *pfOpen;
118 switch (fOpen & RTFILE_O_ACCESS_MASK)
119 {
120 case RTFILE_O_READ:
121 fOpen |= g_fOpenReadSet;
122 fOpen &= ~g_fOpenReadMask;
123 break;
124 case RTFILE_O_WRITE:
125 fOpen |= g_fOpenWriteSet;
126 fOpen &= ~g_fOpenWriteMask;
127 break;
128 case RTFILE_O_READWRITE:
129 fOpen |= g_fOpenReadWriteSet;
130 fOpen &= ~g_fOpenReadWriteMask;
131 break;
132 default:
133 AssertMsgFailed(("Invalid RW value, fOpen=%#llx\n", fOpen));
134 return VERR_INVALID_PARAMETER;
135 }
136
137 /*
138 * Validate .
139 */
140 AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
141#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
142 AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
143#else
144 AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
145#endif
146 AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
147
148 switch (fOpen & RTFILE_O_ACTION_MASK)
149 {
150 case 0: /* temporarily */
151 AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n"));
152 fOpen |= RTFILE_O_OPEN;
153 break;
154 case RTFILE_O_OPEN:
155 AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
156 case RTFILE_O_OPEN_CREATE:
157 case RTFILE_O_CREATE:
158 case RTFILE_O_CREATE_REPLACE:
159 break;
160 default:
161 AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen));
162 return VERR_INVALID_PARAMETER;
163 }
164
165 switch (fOpen & RTFILE_O_DENY_MASK)
166 {
167 case 0: /* temporarily */
168 AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n"));
169 fOpen |= RTFILE_O_DENY_NONE;
170 break;
171 case RTFILE_O_DENY_NONE:
172 case RTFILE_O_DENY_READ:
173 case RTFILE_O_DENY_WRITE:
174 case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
175 case RTFILE_O_DENY_NOT_DELETE:
176 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ:
177 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE:
178 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
179 break;
180 default:
181 AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen));
182 return VERR_INVALID_PARAMETER;
183 }
184
185 /* done */
186 *pfOpen = fOpen;
187 return VINF_SUCCESS;
188}
189
190
191
192/**
193 * Read bytes from a file at a given offset.
194 * This function may modify the file position.
195 *
196 * @returns iprt status code.
197 * @param File Handle to the file.
198 * @param off Where to read.
199 * @param pvBuf Where to put the bytes we read.
200 * @param cbToRead How much to read.
201 * @param *pcbRead How much we actually read.
202 * If NULL an error will be returned for a partial read.
203 */
204RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
205{
206 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
207 if (RT_SUCCESS(rc))
208 rc = RTFileRead(File, pvBuf, cbToRead, pcbRead);
209 return rc;
210}
211
212
213/**
214 * Read bytes from a file at a given offset into a S/G buffer.
215 * This function may modify the file position.
216 *
217 * @returns iprt status code.
218 * @param hFile Handle to the file.
219 * @param off Where to read.
220 * @param pSgBuf Pointer to the S/G buffer to read into.
221 * @param cbToRead How much to read.
222 * @param pcbRead How much we actually read.
223 * If NULL an error will be returned for a partial read.
224 */
225RTR3DECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
226{
227 int rc = VINF_SUCCESS;
228 size_t cbRead = 0;
229
230 while (cbToRead)
231 {
232 size_t cbThisRead = 0;
233 size_t cbBuf = cbToRead;
234 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
235
236 rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);
237 if (RT_SUCCESS(rc))
238 cbRead += cbThisRead;
239
240 if ( RT_FAILURE(rc)
241 || ( cbThisRead < cbBuf
242 && pcbRead))
243 break;
244
245 cbToRead -= cbBuf;
246 off += cbBuf;
247 }
248
249 if (pcbRead)
250 *pcbRead = cbRead;
251
252 return rc;
253}
254
255
256/**
257 * Write bytes to a file at a given offset.
258 * This function may modify the file position.
259 *
260 * @returns iprt status code.
261 * @param File Handle to the file.
262 * @param off Where to write.
263 * @param pvBuf What to write.
264 * @param cbToWrite How much to write.
265 * @param *pcbWritten How much we actually wrote.
266 * If NULL an error will be returned for a partial write.
267 */
268RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
269{
270 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);
271 if (RT_SUCCESS(rc))
272 rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten);
273 return rc;
274}
275
276
277/**
278 * Write bytes from a S/G buffer to a file at a given offset.
279 * This function may modify the file position.
280 *
281 * @returns iprt status code.
282 * @param hFile Handle to the file.
283 * @param off Where to write.
284 * @param pSgBuf What to write.
285 * @param cbToWrite How much to write.
286 * @param pcbWritten How much we actually wrote.
287 * If NULL an error will be returned for a partial write.
288 */
289RTR3DECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
290{
291 int rc = VINF_SUCCESS;
292 size_t cbWritten = 0;
293
294 while (cbToWrite)
295 {
296 size_t cbThisWritten = 0;
297 size_t cbBuf = cbToWrite;
298 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);
299
300 rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);
301 if (RT_SUCCESS(rc))
302 cbWritten += cbThisWritten;
303
304 if ( RT_FAILURE(rc)
305 || ( cbThisWritten < cbBuf
306 && pcbWritten))
307 break;
308
309 cbToWrite -= cbBuf;
310 off += cbBuf;
311 }
312
313 if (pcbWritten)
314 *pcbWritten = cbWritten;
315
316 return rc;
317}
318
319
320/**
321 * Gets the current file position.
322 *
323 * @returns File offset.
324 * @returns ~0UUL on failure.
325 * @param File File handle.
326 */
327RTR3DECL(uint64_t) RTFileTell(RTFILE File)
328{
329 /*
330 * Call the seek api to query the stuff.
331 */
332 uint64_t off = 0;
333 int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);
334 if (RT_SUCCESS(rc))
335 return off;
336 AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));
337 return ~0ULL;
338}
339
340
341/**
342 * Determine the maximum file size.
343 *
344 * @returns The max size of the file.
345 * -1 on failure, the file position is undefined.
346 * @param File Handle to the file.
347 * @see RTFileGetMaxSizeEx.
348 */
349RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)
350{
351 RTFOFF cbMax;
352 int rc = RTFileGetMaxSizeEx(File, &cbMax);
353 return RT_SUCCESS(rc) ? cbMax : -1;
354}
355
356
357RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)
358{
359 return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);
360}
361
362
363RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
364{
365 /*
366 * Validate input.
367 */
368 AssertMsgReturn(VALID_PTR(pszSrc), ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
369 AssertMsgReturn(*pszSrc, ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);
370 AssertMsgReturn(VALID_PTR(pszDst), ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
371 AssertMsgReturn(*pszDst, ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);
372 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
373 AssertMsgReturn(!(fFlags & ~RTFILECOPY_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
374
375 /*
376 * Open the files.
377 */
378 RTFILE FileSrc;
379 int rc = RTFileOpen(&FileSrc, pszSrc,
380 RTFILE_O_READ | RTFILE_O_OPEN
381 | (fFlags & RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
382 if (RT_SUCCESS(rc))
383 {
384 RTFILE FileDst;
385 rc = RTFileOpen(&FileDst, pszDst,
386 RTFILE_O_WRITE | RTFILE_O_CREATE
387 | (fFlags & RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
388 if (RT_SUCCESS(rc))
389 {
390 /*
391 * Call the ByHandles version and let it do the job.
392 */
393 rc = RTFileCopyByHandlesEx(FileSrc, FileDst, pfnProgress, pvUser);
394
395 /*
396 * Close the files regardless of the result.
397 * Don't bother cleaning up or anything like that.
398 */
399 int rc2 = RTFileClose(FileDst);
400 AssertRC(rc2);
401 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
402 rc = rc2;
403 }
404
405 int rc2 = RTFileClose(FileSrc);
406 AssertRC(rc2);
407 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
408 rc = rc2;
409 }
410 return rc;
411}
412
413
414RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser)
415{
416 /*
417 * Validate input.
418 */
419 AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER);
420 AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER);
421 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
422
423 /*
424 * Save file offset.
425 */
426 RTFOFF offSrcSaved;
427 int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved);
428 if (RT_FAILURE(rc))
429 return rc;
430
431 /*
432 * Get the file size.
433 */
434 RTFOFF cbSrc;
435 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc);
436 if (RT_FAILURE(rc))
437 return rc;
438
439 /*
440 * Allocate buffer.
441 */
442 size_t cbBuf;
443 uint8_t *pbBufFree = NULL;
444 uint8_t *pbBuf;
445 if (cbSrc < _512K)
446 {
447 cbBuf = 8*_1K;
448 pbBuf = (uint8_t *)alloca(cbBuf);
449 }
450 else
451 {
452 cbBuf = _128K;
453 pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf);
454 }
455 if (pbBuf)
456 {
457 /*
458 * Seek to the start of each file
459 * and set the size of the destination file.
460 */
461 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL);
462 if (RT_SUCCESS(rc))
463 {
464 rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL);
465 if (RT_SUCCESS(rc))
466 rc = RTFileSetSize(FileDst, cbSrc);
467 if (RT_SUCCESS(rc) && pfnProgress)
468 rc = pfnProgress(0, pvUser);
469 if (RT_SUCCESS(rc))
470 {
471 /*
472 * Copy loop.
473 */
474 unsigned uPercentage = 0;
475 RTFOFF off = 0;
476 RTFOFF cbPercent = cbSrc / 100;
477 RTFOFF offNextPercent = cbPercent;
478 while (off < cbSrc)
479 {
480 /* copy block */
481 RTFOFF cbLeft = cbSrc - off;
482 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
483 rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL);
484 if (RT_FAILURE(rc))
485 break;
486 rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL);
487 if (RT_FAILURE(rc))
488 break;
489
490 /* advance */
491 off += cbBlock;
492 if (pfnProgress && offNextPercent < off)
493 {
494 while (offNextPercent < off)
495 {
496 uPercentage++;
497 offNextPercent += cbPercent;
498 }
499 rc = pfnProgress(uPercentage, pvUser);
500 if (RT_FAILURE(rc))
501 break;
502 }
503 }
504
505#if 0
506 /*
507 * Copy OS specific data (EAs and stuff).
508 */
509 rtFileCopyOSStuff(FileSrc, FileDst);
510#endif
511
512 /* 100% */
513 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
514 rc = pfnProgress(100, pvUser);
515 }
516 }
517 RTMemTmpFree(pbBufFree);
518 }
519 else
520 rc = VERR_NO_MEMORY;
521
522 /*
523 * Restore source position.
524 */
525 RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL);
526
527 return rc;
528}
529
530
531RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2)
532{
533 return RTFileCompareEx(pszFile1, pszFile2, 0 /*fFlags*/, NULL, NULL);
534}
535
536
537RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2)
538{
539 return RTFileCompareByHandlesEx(hFile1, hFile2, 0 /*fFlags*/, NULL, NULL);
540}
541
542
543RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
544{
545 /*
546 * Validate input.
547 */
548 AssertPtrReturn(pszFile1, VERR_INVALID_POINTER);
549 AssertReturn(*pszFile1, VERR_INVALID_PARAMETER);
550 AssertPtrReturn(pszFile2, VERR_INVALID_POINTER);
551 AssertReturn(*pszFile2, VERR_INVALID_PARAMETER);
552 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
553 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
554
555 /*
556 * Open the files.
557 */
558 RTFILE hFile1;
559 int rc = RTFileOpen(&hFile1, pszFile1,
560 RTFILE_O_READ | RTFILE_O_OPEN
561 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
562 if (RT_SUCCESS(rc))
563 {
564 RTFILE hFile2;
565 rc = RTFileOpen(&hFile2, pszFile2,
566 RTFILE_O_READ | RTFILE_O_OPEN
567 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
568 if (RT_SUCCESS(rc))
569 {
570 /*
571 * Call the ByHandles version and let it do the job.
572 */
573 rc = RTFileCompareByHandlesEx(hFile1, hFile2, fFlags, pfnProgress, pvUser);
574
575 /* Clean up */
576 int rc2 = RTFileClose(hFile2);
577 AssertRC(rc2);
578 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
579 rc = rc2;
580 }
581
582 int rc2 = RTFileClose(hFile1);
583 AssertRC(rc2);
584 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
585 rc = rc2;
586 }
587 return rc;
588}
589
590
591RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
592{
593 /*
594 * Validate input.
595 */
596 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
597 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
598 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);
599 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
600
601 /*
602 * Compare the file sizes first.
603 */
604 uint64_t cbFile1;
605 int rc = RTFileGetSize(hFile1, &cbFile1);
606 if (RT_FAILURE(rc))
607 return rc;
608
609 uint64_t cbFile2;
610 rc = RTFileGetSize(hFile1, &cbFile2);
611 if (RT_FAILURE(rc))
612 return rc;
613
614 if (cbFile1 != cbFile2)
615 return VERR_NOT_EQUAL;
616
617
618 /*
619 * Allocate buffer.
620 */
621 size_t cbBuf;
622 uint8_t *pbBuf1Free = NULL;
623 uint8_t *pbBuf1;
624 uint8_t *pbBuf2Free = NULL;
625 uint8_t *pbBuf2;
626 if (cbFile1 < _512K)
627 {
628 cbBuf = 8*_1K;
629 pbBuf1 = (uint8_t *)alloca(cbBuf);
630 pbBuf2 = (uint8_t *)alloca(cbBuf);
631 }
632 else
633 {
634 cbBuf = _128K;
635 pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
636 pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
637 }
638 if (pbBuf1 && pbBuf2)
639 {
640 /*
641 * Seek to the start of each file
642 * and set the size of the destination file.
643 */
644 rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL);
645 if (RT_SUCCESS(rc))
646 {
647 rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL);
648 if (RT_SUCCESS(rc) && pfnProgress)
649 rc = pfnProgress(0, pvUser);
650 if (RT_SUCCESS(rc))
651 {
652 /*
653 * Compare loop.
654 */
655 unsigned uPercentage = 0;
656 RTFOFF off = 0;
657 RTFOFF cbPercent = cbFile1 / 100;
658 RTFOFF offNextPercent = cbPercent;
659 while (off < (RTFOFF)cbFile1)
660 {
661 /* read the blocks */
662 RTFOFF cbLeft = cbFile1 - off;
663 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
664 rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL);
665 if (RT_FAILURE(rc))
666 break;
667 rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL);
668 if (RT_FAILURE(rc))
669 break;
670
671 /* compare */
672 if (memcmp(pbBuf1, pbBuf2, cbBlock))
673 {
674 rc = VERR_NOT_EQUAL;
675 break;
676 }
677
678 /* advance */
679 off += cbBlock;
680 if (pfnProgress && offNextPercent < off)
681 {
682 while (offNextPercent < off)
683 {
684 uPercentage++;
685 offNextPercent += cbPercent;
686 }
687 rc = pfnProgress(uPercentage, pvUser);
688 if (RT_FAILURE(rc))
689 break;
690 }
691 }
692
693#if 0
694 /*
695 * Compare OS specific data (EAs and stuff).
696 */
697 if (RT_SUCCESS(rc))
698 rc = rtFileCompareOSStuff(hFile1, hFile2);
699#endif
700
701 /* 100% */
702 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
703 rc = pfnProgress(100, pvUser);
704 }
705 }
706 }
707 else
708 rc = VERR_NO_MEMORY;
709 RTMemTmpFree(pbBuf2Free);
710 RTMemTmpFree(pbBuf1Free);
711
712 return rc;
713}
714
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