Changeset 33289 in vbox for trunk/src/VBox/Runtime/common/checksum
- Timestamp:
- Oct 21, 2010 10:00:15 AM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 66857
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/checksum/manifest.cpp
r33057 r33289 67 67 typedef RTMANIFESTCALLBACKDATA* PRTMANIFESTCALLBACKDATA; 68 68 69 /******************************************************************************* 70 * Private functions 71 *******************************************************************************/ 72 73 DECLINLINE(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 82 DECLINLINE(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 } 69 90 70 91 int rtSHAProgressCallback(unsigned uPercent, void *pvUser) … … 76 97 } 77 98 99 /******************************************************************************* 100 * Public functions 101 *******************************************************************************/ 102 78 103 RTR3DECL(int) RTManifestVerify(const char *pszManifestFile, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed) 79 104 { 80 105 /* Validate input */ 81 106 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 150 RTR3DECL(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 198 RTR3DECL(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 266 RTR3DECL(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); 82 271 AssertPtrReturn(paTests, VERR_INVALID_POINTER); 83 272 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; 90 276 91 277 PRTMANIFESTFILEENTRY paFiles = (PRTMANIFESTFILEENTRY)RTMemTmpAllocZ(sizeof(RTMANIFESTFILEENTRY) * cTests); 92 278 if (!paFiles) 93 {94 RTStrmClose(pStream);95 279 return VERR_NO_MEMORY; 96 }97 280 98 281 /* Fill our compare list */ … … 100 283 paFiles[i].pTestPattern = &paTests[i]; 101 284 285 char *pcBuf = (char*)pvBuf; 286 size_t cbRead = 0; 102 287 /* Parse the manifest file line by line */ 103 char szLine[1024];104 288 for (;;) 105 289 { 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; 113 304 continue; 305 } 114 306 115 307 /** @todo r=bird: 308 * -# Better deal with this EOF line platform dependency 116 309 * -# The SHA1 test should probably include a blank space check. 117 310 * -# If there is a specific order to the elements in the string, it would be … … 122 315 /* Check for the digest algorithm */ 123 316 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')) 128 321 { 129 322 /* Digest unsupported */ … … 133 326 134 327 /* Try to find the filename */ 135 char *pszNameStart = strchr(szLine, '(');328 char *pszNameStart = rtManifestPosOfCharInBuf(pcBuf, cch, '('); 136 329 if (!pszNameStart) 137 330 { … … 139 332 break; 140 333 } 141 char *pszNameEnd = strchr(szLine, ')');334 char *pszNameEnd = rtManifestPosOfCharInBuf(pcBuf, cch, ')'); 142 335 if (!pszNameEnd) 143 336 { … … 158 351 159 352 /* Try to find the digest sum */ 160 char *pszDigestStart = strchr(szLine, '=');353 char *pszDigestStart = rtManifestPosOfCharInBuf(pcBuf, cch, '=') + 1; 161 354 if (!pszDigestStart) 162 355 { … … 165 358 break; 166 359 } 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'; 168 378 169 379 /* Check our file list against the extracted data */ … … 181 391 } 182 392 RTMemTmpFree(pszName); 393 RTMemTmpFree(pszDigest); 183 394 if (!fFound) 184 395 { … … 187 398 break; 188 399 } 189 } 190 RTStrmClose(pStream); 400 401 pcBuf += cch; 402 cbRead += cch; 403 } 191 404 192 405 if ( rc == VINF_SUCCESS … … 229 442 } 230 443 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) 444 RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, PRTMANIFESTTEST paFiles, size_t cFiles) 331 445 { 332 446 /* Validate input */ 333 447 AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER); 334 448 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER); 335 AssertPtrReturn(papszFileNames, VERR_INVALID_POINTER); 336 AssertPtrReturn(papszFileDigests, VERR_INVALID_POINTER); 449 AssertPtrReturn(paFiles, VERR_INVALID_POINTER); 337 450 AssertReturn(cFiles > 0, VERR_INVALID_PARAMETER); 338 451 … … 342 455 for (size_t i = 0; i < cFiles; ++i) 343 456 { 344 size_t cbTmp = strlen(RTPathFilename(pa pszFileNames[i])) + strlen(papszFileDigests[i]) + 10;457 size_t cbTmp = strlen(RTPathFilename(paFiles[i].pszTestFile)) + strlen(paFiles[i].pszTestDigest) + 10; 345 458 cbMaxSize = RT_MAX(cbMaxSize, cbTmp); 346 459 cbSize += cbTmp; … … 357 470 for (size_t i = 0; i < cFiles; ++i) 358 471 { 359 size_t cch = RTStrPrintf(pszTmp, cbMaxSize + 1, "SHA1 (%s)= %s\n", RTPathFilename(pa pszFileNames[i]), papszFileDigests[i]);472 size_t cch = RTStrPrintf(pszTmp, cbMaxSize + 1, "SHA1 (%s)= %s\n", RTPathFilename(paFiles[i].pszTestFile), paFiles[i].pszTestDigest); 360 473 memcpy(&((char*)pvBuf)[cbPos], pszTmp, cch); 361 474 cbPos += cch;
Note:
See TracChangeset
for help on using the changeset viewer.