Changeset 33289 in vbox for trunk/src/VBox/Runtime/common/misc/tar.cpp
- Timestamp:
- Oct 21, 2010 10:00:15 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/tar.cpp
r33058 r33289 92 92 #endif 93 93 94 typedef struct RTTARFILEINTERNAL* PRTTARFILEINTERNAL; 94 95 typedef struct RTTARINTERNAL 95 96 { … … 98 99 bool fFileOpenForWrite; 99 100 uint32_t fOpenMode; 101 bool fStreamMode; 102 PRTTARFILEINTERNAL pFileCache; 100 103 } RTTARINTERNAL; 101 104 typedef RTTARINTERNAL* PRTTARINTERNAL; … … 275 278 276 279 return rc; 280 } 281 282 DECLINLINE(PRTTARFILEINTERNAL) rtCreateTarFileInternal(PRTTARINTERNAL pInt, const char *pszFilename, uint32_t fOpen) 283 { 284 PRTTARFILEINTERNAL pFileInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL)); 285 if (!pFileInt) 286 return NULL; 287 288 pFileInt->u32Magic = RTTARFILE_MAGIC; 289 pFileInt->pTar = pInt; 290 pFileInt->pszFilename = RTStrDup(pszFilename); 291 pFileInt->fOpenMode = fOpen; 292 293 return pFileInt; 294 } 295 296 DECLINLINE(PRTTARFILEINTERNAL) rtCopyTarFileInternal(PRTTARFILEINTERNAL pInt) 297 { 298 PRTTARFILEINTERNAL pNewInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL)); 299 if (!pNewInt) 300 return NULL; 301 302 memcpy(pNewInt, pInt, sizeof(RTTARFILEINTERNAL)); 303 pNewInt->pszFilename = RTStrDup(pInt->pszFilename); 304 305 return pNewInt; 306 } 307 308 DECLINLINE(void) rtDeleteTarFileInternal(PRTTARFILEINTERNAL pInt) 309 { 310 if (pInt) 311 { 312 if (pInt->pszFilename) 313 RTStrFree(pInt->pszFilename); 314 pInt->u32Magic = RTTARFILE_MAGIC_DEAD; 315 RTMemFree(pInt); 316 } 277 317 } 278 318 … … 563 603 ******************************************************************************/ 564 604 565 RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char* pszTarname, uint32_t fMode )605 RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char* pszTarname, uint32_t fMode, bool fStream) 566 606 { 567 607 PRTTARINTERNAL pInt = (PRTTARINTERNAL)RTMemAllocZ(sizeof(RTTARINTERNAL)); … … 571 611 pInt->u32Magic = RTTAR_MAGIC; 572 612 pInt->fOpenMode = fMode; 613 pInt->fStreamMode = fStream && (fMode & RTFILE_O_READ); 573 614 574 615 int rc = VINF_SUCCESS; … … 618 659 rc = RTFileClose(pInt->hTarFile); 619 660 661 /* Delete any remaining cached file headers. */ 662 if (pInt->pFileCache) 663 { 664 rtDeleteTarFileInternal(pInt->pFileCache); 665 pInt->pFileCache = 0; 666 } 667 620 668 pInt->u32Magic = RTTAR_MAGIC_DEAD; 621 669 … … 634 682 if (!pInt->hTarFile) 635 683 return VERR_INVALID_HANDLE; 684 685 if (pInt->fStreamMode) 686 return VERR_INVALID_STATE; 636 687 637 688 if (fOpen & RTFILE_O_WRITE) … … 643 694 } 644 695 645 PRTTARFILEINTERNAL pFileInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL));696 PRTTARFILEINTERNAL pFileInt = rtCreateTarFileInternal(pInt, pszFilename, fOpen); 646 697 if (!pFileInt) 647 698 return VERR_NO_MEMORY; 648 699 649 pFileInt->u32Magic = RTTARFILE_MAGIC;650 651 700 int rc = VINF_SUCCESS; 652 701 do 653 702 { 654 pFileInt->pTar = pInt;655 pFileInt->pszFilename = RTStrDup(pszFilename);656 pFileInt->uStart = 0;657 pFileInt->cbSize = 0;658 pFileInt->cbSetSize = 0;659 pFileInt->fOpenMode = fOpen;660 pFileInt->uCurrentPos = 0;661 662 703 if (pFileInt->fOpenMode & RTFILE_O_WRITE) 663 704 { … … 718 759 719 760 /* In write mode: */ 720 if (pFileInt->fOpenMode & RTFILE_O_WRITE) 761 if (pFileInt->fOpenMode & RTFILE_O_READ) 762 { 763 /* In read mode, we want to make sure to stay at the aligned end of this 764 * file, so the next file could be read immediately. */ 765 uint64_t uCurPos = RTFileTell(pFileInt->pTar->hTarFile); 766 /* Check that the file pointer is somewhere within the last open file. 767 * If we are at the beginning (nothing read yet) nothing will be done. 768 * A user could open/close a file more than once, without reading 769 * something. */ 770 if (pFileInt->uStart + sizeof(RTTARRECORD) < uCurPos && uCurPos < RT_ALIGN(pFileInt->uStart + sizeof(RTTARRECORD) + pFileInt->cbSize, sizeof(RTTARRECORD))) 771 { 772 /* Seek to the next file header. */ 773 uint64_t uNextPos = RT_ALIGN(pFileInt->uStart + sizeof(RTTARRECORD) + pFileInt->cbSize, sizeof(RTTARRECORD)); 774 rc = RTFileSeek(pFileInt->pTar->hTarFile, uNextPos - uCurPos, RTFILE_SEEK_CURRENT, NULL); 775 } 776 } 777 else if (pFileInt->fOpenMode & RTFILE_O_WRITE) 721 778 { 722 779 pFileInt->pTar->fFileOpenForWrite = false; … … 756 813 while(0); 757 814 } 758 /* Nothing special in readmode. */759 815 760 816 /* Now cleanup and delete the handle */ 761 RTStrFree(pFileInt->pszFilename); 762 pFileInt->u32Magic = RTTARFILE_MAGIC_DEAD; 763 RTMemFree(pFileInt); 817 rtDeleteTarFileInternal(pFileInt); 764 818 765 819 return rc; … … 770 824 PRTTARFILEINTERNAL pFileInt = hFile; 771 825 RTTARFILE_VALID_RETURN(pFileInt); 826 827 if (pFileInt->pTar->fStreamMode) 828 return VERR_INVALID_STATE; 772 829 773 830 switch (uMethod) … … 822 879 RTTARFILE_VALID_RETURN(pFileInt); 823 880 881 /* Check that we not read behind the end of file. If so return immediately. */ 882 if (uOffset > pFileInt->cbSize) 883 { 884 if (pcbRead) 885 *pcbRead = 0; 886 return VINF_SUCCESS; /* ??? VERR_EOF */ 887 } 888 889 size_t cbToCopy = RT_MIN(pFileInt->cbSize - uOffset, cbToRead); 824 890 size_t cbTmpRead = 0; 825 int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbTo Read, &cbTmpRead);891 int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbToCopy, &cbTmpRead); 826 892 pFileInt->uCurrentPos = uOffset + cbTmpRead; 827 893 if (pcbRead) … … 1021 1087 /* Open the tar file */ 1022 1088 RTTAR hTar; 1023 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE );1089 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, false); 1024 1090 if (RT_FAILURE(rc)) 1025 1091 return rc; … … 1045 1111 /* Open the tar file */ 1046 1112 RTTAR hTar; 1047 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE );1113 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, false); 1048 1114 if (RT_FAILURE(rc)) 1049 1115 return rc; … … 1152 1218 do 1153 1219 { 1154 rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE );1220 rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, false); 1155 1221 if (RT_FAILURE(rc)) 1156 1222 break; … … 1215 1281 /* Open the tar file */ 1216 1282 RTTAR hTar; 1217 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE );1283 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, false); 1218 1284 if (RT_FAILURE(rc)) 1219 1285 return rc; … … 1286 1352 1287 1353 RTTAR hTar; 1288 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_CREATE | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE );1354 int rc = RTTarOpen(&hTar, pszTarFile, RTFILE_O_CREATE | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE, false); 1289 1355 if (RT_FAILURE(rc)) 1290 1356 return rc; … … 1316 1382 } 1317 1383 1384 /****************************************************************************** 1385 * Streaming Functions * 1386 ******************************************************************************/ 1387 1388 RTR3DECL(int) RTTarCurrentFile(RTTAR hTar, char **ppszFilename) 1389 { 1390 /* Validate input. */ 1391 AssertPtrNullReturn(ppszFilename, VERR_INVALID_POINTER); 1392 1393 PRTTARINTERNAL pInt = hTar; 1394 RTTAR_VALID_RETURN(pInt); 1395 1396 /* Open and close the file on the current position. This makes sure the 1397 * cache is filled in case we never read something before. On success it 1398 * will return the current filename. */ 1399 RTTARFILE hFile; 1400 int rc = RTTarFileOpenCurrentFile(hTar, &hFile, ppszFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE); 1401 if (RT_SUCCESS(rc)) 1402 RTTarFileClose(hFile); 1403 1404 return rc; 1405 } 1406 1407 RTR3DECL(int) RTTarSeekNextFile(RTTAR hTar) 1408 { 1409 PRTTARINTERNAL pInt = hTar; 1410 RTTAR_VALID_RETURN(pInt); 1411 1412 int rc = VINF_SUCCESS; 1413 1414 if (!pInt->fStreamMode) 1415 return VERR_INVALID_STATE; 1416 1417 /* If there is nothing in the cache, it means we never read something. Just 1418 * ask for the current filename to fill the cache. */ 1419 if (!pInt->pFileCache) 1420 { 1421 rc = RTTarCurrentFile(hTar, 0); 1422 if (RT_FAILURE(rc)) 1423 return rc; 1424 } 1425 1426 /* Check that the file pointer is somewhere within the last open file. 1427 * If not we are somehow busted. */ 1428 uint64_t uCurPos = RTFileTell(pInt->hTarFile); 1429 if (!(pInt->pFileCache->uStart <= uCurPos && uCurPos < pInt->pFileCache->uStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize)) 1430 return VERR_INVALID_STATE; 1431 1432 /* Seek to the next file header. */ 1433 uint64_t uNextPos = RT_ALIGN(pInt->pFileCache->uStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize, sizeof(RTTARRECORD)); 1434 rc = RTFileSeek(pInt->hTarFile, uNextPos - uCurPos, RTFILE_SEEK_CURRENT, NULL); 1435 if (RT_FAILURE(rc)) 1436 return rc; 1437 1438 /* Again check the current filename to fill the cache with the new value. */ 1439 return RTTarCurrentFile(hTar, 0); 1440 } 1441 1442 RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **ppszFilename, uint32_t fOpen) 1443 { 1444 /* Validate input. */ 1445 AssertPtrReturn(phFile, VERR_INVALID_POINTER); 1446 AssertPtrNullReturn(ppszFilename, VERR_INVALID_POINTER); 1447 AssertReturn((fOpen & RTFILE_O_READ), VERR_INVALID_PARAMETER); /* Only valid in read mode. */ 1448 1449 PRTTARINTERNAL pInt = hTar; 1450 RTTAR_VALID_RETURN(pInt); 1451 1452 if (!pInt->fStreamMode) 1453 return VERR_INVALID_STATE; 1454 1455 int rc = VINF_SUCCESS; 1456 1457 /* Is there some cached entry? */ 1458 if (pInt->pFileCache) 1459 { 1460 /* Are we still direct behind that header? */ 1461 if (pInt->pFileCache->uStart + sizeof(RTTARRECORD) == RTFileTell(pInt->hTarFile)) 1462 { 1463 /* Yes, so the streaming can start. Just return the cached file 1464 * structure to the caller. */ 1465 *phFile = rtCopyTarFileInternal(pInt->pFileCache); 1466 if (ppszFilename) 1467 *ppszFilename = RTStrDup(pInt->pFileCache->pszFilename); 1468 return VINF_SUCCESS; 1469 }else 1470 { 1471 /* Else delete the last open file cache. Might be recreated below. */ 1472 rtDeleteTarFileInternal(pInt->pFileCache); 1473 pInt->pFileCache = 0; 1474 } 1475 } 1476 1477 PRTTARFILEINTERNAL pFileInt = 0; 1478 do 1479 { 1480 /* Try to read a header entry from the current position. If we aren't 1481 * on a header record, the header checksum will show and an error will 1482 * be returned. */ 1483 RTTARRECORD record; 1484 /* Read & verify a header record */ 1485 rc = rtTarReadHeaderRecord(pInt->hTarFile, &record); 1486 /* Check for error or EOF. */ 1487 if (RT_FAILURE(rc)) 1488 break; 1489 /* We support normal files only */ 1490 if ( record.h.linkflag == LF_OLDNORMAL 1491 || record.h.linkflag == LF_NORMAL) 1492 { 1493 pFileInt = rtCreateTarFileInternal(pInt, record.h.name, fOpen); 1494 if (!pFileInt) 1495 { 1496 rc = VERR_NO_MEMORY; 1497 break; 1498 } 1499 /* Get the file size */ 1500 rc = RTStrToUInt64Full(record.h.size, 8, &pFileInt->cbSize); 1501 if (RT_FAILURE(rc)) 1502 break; 1503 /* The start is -512 from here. */ 1504 pFileInt->uStart = RTFileTell(pInt->hTarFile) - sizeof(RTTARRECORD); 1505 /* Copy the new file structure to our cache. */ 1506 pInt->pFileCache = rtCopyTarFileInternal(pFileInt); 1507 if (ppszFilename) 1508 *ppszFilename = RTStrDup(pFileInt->pszFilename); 1509 } 1510 }while (0); 1511 1512 if (RT_FAILURE(rc)) 1513 { 1514 if (pFileInt) 1515 rtDeleteTarFileInternal(pFileInt); 1516 } 1517 else 1518 *phFile = pFileInt; 1519 1520 return rc; 1521 } 1522
Note:
See TracChangeset
for help on using the changeset viewer.