RTR3DECL(int) RTSha256Digest(void* pvBuf, size_t cbBuf, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser) { /* Validate input */ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER); int rc = VINF_SUCCESS; *ppszDigest = NULL; /* Initialize the hash context. */ RTSHA256CONTEXT Ctx; RTSha256Init(&Ctx); /* Buffer size for progress callback */ double rdMulti = 100.0 / (cbBuf ? cbBuf : 1); /* Working buffer */ char *pvTmp = (char*)pvBuf; /* Process the memory in blocks */ size_t cbReadTotal = 0; for (;;) { size_t cbRead = RT_MIN(cbBuf - cbReadTotal, _1M); RTSha256Update(&Ctx, pvTmp, cbRead); cbReadTotal += cbRead; pvTmp += cbRead; /* Call the progress callback if one is defined */ if (pfnProgressCallback) { rc = pfnProgressCallback((unsigned)(cbReadTotal * rdMulti), pvUser); if (RT_FAILURE(rc)) break; /* canceled */ } /* Finished? */ if (cbReadTotal == cbBuf) break; } if (RT_SUCCESS(rc)) { /* Finally calculate & format the SHA256 sum */ uint8_t abHash[RTSHA256_HASH_SIZE]; RTSha256Final(&Ctx, abHash); char *pszDigest; rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) { rc = RTSha256ToString(abHash, pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) *ppszDigest = pszDigest; else RTStrFree(pszDigest); } } return rc; }
/** * Basic API checks. * We'll return if any of these fails. */ static void tst1(void) { RTTestISub("Basics"); char *psz; int rc = VINF_SUCCESS; /* RTStrAlloc */ RTTESTI_CHECK(psz = RTStrAlloc(0)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrAlloc(1)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrAlloc(128)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); /* RTStrAllocEx */ psz = (char*)"asdfasdf"; RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 1), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 128), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); /* RTStrRealloc */ psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 10), VINF_SUCCESS); RTTESTI_CHECK(psz && !psz[0]); RTTESTI_CHECK(psz && !psz[9]); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 128), VINF_SUCCESS); RTTESTI_CHECK(psz && !psz[0]); RTTESTI_CHECK(psz && !psz[127]); if (psz) { memset(psz, 'a', 127); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 160), VINF_SUCCESS); if (RT_SUCCESS(rc) && psz) { RTTESTI_CHECK(!psz[127]); RTTESTI_CHECK(!psz[159]); RTTESTI_CHECK(ASMMemIsAll8(psz, 127, 'a') == NULL); memset(psz, 'b', 159); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 79), VINF_SUCCESS); if (RT_SUCCESS(rc)) { RTTESTI_CHECK(!psz[78]); RTTESTI_CHECK(ASMMemIsAll8(psz, 78, 'b') == NULL); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); } } } RTStrFree(psz); /* RTStrDup */ RTTESTI_CHECK(psz = RTStrDup("")); RTTESTI_CHECK(psz && *psz == '\0'); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abcdefghijklmnop")); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnop")); RTStrFree(psz); /* RTStrDupEx */ psz = NULL; RTTESTI_CHECK_RC(RTStrDupEx(&psz, ""), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || *psz == '\0'); if (RT_SUCCESS(rc)) RTStrFree(psz); psz = (char*)"asdfasdfasdfasdf"; RTTESTI_CHECK_RC(rc = RTStrDupEx(&psz, "abcdefghijklmnop"), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || !RTStrCmp(psz, "abcdefghijklmnop")); if (RT_SUCCESS(rc)) RTStrFree(psz); /* RTStrDupN */ RTTESTI_CHECK(psz = RTStrDupN("abcdefg", 3)); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDupN("abc", 100000)); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDupN("abc", 0)); RTTESTI_CHECK(psz && *psz == '\0'); RTStrFree(psz); /* RTStrAAppend */ RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, "def"), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdef")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, ""), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, NULL), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrAAppend(&psz, "xyz"), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "xyz")); RTStrFree(psz); /* RTStrAAppendN */ RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "def", 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcd")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, NULL, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "abc", 2), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "ab")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "cdefghijklm", 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "defghijklm", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklm")); RTStrFree(psz); /* RTStrAAppendExN / RTStrAAppendExNV */ psz = NULL; RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 5, "a", (size_t)1, "bc", (size_t)1, "cdefg", RTSTR_MAX, "hijkl", (size_t)2, "jklmnopqrstuvwxyz", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 2, NULL, (size_t)0, "", (size_t)0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 1, "-", (size_t)1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz-")); RTStrFree(psz); /* RTStrATruncate */ psz = NULL; RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); RTTESTI_CHECK(psz = RTStrDup("")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("1234567890")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 5), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "12345")); RTStrFree(psz); psz = NULL; for (uint32_t i = 0; i < 128; i++) RTTESTI_CHECK_RC_RETV(RTStrAAppend(&psz, "abcdefghijklmnopqrstuvwxyz"), VINF_SUCCESS); RTTESTI_CHECK_RC(RTStrATruncate(&psz, sizeof("abcdefghijklmnopqrstuvwxyz") - 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 6), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdef")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "a")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "")); RTStrFree(psz); }
RTR3DECL(int) RTSha256DigestFromFile(const char *pszFile, char **ppszDigest, PFNRTPROGRESS pfnProgressCallback, void *pvUser) { /* Validate input */ AssertPtrReturn(pszFile, VERR_INVALID_POINTER); AssertPtrReturn(ppszDigest, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_PARAMETER); *ppszDigest = NULL; /* Initialize the hash context. */ RTSHA256CONTEXT Ctx; RTSha256Init(&Ctx); /* Open the file to calculate a SHA256 sum of */ RTFILE hFile; int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) return rc; /* Fetch the file size. Only needed if there is a progress callback. */ double rdMulti = 0; if (pfnProgressCallback) { uint64_t cbFile; rc = RTFileGetSize(hFile, &cbFile); if (RT_FAILURE(rc)) { RTFileClose(hFile); return rc; } rdMulti = 100.0 / (cbFile ? cbFile : 1); } /* Allocate a reasonably large buffer, fall back on a tiny one. */ void *pvBufFree; size_t cbBuf = _1M; void *pvBuf = pvBufFree = RTMemTmpAlloc(cbBuf); if (!pvBuf) { cbBuf = 0x1000; pvBuf = alloca(cbBuf); } /* Read that file in blocks */ size_t cbReadTotal = 0; for (;;) { size_t cbRead; rc = RTFileRead(hFile, pvBuf, cbBuf, &cbRead); if (RT_FAILURE(rc) || !cbRead) break; RTSha256Update(&Ctx, pvBuf, cbRead); cbReadTotal += cbRead; /* Call the progress callback if one is defined */ if (pfnProgressCallback) { rc = pfnProgressCallback((unsigned)(cbReadTotal * rdMulti), pvUser); if (RT_FAILURE(rc)) break; /* canceled */ } } RTMemTmpFree(pvBufFree); RTFileClose(hFile); if (RT_FAILURE(rc)) return rc; /* Finally calculate & format the SHA256 sum */ uint8_t abHash[RTSHA256_HASH_SIZE]; RTSha256Final(&Ctx, abHash); char *pszDigest; rc = RTStrAllocEx(&pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) { rc = RTSha256ToString(abHash, pszDigest, RTSHA256_DIGEST_LEN + 1); if (RT_SUCCESS(rc)) *ppszDigest = pszDigest; else RTStrFree(pszDigest); } return rc; }
/** * Provide information about active users. */ static int vboxserviceVMInfoWriteUsers(void) { int rc = VINF_SUCCESS; char *pszUserList = NULL; uint32_t cUsersInList = 0; #ifdef RT_OS_WINDOWS # ifndef TARGET_NT4 rc = VBoxServiceVMInfoWinWriteUsers(&pszUserList, &cUsersInList); # else rc = VERR_NOT_IMPLEMENTED; # endif #elif defined(RT_OS_FREEBSD) /** @todo FreeBSD: Port logged on user info retrieval. * However, FreeBSD 9 supports utmpx, so we could use the code * block below (?). */ rc = VERR_NOT_IMPLEMENTED; #elif defined(RT_OS_OS2) /** @todo OS/2: Port logged on (LAN/local/whatever) user info retrieval. */ rc = VERR_NOT_IMPLEMENTED; #else setutxent(); utmpx *ut_user; uint32_t cListSize = 32; /* Allocate a first array to hold 32 users max. */ char **papszUsers = (char **)RTMemAllocZ(cListSize * sizeof(char *)); if (papszUsers == NULL) rc = VERR_NO_MEMORY; /* Process all entries in the utmp file. */ while ( (ut_user = getutxent()) && RT_SUCCESS(rc)) { VBoxServiceVerbose(4, "Found logged in user \"%s\"\n", ut_user->ut_user); if (cUsersInList > cListSize) { cListSize += 32; void *pvNew = RTMemRealloc(papszUsers, cListSize * sizeof(char*)); AssertPtrBreakStmt(pvNew, cListSize -= 32); papszUsers = (char **)pvNew; } /* Make sure we don't add user names which are not * part of type USER_PROCESS. */ if (ut_user->ut_type == USER_PROCESS) { bool fFound = false; for (uint32_t i = 0; i < cUsersInList && !fFound; i++) fFound = strcmp(papszUsers[i], ut_user->ut_user) == 0; if (!fFound) { rc = RTStrDupEx(&papszUsers[cUsersInList], (const char *)ut_user->ut_user); if (RT_FAILURE(rc)) break; cUsersInList++; } } } /* Calc the string length. */ size_t cchUserList = 0; for (uint32_t i = 0; i < cUsersInList; i++) cchUserList += (i != 0) + strlen(papszUsers[i]); /* Build the user list. */ rc = RTStrAllocEx(&pszUserList, cchUserList + 1); if (RT_SUCCESS(rc)) { char *psz = pszUserList; for (uint32_t i = 0; i < cUsersInList; i++) { if (i != 0) *psz++ = ','; size_t cch = strlen(papszUsers[i]); memcpy(psz, papszUsers[i], cch); psz += cch; } *psz = '\0'; } /* Cleanup. */ for (uint32_t i = 0; i < cUsersInList; i++) RTStrFree(papszUsers[i]); RTMemFree(papszUsers); endutxent(); /* Close utmpx file. */ #endif Assert(RT_FAILURE(rc) || cUsersInList == 0 || (pszUserList && *pszUserList)); /* If the user enumeration above failed, reset the user count to 0 except * we didn't have enough memory anymore. In that case we want to preserve * the previous user count in order to not confuse third party tools which * rely on that count. */ if (RT_FAILURE(rc)) { if (rc == VERR_NO_MEMORY) { static int s_iVMInfoBitchedOOM = 0; if (s_iVMInfoBitchedOOM++ < 3) VBoxServiceVerbose(0, "Warning: Not enough memory available to enumerate users! Keeping old value (%u)\n", g_cVMInfoLoggedInUsers); cUsersInList = g_cVMInfoLoggedInUsers; } else cUsersInList = 0; } VBoxServiceVerbose(4, "cUsersInList: %u, pszUserList: %s, rc=%Rrc\n", cUsersInList, pszUserList ? pszUserList : "<NULL>", rc); if (pszUserList && cUsersInList > 0) VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", "%s", pszUserList); else VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", NULL); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsers", "%u", cUsersInList); if (g_cVMInfoLoggedInUsers != cUsersInList) { VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers", cUsersInList == 0 ? "true" : "false"); g_cVMInfoLoggedInUsers = cUsersInList; } if (RT_SUCCESS(rc) && pszUserList) RTStrFree(pszUserList); return rc; }
/** * Queries the value of an SVN property. * * This will automatically adjust for scheduled changes. * * @returns IPRT status code. * @retval VERR_INVALID_STATE if not a SVN WC file. * @retval VERR_NOT_FOUND if the property wasn't found. * @param pState The rewrite state to work on. * @param pszName The property name. * @param ppszValue Where to return the property value. Free this * using RTStrFree. Optional. */ int ScmSvnQueryProperty(PSCMRWSTATE pState, const char *pszName, char **ppszValue) { /* * Look it up in the scheduled changes. */ size_t i = pState->cSvnPropChanges; while (i-- > 0) if (!strcmp(pState->paSvnPropChanges[i].pszName, pszName)) { const char *pszValue = pState->paSvnPropChanges[i].pszValue; if (!pszValue) return VERR_NOT_FOUND; if (ppszValue) return RTStrDupEx(ppszValue, pszValue); return VINF_SUCCESS; } #ifdef SCM_WITHOUT_LIBSVN int rc; scmSvnFindSvnBinary(pState); if (g_enmSvnVersion < kScmSvnVersion_1_7) { /* * Hack: Read the .svn/props/<file>.svn-work file exists. */ char szPath[RTPATH_MAX]; rc = scmSvnConstructName(pState, ".svn/props/", ".svn-work", szPath); if (RT_SUCCESS(rc) && !RTFileExists(szPath)) rc = scmSvnConstructName(pState, ".svn/prop-base/", ".svn-base", szPath); if (RT_SUCCESS(rc)) { SCMSTREAM Stream; rc = ScmStreamInitForReading(&Stream, szPath); if (RT_SUCCESS(rc)) { /* * The current format is K len\n<name>\nV len\n<value>\n" ... END. */ rc = VERR_NOT_FOUND; size_t const cchName = strlen(pszName); SCMEOL enmEol; size_t cchLine; const char *pchLine; while ((pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol)) != NULL) { /* * Parse the 'K num' / 'END' line. */ if ( cchLine == 3 && !memcmp(pchLine, "END", 3)) break; size_t cchKey; if ( cchLine < 3 || pchLine[0] != 'K' || pchLine[1] != ' ' || !scmSvnReadNumber(&pchLine[2], cchLine - 2, &cchKey) || cchKey == 0 || cchKey > 4096) { RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine); rc = VERR_PARSE_ERROR; break; } /* * Match the key and skip to the value line. Don't bother with * names containing EOL markers. */ size_t const offKey = ScmStreamTell(&Stream); bool fMatch = cchName == cchKey; if (fMatch) { pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol); if (!pchLine) break; fMatch = cchLine == cchName && !memcmp(pchLine, pszName, cchName); } if (RT_FAILURE(ScmStreamSeekAbsolute(&Stream, offKey + cchKey))) break; if (RT_FAILURE(ScmStreamSeekByLine(&Stream, ScmStreamTellLine(&Stream) + 1))) break; /* * Read and Parse the 'V num' line. */ pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol); if (!pchLine) break; size_t cchValue; if ( cchLine < 3 || pchLine[0] != 'V' || pchLine[1] != ' ' || !scmSvnReadNumber(&pchLine[2], cchLine - 2, &cchValue) || cchValue > _1M) { RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine); rc = VERR_PARSE_ERROR; break; } /* * If we have a match, allocate a return buffer and read the * value into it. Otherwise skip this value and continue * searching. */ if (fMatch) { if (!ppszValue) rc = VINF_SUCCESS; else { char *pszValue; rc = RTStrAllocEx(&pszValue, cchValue + 1); if (RT_SUCCESS(rc)) { rc = ScmStreamRead(&Stream, pszValue, cchValue); if (RT_SUCCESS(rc)) *ppszValue = pszValue; else RTStrFree(pszValue); } } break; } if (RT_FAILURE(ScmStreamSeekRelative(&Stream, cchValue))) break; if (RT_FAILURE(ScmStreamSeekByLine(&Stream, ScmStreamTellLine(&Stream) + 1))) break; } if (RT_FAILURE(ScmStreamGetStatus(&Stream))) { rc = ScmStreamGetStatus(&Stream); RTMsgError("%s: stream error %Rrc\n", szPath, rc); } ScmStreamDelete(&Stream); } } if (rc == VERR_FILE_NOT_FOUND) rc = VERR_NOT_FOUND; } else { const char *apszArgs[] = { g_szSvnPath, "propget", "--strict", pszName, pState->pszFilename, NULL }; char *pszValue; rc = scmSvnRunAndGetOutput(pState, apszArgs, false, &pszValue); if (RT_SUCCESS(rc)) { if (pszValue && *pszValue) { if (ppszValue) { *ppszValue = pszValue; pszValue = NULL; } } else rc = VERR_NOT_FOUND; RTStrFree(pszValue); } } return rc; #else NOREF(pState); #endif return VERR_NOT_FOUND; }
static int shaCloseCallback(void *pvUser, void *pvStorage) { /* Validate input. */ AssertPtrReturn(pvUser, VERR_INVALID_POINTER); AssertPtrReturn(pvStorage, VERR_INVALID_POINTER); PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser; PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces); AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER); PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)pvStorage; DEBUG_PRINT_FLOW(); int rc = VINF_SUCCESS; /* Make sure all pending writes are flushed */ rc = shaFlushCurBuf(pInt); if (pInt->pWorkerThread) { /* Signal the worker thread to end himself */ rc = shaSignalManifestThread(pInt, STATUS_END); /* Worker thread stopped? */ rc = RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0); } if ( RT_SUCCESS(rc) && pShaStorage->fCreateDigest) { /* Finally calculate & format the SHA1/SHA256 sum */ unsigned char auchDig[RTSHA256_HASH_SIZE]; char *pszDigest; size_t cbDigest; if (pShaStorage->fSha256) { RTSha256Final(&pInt->ctx.Sha256, auchDig); cbDigest = RTSHA256_DIGEST_LEN; } else { RTSha1Final(&pInt->ctx.Sha1, auchDig); cbDigest = RTSHA1_DIGEST_LEN; } rc = RTStrAllocEx(&pszDigest, cbDigest + 1); if (RT_SUCCESS(rc)) { if (pShaStorage->fSha256) rc = RTSha256ToString(auchDig, pszDigest, cbDigest + 1); else rc = RTSha1ToString(auchDig, pszDigest, cbDigest + 1); if (RT_SUCCESS(rc)) pShaStorage->strDigest = pszDigest; RTStrFree(pszDigest); } } /* Close the file */ rc = vdIfIoFileClose(pIfIo, pInt->pvStorage); // RTPrintf("%lu %lu\n", pInt->calls, pInt->waits); /* Cleanup */ if (pInt->workFinishedEvent) RTSemEventDestroy(pInt->workFinishedEvent); if (pInt->newStatusEvent) RTSemEventDestroy(pInt->newStatusEvent); if (pInt->pCircBuf) RTCircBufDestroy(pInt->pCircBuf); if (pInt->pvZeroBuf) RTMemFree(pInt->pvZeroBuf); RTMemFree(pInt); return rc; }