VirtualBox

Ignore:
Timestamp:
Sep 16, 2010 2:42:36 PM (14 years ago)
Author:
vboxsync
Message:

Runtime: in-memory extraction support for tar

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/tar.cpp

    r31624 r32566  
    134134        return VINF_SUCCESS;
    135135    return VERR_TAR_CHKSUM_MISMATCH;
     136}
     137
     138static int rtTarCopyFileFromToBuf(RTFILE hFile, void **ppvBuf, uint64_t *pcbSize, PRTTARRECORD pRecord, const uint64_t cbOverallSize, uint64_t &cbOverallWritten, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     139{
     140    int rc = VINF_SUCCESS;
     141
     142    uint64_t cbToCopy = RTStrToUInt64(pRecord->h.size);
     143
     144    *ppvBuf = RTMemAlloc(cbToCopy);
     145    char* pcsTmp = (char*)*ppvBuf;
     146    if (!pcsTmp)
     147        return VERR_NO_MEMORY;
     148
     149    uint64_t cbAllWritten = 0;
     150    RTTARRECORD record;
     151    /* Copy the content from hFile over to the memory. This is done block
     152     * wise in 512 byte steps. After this copying is finished hFile will be on
     153     * a 512 byte boundary, regardless if the file copied is 512 byte size
     154     * aligned. */
     155    for (;;)
     156    {
     157        if (pfnProgressCallback)
     158            pfnProgressCallback((unsigned)(100.0 / cbOverallSize * cbOverallWritten), pvUser);
     159        /* Finished already? */
     160        if (cbAllWritten == cbToCopy)
     161            break;
     162        /* Read one block */
     163        rc = RTFileRead(hFile, &record, sizeof(record), NULL);
     164        if (RT_FAILURE(rc))
     165            break;
     166        uint64_t cbToWrite = sizeof(record);
     167        /* Check for the last block which has not to be 512 bytes in size. */
     168        if (cbAllWritten + cbToWrite > cbToCopy)
     169            cbToWrite = cbToCopy - cbAllWritten;
     170        /* Write the block */
     171        memcpy(pcsTmp, &record, cbToWrite);
     172        /* Count how many bytes are written already */
     173        cbAllWritten += cbToWrite;
     174        cbOverallWritten += cbToWrite;
     175        pcsTmp += cbToWrite;
     176    }
     177
     178    /* Make sure the called doesn't mix truncated tar files with the official
     179     * end indicated by rtTarCalcChkSum. */
     180    if (rc == VERR_EOF)
     181        rc = VERR_FILE_IO_ERROR;
     182
     183    if (RT_FAILURE(rc))
     184        RTMemFree(*ppvBuf);
     185    else
     186        *pcbSize = cbToCopy;
     187
     188    return rc;
    136189}
    137190
     
    516569        RTMemFree(papszFiles);
    517570    }
     571    return rc;
     572}
     573
     574RTR3DECL(int) RTTarExtractFileToBuf(const char *pszTarFile, void **ppvBuf, uint64_t *pcbSize, const char *pszFile, PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     575{
     576    /* Validate input */
     577    AssertPtrReturn(pszTarFile, VERR_INVALID_POINTER);
     578    AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
     579
     580    /* Open the tar file */
     581    RTFILE hFile;
     582    int rc = RTFileOpen(&hFile, pszTarFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     583    if (RT_FAILURE(rc))
     584        return rc;
     585
     586    /* Get the overall size of all files to extract out of the tar archive
     587       headers. Only necessary if there is a progress callback. */
     588    uint64_t cbOverallSize = 0;
     589    if (pfnProgressCallback)
     590        rc = rtTarGetFilesOverallSize(hFile, &pszFile, 1, &cbOverallSize);
     591    if (RT_SUCCESS(rc))
     592    {
     593        /* Iterate through the tar file record by record. */
     594        RTTARRECORD record;
     595        bool fFound = false;
     596        uint64_t cbOverallWritten = 0;
     597        for (;;)
     598        {
     599            rc = RTFileRead(hFile, &record, sizeof(record), NULL);
     600            /* Check for error or EOF. */
     601            if (RT_FAILURE(rc))
     602                break;
     603            /* Check for EOF & data integrity */
     604            rc = rtTarCheckHeader(&record);
     605            if (RT_FAILURE(rc))
     606                break;
     607            /* We support normal files only */
     608            if (   record.h.linkflag == LF_OLDNORMAL
     609                || record.h.linkflag == LF_NORMAL)
     610            {
     611                if (!RTStrCmp(record.h.name, pszFile))
     612                {
     613                    fFound = true;
     614                    rc = rtTarCopyFileFromToBuf(hFile, ppvBuf, pcbSize, &record, cbOverallSize, cbOverallWritten, pfnProgressCallback, pvUser);
     615                    /* We are finished */
     616                    break;
     617                }
     618                else
     619                {
     620                    rc = rtTarSkipData(hFile, &record);
     621                    if (RT_FAILURE(rc))
     622                        break;
     623                }
     624            }
     625        }
     626
     627        if (rc == VERR_EOF)
     628            rc = VINF_SUCCESS;
     629
     630        /* If we didn't found the file, indicate an error */
     631        if (!fFound && RT_SUCCESS(rc))
     632            rc = VERR_FILE_NOT_FOUND;
     633    }
     634
     635    RTFileClose(hFile);
    518636    return rc;
    519637}
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