VirtualBox

Ignore:
Timestamp:
May 30, 2017 7:23:25 PM (8 years ago)
Author:
vboxsync
Message:

IPRT/vfstarwriter.cpp: Early version of API for pushing file data into the FS stream.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/zip/tarvfswriter.cpp

    r67134 r67149  
    111111typedef RTZIPTARSPARSE const *PCRTZIPTARSPARSE;
    112112
     113
     114/** Pointer to a the private data of a TAR filesystem stream. */
     115typedef struct RTZIPTARFSSTREAMWRITER *PRTZIPTARFSSTREAMWRITER;
     116
     117
     118/**
     119 * Instance data for a file or I/O stream returned by
     120 * RTVFSFSSTREAMOPS::pfnPushFile.
     121 */
     122typedef 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. */
     142typedef RTZIPTARFSSTREAMWRITERPUSH *PRTZIPTARFSSTREAMWRITERPUSH;
     143
     144
    113145/**
    114146 * Tar filesystem stream private data.
     
    120152    /** Non-nil if the output is a file.  */
    121153    RTVFSFILE               hVfsFile;
     154
     155    /** The current push file.  NULL if none. */
     156    PRTZIPTARFSSTREAMWRITERPUSH pPush;
    122157
    123158    /** The TAR format. */
     
    136171    RTZIPTARHDR             aHdrs[3];
    137172} RTZIPTARFSSTREAMWRITER;
    138 /** Pointer to a the private data of a TAR filesystem stream. */
    139 typedef RTZIPTARFSSTREAMWRITER *PRTZIPTARFSSTREAMWRITER;
    140173
    141174
     
    143176*   Internal Functions                                                                                                           *
    144177*********************************************************************************************************************************/
     178static int rtZipTarFssWriter_CompleteCurrentPushFile(PRTZIPTARFSSTREAMWRITER pThis);
    145179static int rtZipTarFssWriter_AddFile(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, RTVFSIOSTREAM hVfsIos,
    146180                                     PCRTFSOBJINFO pObjInfo, const char *pszOwnerNm, const char *pszGroupNm);
     
    378412    pThis->cHdrs = 1;
    379413    return rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrs[0]);
     414}
     415
     416
     417
     418
     419/**
     420 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
     421 */
     422static 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 */
     440static 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 */
     491static 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 */
     503static 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 */
     620static 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 */
     635static 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 */
     648static 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 */
     659static 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 */
     670static 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 */
     681static 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 */
     693static 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 */
     704static 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 */
     803static 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 */
     814DECL_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 */
     840DECL_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 */
     889static 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;
    380950}
    381951
     
    11001670    PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
    11011671
     1672    rtZipTarFssWriter_CompleteCurrentPushFile(pThis);
     1673
    11021674    RTVfsIoStrmRelease(pThis->hVfsIos);
    11031675    pThis->hVfsIos = NIL_RTVFSIOSTREAM;
     
    11331705
    11341706    /*
    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;
    11391712
    11401713    /*
     
    11421715     */
    11431716    RTFSOBJINFO ObjInfo;
    1144     int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_UNIX);
     1717    rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_UNIX);
    11451718    AssertRCReturn(rc, rc);
    11461719
     
    12031776
    12041777/**
     1778 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnPushFile}
     1779 */
     1780static 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/**
    12051908 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnEnd}
    12061909 */
     
    12081911{
    12091912    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);
    12111918    if (RT_SUCCESS(rc))
    12121919    {
     
    12511958    NULL,
    12521959    rtZipTarFssWriter_Add,
     1960    rtZipTarFssWriter_PushFile,
    12531961    rtZipTarFssWriter_End,
    12541962    RTVFSFSSTREAMOPS_VERSION
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette