VirtualBox

Ignore:
Timestamp:
Oct 21, 2010 10:00:15 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
66857
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/checksum/manifest.cpp

    r33057 r33289  
    6767typedef RTMANIFESTCALLBACKDATA* PRTMANIFESTCALLBACKDATA;
    6868
     69/*******************************************************************************
     70*   Private functions
     71*******************************************************************************/
     72
     73DECLINLINE(char *) rtManifestPosOfCharInBuf(char const *pv, size_t cb, char c)
     74{
     75    char *pb = (char *)pv;
     76    for (; cb; --cb, ++pb)
     77        if (RT_UNLIKELY(*pb == c))
     78            return pb;
     79    return NULL;
     80}
     81
     82DECLINLINE(size_t) rtManifestIndexOfCharInBuf(char const *pv, size_t cb, char c)
     83{
     84    char const *pb = (char const *)pv;
     85    for (size_t i=0; i < cb; ++i, ++pb)
     86        if (RT_UNLIKELY(*pb == c))
     87            return i;
     88    return cb;
     89}
    6990
    7091int rtSHAProgressCallback(unsigned uPercent, void *pvUser)
     
    7697}
    7798
     99/*******************************************************************************
     100*   Public functions
     101*******************************************************************************/
     102
    78103RTR3DECL(int) RTManifestVerify(const char *pszManifestFile, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
    79104{
    80105    /* Validate input */
    81106    AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
     107
     108    /* Open the manifest file */
     109    RTFILE file;
     110    int rc = RTFileOpen(&file, pszManifestFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     111    if (RT_FAILURE(rc))
     112        return rc;
     113
     114    void *pvBuf = 0;
     115    do
     116    {
     117        uint64_t cbSize;
     118        rc = RTFileGetSize(file, &cbSize);
     119        if (RT_FAILURE(rc))
     120            break;
     121
     122        /* Cast down for the case size_t < uint64_t. This isn't really correct,
     123           but we consider manifest files bigger than size_t as not supported
     124           by now. */
     125        size_t cbToRead = (size_t)cbSize;
     126        pvBuf = RTMemAlloc(cbToRead);
     127        if (!pvBuf)
     128        {
     129            rc = VERR_NO_MEMORY;
     130            break;
     131        }
     132
     133        size_t cbRead = 0;
     134        rc = RTFileRead(file, pvBuf, cbToRead, &cbRead);
     135        if (RT_FAILURE(rc))
     136            break;
     137
     138        rc = RTManifestVerifyFilesBuf(pvBuf, cbRead, paTests, cTests, piFailed);
     139    }while (0);
     140
     141    /* Cleanup */
     142    if (pvBuf)
     143        RTMemFree(pvBuf);
     144
     145    RTFileClose(file);
     146
     147    return rc;
     148}
     149
     150RTR3DECL(int) RTManifestVerifyFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles, size_t *piFailed,
     151                                    PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     152{
     153    /* Validate input */
     154    AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
     155    AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
     156    AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
     157
     158    int rc = VINF_SUCCESS;
     159
     160    /* Create our compare list */
     161    PRTMANIFESTTEST paFiles = (PRTMANIFESTTEST)RTMemTmpAllocZ(sizeof(RTMANIFESTTEST) * cFiles);
     162    if (!paFiles)
     163        return VERR_NO_MEMORY;
     164
     165    RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 };
     166    /* Fill our compare list */
     167    for (size_t i = 0; i < cFiles; ++i)
     168    {
     169        char *pszDigest;
     170        if (pfnProgressCallback)
     171        {
     172            callback.cCurrentFile = i;
     173            rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, rtSHAProgressCallback, &callback);
     174        }
     175        else
     176            rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, NULL, NULL);
     177        if (RT_FAILURE(rc))
     178            break;
     179        paFiles[i].pszTestFile = (char*)papszFiles[i];
     180        paFiles[i].pszTestDigest = pszDigest;
     181    }
     182
     183    /* Do the verification */
     184    if (RT_SUCCESS(rc))
     185        rc = RTManifestVerify(pszManifestFile, paFiles, cFiles, piFailed);
     186
     187    /* Cleanup */
     188    for (size_t i = 0; i < cFiles; ++i)
     189    {
     190        if (paFiles[i].pszTestDigest)
     191            RTStrFree((char*)paFiles[i].pszTestDigest);
     192    }
     193    RTMemTmpFree(paFiles);
     194
     195    return rc;
     196}
     197
     198RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles,
     199                                   PFNRTPROGRESS pfnProgressCallback, void *pvUser)
     200{
     201    /* Validate input */
     202    AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
     203    AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
     204    AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);
     205
     206    RTFILE file;
     207    int rc = RTFileOpen(&file, pszManifestFile, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL);
     208    if (RT_FAILURE(rc))
     209        return rc;
     210
     211    PRTMANIFESTTEST paFiles = 0;
     212    void *pvBuf = 0;
     213    do
     214    {
     215        paFiles = (PRTMANIFESTTEST)RTMemAllocZ(sizeof(RTMANIFESTTEST) * cFiles);
     216        if (!paFiles)
     217        {
     218            rc = VERR_NO_MEMORY;
     219            break;
     220        }
     221
     222        RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 };
     223        for (size_t i = 0; i < cFiles; ++i)
     224        {
     225            paFiles[i].pszTestFile = papszFiles[i];
     226            /* Calculate the SHA1 digest of every file */
     227            if (pfnProgressCallback)
     228            {
     229                callback.cCurrentFile = i;
     230                rc = RTSha1DigestFromFile(paFiles[i].pszTestFile, (char**)&paFiles[i].pszTestDigest, rtSHAProgressCallback, &callback);
     231            }
     232            else
     233                rc = RTSha1DigestFromFile(paFiles[i].pszTestFile, (char**)&paFiles[i].pszTestDigest, NULL, NULL);
     234            if (RT_FAILURE(rc))
     235                break;
     236        }
     237
     238        if (RT_SUCCESS(rc))
     239        {
     240            size_t cbSize = 0;
     241            rc = RTManifestWriteFilesBuf(&pvBuf, &cbSize, paFiles, cFiles);
     242            if (RT_FAILURE(rc))
     243                break;
     244
     245            rc = RTFileWrite(file, pvBuf, cbSize, 0);
     246        }
     247    }while (0);
     248
     249    RTFileClose(file);
     250
     251    /* Cleanup */
     252    if (pvBuf)
     253        RTMemFree(pvBuf);
     254    for (size_t i = 0; i < cFiles; ++i)
     255        if (paFiles[i].pszTestDigest)
     256            RTStrFree((char*)paFiles[i].pszTestDigest);
     257    RTMemFree(paFiles);
     258
     259    /* Delete the manifest file on failure */
     260    if (RT_FAILURE(rc))
     261        RTFileDelete(pszManifestFile);
     262
     263    return rc;
     264}
     265
     266RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
     267{
     268    /* Validate input */
     269    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     270    AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER);
    82271    AssertPtrReturn(paTests, VERR_INVALID_POINTER);
    83272    AssertReturn(cTests > 0, VERR_INVALID_PARAMETER);
    84 
    85     /* Open the manifest file */
    86     PRTSTREAM pStream;
    87     int rc = RTStrmOpen(pszManifestFile, "r", &pStream);
    88     if (RT_FAILURE(rc))
    89         return rc;
     273    AssertPtrNullReturn(piFailed, VERR_INVALID_POINTER);
     274
     275    int rc = VINF_SUCCESS;
    90276
    91277    PRTMANIFESTFILEENTRY paFiles = (PRTMANIFESTFILEENTRY)RTMemTmpAllocZ(sizeof(RTMANIFESTFILEENTRY) * cTests);
    92278    if (!paFiles)
    93     {
    94         RTStrmClose(pStream);
    95279        return VERR_NO_MEMORY;
    96     }
    97280
    98281    /* Fill our compare list */
     
    100283        paFiles[i].pTestPattern = &paTests[i];
    101284
     285    char *pcBuf = (char*)pvBuf;
     286    size_t cbRead = 0;
    102287    /* Parse the manifest file line by line */
    103     char szLine[1024];
    104288    for (;;)
    105289    {
    106         rc = RTStrmGetLine(pStream, szLine, sizeof(szLine));
    107         if (RT_FAILURE(rc))
    108             break;
    109         size_t cch = strlen(szLine);
    110 
    111         /* Skip empty lines */
    112         if (cch == 0)
     290        if (cbRead >= cbSize)
     291            break;
     292
     293        size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1;
     294
     295        /* Skip empty lines (UNIX/DOS format) */
     296        if (   (   cch == 1
     297                && pcBuf[0] == '\n')
     298            || (   cch == 2
     299                && pcBuf[0] == '\r'
     300                && pcBuf[1] == '\n'))
     301        {
     302            pcBuf += cch;
     303            cbRead += cch;
    113304            continue;
     305        }
    114306
    115307        /** @todo r=bird:
     308         *  -# Better deal with this EOF line platform dependency
    116309         *  -# The SHA1 test should probably include a blank space check.
    117310         *  -# If there is a specific order to the elements in the string, it would be
     
    122315        /* Check for the digest algorithm */
    123316        if (   cch < 4
    124             || !(  szLine[0] == 'S'
    125                 && szLine[1] == 'H'
    126                 && szLine[2] == 'A'
    127                 && szLine[3] == '1'))
     317            || !(   pcBuf[0] == 'S'
     318                 && pcBuf[1] == 'H'
     319                 && pcBuf[2] == 'A'
     320                 && pcBuf[3] == '1'))
    128321        {
    129322            /* Digest unsupported */
     
    133326
    134327        /* Try to find the filename */
    135         char *pszNameStart = strchr(szLine, '(');
     328        char *pszNameStart = rtManifestPosOfCharInBuf(pcBuf, cch, '(');
    136329        if (!pszNameStart)
    137330        {
     
    139332            break;
    140333        }
    141         char *pszNameEnd = strchr(szLine, ')');
     334        char *pszNameEnd = rtManifestPosOfCharInBuf(pcBuf, cch, ')');
    142335        if (!pszNameEnd)
    143336        {
     
    158351
    159352        /* Try to find the digest sum */
    160         char *pszDigestStart = strchr(szLine, '=');
     353        char *pszDigestStart = rtManifestPosOfCharInBuf(pcBuf, cch, '=') + 1;
    161354        if (!pszDigestStart)
    162355        {
     
    165358            break;
    166359        }
    167         char *pszDigest = ++pszDigestStart;
     360        char *pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\r');
     361        if (!pszDigestEnd)
     362            pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\n');
     363        if (!pszDigestEnd)
     364        {
     365            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
     366            break;
     367        }
     368        /* Copy the digest part */
     369        size_t cchDigest = pszDigestEnd - pszDigestStart - 1;
     370        char *pszDigest = (char *)RTMemTmpAlloc(cchDigest + 1);
     371        if (!pszDigest)
     372        {
     373            rc = VERR_NO_MEMORY;
     374            break;
     375        }
     376        memcpy(pszDigest, pszDigestStart + 1, cchDigest);
     377        pszDigest[cchDigest] = '\0';
    168378
    169379        /* Check our file list against the extracted data */
     
    181391        }
    182392        RTMemTmpFree(pszName);
     393        RTMemTmpFree(pszDigest);
    183394        if (!fFound)
    184395        {
     
    187398            break;
    188399        }
    189     }
    190     RTStrmClose(pStream);
     400
     401        pcBuf += cch;
     402        cbRead += cch;
     403    }
    191404
    192405    if (   rc == VINF_SUCCESS
     
    229442}
    230443
    231 
    232 RTR3DECL(int) RTManifestVerifyFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles, size_t *piFailed,
    233                                     PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    234 {
    235     /* Validate input */
    236     AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
    237     AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
    238     AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
    239 
    240     int rc = VINF_SUCCESS;
    241 
    242     /* Create our compare list */
    243     PRTMANIFESTTEST paFiles = (PRTMANIFESTTEST)RTMemTmpAllocZ(sizeof(RTMANIFESTTEST) * cFiles);
    244     if (!paFiles)
    245         return VERR_NO_MEMORY;
    246 
    247     RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 };
    248     /* Fill our compare list */
    249     for (size_t i = 0; i < cFiles; ++i)
    250     {
    251         char *pszDigest;
    252         if (pfnProgressCallback)
    253         {
    254             callback.cCurrentFile = i;
    255             rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, rtSHAProgressCallback, &callback);
    256         }
    257         else
    258             rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, NULL, NULL);
    259         if (RT_FAILURE(rc))
    260             break;
    261         paFiles[i].pszTestFile = (char*)papszFiles[i];
    262         paFiles[i].pszTestDigest = pszDigest;
    263     }
    264 
    265     /* Do the verification */
    266     if (RT_SUCCESS(rc))
    267         rc = RTManifestVerify(pszManifestFile, paFiles, cFiles, piFailed);
    268 
    269     /* Cleanup */
    270     for (size_t i = 0; i < cFiles; ++i)
    271     {
    272         if (paFiles[i].pszTestDigest)
    273             RTStrFree(paFiles[i].pszTestDigest);
    274     }
    275     RTMemTmpFree(paFiles);
    276 
    277     return rc;
    278 }
    279 
    280 
    281 RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles,
    282                                    PFNRTPROGRESS pfnProgressCallback, void *pvUser)
    283 {
    284     /* Validate input */
    285     AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
    286     AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
    287     AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER);
    288 
    289     /* Open a file to stream in */
    290     PRTSTREAM pStream;
    291     int rc = RTStrmOpen(pszManifestFile, "w", &pStream);
    292     if (RT_FAILURE(rc))
    293         return rc;
    294 
    295     RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 };
    296     for (size_t i = 0; i < cFiles; ++i)
    297     {
    298         /* Calculate the SHA1 digest of every file */
    299         char *pszDigest;
    300         if (pfnProgressCallback)
    301         {
    302             callback.cCurrentFile = i;
    303             rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, rtSHAProgressCallback, &callback);
    304         }
    305         else
    306             rc = RTSha1DigestFromFile(papszFiles[i], &pszDigest, NULL, NULL);
    307         if (RT_FAILURE(rc))
    308             break;
    309 
    310         /* Add the entry to the manifest file */
    311         int cch = RTStrmPrintf(pStream, "SHA1 (%s)= %s\n", RTPathFilename(papszFiles[i]), pszDigest);
    312         RTStrFree(pszDigest);
    313         if (RT_UNLIKELY(cch < 0))
    314         {
    315             rc = VERR_INTERNAL_ERROR;
    316             break;
    317         }
    318     }
    319     int rc2 = RTStrmClose(pStream);
    320     if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    321         rc2 = rc;
    322 
    323     /* Delete the manifest file on failure */
    324     if (RT_FAILURE(rc))
    325         RTFileDelete(pszManifestFile);
    326 
    327     return rc;
    328 }
    329 
    330 RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, const char * const *papszFileNames, const char * const *papszFileDigests, size_t cFiles)
     444RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, PRTMANIFESTTEST paFiles, size_t cFiles)
    331445{
    332446    /* Validate input */
    333447    AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER);
    334448    AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
    335     AssertPtrReturn(papszFileNames, VERR_INVALID_POINTER);
    336     AssertPtrReturn(papszFileDigests, VERR_INVALID_POINTER);
     449    AssertPtrReturn(paFiles, VERR_INVALID_POINTER);
    337450    AssertReturn(cFiles > 0, VERR_INVALID_PARAMETER);
    338451
     
    342455    for (size_t i = 0; i < cFiles; ++i)
    343456    {
    344         size_t cbTmp = strlen(RTPathFilename(papszFileNames[i])) + strlen(papszFileDigests[i]) + 10;
     457        size_t cbTmp = strlen(RTPathFilename(paFiles[i].pszTestFile)) + strlen(paFiles[i].pszTestDigest) + 10;
    345458        cbMaxSize = RT_MAX(cbMaxSize, cbTmp);
    346459        cbSize += cbTmp;
     
    357470    for (size_t i = 0; i < cFiles; ++i)
    358471    {
    359         size_t cch = RTStrPrintf(pszTmp, cbMaxSize + 1, "SHA1 (%s)= %s\n", RTPathFilename(papszFileNames[i]), papszFileDigests[i]);
     472        size_t cch = RTStrPrintf(pszTmp, cbMaxSize + 1, "SHA1 (%s)= %s\n", RTPathFilename(paFiles[i].pszTestFile), paFiles[i].pszTestDigest);
    360473        memcpy(&((char*)pvBuf)[cbPos], pszTmp, cch);
    361474        cbPos += cch;
Note: See TracChangeset for help on using the changeset viewer.

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