Changeset 77209 in vbox
- Timestamp:
- Feb 7, 2019 11:46:50 PM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 128712
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/Makefile.kmk
r76553 r77209 815 815 generic/RTDirExists-generic.cpp \ 816 816 generic/RTDirSetTimes-generic.cpp \ 817 generic/fileio-at-generic.cpp \ 818 generic/fileio-sg-generic.cpp \ 817 819 generic/RTFileExists-generic.cpp \ 818 820 generic/RTFileSetAllocationSize-generic.cpp \ … … 906 908 generic/RTDirQueryInfo-generic.cpp \ 907 909 generic/RTDirSetTimes-generic.cpp \ 910 generic/fileio-at-generic.cpp \ 911 generic/fileio-sg-generic.cpp \ 908 912 generic/RTFileMove-generic.cpp \ 909 913 generic/RTLogWriteDebugger-generic.cpp \ … … 1004 1008 generic/RTDirQueryInfo-generic.cpp \ 1005 1009 generic/RTDirSetTimes-generic.cpp \ 1010 generic/fileio-at-generic.cpp \ 1011 generic/fileio-sg-generic.cpp \ 1006 1012 generic/RTFileMove-generic.cpp \ 1007 1013 generic/RTFileSetAllocationSize-generic.cpp \ … … 1085 1091 generic/RTDirQueryInfo-generic.cpp \ 1086 1092 generic/RTDirSetTimes-generic.cpp \ 1093 generic/fileio-at-generic.cpp \ 1094 generic/fileio-sg-generic.cpp \ 1087 1095 generic/RTFileMove-generic.cpp \ 1088 1096 generic/RTFileSetAllocationSize-generic.cpp \ … … 1167 1175 generic/RTDirQueryInfo-generic.cpp \ 1168 1176 generic/RTDirSetTimes-generic.cpp \ 1177 generic/fileio-at-generic.cpp \ 1178 generic/fileio-sg-generic.cpp \ 1169 1179 generic/RTFileMove-generic.cpp \ 1170 1180 generic/RTFileSetAllocationSize-generic.cpp \ … … 1247 1257 generic/RTDirQueryInfo-generic.cpp \ 1248 1258 generic/RTDirSetTimes-generic.cpp \ 1259 generic/fileio-at-generic.cpp \ 1260 generic/fileio-sg-generic.cpp \ 1249 1261 generic/RTFileMove-generic.cpp \ 1250 1262 generic/RTLogWriteDebugger-generic.cpp \ … … 1325 1337 generic/RTDirQueryInfo-generic.cpp \ 1326 1338 generic/RTDirSetTimes-generic.cpp \ 1339 generic/fileio-at-generic.cpp \ 1340 generic/fileio-sg-generic.cpp \ 1327 1341 generic/RTFileMove-generic.cpp \ 1328 1342 generic/RTLogWriteDebugger-generic.cpp \ … … 1414 1428 generic/RTDirQueryInfo-generic.cpp \ 1415 1429 generic/RTDirSetTimes-generic.cpp \ 1430 generic/fileio-at-generic.cpp \ 1431 generic/fileio-sg-generic.cpp \ 1416 1432 generic/RTFileMove-generic.cpp \ 1417 1433 generic/RTFileSetAllocationSize-generic.cpp \ … … 1803 1819 generic/cdrom-generic.cpp \ 1804 1820 generic/RTFileMove-generic.cpp \ 1821 generic/fileio-at-generic.cpp \ 1805 1822 generic/RTPathGetCurrentOnDrive-generic.cpp \ 1806 1823 generic/RTProcDaemonize-generic.cpp \ … … 1841 1858 generic/RTDirExists-generic.cpp \ 1842 1859 generic/RTDirSetTimes-generic.cpp \ 1860 generic/fileio-at-generic.cpp \ 1843 1861 generic/RTFileExists-generic.cpp \ 1844 1862 generic/RTFileSetAllocationSize-generic.cpp \ … … 1908 1926 generic/RTDirQueryInfo-generic.cpp \ 1909 1927 generic/RTDirSetTimes-generic.cpp \ 1928 generic/fileio-at-generic.cpp \ 1910 1929 generic/RTFileMove-generic.cpp \ 1911 1930 generic/RTFileSetAllocationSize-generic.cpp \ -
trunk/src/VBox/Runtime/generic/fileio-at-generic.cpp
r77183 r77209 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - File I/O .3 * IPRT - File I/O, RTFileReadAt and RTFileWriteAt, generic. 4 4 */ 5 5 … … 32 32 #include <iprt/file.h> 33 33 34 #include <iprt/mem.h> 35 #include <iprt/assert.h> 36 #include <iprt/alloca.h> 37 #include <iprt/string.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. */ 46 static unsigned g_fOpenReadSet = 0; 47 48 /** Set of forced cleared open flags for files opened read-only. */ 49 static unsigned g_fOpenReadMask = 0; 50 51 /** Set of forced set open flags for files opened write-only. */ 52 static unsigned g_fOpenWriteSet = 0; 53 54 /** Set of forced cleared open flags for files opened write-only. */ 55 static unsigned g_fOpenWriteMask = 0; 56 57 /** Set of forced set open flags for files opened read-write. */ 58 static unsigned g_fOpenReadWriteSet = 0; 59 60 /** Set of forced cleared open flags for files opened read-write. */ 61 static 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 */ 73 RTR3DECL(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 */ 113 int rtFileRecalcAndValidateFlags(uint64_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 #ifdef RT_OS_WINDOWS 134 case RTFILE_O_ATTR_ONLY: 135 if (fOpen & RTFILE_O_ACCESS_ATTR_MASK) 136 break; 137 #endif 138 default: 139 AssertMsgFailed(("Invalid access mode value, fOpen=%#llx\n", fOpen)); 140 return VERR_INVALID_PARAMETER; 141 } 142 143 /* 144 * Validate . 145 */ 146 #ifdef RT_OS_WINDOWS 147 AssertMsgReturn((fOpen & RTFILE_O_ACCESS_MASK) || (fOpen & RTFILE_O_ACCESS_ATTR_MASK), 148 ("Missing RTFILE_O_READ/WRITE/ACCESS_ATTR: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER); 149 #else 150 AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER); 151 #endif 152 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 153 AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 154 #else 155 AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 156 #endif 157 AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 158 159 switch (fOpen & RTFILE_O_ACTION_MASK) 160 { 161 case 0: /* temporarily */ 162 AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n")); 163 fOpen |= RTFILE_O_OPEN; 164 break; 165 case RTFILE_O_OPEN: 166 AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 167 case RTFILE_O_OPEN_CREATE: 168 case RTFILE_O_CREATE: 169 case RTFILE_O_CREATE_REPLACE: 170 break; 171 default: 172 AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen)); 173 return VERR_INVALID_PARAMETER; 174 } 175 176 switch (fOpen & RTFILE_O_DENY_MASK) 177 { 178 case 0: /* temporarily */ 179 AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n")); 180 fOpen |= RTFILE_O_DENY_NONE; 181 break; 182 case RTFILE_O_DENY_NONE: 183 case RTFILE_O_DENY_READ: 184 case RTFILE_O_DENY_WRITE: 185 case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ: 186 case RTFILE_O_DENY_NOT_DELETE: 187 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ: 188 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE: 189 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ: 190 break; 191 default: 192 AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen)); 193 return VERR_INVALID_PARAMETER; 194 } 195 196 /* done */ 197 *pfOpen = fOpen; 198 return VINF_SUCCESS; 199 } 34 #include <iprt/errcore.h> 200 35 201 36 … … 213 48 * If NULL an error will be returned for a partial read. 214 49 */ 215 RT R3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)50 RTDECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead) 216 51 { 217 52 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL); 218 53 if (RT_SUCCESS(rc)) 219 54 rc = RTFileRead(File, pvBuf, cbToRead, pcbRead); 220 return rc;221 }222 223 224 /**225 * Read bytes from a file at a given offset into a S/G buffer.226 * This function may modify the file position.227 *228 * @returns iprt status code.229 * @param hFile Handle to the file.230 * @param off Where to read.231 * @param pSgBuf Pointer to the S/G buffer to read into.232 * @param cbToRead How much to read.233 * @param pcbRead How much we actually read.234 * If NULL an error will be returned for a partial read.235 */236 RTR3DECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)237 {238 int rc = VINF_SUCCESS;239 size_t cbRead = 0;240 241 while (cbToRead)242 {243 size_t cbThisRead = 0;244 size_t cbBuf = cbToRead;245 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);246 247 rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);248 if (RT_SUCCESS(rc))249 cbRead += cbThisRead;250 251 if ( RT_FAILURE(rc)252 || ( cbThisRead < cbBuf253 && pcbRead))254 break;255 256 cbToRead -= cbBuf;257 off += cbBuf;258 }259 260 if (pcbRead)261 *pcbRead = cbRead;262 263 55 return rc; 264 56 } … … 277 69 * If NULL an error will be returned for a partial write. 278 70 */ 279 RT R3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)71 RTDECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten) 280 72 { 281 73 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL); … … 285 77 } 286 78 287 288 /**289 * Write bytes from a S/G buffer to a file at a given offset.290 * This function may modify the file position.291 *292 * @returns iprt status code.293 * @param hFile Handle to the file.294 * @param off Where to write.295 * @param pSgBuf What to write.296 * @param cbToWrite How much to write.297 * @param pcbWritten How much we actually wrote.298 * If NULL an error will be returned for a partial write.299 */300 RTR3DECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)301 {302 int rc = VINF_SUCCESS;303 size_t cbWritten = 0;304 305 while (cbToWrite)306 {307 size_t cbThisWritten = 0;308 size_t cbBuf = cbToWrite;309 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);310 311 rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);312 if (RT_SUCCESS(rc))313 cbWritten += cbThisWritten;314 315 if ( RT_FAILURE(rc)316 || ( cbThisWritten < cbBuf317 && pcbWritten))318 break;319 320 cbToWrite -= cbBuf;321 off += cbBuf;322 }323 324 if (pcbWritten)325 *pcbWritten = cbWritten;326 327 return rc;328 }329 330 331 /**332 * Gets the current file position.333 *334 * @returns File offset.335 * @returns ~0UUL on failure.336 * @param File File handle.337 */338 RTR3DECL(uint64_t) RTFileTell(RTFILE File)339 {340 /*341 * Call the seek api to query the stuff.342 */343 uint64_t off = 0;344 int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);345 if (RT_SUCCESS(rc))346 return off;347 AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));348 return ~0ULL;349 }350 351 352 /**353 * Determine the maximum file size.354 *355 * @returns The max size of the file.356 * -1 on failure, the file position is undefined.357 * @param File Handle to the file.358 * @see RTFileGetMaxSizeEx.359 */360 RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)361 {362 RTFOFF cbMax;363 int rc = RTFileGetMaxSizeEx(File, &cbMax);364 return RT_SUCCESS(rc) ? cbMax : -1;365 }366 367 368 RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)369 {370 return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);371 }372 373 374 RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)375 {376 /*377 * Validate input.378 */379 AssertMsgReturn(VALID_PTR(pszSrc), ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);380 AssertMsgReturn(*pszSrc, ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);381 AssertMsgReturn(VALID_PTR(pszDst), ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);382 AssertMsgReturn(*pszDst, ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);383 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);384 AssertMsgReturn(!(fFlags & ~RTFILECOPY_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);385 386 /*387 * Open the files.388 */389 RTFILE FileSrc;390 int rc = RTFileOpen(&FileSrc, pszSrc,391 RTFILE_O_READ | RTFILE_O_OPEN392 | (fFlags & RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));393 if (RT_SUCCESS(rc))394 {395 RTFILE FileDst;396 rc = RTFileOpen(&FileDst, pszDst,397 RTFILE_O_WRITE | RTFILE_O_CREATE398 | (fFlags & RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));399 if (RT_SUCCESS(rc))400 {401 /*402 * Call the ByHandles version and let it do the job.403 */404 rc = RTFileCopyByHandlesEx(FileSrc, FileDst, pfnProgress, pvUser);405 406 /*407 * Close the files regardless of the result.408 * Don't bother cleaning up or anything like that.409 */410 int rc2 = RTFileClose(FileDst);411 AssertRC(rc2);412 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))413 rc = rc2;414 }415 416 int rc2 = RTFileClose(FileSrc);417 AssertRC(rc2);418 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))419 rc = rc2;420 }421 return rc;422 }423 424 425 RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser)426 {427 /*428 * Validate input.429 */430 AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER);431 AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER);432 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);433 434 /*435 * Save file offset.436 */437 RTFOFF offSrcSaved;438 int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved);439 if (RT_FAILURE(rc))440 return rc;441 442 /*443 * Get the file size.444 */445 RTFOFF cbSrc;446 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc);447 if (RT_FAILURE(rc))448 return rc;449 450 /*451 * Allocate buffer.452 */453 size_t cbBuf;454 uint8_t *pbBufFree = NULL;455 uint8_t *pbBuf;456 if (cbSrc < _512K)457 {458 cbBuf = 8*_1K;459 pbBuf = (uint8_t *)alloca(cbBuf);460 }461 else462 {463 cbBuf = _128K;464 pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf);465 }466 if (pbBuf)467 {468 /*469 * Seek to the start of each file470 * and set the size of the destination file.471 */472 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL);473 if (RT_SUCCESS(rc))474 {475 rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL);476 if (RT_SUCCESS(rc))477 rc = RTFileSetSize(FileDst, cbSrc);478 if (RT_SUCCESS(rc) && pfnProgress)479 rc = pfnProgress(0, pvUser);480 if (RT_SUCCESS(rc))481 {482 /*483 * Copy loop.484 */485 unsigned uPercentage = 0;486 RTFOFF off = 0;487 RTFOFF cbPercent = cbSrc / 100;488 RTFOFF offNextPercent = cbPercent;489 while (off < cbSrc)490 {491 /* copy block */492 RTFOFF cbLeft = cbSrc - off;493 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;494 rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL);495 if (RT_FAILURE(rc))496 break;497 rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL);498 if (RT_FAILURE(rc))499 break;500 501 /* advance */502 off += cbBlock;503 if (pfnProgress && offNextPercent < off && uPercentage < 100)504 {505 do506 {507 uPercentage++;508 offNextPercent += cbPercent;509 } while (offNextPercent < off && uPercentage < 100);510 rc = pfnProgress(uPercentage, pvUser);511 if (RT_FAILURE(rc))512 break;513 }514 }515 516 #if 0517 /*518 * Copy OS specific data (EAs and stuff).519 */520 rtFileCopyOSStuff(FileSrc, FileDst);521 #endif522 523 /* 100% */524 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))525 rc = pfnProgress(100, pvUser);526 }527 }528 RTMemTmpFree(pbBufFree);529 }530 else531 rc = VERR_NO_MEMORY;532 533 /*534 * Restore source position.535 */536 RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL);537 538 return rc;539 }540 541 542 RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2)543 {544 return RTFileCompareEx(pszFile1, pszFile2, 0 /*fFlags*/, NULL, NULL);545 }546 547 548 RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2)549 {550 return RTFileCompareByHandlesEx(hFile1, hFile2, 0 /*fFlags*/, NULL, NULL);551 }552 553 554 RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)555 {556 /*557 * Validate input.558 */559 AssertPtrReturn(pszFile1, VERR_INVALID_POINTER);560 AssertReturn(*pszFile1, VERR_INVALID_PARAMETER);561 AssertPtrReturn(pszFile2, VERR_INVALID_POINTER);562 AssertReturn(*pszFile2, VERR_INVALID_PARAMETER);563 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);564 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);565 566 /*567 * Open the files.568 */569 RTFILE hFile1;570 int rc = RTFileOpen(&hFile1, pszFile1,571 RTFILE_O_READ | RTFILE_O_OPEN572 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));573 if (RT_SUCCESS(rc))574 {575 RTFILE hFile2;576 rc = RTFileOpen(&hFile2, pszFile2,577 RTFILE_O_READ | RTFILE_O_OPEN578 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));579 if (RT_SUCCESS(rc))580 {581 /*582 * Call the ByHandles version and let it do the job.583 */584 rc = RTFileCompareByHandlesEx(hFile1, hFile2, fFlags, pfnProgress, pvUser);585 586 /* Clean up */587 int rc2 = RTFileClose(hFile2);588 AssertRC(rc2);589 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))590 rc = rc2;591 }592 593 int rc2 = RTFileClose(hFile1);594 AssertRC(rc2);595 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))596 rc = rc2;597 }598 return rc;599 }600 601 602 RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)603 {604 /*605 * Validate input.606 */607 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);608 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);609 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);610 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);611 612 /*613 * Compare the file sizes first.614 */615 uint64_t cbFile1;616 int rc = RTFileGetSize(hFile1, &cbFile1);617 if (RT_FAILURE(rc))618 return rc;619 620 uint64_t cbFile2;621 rc = RTFileGetSize(hFile1, &cbFile2);622 if (RT_FAILURE(rc))623 return rc;624 625 if (cbFile1 != cbFile2)626 return VERR_NOT_EQUAL;627 628 629 /*630 * Allocate buffer.631 */632 size_t cbBuf;633 uint8_t *pbBuf1Free = NULL;634 uint8_t *pbBuf1;635 uint8_t *pbBuf2Free = NULL;636 uint8_t *pbBuf2;637 if (cbFile1 < _512K)638 {639 cbBuf = 8*_1K;640 pbBuf1 = (uint8_t *)alloca(cbBuf);641 pbBuf2 = (uint8_t *)alloca(cbBuf);642 }643 else644 {645 cbBuf = _128K;646 pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf);647 pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf);648 }649 if (pbBuf1 && pbBuf2)650 {651 /*652 * Seek to the start of each file653 * and set the size of the destination file.654 */655 rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL);656 if (RT_SUCCESS(rc))657 {658 rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL);659 if (RT_SUCCESS(rc) && pfnProgress)660 rc = pfnProgress(0, pvUser);661 if (RT_SUCCESS(rc))662 {663 /*664 * Compare loop.665 */666 unsigned uPercentage = 0;667 RTFOFF off = 0;668 RTFOFF cbPercent = cbFile1 / 100;669 RTFOFF offNextPercent = cbPercent;670 while (off < (RTFOFF)cbFile1)671 {672 /* read the blocks */673 RTFOFF cbLeft = cbFile1 - off;674 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;675 rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL);676 if (RT_FAILURE(rc))677 break;678 rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL);679 if (RT_FAILURE(rc))680 break;681 682 /* compare */683 if (memcmp(pbBuf1, pbBuf2, cbBlock))684 {685 rc = VERR_NOT_EQUAL;686 break;687 }688 689 /* advance */690 off += cbBlock;691 if (pfnProgress && offNextPercent < off)692 {693 while (offNextPercent < off)694 {695 uPercentage++;696 offNextPercent += cbPercent;697 }698 rc = pfnProgress(uPercentage, pvUser);699 if (RT_FAILURE(rc))700 break;701 }702 }703 704 #if 0705 /*706 * Compare OS specific data (EAs and stuff).707 */708 if (RT_SUCCESS(rc))709 rc = rtFileCompareOSStuff(hFile1, hFile2);710 #endif711 712 /* 100% */713 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))714 rc = pfnProgress(100, pvUser);715 }716 }717 }718 else719 rc = VERR_NO_MEMORY;720 RTMemTmpFree(pbBuf2Free);721 RTMemTmpFree(pbBuf1Free);722 723 return rc;724 }725 -
trunk/src/VBox/Runtime/generic/fileio-sg-generic.cpp
r77183 r77209 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - File I/O .3 * IPRT - File I/O, RTFileSgReadAt & RTFileSgWriteAt, generic. 4 4 */ 5 5 … … 32 32 #include <iprt/file.h> 33 33 34 #include <iprt/mem.h> 35 #include <iprt/assert.h> 36 #include <iprt/alloca.h> 37 #include <iprt/string.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. */ 46 static unsigned g_fOpenReadSet = 0; 47 48 /** Set of forced cleared open flags for files opened read-only. */ 49 static unsigned g_fOpenReadMask = 0; 50 51 /** Set of forced set open flags for files opened write-only. */ 52 static unsigned g_fOpenWriteSet = 0; 53 54 /** Set of forced cleared open flags for files opened write-only. */ 55 static unsigned g_fOpenWriteMask = 0; 56 57 /** Set of forced set open flags for files opened read-write. */ 58 static unsigned g_fOpenReadWriteSet = 0; 59 60 /** Set of forced cleared open flags for files opened read-write. */ 61 static 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 */ 73 RTR3DECL(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 */ 113 int rtFileRecalcAndValidateFlags(uint64_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 #ifdef RT_OS_WINDOWS 134 case RTFILE_O_ATTR_ONLY: 135 if (fOpen & RTFILE_O_ACCESS_ATTR_MASK) 136 break; 137 #endif 138 default: 139 AssertMsgFailed(("Invalid access mode value, fOpen=%#llx\n", fOpen)); 140 return VERR_INVALID_PARAMETER; 141 } 142 143 /* 144 * Validate . 145 */ 146 #ifdef RT_OS_WINDOWS 147 AssertMsgReturn((fOpen & RTFILE_O_ACCESS_MASK) || (fOpen & RTFILE_O_ACCESS_ATTR_MASK), 148 ("Missing RTFILE_O_READ/WRITE/ACCESS_ATTR: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER); 149 #else 150 AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER); 151 #endif 152 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 153 AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 154 #else 155 AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 156 #endif 157 AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 158 159 switch (fOpen & RTFILE_O_ACTION_MASK) 160 { 161 case 0: /* temporarily */ 162 AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n")); 163 fOpen |= RTFILE_O_OPEN; 164 break; 165 case RTFILE_O_OPEN: 166 AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); 167 case RTFILE_O_OPEN_CREATE: 168 case RTFILE_O_CREATE: 169 case RTFILE_O_CREATE_REPLACE: 170 break; 171 default: 172 AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen)); 173 return VERR_INVALID_PARAMETER; 174 } 175 176 switch (fOpen & RTFILE_O_DENY_MASK) 177 { 178 case 0: /* temporarily */ 179 AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n")); 180 fOpen |= RTFILE_O_DENY_NONE; 181 break; 182 case RTFILE_O_DENY_NONE: 183 case RTFILE_O_DENY_READ: 184 case RTFILE_O_DENY_WRITE: 185 case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ: 186 case RTFILE_O_DENY_NOT_DELETE: 187 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ: 188 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE: 189 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ: 190 break; 191 default: 192 AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen)); 193 return VERR_INVALID_PARAMETER; 194 } 195 196 /* done */ 197 *pfOpen = fOpen; 198 return VINF_SUCCESS; 199 } 200 201 202 203 /** 204 * Read bytes from a file at a given offset. 205 * This function may modify the file position. 206 * 207 * @returns iprt status code. 208 * @param File Handle to the file. 209 * @param off Where to read. 210 * @param pvBuf Where to put the bytes we read. 211 * @param cbToRead How much to read. 212 * @param *pcbRead How much we actually read. 213 * If NULL an error will be returned for a partial read. 214 */ 215 RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead) 216 { 217 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL); 218 if (RT_SUCCESS(rc)) 219 rc = RTFileRead(File, pvBuf, cbToRead, pcbRead); 220 return rc; 221 } 34 #include <iprt/errcore.h> 222 35 223 36 … … 234 47 * If NULL an error will be returned for a partial read. 235 48 */ 236 RT R3DECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)49 RTDECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead) 237 50 { 238 51 int rc = VINF_SUCCESS; 239 52 size_t cbRead = 0; 240 241 53 while (cbToRead) 242 54 { 55 size_t cbBuf = cbToRead; 56 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf); 57 243 58 size_t cbThisRead = 0; 244 size_t cbBuf = cbToRead;245 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);246 247 59 rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL); 248 60 if (RT_SUCCESS(rc)) 249 61 cbRead += cbThisRead; 250 251 if ( RT_FAILURE(rc)252 ||( cbThisRead < cbBuf253 && pcbRead))62 else 63 break; 64 if ( cbThisRead < cbBuf 65 && pcbRead) 254 66 break; 255 67 … … 261 73 *pcbRead = cbRead; 262 74 263 return rc;264 }265 266 267 /**268 * Write bytes to a file at a given offset.269 * This function may modify the file position.270 *271 * @returns iprt status code.272 * @param File Handle to the file.273 * @param off Where to write.274 * @param pvBuf What to write.275 * @param cbToWrite How much to write.276 * @param *pcbWritten How much we actually wrote.277 * If NULL an error will be returned for a partial write.278 */279 RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)280 {281 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);282 if (RT_SUCCESS(rc))283 rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten);284 75 return rc; 285 76 } … … 298 89 * If NULL an error will be returned for a partial write. 299 90 */ 300 RT R3DECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)91 RTDECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten) 301 92 { 302 93 int rc = VINF_SUCCESS; 303 94 size_t cbWritten = 0; 304 305 95 while (cbToWrite) 306 96 { 97 size_t cbBuf = cbToWrite; 98 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf); 99 307 100 size_t cbThisWritten = 0; 308 size_t cbBuf = cbToWrite;309 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);310 311 101 rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL); 312 102 if (RT_SUCCESS(rc)) 313 103 cbWritten += cbThisWritten; 314 315 if ( RT_FAILURE(rc)316 ||( cbThisWritten < cbBuf317 && pcbWritten))104 else 105 break; 106 if ( cbThisWritten < cbBuf 107 && pcbWritten) 318 108 break; 319 109 … … 328 118 } 329 119 330 331 /**332 * Gets the current file position.333 *334 * @returns File offset.335 * @returns ~0UUL on failure.336 * @param File File handle.337 */338 RTR3DECL(uint64_t) RTFileTell(RTFILE File)339 {340 /*341 * Call the seek api to query the stuff.342 */343 uint64_t off = 0;344 int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);345 if (RT_SUCCESS(rc))346 return off;347 AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));348 return ~0ULL;349 }350 351 352 /**353 * Determine the maximum file size.354 *355 * @returns The max size of the file.356 * -1 on failure, the file position is undefined.357 * @param File Handle to the file.358 * @see RTFileGetMaxSizeEx.359 */360 RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)361 {362 RTFOFF cbMax;363 int rc = RTFileGetMaxSizeEx(File, &cbMax);364 return RT_SUCCESS(rc) ? cbMax : -1;365 }366 367 368 RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)369 {370 return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);371 }372 373 374 RTDECL(int) RTFileCopyEx(const char *pszSrc, const char *pszDst, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)375 {376 /*377 * Validate input.378 */379 AssertMsgReturn(VALID_PTR(pszSrc), ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);380 AssertMsgReturn(*pszSrc, ("pszSrc=%p\n", pszSrc), VERR_INVALID_PARAMETER);381 AssertMsgReturn(VALID_PTR(pszDst), ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);382 AssertMsgReturn(*pszDst, ("pszDst=%p\n", pszDst), VERR_INVALID_PARAMETER);383 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);384 AssertMsgReturn(!(fFlags & ~RTFILECOPY_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);385 386 /*387 * Open the files.388 */389 RTFILE FileSrc;390 int rc = RTFileOpen(&FileSrc, pszSrc,391 RTFILE_O_READ | RTFILE_O_OPEN392 | (fFlags & RTFILECOPY_FLAGS_NO_SRC_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));393 if (RT_SUCCESS(rc))394 {395 RTFILE FileDst;396 rc = RTFileOpen(&FileDst, pszDst,397 RTFILE_O_WRITE | RTFILE_O_CREATE398 | (fFlags & RTFILECOPY_FLAGS_NO_DST_DENY_WRITE ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));399 if (RT_SUCCESS(rc))400 {401 /*402 * Call the ByHandles version and let it do the job.403 */404 rc = RTFileCopyByHandlesEx(FileSrc, FileDst, pfnProgress, pvUser);405 406 /*407 * Close the files regardless of the result.408 * Don't bother cleaning up or anything like that.409 */410 int rc2 = RTFileClose(FileDst);411 AssertRC(rc2);412 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))413 rc = rc2;414 }415 416 int rc2 = RTFileClose(FileSrc);417 AssertRC(rc2);418 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))419 rc = rc2;420 }421 return rc;422 }423 424 425 RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser)426 {427 /*428 * Validate input.429 */430 AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER);431 AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER);432 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);433 434 /*435 * Save file offset.436 */437 RTFOFF offSrcSaved;438 int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved);439 if (RT_FAILURE(rc))440 return rc;441 442 /*443 * Get the file size.444 */445 RTFOFF cbSrc;446 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc);447 if (RT_FAILURE(rc))448 return rc;449 450 /*451 * Allocate buffer.452 */453 size_t cbBuf;454 uint8_t *pbBufFree = NULL;455 uint8_t *pbBuf;456 if (cbSrc < _512K)457 {458 cbBuf = 8*_1K;459 pbBuf = (uint8_t *)alloca(cbBuf);460 }461 else462 {463 cbBuf = _128K;464 pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf);465 }466 if (pbBuf)467 {468 /*469 * Seek to the start of each file470 * and set the size of the destination file.471 */472 rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL);473 if (RT_SUCCESS(rc))474 {475 rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL);476 if (RT_SUCCESS(rc))477 rc = RTFileSetSize(FileDst, cbSrc);478 if (RT_SUCCESS(rc) && pfnProgress)479 rc = pfnProgress(0, pvUser);480 if (RT_SUCCESS(rc))481 {482 /*483 * Copy loop.484 */485 unsigned uPercentage = 0;486 RTFOFF off = 0;487 RTFOFF cbPercent = cbSrc / 100;488 RTFOFF offNextPercent = cbPercent;489 while (off < cbSrc)490 {491 /* copy block */492 RTFOFF cbLeft = cbSrc - off;493 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;494 rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL);495 if (RT_FAILURE(rc))496 break;497 rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL);498 if (RT_FAILURE(rc))499 break;500 501 /* advance */502 off += cbBlock;503 if (pfnProgress && offNextPercent < off && uPercentage < 100)504 {505 do506 {507 uPercentage++;508 offNextPercent += cbPercent;509 } while (offNextPercent < off && uPercentage < 100);510 rc = pfnProgress(uPercentage, pvUser);511 if (RT_FAILURE(rc))512 break;513 }514 }515 516 #if 0517 /*518 * Copy OS specific data (EAs and stuff).519 */520 rtFileCopyOSStuff(FileSrc, FileDst);521 #endif522 523 /* 100% */524 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))525 rc = pfnProgress(100, pvUser);526 }527 }528 RTMemTmpFree(pbBufFree);529 }530 else531 rc = VERR_NO_MEMORY;532 533 /*534 * Restore source position.535 */536 RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL);537 538 return rc;539 }540 541 542 RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2)543 {544 return RTFileCompareEx(pszFile1, pszFile2, 0 /*fFlags*/, NULL, NULL);545 }546 547 548 RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2)549 {550 return RTFileCompareByHandlesEx(hFile1, hFile2, 0 /*fFlags*/, NULL, NULL);551 }552 553 554 RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)555 {556 /*557 * Validate input.558 */559 AssertPtrReturn(pszFile1, VERR_INVALID_POINTER);560 AssertReturn(*pszFile1, VERR_INVALID_PARAMETER);561 AssertPtrReturn(pszFile2, VERR_INVALID_POINTER);562 AssertReturn(*pszFile2, VERR_INVALID_PARAMETER);563 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);564 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);565 566 /*567 * Open the files.568 */569 RTFILE hFile1;570 int rc = RTFileOpen(&hFile1, pszFile1,571 RTFILE_O_READ | RTFILE_O_OPEN572 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));573 if (RT_SUCCESS(rc))574 {575 RTFILE hFile2;576 rc = RTFileOpen(&hFile2, pszFile2,577 RTFILE_O_READ | RTFILE_O_OPEN578 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));579 if (RT_SUCCESS(rc))580 {581 /*582 * Call the ByHandles version and let it do the job.583 */584 rc = RTFileCompareByHandlesEx(hFile1, hFile2, fFlags, pfnProgress, pvUser);585 586 /* Clean up */587 int rc2 = RTFileClose(hFile2);588 AssertRC(rc2);589 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))590 rc = rc2;591 }592 593 int rc2 = RTFileClose(hFile1);594 AssertRC(rc2);595 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))596 rc = rc2;597 }598 return rc;599 }600 601 602 RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)603 {604 /*605 * Validate input.606 */607 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);608 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);609 AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER);610 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);611 612 /*613 * Compare the file sizes first.614 */615 uint64_t cbFile1;616 int rc = RTFileGetSize(hFile1, &cbFile1);617 if (RT_FAILURE(rc))618 return rc;619 620 uint64_t cbFile2;621 rc = RTFileGetSize(hFile1, &cbFile2);622 if (RT_FAILURE(rc))623 return rc;624 625 if (cbFile1 != cbFile2)626 return VERR_NOT_EQUAL;627 628 629 /*630 * Allocate buffer.631 */632 size_t cbBuf;633 uint8_t *pbBuf1Free = NULL;634 uint8_t *pbBuf1;635 uint8_t *pbBuf2Free = NULL;636 uint8_t *pbBuf2;637 if (cbFile1 < _512K)638 {639 cbBuf = 8*_1K;640 pbBuf1 = (uint8_t *)alloca(cbBuf);641 pbBuf2 = (uint8_t *)alloca(cbBuf);642 }643 else644 {645 cbBuf = _128K;646 pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf);647 pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf);648 }649 if (pbBuf1 && pbBuf2)650 {651 /*652 * Seek to the start of each file653 * and set the size of the destination file.654 */655 rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL);656 if (RT_SUCCESS(rc))657 {658 rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL);659 if (RT_SUCCESS(rc) && pfnProgress)660 rc = pfnProgress(0, pvUser);661 if (RT_SUCCESS(rc))662 {663 /*664 * Compare loop.665 */666 unsigned uPercentage = 0;667 RTFOFF off = 0;668 RTFOFF cbPercent = cbFile1 / 100;669 RTFOFF offNextPercent = cbPercent;670 while (off < (RTFOFF)cbFile1)671 {672 /* read the blocks */673 RTFOFF cbLeft = cbFile1 - off;674 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;675 rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL);676 if (RT_FAILURE(rc))677 break;678 rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL);679 if (RT_FAILURE(rc))680 break;681 682 /* compare */683 if (memcmp(pbBuf1, pbBuf2, cbBlock))684 {685 rc = VERR_NOT_EQUAL;686 break;687 }688 689 /* advance */690 off += cbBlock;691 if (pfnProgress && offNextPercent < off)692 {693 while (offNextPercent < off)694 {695 uPercentage++;696 offNextPercent += cbPercent;697 }698 rc = pfnProgress(uPercentage, pvUser);699 if (RT_FAILURE(rc))700 break;701 }702 }703 704 #if 0705 /*706 * Compare OS specific data (EAs and stuff).707 */708 if (RT_SUCCESS(rc))709 rc = rtFileCompareOSStuff(hFile1, hFile2);710 #endif711 712 /* 100% */713 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))714 rc = pfnProgress(100, pvUser);715 }716 }717 }718 else719 rc = VERR_NO_MEMORY;720 RTMemTmpFree(pbBuf2Free);721 RTMemTmpFree(pbBuf1Free);722 723 return rc;724 }725 -
trunk/src/VBox/Runtime/r3/fileio.cpp
r76553 r77209 197 197 *pfOpen = fOpen; 198 198 return VINF_SUCCESS; 199 }200 201 202 203 /**204 * Read bytes from a file at a given offset.205 * This function may modify the file position.206 *207 * @returns iprt status code.208 * @param File Handle to the file.209 * @param off Where to read.210 * @param pvBuf Where to put the bytes we read.211 * @param cbToRead How much to read.212 * @param *pcbRead How much we actually read.213 * If NULL an error will be returned for a partial read.214 */215 RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)216 {217 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);218 if (RT_SUCCESS(rc))219 rc = RTFileRead(File, pvBuf, cbToRead, pcbRead);220 return rc;221 }222 223 224 /**225 * Read bytes from a file at a given offset into a S/G buffer.226 * This function may modify the file position.227 *228 * @returns iprt status code.229 * @param hFile Handle to the file.230 * @param off Where to read.231 * @param pSgBuf Pointer to the S/G buffer to read into.232 * @param cbToRead How much to read.233 * @param pcbRead How much we actually read.234 * If NULL an error will be returned for a partial read.235 */236 RTR3DECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)237 {238 int rc = VINF_SUCCESS;239 size_t cbRead = 0;240 241 while (cbToRead)242 {243 size_t cbThisRead = 0;244 size_t cbBuf = cbToRead;245 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);246 247 rc = RTFileReadAt(hFile, off, pvBuf, cbBuf, pcbRead ? &cbThisRead : NULL);248 if (RT_SUCCESS(rc))249 cbRead += cbThisRead;250 251 if ( RT_FAILURE(rc)252 || ( cbThisRead < cbBuf253 && pcbRead))254 break;255 256 cbToRead -= cbBuf;257 off += cbBuf;258 }259 260 if (pcbRead)261 *pcbRead = cbRead;262 263 return rc;264 }265 266 267 /**268 * Write bytes to a file at a given offset.269 * This function may modify the file position.270 *271 * @returns iprt status code.272 * @param File Handle to the file.273 * @param off Where to write.274 * @param pvBuf What to write.275 * @param cbToWrite How much to write.276 * @param *pcbWritten How much we actually wrote.277 * If NULL an error will be returned for a partial write.278 */279 RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)280 {281 int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL);282 if (RT_SUCCESS(rc))283 rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten);284 return rc;285 }286 287 288 /**289 * Write bytes from a S/G buffer to a file at a given offset.290 * This function may modify the file position.291 *292 * @returns iprt status code.293 * @param hFile Handle to the file.294 * @param off Where to write.295 * @param pSgBuf What to write.296 * @param cbToWrite How much to write.297 * @param pcbWritten How much we actually wrote.298 * If NULL an error will be returned for a partial write.299 */300 RTR3DECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)301 {302 int rc = VINF_SUCCESS;303 size_t cbWritten = 0;304 305 while (cbToWrite)306 {307 size_t cbThisWritten = 0;308 size_t cbBuf = cbToWrite;309 void *pvBuf = RTSgBufGetNextSegment(pSgBuf, &cbBuf);310 311 rc = RTFileWriteAt(hFile, off, pvBuf, cbBuf, pcbWritten ? &cbThisWritten : NULL);312 if (RT_SUCCESS(rc))313 cbWritten += cbThisWritten;314 315 if ( RT_FAILURE(rc)316 || ( cbThisWritten < cbBuf317 && pcbWritten))318 break;319 320 cbToWrite -= cbBuf;321 off += cbBuf;322 }323 324 if (pcbWritten)325 *pcbWritten = cbWritten;326 327 return rc;328 199 } 329 200
Note:
See TracChangeset
for help on using the changeset viewer.