VirtualBox

Ignore:
Timestamp:
Oct 21, 2010 10:00:15 AM (14 years ago)
Author:
vboxsync
Message:

Runtime;Main-OVF-Import: added online creation of SHA1 sums; preread/calc is done in a second worker thread; reading is cached; directly read out of an ova file; started to make reading fully streaming aware

File:
1 edited

Legend:

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

    r33058 r33289  
    9292#endif
    9393
     94typedef struct RTTARFILEINTERNAL* PRTTARFILEINTERNAL;
    9495typedef struct RTTARINTERNAL
    9596{
     
    9899    bool            fFileOpenForWrite;
    99100    uint32_t        fOpenMode;
     101    bool            fStreamMode;
     102    PRTTARFILEINTERNAL pFileCache;
    100103} RTTARINTERNAL;
    101104typedef RTTARINTERNAL* PRTTARINTERNAL;
     
    275278
    276279    return rc;
     280}
     281
     282DECLINLINE(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
     296DECLINLINE(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
     308DECLINLINE(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    }
    277317}
    278318
     
    563603 ******************************************************************************/
    564604
    565 RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char* pszTarname, uint32_t fMode)
     605RTR3DECL(int) RTTarOpen(PRTTAR phTar, const char* pszTarname, uint32_t fMode, bool fStream)
    566606{
    567607    PRTTARINTERNAL pInt = (PRTTARINTERNAL)RTMemAllocZ(sizeof(RTTARINTERNAL));
     
    571611    pInt->u32Magic = RTTAR_MAGIC;
    572612    pInt->fOpenMode = fMode;
     613    pInt->fStreamMode = fStream && (fMode & RTFILE_O_READ);
    573614
    574615    int rc = VINF_SUCCESS;
     
    618659        rc = RTFileClose(pInt->hTarFile);
    619660
     661    /* Delete any remaining cached file headers. */
     662    if (pInt->pFileCache)
     663    {
     664        rtDeleteTarFileInternal(pInt->pFileCache);
     665        pInt->pFileCache = 0;
     666    }
     667
    620668    pInt->u32Magic = RTTAR_MAGIC_DEAD;
    621669
     
    634682    if (!pInt->hTarFile)
    635683        return VERR_INVALID_HANDLE;
     684
     685    if (pInt->fStreamMode)
     686        return VERR_INVALID_STATE;
    636687
    637688    if (fOpen & RTFILE_O_WRITE)
     
    643694    }
    644695
    645     PRTTARFILEINTERNAL pFileInt = (PRTTARFILEINTERNAL)RTMemAllocZ(sizeof(RTTARFILEINTERNAL));
     696    PRTTARFILEINTERNAL pFileInt = rtCreateTarFileInternal(pInt, pszFilename, fOpen);
    646697    if (!pFileInt)
    647698        return VERR_NO_MEMORY;
    648699
    649     pFileInt->u32Magic = RTTARFILE_MAGIC;
    650 
    651700    int rc = VINF_SUCCESS;
    652701    do
    653702    {
    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 
    662703        if (pFileInt->fOpenMode & RTFILE_O_WRITE)
    663704        {
     
    718759
    719760    /* 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)
    721778    {
    722779        pFileInt->pTar->fFileOpenForWrite = false;
     
    756813        while(0);
    757814    }
    758     /* Nothing special in readmode. */
    759815
    760816    /* Now cleanup and delete the handle */
    761     RTStrFree(pFileInt->pszFilename);
    762     pFileInt->u32Magic = RTTARFILE_MAGIC_DEAD;
    763     RTMemFree(pFileInt);
     817    rtDeleteTarFileInternal(pFileInt);
    764818
    765819    return rc;
     
    770824    PRTTARFILEINTERNAL pFileInt = hFile;
    771825    RTTARFILE_VALID_RETURN(pFileInt);
     826
     827    if (pFileInt->pTar->fStreamMode)
     828        return VERR_INVALID_STATE;
    772829
    773830    switch (uMethod)
     
    822879    RTTARFILE_VALID_RETURN(pFileInt);
    823880
     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);
    824890    size_t cbTmpRead = 0;
    825     int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbToRead, &cbTmpRead);
     891    int rc = RTFileReadAt(pFileInt->pTar->hTarFile, pFileInt->uStart + 512 + uOffset, pvBuf, cbToCopy, &cbTmpRead);
    826892    pFileInt->uCurrentPos = uOffset + cbTmpRead;
    827893    if (pcbRead)
     
    10211087    /* Open the tar file */
    10221088    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);
    10241090    if (RT_FAILURE(rc))
    10251091        return rc;
     
    10451111    /* Open the tar file */
    10461112    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);
    10481114    if (RT_FAILURE(rc))
    10491115        return rc;
     
    11521218    do
    11531219    {
    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);
    11551221        if (RT_FAILURE(rc))
    11561222            break;
     
    12151281    /* Open the tar file */
    12161282    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);
    12181284    if (RT_FAILURE(rc))
    12191285        return rc;
     
    12861352
    12871353    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);
    12891355    if (RT_FAILURE(rc))
    12901356        return rc;
     
    13161382}
    13171383
     1384/******************************************************************************
     1385 *   Streaming Functions                                                      *
     1386 ******************************************************************************/
     1387
     1388RTR3DECL(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
     1407RTR3DECL(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
     1442RTR3DECL(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.

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