Changeset 67149 in vbox for trunk/src/VBox/Runtime/common/zip/tarvfswriter.cpp
- Timestamp:
- May 30, 2017 7:23:25 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/zip/tarvfswriter.cpp
r67134 r67149 111 111 typedef RTZIPTARSPARSE const *PCRTZIPTARSPARSE; 112 112 113 114 /** Pointer to a the private data of a TAR filesystem stream. */ 115 typedef struct RTZIPTARFSSTREAMWRITER *PRTZIPTARFSSTREAMWRITER; 116 117 118 /** 119 * Instance data for a file or I/O stream returned by 120 * RTVFSFSSTREAMOPS::pfnPushFile. 121 */ 122 typedef struct RTZIPTARFSSTREAMWRITERPUSH 123 { 124 /** Pointer to the parent FS stream writer instance. 125 * This is set to NULL should the push object live longer than the stream. */ 126 PRTZIPTARFSSTREAMWRITER pParent; 127 /** The header offset, UINT64_MAX if non-seekable output. */ 128 uint64_t offHdr; 129 /** The data offset, UINT64_MAX if non-seekable output. */ 130 uint64_t offData; 131 /** The current I/O stream position (relative to offData). */ 132 uint64_t offCurrent; 133 /** The expected size amount of file content. This is set to UINT64_MAX if 134 * open-ended file size. */ 135 uint64_t cbExpected; 136 /** The current amount of file content written. */ 137 uint64_t cbCurrent; 138 /** Object info copy for rtZipTarWriterPush_QueryInfo. */ 139 RTFSOBJINFO ObjInfo; 140 } RTZIPTARFSSTREAMWRITERPUSH; 141 /** Pointer to a push I/O instance. */ 142 typedef RTZIPTARFSSTREAMWRITERPUSH *PRTZIPTARFSSTREAMWRITERPUSH; 143 144 113 145 /** 114 146 * Tar filesystem stream private data. … … 120 152 /** Non-nil if the output is a file. */ 121 153 RTVFSFILE hVfsFile; 154 155 /** The current push file. NULL if none. */ 156 PRTZIPTARFSSTREAMWRITERPUSH pPush; 122 157 123 158 /** The TAR format. */ … … 136 171 RTZIPTARHDR aHdrs[3]; 137 172 } RTZIPTARFSSTREAMWRITER; 138 /** Pointer to a the private data of a TAR filesystem stream. */139 typedef RTZIPTARFSSTREAMWRITER *PRTZIPTARFSSTREAMWRITER;140 173 141 174 … … 143 176 * Internal Functions * 144 177 *********************************************************************************************************************************/ 178 static int rtZipTarFssWriter_CompleteCurrentPushFile(PRTZIPTARFSSTREAMWRITER pThis); 145 179 static int rtZipTarFssWriter_AddFile(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, RTVFSIOSTREAM hVfsIos, 146 180 PCRTFSOBJINFO pObjInfo, const char *pszOwnerNm, const char *pszGroupNm); … … 378 412 pThis->cHdrs = 1; 379 413 return rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrs[0]); 414 } 415 416 417 418 419 /** 420 * @interface_method_impl{RTVFSOBJOPS,pfnClose} 421 */ 422 static DECLCALLBACK(int) rtZipTarWriterPush_Close(void *pvThis) 423 { 424 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 425 PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent; 426 if (pParent) 427 { 428 if (pParent->pPush == pPush) 429 rtZipTarFssWriter_CompleteCurrentPushFile(pParent); 430 else 431 AssertFailedStmt(pPush->pParent = NULL); 432 } 433 return VINF_SUCCESS; 434 } 435 436 437 /** 438 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo} 439 */ 440 static DECLCALLBACK(int) rtZipTarWriterPush_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr) 441 { 442 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 443 444 /* Basic info (w/ additional unix attribs). */ 445 *pObjInfo = pPush->ObjInfo; 446 pObjInfo->cbObject = pPush->cbCurrent; 447 pObjInfo->cbAllocated = RT_ALIGN_64(pPush->cbCurrent, RTZIPTAR_BLOCKSIZE); 448 449 /* Additional info. */ 450 switch (enmAddAttr) 451 { 452 case RTFSOBJATTRADD_NOTHING: 453 case RTFSOBJATTRADD_UNIX: 454 Assert(pObjInfo->Attr.enmAdditional == RTFSOBJATTRADD_UNIX); 455 break; 456 457 case RTFSOBJATTRADD_UNIX_OWNER: 458 pObjInfo->Attr.u.UnixOwner.uid = pPush->ObjInfo.Attr.u.Unix.uid; 459 if (pPush->pParent) 460 strcpy(pObjInfo->Attr.u.UnixOwner.szName, pPush->pParent->aHdrs[0].Common.uname); 461 else 462 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; 463 pObjInfo->Attr.enmAdditional = enmAddAttr; 464 break; 465 466 case RTFSOBJATTRADD_UNIX_GROUP: 467 pObjInfo->Attr.u.UnixGroup.gid = pPush->ObjInfo.Attr.u.Unix.gid; 468 if (pPush->pParent) 469 strcpy(pObjInfo->Attr.u.UnixGroup.szName, pPush->pParent->aHdrs[0].Common.uname); 470 else 471 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0'; 472 pObjInfo->Attr.enmAdditional = enmAddAttr; 473 break; 474 475 case RTFSOBJATTRADD_EASIZE: 476 pObjInfo->Attr.u.EASize.cb = 0; 477 pObjInfo->Attr.enmAdditional = enmAddAttr; 478 break; 479 480 default: 481 AssertFailed(); 482 } 483 484 return VINF_SUCCESS; 485 } 486 487 488 /** 489 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead} 490 */ 491 static DECLCALLBACK(int) rtZipTarWriterPush_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead) 492 { 493 /* No read support, sorry. */ 494 RT_NOREF(pvThis, off, pSgBuf, fBlocking, pcbRead); 495 AssertFailed(); 496 return VERR_ACCESS_DENIED; 497 } 498 499 500 /** 501 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite} 502 */ 503 static DECLCALLBACK(int) rtZipTarWriterPush_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten) 504 { 505 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 506 PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent; 507 AssertPtrReturn(pParent, VERR_WRONG_ORDER); 508 Assert(!pcbWritten || !*pcbWritten /* assume caller sets this to zero so we can be lazy here */); 509 510 int rc = pParent->rcFatal; 511 AssertRCReturn(rc, rc); 512 513 /* 514 * Single segment at a time. 515 */ 516 Assert(pSgBuf->cSegs == 1); 517 size_t cbToWrite = pSgBuf->paSegs[0].cbSeg; 518 void const *pvToWrite = pSgBuf->paSegs[0].pvSeg; 519 520 /* 521 * Deal with simple non-seeking write first. 522 */ 523 Assert(pPush->offCurrent <= pPush->cbExpected); 524 Assert(pPush->offCurrent <= pPush->cbCurrent); 525 if ( off < 0 526 || (uint64_t)off == pPush->offCurrent) 527 { 528 AssertMsgReturn(cbToWrite <= pPush->cbExpected - pPush->offCurrent, 529 ("offCurrent=%#RX64 + cbToWrite=%#zx = %#RX64; cbExpected=%RX64\n", 530 pPush->offCurrent, cbToWrite, pPush->offCurrent + cbToWrite, pPush->cbExpected), 531 VERR_DISK_FULL); 532 size_t cbWritten = 0; 533 rc = RTVfsIoStrmWrite(pParent->hVfsIos, pvToWrite, cbToWrite, fBlocking, &cbWritten); 534 if (RT_SUCCESS(rc)) 535 { 536 pPush->offCurrent += cbWritten; 537 if (pPush->offCurrent > pPush->cbCurrent) 538 { 539 pParent->cbWritten = pPush->offCurrent - pPush->cbCurrent; 540 pPush->cbCurrent = pPush->offCurrent; 541 } 542 } 543 } 544 /* 545 * Needs to seek, more validation, possible zero filling of the space in between. 546 */ 547 else 548 { 549 AssertMsgReturn((uint64_t)off <= pPush->cbExpected, 550 ("off=%#RX64 cbExpected=%#RX64", (uint64_t)off, pPush->cbExpected), 551 VERR_SEEK); 552 AssertMsgReturn(cbToWrite <= pPush->cbExpected - (uint64_t)off, 553 ("off=%#RX64 + cbToWrite=%#zx = %#RX64; cbExpected=%RX64\n", 554 (uint64_t)off, cbToWrite, (uint64_t)off + cbToWrite, pPush->cbExpected), 555 VERR_DISK_FULL); 556 557 /* Zero fill seek gap if necessary. */ 558 if ((uint64_t)off > pPush->cbCurrent) 559 { 560 if (pPush->offCurrent == pPush->cbCurrent) 561 rc = VINF_SUCCESS; 562 else 563 { 564 AssertReturn(pParent->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE); 565 rc = RTVfsFileSeek(pParent->hVfsFile, pPush->offData + pPush->cbCurrent, RTFILE_SEEK_BEGIN, NULL); 566 if (RT_SUCCESS(rc)) 567 pPush->offCurrent = pPush->cbCurrent; 568 } 569 570 if (RT_SUCCESS(rc)) 571 { 572 uint64_t cbToZero = (uint64_t)off - pPush->cbCurrent; 573 rc = RTVfsIoStrmZeroFill(pParent->hVfsIos, cbToZero); 574 if (RT_SUCCESS(rc)) 575 { 576 pPush->offCurrent += cbToZero; 577 pParent->cbWritten += cbToZero; 578 } 579 } 580 } 581 /* Seek backwards to the desired position. */ 582 else 583 { 584 AssertReturn(pParent->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE); 585 rc = RTVfsFileSeek(pParent->hVfsFile, pPush->offData + (uint64_t)off, RTFILE_SEEK_BEGIN, NULL); 586 if (RT_SUCCESS(rc)) 587 pPush->offCurrent = (uint64_t)off; 588 } 589 590 /* Do the write. */ 591 if (RT_SUCCESS(rc)) 592 { 593 size_t cbWritten = 0; 594 rc = RTVfsIoStrmWrite(pParent->hVfsIos, pvToWrite, cbToWrite, fBlocking, &cbWritten); 595 if (RT_SUCCESS(rc)) 596 { 597 pPush->offCurrent += cbWritten; 598 if (pPush->offCurrent > pPush->cbCurrent) 599 { 600 pParent->cbWritten = pPush->offCurrent - pPush->cbCurrent; 601 pPush->cbCurrent = pPush->offCurrent; 602 } 603 } 604 } 605 } 606 607 /* 608 * Fatal errors get down here, non-fatal ones returns earlier. 609 */ 610 if (RT_SUCCESS(rc)) 611 return VINF_SUCCESS; 612 pParent->rcFatal = rc; 613 return rc; 614 } 615 616 617 /** 618 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush} 619 */ 620 static DECLCALLBACK(int) rtZipTarWriterPush_Flush(void *pvThis) 621 { 622 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 623 PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent; 624 AssertPtrReturn(pParent, VERR_WRONG_ORDER); 625 int rc = pParent->rcFatal; 626 if (RT_SUCCESS(rc)) 627 pParent->rcFatal = rc = RTVfsIoStrmFlush(pParent->hVfsIos); 628 return rc; 629 } 630 631 632 /** 633 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne} 634 */ 635 static DECLCALLBACK(int) rtZipTarWriterPush_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, 636 uint32_t *pfRetEvents) 637 { 638 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 639 PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent; 640 AssertPtrReturn(pParent, VERR_WRONG_ORDER); 641 return RTVfsIoStrmPoll(pParent->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents); 642 } 643 644 645 /** 646 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell} 647 */ 648 static DECLCALLBACK(int) rtZipTarWriterPush_Tell(void *pvThis, PRTFOFF poffActual) 649 { 650 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 651 *poffActual = (RTFOFF)pPush->offCurrent; 652 return VINF_SUCCESS; 653 } 654 655 656 /** 657 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip} 658 */ 659 static DECLCALLBACK(int) rtZipTarWriterPush_Skip(void *pvThis, RTFOFF cb) 660 { 661 RT_NOREF(pvThis, cb); 662 AssertFailed(); 663 return VERR_ACCESS_DENIED; 664 } 665 666 667 /** 668 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode} 669 */ 670 static DECLCALLBACK(int) rtZipTarWriterPush_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask) 671 { 672 RT_NOREF(pvThis, fMode, fMask); 673 AssertFailed(); 674 return VERR_ACCESS_DENIED; 675 } 676 677 678 /** 679 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes} 680 */ 681 static DECLCALLBACK(int) rtZipTarWriterPush_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, 682 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime) 683 { 684 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime); 685 AssertFailed(); 686 return VERR_ACCESS_DENIED; 687 } 688 689 690 /** 691 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner} 692 */ 693 static DECLCALLBACK(int) rtZipTarWriterPush_SetOwner(void *pvThis, RTUID uid, RTGID gid) 694 { 695 RT_NOREF(pvThis, uid, gid); 696 AssertFailed(); 697 return VERR_ACCESS_DENIED; 698 } 699 700 701 /** 702 * @interface_method_impl{RTVFSFILEOPS,pfnSeek} 703 */ 704 static DECLCALLBACK(int) rtZipTarWriterPush_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual) 705 { 706 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 707 PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent; 708 AssertPtrReturn(pParent, VERR_WRONG_ORDER); 709 710 int rc = pParent->rcFatal; 711 AssertRCReturn(rc, rc); 712 713 /* 714 * Calculate the new file offset. 715 */ 716 uint64_t offNew; 717 switch (uMethod) 718 { 719 case RTFILE_SEEK_BEGIN: 720 AssertReturn(offSeek >= 0, VERR_NEGATIVE_SEEK); 721 offNew = (uint64_t)offSeek; 722 break; 723 724 case RTFILE_SEEK_CURRENT: 725 if (offSeek >= 0) 726 { 727 offNew = (uint64_t)offSeek + pPush->offCurrent; 728 AssertReturn(offNew >= pPush->offCurrent, VERR_SEEK); 729 } 730 else if ((uint64_t)-offSeek <= pPush->offCurrent) 731 offNew = 0; 732 else 733 offNew = pPush->offCurrent + offSeek; 734 break; 735 736 case RTFILE_SEEK_END: 737 if (offSeek >= 0) 738 { 739 offNew = (uint64_t)offSeek + pPush->cbCurrent; 740 AssertReturn(offNew >= pPush->cbCurrent, VERR_SEEK); 741 } 742 else if ((uint64_t)-offSeek <= pPush->cbCurrent) 743 offNew = 0; 744 else 745 offNew = pPush->cbCurrent + offSeek; 746 break; 747 748 default: 749 AssertFailedReturn(VERR_INTERNAL_ERROR_5); 750 } 751 752 /* 753 * Check the new file offset against expectations. 754 */ 755 AssertMsgReturn(offNew <= pPush->cbExpected, ("offNew=%#RX64 cbExpected=%#Rx64\n", offNew, pPush->cbExpected), VERR_SEEK); 756 757 /* 758 * Any change at all? We can always hope... 759 */ 760 if (offNew == pPush->offCurrent) 761 { } 762 /* 763 * Gap that needs zero filling? 764 */ 765 else if (offNew > pPush->cbCurrent) 766 { 767 if (pPush->offCurrent != pPush->cbCurrent) 768 { 769 AssertReturn(pParent->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE); 770 rc = RTVfsFileSeek(pParent->hVfsFile, pPush->offData + pPush->cbCurrent, RTFILE_SEEK_BEGIN, NULL); 771 if (RT_FAILURE(rc)) 772 return pParent->rcFatal = rc; 773 pPush->offCurrent = pPush->cbCurrent; 774 } 775 776 uint64_t cbToZero = offNew - pPush->cbCurrent; 777 rc = RTVfsIoStrmZeroFill(pParent->hVfsIos, cbToZero); 778 if (RT_FAILURE(rc)) 779 return pParent->rcFatal = rc; 780 pParent->cbWritten += cbToZero; 781 pPush->cbCurrent = pPush->offCurrent = offNew; 782 } 783 /* 784 * Just change the file positions. 785 */ 786 else 787 { 788 AssertReturn(pParent->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE); 789 rc = RTVfsFileSeek(pParent->hVfsFile, pPush->offData + offNew, RTFILE_SEEK_BEGIN, NULL); 790 if (RT_FAILURE(rc)) 791 return pParent->rcFatal = rc; 792 pPush->offCurrent = offNew; 793 } 794 795 *poffActual = pPush->offCurrent; 796 return VINF_SUCCESS; 797 } 798 799 800 /** 801 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize} 802 */ 803 static DECLCALLBACK(int) rtZipTarWriterPush_QuerySize(void *pvThis, uint64_t *pcbFile) 804 { 805 PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis; 806 *pcbFile = pPush->cbCurrent; 807 return VINF_SUCCESS; 808 } 809 810 811 /** 812 * TAR writer push I/O stream operations. 813 */ 814 DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtZipTarWriterIoStrmOps = 815 { 816 { /* Obj */ 817 RTVFSOBJOPS_VERSION, 818 RTVFSOBJTYPE_IO_STREAM, 819 "TAR push I/O Stream", 820 rtZipTarWriterPush_Close, 821 rtZipTarWriterPush_QueryInfo, 822 RTVFSOBJOPS_VERSION 823 }, 824 RTVFSIOSTREAMOPS_VERSION, 825 RTVFSIOSTREAMOPS_FEAT_NO_SG, 826 rtZipTarWriterPush_Read, 827 rtZipTarWriterPush_Write, 828 rtZipTarWriterPush_Flush, 829 rtZipTarWriterPush_PollOne, 830 rtZipTarWriterPush_Tell, 831 rtZipTarWriterPush_Skip, 832 NULL /*ZeroFill*/, 833 RTVFSIOSTREAMOPS_VERSION, 834 }; 835 836 837 /** 838 * TAR writer push file operations. 839 */ 840 DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtZipTarWriterFileOps = 841 { 842 { /* Stream */ 843 { /* Obj */ 844 RTVFSOBJOPS_VERSION, 845 RTVFSOBJTYPE_FILE, 846 "TAR push file", 847 rtZipTarWriterPush_Close, 848 rtZipTarWriterPush_QueryInfo, 849 RTVFSOBJOPS_VERSION 850 }, 851 RTVFSIOSTREAMOPS_VERSION, 852 RTVFSIOSTREAMOPS_FEAT_NO_SG, 853 rtZipTarWriterPush_Read, 854 rtZipTarWriterPush_Write, 855 rtZipTarWriterPush_Flush, 856 rtZipTarWriterPush_PollOne, 857 rtZipTarWriterPush_Tell, 858 rtZipTarWriterPush_Skip, 859 NULL /*ZeroFill*/, 860 RTVFSIOSTREAMOPS_VERSION, 861 }, 862 RTVFSFILEOPS_VERSION, 863 0, 864 { /* ObjSet */ 865 RTVFSOBJSETOPS_VERSION, 866 RT_OFFSETOF(RTVFSFILEOPS, Stream.Obj) - RT_OFFSETOF(RTVFSFILEOPS, ObjSet), 867 rtZipTarWriterPush_SetMode, 868 rtZipTarWriterPush_SetTimes, 869 rtZipTarWriterPush_SetOwner, 870 RTVFSOBJSETOPS_VERSION 871 }, 872 rtZipTarWriterPush_Seek, 873 rtZipTarWriterPush_QuerySize, 874 RTVFSFILEOPS_VERSION 875 }; 876 877 878 879 /** 880 * Checks rcFatal and completes any current push file. 881 * 882 * On return the output stream position will be at the next header location. 883 * 884 * After this call, the push object no longer can write anything. 885 * 886 * @returns IPRT status code. 887 * @param pThis The TAR writer instance. 888 */ 889 static int rtZipTarFssWriter_CompleteCurrentPushFile(PRTZIPTARFSSTREAMWRITER pThis) 890 { 891 /* 892 * Check if there is a push file pending, remove it if there is. 893 * We also check for fatal errors at this point so the caller doesn't need to. 894 */ 895 PRTZIPTARFSSTREAMWRITERPUSH pPush = pThis->pPush; 896 if (!pPush) 897 { 898 AssertRC(pThis->rcFatal); 899 return pThis->rcFatal; 900 } 901 902 pThis->pPush = NULL; 903 pPush->pParent = NULL; 904 905 int rc = pThis->rcFatal; 906 AssertRCReturn(rc, rc); 907 908 /* 909 * Do we need to update the header. pThis->aHdrs[0] will retain the current 910 * content at pPush->offHdr and we only need to update the size. 911 */ 912 if (pPush->cbExpected == UINT64_MAX) 913 { 914 rc = rtZipTarFssWriter_FormatOffset(pThis->aHdrs[0].Common.size, pPush->cbCurrent); 915 if (RT_SUCCESS(rc)) 916 rc = rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrs[0]); 917 if (RT_SUCCESS(rc)) 918 { 919 rc = RTVfsFileWriteAt(pThis->hVfsFile, pPush->offHdr, &pThis->aHdrs[0], sizeof(pThis->aHdrs[0]), NULL); 920 if (RT_SUCCESS(rc)) 921 rc = RTVfsFileSeek(pThis->hVfsFile, pPush->offData + pPush->cbCurrent, RTFILE_SEEK_BEGIN, NULL); 922 } 923 } 924 /* 925 * Check that we've received all the data we were promissed in the PushFile 926 * call, fail if we weren't. 927 */ 928 else 929 AssertMsgStmt(pPush->cbCurrent == pPush->cbExpected, 930 ("cbCurrent=%#RX64 cbExpected=%#RX64\n", pPush->cbCurrent, pPush->cbExpected), 931 rc = VERR_BUFFER_UNDERFLOW); 932 if (RT_SUCCESS(rc)) 933 { 934 /* 935 * Do zero padding if necessary. 936 */ 937 if (pPush->cbCurrent & (RTZIPTAR_BLOCKSIZE - 1)) 938 { 939 size_t cbToZero = RTZIPTAR_BLOCKSIZE - (pPush->cbCurrent & (RTZIPTAR_BLOCKSIZE - 1)); 940 rc = RTVfsIoStrmWrite(pThis->hVfsIos, g_abRTZero4K, cbToZero, true /*fBlocking*/, NULL); 941 if (RT_SUCCESS(rc)) 942 pThis->cbWritten += cbToZero; 943 } 944 } 945 946 if (RT_SUCCESS(rc)) 947 return VINF_SUCCESS; 948 pThis->rcFatal = rc; 949 return rc; 380 950 } 381 951 … … 1100 1670 PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis; 1101 1671 1672 rtZipTarFssWriter_CompleteCurrentPushFile(pThis); 1673 1102 1674 RTVfsIoStrmRelease(pThis->hVfsIos); 1103 1675 pThis->hVfsIos = NIL_RTVFSIOSTREAM; … … 1133 1705 1134 1706 /* 1135 * Refuse to do anything if we've encountered a fatal error. 1136 * Assert this because the caller should know better than calling us again. 1137 */ 1138 AssertRCReturn(pThis->rcFatal, pThis->rcFatal); 1707 * Before we continue we must complete any current push file and check rcFatal. 1708 */ 1709 int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis); 1710 if (RT_FAILURE(rc)) 1711 return rc; 1139 1712 1140 1713 /* … … 1142 1715 */ 1143 1716 RTFSOBJINFO ObjInfo; 1144 intrc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_UNIX);1717 rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_UNIX); 1145 1718 AssertRCReturn(rc, rc); 1146 1719 … … 1203 1776 1204 1777 /** 1778 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnPushFile} 1779 */ 1780 static DECLCALLBACK(int) rtZipTarFssWriter_PushFile(void *pvThis, const char *pszPath, uint64_t cbFile, PCRTFSOBJINFO paObjInfo, 1781 uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos) 1782 { 1783 PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis; 1784 1785 /* 1786 * We can only deal with output of indeterminate length if the output is 1787 * seekable (see also rtZipTarFssWriter_AddFileStream). 1788 */ 1789 AssertReturn(cbFile != UINT64_MAX || pThis->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE); 1790 AssertReturn(RT_BOOL(cbFile == UINT64_MAX) == RT_BOOL(fFlags & RTVFSFSSTRM_ADD_F_STREAM), VERR_INVALID_FLAGS); 1791 1792 /* 1793 * Before we continue we must complete any current push file and check rcFatal. 1794 */ 1795 int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis); 1796 if (RT_FAILURE(rc)) 1797 return rc; 1798 1799 /* 1800 * If no object info was provideded, fake up some. 1801 */ 1802 const char *pszOwnerNm = "someone"; 1803 const char *pszGroupNm = "somegroup"; 1804 RTFSOBJINFO ObjInfo; 1805 if (cObjInfo == 0) 1806 { 1807 /* Fake up a info. */ 1808 RT_ZERO(ObjInfo); 1809 ObjInfo.cbObject = cbFile != UINT64_MAX ? cbFile : 0; 1810 ObjInfo.cbAllocated = cbFile != UINT64_MAX ? RT_ALIGN_64(cbFile, RTZIPTAR_BLOCKSIZE) : UINT64_MAX; 1811 RTTimeNow(&ObjInfo.ModificationTime); 1812 ObjInfo.BirthTime = ObjInfo.ModificationTime; 1813 ObjInfo.ChangeTime = ObjInfo.ModificationTime; 1814 ObjInfo.AccessTime = ObjInfo.ModificationTime; 1815 ObjInfo.Attr.fMode = RTFS_TYPE_FILE | 0666; 1816 ObjInfo.Attr.enmAdditional = RTFSOBJATTRADD_UNIX; 1817 ObjInfo.Attr.u.Unix.uid = NIL_RTUID; 1818 ObjInfo.Attr.u.Unix.gid = NIL_RTGID; 1819 ObjInfo.Attr.u.Unix.cHardlinks = 1; 1820 //ObjInfo.Attr.u.Unix.INodeIdDevice = 0; 1821 //ObjInfo.Attr.u.Unix.INodeId = 0; 1822 //ObjInfo.Attr.u.Unix.fFlags = 0; 1823 //ObjInfo.Attr.u.Unix.GenerationId = 0; 1824 //ObjInfo.Attr.u.Unix.Device = 0; 1825 } 1826 else 1827 { 1828 /* Make a copy of the object info and adjust the size, if necessary. */ 1829 ObjInfo = paObjInfo[0]; 1830 Assert(ObjInfo.Attr.enmAdditional == RTFSOBJATTRADD_UNIX); 1831 Assert(RTFS_IS_FILE(ObjInfo.Attr.fMode)); 1832 if ((uint64_t)ObjInfo.cbObject != cbFile) 1833 { 1834 ObjInfo.cbObject = cbFile != UINT64_MAX ? cbFile : 0; 1835 ObjInfo.cbAllocated = cbFile != UINT64_MAX ? RT_ALIGN_64(cbFile, RTZIPTAR_BLOCKSIZE) : UINT64_MAX; 1836 } 1837 1838 /* Lookup the group and user names. */ 1839 for (uint32_t i = 0; i < cObjInfo; i++) 1840 if ( paObjInfo[i].Attr.enmAdditional == RTFSOBJATTRADD_UNIX_OWNER 1841 && paObjInfo[i].Attr.u.UnixOwner.szName[0] != '\0') 1842 pszOwnerNm = paObjInfo[i].Attr.u.UnixOwner.szName; 1843 else if ( paObjInfo[i].Attr.enmAdditional == RTFSOBJATTRADD_UNIX_GROUP 1844 && paObjInfo[i].Attr.u.UnixGroup.szName[0] != '\0') 1845 pszGroupNm = paObjInfo[i].Attr.u.UnixGroup.szName; 1846 } 1847 1848 /* 1849 * Create an I/O stream object for the caller to use. 1850 */ 1851 PRTZIPTARFSSTREAMWRITERPUSH pPush; 1852 RTVFSIOSTREAM hVfsIos; 1853 if (pThis->hVfsFile == NIL_RTVFSFILE) 1854 { 1855 rc = RTVfsNewIoStream(&g_rtZipTarWriterIoStrmOps, sizeof(*pPush), RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK, 1856 &hVfsIos, (void **)&pPush); 1857 if (RT_FAILURE(rc)) 1858 return rc; 1859 } 1860 else 1861 { 1862 RTVFSFILE hVfsFile; 1863 rc = RTVfsNewFile(&g_rtZipTarWriterFileOps, sizeof(*pPush), RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK, 1864 &hVfsFile, (void **)&pPush); 1865 if (RT_FAILURE(rc)) 1866 return rc; 1867 hVfsIos = RTVfsFileToIoStream(hVfsFile); 1868 RTVfsFileRelease(hVfsFile); 1869 } 1870 pPush->pParent = NULL; 1871 pPush->cbExpected = cbFile; 1872 pPush->offHdr = RTVfsIoStrmTell(pThis->hVfsIos); 1873 pPush->offData = 0; 1874 pPush->offCurrent = 0; 1875 pPush->cbCurrent = 0; 1876 pPush->ObjInfo = ObjInfo; 1877 1878 /* 1879 * Produce and write file headers. 1880 */ 1881 rc = rtZipTarFssWriter_ObjInfoToHdr(pThis, pszPath, &ObjInfo, pszOwnerNm, pszGroupNm, RTZIPTAR_TF_NORMAL); 1882 if (RT_SUCCESS(rc)) 1883 { 1884 rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->aHdrs, pThis->cHdrs * sizeof(pThis->aHdrs[0]), true /*fBlocking*/, NULL); 1885 if (RT_SUCCESS(rc)) 1886 { 1887 pThis->cbWritten += pThis->cHdrs * sizeof(pThis->aHdrs[0]); 1888 1889 /* 1890 * Complete the object and return. 1891 */ 1892 pPush->offData = RTVfsIoStrmTell(pThis->hVfsIos); 1893 pPush->pParent = pThis; 1894 pThis->pPush = pPush; 1895 1896 *phVfsIos = hVfsIos; 1897 return VINF_SUCCESS; 1898 } 1899 pThis->rcFatal = rc; 1900 } 1901 1902 RTVfsIoStrmRelease(hVfsIos); 1903 return rc; 1904 } 1905 1906 1907 /** 1205 1908 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnEnd} 1206 1909 */ … … 1208 1911 { 1209 1912 PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis; 1210 int rc = pThis->rcFatal; 1913 1914 /* 1915 * Make sure to complete any pending push file and that rcFatal is fine. 1916 */ 1917 int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis); 1211 1918 if (RT_SUCCESS(rc)) 1212 1919 { … … 1251 1958 NULL, 1252 1959 rtZipTarFssWriter_Add, 1960 rtZipTarFssWriter_PushFile, 1253 1961 rtZipTarFssWriter_End, 1254 1962 RTVFSFSSTREAMOPS_VERSION
Note:
See TracChangeset
for help on using the changeset viewer.