/** * Elf function to write 64-bit note header. * * @param hFile The file to write to. * @param Type Type of this section. * @param pszName Name of this section. * @param pcv Opaque pointer to the data, if NULL only computes size. * @param cbData Size of the data. * * @return IPRT status code. */ static int Elf64WriteNoteHdr(RTFILE hFile, uint16_t Type, const char *pszName, const void *pcvData, uint64_t cbData) { AssertReturn(pcvData, VERR_INVALID_POINTER); AssertReturn(cbData > 0, VERR_NO_DATA); char szNoteName[s_cbNoteName]; RT_ZERO(szNoteName); RTStrCopy(szNoteName, sizeof(szNoteName), pszName); size_t cchName = strlen(szNoteName) + 1; size_t cchNameAlign = RT_ALIGN_Z(cchName, s_NoteAlign); uint64_t cbDataAlign = RT_ALIGN_64(cbData, s_NoteAlign); /* * Yell loudly and bail if we are going to be writing a core file that is not compatible with * both Solaris and the 64-bit ELF spec. which dictates 8-byte alignment. See @bugref{5211} comment 3. */ if (cchNameAlign - cchName > 3) { LogRel((DBGFLOG_NAME ": Elf64WriteNoteHdr pszName=%s cchName=%u cchNameAlign=%u, cchName aligns to 4 not 8-bytes!\n", pszName, cchName, cchNameAlign)); return VERR_INVALID_PARAMETER; } if (cbDataAlign - cbData > 3) { LogRel((DBGFLOG_NAME ": Elf64WriteNoteHdr pszName=%s cbData=%u cbDataAlign=%u, cbData aligns to 4 not 8-bytes!\n", pszName, cbData, cbDataAlign)); return VERR_INVALID_PARAMETER; } static const char s_achPad[7] = { 0, 0, 0, 0, 0, 0, 0 }; AssertCompile(sizeof(s_achPad) >= s_NoteAlign - 1); Elf64_Nhdr ElfNoteHdr; RT_ZERO(ElfNoteHdr); ElfNoteHdr.n_namesz = (Elf64_Word)cchName - 1; /* Again a discrepancy between ELF-64 and Solaris (@bugref{5211} comment 3), we will follow ELF-64 */ ElfNoteHdr.n_type = Type; ElfNoteHdr.n_descsz = (Elf64_Word)cbDataAlign; /* * Write note header. */ int rc = RTFileWrite(hFile, &ElfNoteHdr, sizeof(ElfNoteHdr), NULL /* all */); if (RT_SUCCESS(rc)) { /* * Write note name. */ rc = RTFileWrite(hFile, szNoteName, cchName, NULL /* all */); if (RT_SUCCESS(rc)) { /* * Write note name padding if required. */ if (cchNameAlign > cchName) rc = RTFileWrite(hFile, s_achPad, cchNameAlign - cchName, NULL); if (RT_SUCCESS(rc)) { /* * Write note data. */ rc = RTFileWrite(hFile, pcvData, cbData, NULL /* all */); if (RT_SUCCESS(rc)) { /* * Write note data padding if required. */ if (cbDataAlign > cbData) rc = RTFileWrite(hFile, s_achPad, cbDataAlign - cbData, NULL /* all*/); } } } } if (RT_FAILURE(rc)) LogRel((DBGFLOG_NAME ": RTFileWrite failed. rc=%Rrc pszName=%s cchName=%u cchNameAlign=%u cbData=%u cbDataAlign=%u\n", rc, pszName, cchName, cchNameAlign, cbData, cbDataAlign)); return rc; }
/** * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventMultiWaitEx. * @param uTimeout See RTSemEventMultiWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventMultiHkuWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { status_t status; int rc; int32 flags = 0; bigtime_t timeout; /* in microseconds */ /* * Validate the input. */ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) timeout = B_INFINITE_TIMEOUT; else { if (fFlags & RTSEMWAIT_FLAGS_NANOSECS) timeout = uTimeout / 1000; else if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) timeout = uTimeout * 1000; else return VERR_INVALID_PARAMETER; if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) flags |= B_RELATIVE_TIMEOUT; else if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE) flags |= B_ABSOLUTE_TIMEOUT; else return VERR_INVALID_PARAMETER; } if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE) flags |= B_CAN_INTERRUPT; // likely not: //else // flags |= B_KILL_CAN_INTERRUPT; rtR0SemEventMultiHkuRetain(pThis); status = acquire_sem_etc(pThis->SemId, 1, flags, timeout); switch (status) { case B_OK: rc = VINF_SUCCESS; break; case B_BAD_SEM_ID: rc = VERR_SEM_DESTROYED; break; case B_INTERRUPTED: rc = VERR_INTERRUPTED; break; case B_WOULD_BLOCK: /* fallthrough? */ case B_TIMED_OUT: rc = VERR_TIMEOUT; break; default: rc = RTErrConvertFromHaikuKernReturn(status); break; } rtR0SemEventMultiHkuRelease(pThis); return rc; }
bool UIWizardExportApp::exportVMs(CAppliance &appliance) { /* Get the map of the password IDs: */ EncryptedMediumMap encryptedMediums; foreach (const QString &strPasswordId, appliance.GetPasswordIds()) foreach (const QString &strMediumId, appliance.GetMediumIdsForPasswordId(strPasswordId)) encryptedMediums.insert(strPasswordId, strMediumId); /* Ask for the disk encryption passwords if necessary: */ if (!encryptedMediums.isEmpty()) { /* Create corresponding dialog: */ QPointer<UIAddDiskEncryptionPasswordDialog> pDlg = new UIAddDiskEncryptionPasswordDialog(this, window()->windowTitle(), encryptedMediums); /* Execute the dialog: */ if (pDlg->exec() == QDialog::Accepted) { /* Acquire the passwords provided: */ const EncryptionPasswordMap encryptionPasswords = pDlg->encryptionPasswords(); /* Delete the dialog: */ delete pDlg; /* Make sure the passwords were really provided: */ AssertReturn(!encryptionPasswords.isEmpty(), false); /* Provide appliance with passwords if possible: */ appliance.AddPasswords(encryptionPasswords.keys().toVector(), encryptionPasswords.values().toVector()); if (!appliance.isOk()) { /* Warn the user about failure: */ msgCenter().cannotAddDiskEncryptionPassword(appliance); return false; } } else { /* Any modal dialog can be destroyed in own event-loop * as a part of application termination procedure.. * We have to check if the dialog still valid. */ if (pDlg) { /* Delete the dialog: */ delete pDlg; } return false; } } /* Write the appliance: */ QVector<KExportOptions> options; if (field("manifestSelected").toBool()) options.append(KExportOptions_CreateManifest); CProgress progress = appliance.Write(field("format").toString(), options, uri()); bool fResult = appliance.isOk(); if (fResult) { /* Show some progress, so the user know whats going on: */ msgCenter().showModalProgressDialog(progress, QApplication::translate("UIWizardExportApp", "Exporting Appliance ..."), ":/progress_export_90px.png", this); if (progress.GetCanceled()) return false; if (!progress.isOk() || progress.GetResultCode() != 0) { msgCenter().cannotExportAppliance(progress, appliance.GetPath(), this); return false; } else return true; } if (!fResult) msgCenter().cannotExportAppliance(appliance, this); return false; }
/** * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventWaitEx. * @param uTimeout See RTSemEventWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventLnxWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { int rc; /* * Validate the input. */ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); rtR0SemEventLnxRetain(pThis); /* * Try grab the event without setting up the wait. */ if ( 1 /** @todo check if there are someone waiting already - waitqueue_active, but then what do we do below? */ && ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) rc = VINF_SUCCESS; else { /* * We have to wait. */ IPRT_LINUX_SAVE_EFL_AC(); RTR0SEMLNXWAIT Wait; rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head); if (RT_SUCCESS(rc)) { IPRT_DEBUG_SEMS_STATE(pThis, 'E'); for (;;) { /* The destruction test. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) rc = VERR_SEM_DESTROYED; else { rtR0SemLnxWaitPrepare(&Wait); /* Check the exit conditions. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) rc = VERR_SEM_DESTROYED; else if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) rc = VINF_SUCCESS; else if (rtR0SemLnxWaitHasTimedOut(&Wait)) rc = VERR_TIMEOUT; else if (rtR0SemLnxWaitWasInterrupted(&Wait)) rc = VERR_INTERRUPTED; else { /* Do the wait and then recheck the conditions. */ rtR0SemLnxWaitDoIt(&Wait); continue; } } break; } rtR0SemLnxWaitDelete(&Wait); IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc); } IPRT_LINUX_RESTORE_EFL_AC(); } rtR0SemEventLnxRelease(pThis); return rc; }
RTDECL(int) RTPowerNotificationRegister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser) { PRTPOWERNOTIFYREG pCur; PRTPOWERNOTIFYREG pNew; RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; /* * Validation. */ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER); AssertReturn(g_hRTPowerNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER); RT_ASSERT_PREEMPTIBLE(); RTSpinlockAcquire(g_hRTPowerNotifySpinLock, &Tmp); for (pCur = g_pRTPowerCallbackHead; pCur; pCur = pCur->pNext) if ( pCur->pvUser == pvUser && pCur->pfnCallback == pfnCallback) break; RTSpinlockRelease(g_hRTPowerNotifySpinLock, &Tmp); AssertMsgReturn(!pCur, ("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS); /* * Allocate a new record and attempt to insert it. */ pNew = (PRTPOWERNOTIFYREG)RTMemAlloc(sizeof(*pNew)); if (!pNew) return VERR_NO_MEMORY; pNew->pNext = NULL; pNew->pfnCallback = pfnCallback; pNew->pvUser = pvUser; memset(&pNew->bmDone[0], 0xff, sizeof(pNew->bmDone)); RTSpinlockAcquire(g_hRTPowerNotifySpinLock, &Tmp); pCur = g_pRTPowerCallbackHead; if (!pCur) g_pRTPowerCallbackHead = pNew; else { for (pCur = g_pRTPowerCallbackHead; ; pCur = pCur->pNext) if ( pCur->pvUser == pvUser && pCur->pfnCallback == pfnCallback) break; else if (!pCur->pNext) { pCur->pNext = pNew; pCur = NULL; break; } } ASMAtomicIncU32(&g_iRTPowerGeneration); RTSpinlockRelease(g_hRTPowerNotifySpinLock, &Tmp); /* duplicate? */ if (pCur) { RTMemFree(pCur); AssertMsgFailedReturn(("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS); } return VINF_SUCCESS; }
/** * @callback_method_impl{FNDBGCOPUNARY, Reference register (unary).} */ DECLCALLBACK(int) dbgcOpRegister(PDBGC pDbgc, PCDBGCVAR pArg, DBGCVARCAT enmCat, PDBGCVAR pResult) { LogFlow(("dbgcOpRegister: %s\n", pArg->u.pszString)); AssertReturn(pArg->enmType == DBGCVAR_TYPE_SYMBOL, VERR_DBGC_PARSE_BUG); /* Detect references to hypervisor registers. */ const char *pszReg = pArg->u.pszString; VMCPUID idCpu = pDbgc->idCpu; if (pszReg[0] == '.') { pszReg++; idCpu |= DBGFREG_HYPER_VMCPUID; } /* * If the desired result is a symbol, pass the argument along unmodified. * This is a great help for "r @eax" and such, since it will be translated to "r eax". */ if (enmCat == DBGCVAR_CAT_SYMBOL) { int rc = DBGFR3RegNmValidate(pDbgc->pUVM, idCpu, pszReg); if (RT_SUCCESS(rc)) DBGCVAR_INIT_STRING(pResult, pArg->u.pszString); return rc; } /* * Get the register. */ DBGFREGVALTYPE enmType; DBGFREGVAL Value; int rc = DBGFR3RegNmQuery(pDbgc->pUVM, idCpu, pszReg, &Value, &enmType); if (RT_SUCCESS(rc)) { switch (enmType) { case DBGFREGVALTYPE_U8: DBGCVAR_INIT_NUMBER(pResult, Value.u8); return VINF_SUCCESS; case DBGFREGVALTYPE_U16: DBGCVAR_INIT_NUMBER(pResult, Value.u16); return VINF_SUCCESS; case DBGFREGVALTYPE_U32: DBGCVAR_INIT_NUMBER(pResult, Value.u32); return VINF_SUCCESS; case DBGFREGVALTYPE_U64: DBGCVAR_INIT_NUMBER(pResult, Value.u64); return VINF_SUCCESS; case DBGFREGVALTYPE_U128: DBGCVAR_INIT_NUMBER(pResult, Value.u128.s.Lo); return VINF_SUCCESS; case DBGFREGVALTYPE_R80: #ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE DBGCVAR_INIT_NUMBER(pResult, (uint64_t)Value.r80Ex.lrd); #else DBGCVAR_INIT_NUMBER(pResult, (uint64_t)Value.r80Ex.sj64.u63Fraction); #endif return VINF_SUCCESS; case DBGFREGVALTYPE_DTR: DBGCVAR_INIT_NUMBER(pResult, Value.dtr.u64Base); return VINF_SUCCESS; case DBGFREGVALTYPE_INVALID: case DBGFREGVALTYPE_END: case DBGFREGVALTYPE_32BIT_HACK: break; } rc = VERR_INTERNAL_ERROR_5; } return rc; }
/** * Internal helper for rtZipGzip_Write, rtZipGzip_Flush and rtZipGzip_Close. * * @returns IPRT status code. * @retval VINF_SUCCESS * @retval VINF_TRY_AGAIN - the only informational status. * @retval VERR_INTERRUPTED - call again. * * @param pThis The gzip I/O stream instance data. * @param fBlocking Whether to block or not. */ static int rtZipGzip_WriteOutputBuffer(PRTZIPGZIPSTREAM pThis, bool fBlocking) { /* * Anything to write? No, then just return immediately. */ size_t cbToWrite = sizeof(pThis->abBuffer) - pThis->Zlib.avail_out; if (cbToWrite == 0) { Assert(pThis->Zlib.next_out == &pThis->abBuffer[0]); return VINF_SUCCESS; } Assert(cbToWrite <= sizeof(pThis->abBuffer)); /* * Loop write on VERR_INTERRUPTED. * * Note! Asserting a bit extra here to make sure the * RTVfsIoStrmSgWrite works correctly. */ int rc; size_t cbWrittenOut; for (;;) { /* Set up the buffer. */ pThis->SgSeg.cbSeg = cbToWrite; Assert(pThis->SgSeg.pvSeg == &pThis->abBuffer[0]); RTSgBufReset(&pThis->SgBuf); cbWrittenOut = ~(size_t)0; rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, &pThis->SgBuf, fBlocking, &cbWrittenOut); if (rc != VINF_SUCCESS) { AssertMsg(RT_FAILURE(rc) || rc == VINF_TRY_AGAIN, ("%Rrc\n", rc)); if (rc == VERR_INTERRUPTED) { Assert(cbWrittenOut == 0); continue; } if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN || cbWrittenOut == 0) { AssertReturn(cbWrittenOut == 0, VERR_INTERNAL_ERROR_3); AssertReturn(rc != VINF_SUCCESS, VERR_IPE_UNEXPECTED_INFO_STATUS); return rc; } } break; } AssertMsgReturn(cbWrittenOut > 0 && cbWrittenOut <= sizeof(pThis->abBuffer), ("%zu %Rrc\n", cbWrittenOut, rc), VERR_INTERNAL_ERROR_4); /* * Adjust the Zlib output buffer members. */ if (cbWrittenOut == pThis->SgBuf.paSegs[0].cbSeg) { pThis->Zlib.avail_out = sizeof(pThis->abBuffer); pThis->Zlib.next_out = &pThis->abBuffer[0]; } else { Assert(cbWrittenOut <= pThis->SgBuf.paSegs[0].cbSeg); size_t cbLeft = pThis->SgBuf.paSegs[0].cbSeg - cbWrittenOut; memmove(&pThis->abBuffer[0], &pThis->abBuffer[cbWrittenOut], cbLeft); pThis->Zlib.avail_out += (uInt)cbWrittenOut; pThis->Zlib.next_out = &pThis->abBuffer[cbWrittenOut]; } return VINF_SUCCESS; }
RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs) { int rc = VINF_SUCCESS; /* * Parameter validation. */ PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx; RTFILEAIOCTX_VALID_RETURN(pCtxInt); AssertReturn(cReqs > 0, VERR_INVALID_PARAMETER); AssertPtrReturn(pahReqs, VERR_INVALID_POINTER); uint32_t i = cReqs; PRTFILEAIOREQINTERNAL pReqInt = NULL; /* * Validate requests and associate with the context. */ while (i-- > 0) { pReqInt = pahReqs[i]; if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt)) { /* Undo everything and stop submitting. */ size_t iUndo = cReqs; while (iUndo-- > i) { pReqInt = pahReqs[iUndo]; RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); pReqInt->pCtxInt = NULL; } return VERR_INVALID_HANDLE; } pReqInt->AioContext = pCtxInt->AioContext; pReqInt->pCtxInt = pCtxInt; RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED); } do { /* * We cast pahReqs to the Linux iocb structure to avoid copying the requests * into a temporary array. This is possible because the iocb structure is * the first element in the request structure (see PRTFILEAIOCTXINTERNAL). */ int cReqsSubmitted = 0; rc = rtFileAsyncIoLinuxSubmit(pCtxInt->AioContext, cReqs, (PLNXKAIOIOCB *)pahReqs, &cReqsSubmitted); if (RT_FAILURE(rc)) { /* * We encountered an error. * This means that the first IoCB * is not correctly initialized * (invalid buffer alignment or bad file descriptor). * Revert every request into the prepared state except * the first one which will switch to completed. * Another reason could be insufficient resources. */ i = cReqs; while (i-- > 0) { /* Already validated. */ pReqInt = pahReqs[i]; pReqInt->pCtxInt = NULL; pReqInt->AioContext = 0; RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED); } if (rc == VERR_TRY_AGAIN) return VERR_FILE_AIO_INSUFFICIENT_RESSOURCES; else { /* The first request failed. */ pReqInt = pahReqs[0]; RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); pReqInt->Rc = rc; pReqInt->cbTransfered = 0; return rc; } } /* Advance. */ cReqs -= cReqsSubmitted; pahReqs += cReqsSubmitted; ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmitted); } while (cReqs); return rc; }
RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies, PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs) { /* * Validate the parameters, making sure to always set pcReqs. */ AssertPtrReturn(pcReqs, VERR_INVALID_POINTER); *pcReqs = 0; /* always set */ PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx; RTFILEAIOCTX_VALID_RETURN(pCtxInt); AssertPtrReturn(pahReqs, VERR_INVALID_POINTER); AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER); AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE); /* * Can't wait if there are not requests around. */ if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0)) return VERR_FILE_AIO_NO_REQUEST; /* * Convert the timeout if specified. */ struct timespec *pTimeout = NULL; struct timespec Timeout = {0,0}; uint64_t StartNanoTS = 0; if (cMillies != RT_INDEFINITE_WAIT) { Timeout.tv_sec = cMillies / 1000; Timeout.tv_nsec = cMillies % 1000 * 1000000; pTimeout = &Timeout; StartNanoTS = RTTimeNanoTS(); } /* Wait for at least one. */ if (!cMinReqs) cMinReqs = 1; /* For the wakeup call. */ Assert(pCtxInt->hThreadWait == NIL_RTTHREAD); ASMAtomicWriteHandle(&pCtxInt->hThreadWait, RTThreadSelf()); /* * Loop until we're woken up, hit an error (incl timeout), or * have collected the desired number of requests. */ int rc = VINF_SUCCESS; int cRequestsCompleted = 0; while (!pCtxInt->fWokenUp) { LNXKAIOIOEVENT aPortEvents[AIO_MAXIMUM_REQUESTS_PER_CONTEXT]; int cRequestsToWait = RT_MIN(cReqs, AIO_MAXIMUM_REQUESTS_PER_CONTEXT); ASMAtomicXchgBool(&pCtxInt->fWaiting, true); rc = rtFileAsyncIoLinuxGetEvents(pCtxInt->AioContext, cMinReqs, cRequestsToWait, &aPortEvents[0], pTimeout); ASMAtomicXchgBool(&pCtxInt->fWaiting, false); if (RT_FAILURE(rc)) break; uint32_t const cDone = rc; rc = VINF_SUCCESS; /* * Process received events / requests. */ for (uint32_t i = 0; i < cDone; i++) { /* * The iocb is the first element in our request structure. * So we can safely cast it directly to the handle (see above) */ PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)aPortEvents[i].pIoCB; AssertPtr(pReqInt); Assert(pReqInt->u32Magic == RTFILEAIOREQ_MAGIC); /** @todo aeichner: The rc field contains the result code * like you can find in errno for the normal read/write ops. * But there is a second field called rc2. I don't know the * purpose for it yet. */ if (RT_UNLIKELY(aPortEvents[i].rc < 0)) pReqInt->Rc = RTErrConvertFromErrno(-aPortEvents[i].rc); /* Convert to positive value. */ else { pReqInt->Rc = VINF_SUCCESS; pReqInt->cbTransfered = aPortEvents[i].rc; } /* Mark the request as finished. */ RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED); pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt; } /* * Done Yet? If not advance and try again. */ if (cDone >= cMinReqs) break; cMinReqs -= cDone; cReqs -= cDone; if (cMillies != RT_INDEFINITE_WAIT) { /* The API doesn't return ETIMEDOUT, so we have to fix that ourselves. */ uint64_t NanoTS = RTTimeNanoTS(); uint64_t cMilliesElapsed = (NanoTS - StartNanoTS) / 1000000; if (cMilliesElapsed >= cMillies) { rc = VERR_TIMEOUT; break; } /* The syscall supposedly updates it, but we're paranoid. :-) */ Timeout.tv_sec = (cMillies - (RTMSINTERVAL)cMilliesElapsed) / 1000; Timeout.tv_nsec = (cMillies - (RTMSINTERVAL)cMilliesElapsed) % 1000 * 1000000; } } /* * Update the context state and set the return value. */ *pcReqs = cRequestsCompleted; ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted); Assert(pCtxInt->hThreadWait == RTThreadSelf()); ASMAtomicWriteHandle(&pCtxInt->hThreadWait, NIL_RTTHREAD); /* * Clear the wakeup flag and set rc. */ if ( pCtxInt->fWokenUp && RT_SUCCESS(rc)) { ASMAtomicXchgBool(&pCtxInt->fWokenUp, false); rc = VERR_INTERRUPTED; } return rc; }
RTDECL(int) RTCrX509Certificate_VerifySignature(PCRTCRX509CERTIFICATE pThis, PCRTASN1OBJID pAlgorithm, PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey, PRTERRINFO pErrInfo) { /* * Validate the input a little. */ AssertPtrReturn(pThis, VERR_INVALID_POINTER); AssertReturn(RTCrX509Certificate_IsPresent(pThis), VERR_INVALID_PARAMETER); AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER); AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER); if (pParameters) { AssertPtrReturn(pParameters, VERR_INVALID_POINTER); if (pParameters->enmType == RTASN1TYPE_NULL) pParameters = NULL; } AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER); AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER); /* * Check if the algorithm matches. */ const char *pszCipherOid = RTCrPkixGetCiperOidFromSignatureAlgorithm(&pThis->SignatureAlgorithm.Algorithm); if (!pszCipherOid) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO, "Certificate signature algorithm not known: %s", pThis->SignatureAlgorithm.Algorithm.szObjId); if (RTAsn1ObjId_CompareWithString(pAlgorithm, pszCipherOid) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH, "Certificate signature cipher algorithm mismatch: cert uses %s (%s) while key uses %s", pszCipherOid, pThis->SignatureAlgorithm.Algorithm.szObjId, pAlgorithm->szObjId); /* * Wrap up the public key. */ RTCRKEY hPubKey; int rc = RTCrKeyCreateFromPublicAlgorithmAndBits(&hPubKey, pAlgorithm, pPublicKey, pErrInfo, NULL); if (RT_FAILURE(rc)) return rc; /* * Here we should recode the to-be-signed part as DER, but we'll ASSUME * that it's already in DER encoding and only does this if there the * encoded bits are missing. */ if ( pThis->TbsCertificate.SeqCore.Asn1Core.uData.pu8 && pThis->TbsCertificate.SeqCore.Asn1Core.cb > 0) rc = RTCrPkixPubKeyVerifySignature(&pThis->SignatureAlgorithm.Algorithm, hPubKey, pParameters, &pThis->SignatureValue, RTASN1CORE_GET_RAW_ASN1_PTR(&pThis->TbsCertificate.SeqCore.Asn1Core), RTASN1CORE_GET_RAW_ASN1_SIZE(&pThis->TbsCertificate.SeqCore.Asn1Core), pErrInfo); else { uint32_t cbEncoded; rc = RTAsn1EncodePrepare((PRTASN1CORE)&pThis->TbsCertificate.SeqCore.Asn1Core, RTASN1ENCODE_F_DER, &cbEncoded, pErrInfo); if (RT_SUCCESS(rc)) { void *pvTbsBits = RTMemTmpAlloc(cbEncoded); if (pvTbsBits) { rc = RTAsn1EncodeToBuffer(&pThis->TbsCertificate.SeqCore.Asn1Core, RTASN1ENCODE_F_DER, pvTbsBits, cbEncoded, pErrInfo); if (RT_SUCCESS(rc)) rc = RTCrPkixPubKeyVerifySignature(&pThis->SignatureAlgorithm.Algorithm, hPubKey, pParameters, &pThis->SignatureValue, pvTbsBits, cbEncoded, pErrInfo); else AssertRC(rc); RTMemTmpFree(pvTbsBits); } else rc = VERR_NO_TMP_MEMORY; } } /* Free the public key. */ uint32_t cRefs = RTCrKeyRelease(hPubKey); Assert(cRefs == 0); NOREF(cRefs); return rc; }
/** * Deals with authenticated attributes. * * When authenticated attributes are present (checked by caller) we must: * - fish out the content type and check it against the content inof, * - fish out the message digest among and check it against *phDigest, * - compute the message digest of the authenticated attributes and * replace *phDigest with this for the signature verification. * * @returns IPRT status code. * @param pSignerInfo The signer info being verified. * @param pSignedData The signed data. * @param phDigest On input this is the digest of the content. On * output it will (on success) be a reference to * the message digest of the authenticated * attributes. The input reference is consumed. * The caller shall release the output reference. * @param fFlags Flags. * @param pErrInfo Extended error info, optional. */ static int rtCrPkcs7VerifySignerInfoAuthAttribs(PCRTCRPKCS7SIGNERINFO pSignerInfo, PCRTCRPKCS7SIGNEDDATA pSignedData, PRTCRDIGEST phDigest, uint32_t fFlags, PRTERRINFO pErrInfo) { /* * Scan the attributes and validate the two required attributes * (RFC-2315, chapter 9.2, fourth bullet). Checking that we've got exactly * one of each of them is checked by the santiy checker function, so we'll * just assert that it did it's job here. */ uint32_t cContentTypes = 0; uint32_t cMessageDigests = 0; uint32_t i = pSignerInfo->AuthenticatedAttributes.cItems; while (i-- > 0) { PCRTCRPKCS7ATTRIBUTE pAttrib = &pSignerInfo->AuthenticatedAttributes.paItems[i]; if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_CONTENT_TYPE_OID) == 0) { AssertReturn(!cContentTypes, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->uValues.pObjIds->cItems == 1, VERR_CR_PKCS7_INTERNAL_ERROR); if ( !(fFlags & RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE) /* See note about microsoft below. */ && RTAsn1ObjId_Compare(&pAttrib->uValues.pObjIds->paItems[0], &pSignedData->ContentInfo.ContentType) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_CONTENT_TYPE_ATTRIB_MISMATCH, "Expected content-type %s, found %s", &pAttrib->uValues.pObjIds->paItems[0], pSignedData->ContentInfo.ContentType.szObjId); cContentTypes++; } else if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_MESSAGE_DIGEST_OID) == 0) { AssertReturn(!cMessageDigests, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS, VERR_CR_PKCS7_INTERNAL_ERROR); AssertReturn(pAttrib->uValues.pOctetStrings->cItems == 1, VERR_CR_PKCS7_INTERNAL_ERROR); if (!RTCrDigestMatch(*phDigest, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.uData.pv, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.cb)) { size_t cbHash = RTCrDigestGetHashSize(*phDigest); if (cbHash != pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.cb) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH, "Authenticated message-digest attribute mismatch: cbHash=%#zx cbValue=%#x", cbHash, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.cb); return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_MESSAGE_DIGEST_ATTRIB_MISMATCH, "Authenticated message-digest attribute mismatch (cbHash=%#zx):\n" "signed: %.*Rhxs\n" "our: %.*Rhxs\n", cbHash, cbHash, pAttrib->uValues.pOctetStrings->paItems[0].Asn1Core.uData.pv, cbHash, RTCrDigestGetHash(*phDigest)); } cMessageDigests++; } } /* * Full error reporting here as we don't currently extensively santiy check * counter signatures. * Note! Microsoft includes content info in their timestamp counter signatures, * at least for vista, despite the RFC-3852 stating counter signatures * "MUST NOT contain a content-type". */ if (RT_UNLIKELY( cContentTypes != 1 && !(fFlags & RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE))) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB, "Missing authenticated content-type attribute."); if (RT_UNLIKELY(cMessageDigests != 1)) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB, "Missing authenticated message-digest attribute."); /* * Calculate the digest of the the authenticated attributes for use in the * signature validation. */ if ( pSignerInfo->DigestAlgorithm.Parameters.enmType != RTASN1TYPE_NULL && pSignerInfo->DigestAlgorithm.Parameters.enmType != RTASN1TYPE_NOT_PRESENT) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL, "Digest algorithm has unsupported parameters"); RTCRDIGEST hDigest; int rc = RTCrDigestCreateByObjId(&hDigest, &pSignerInfo->DigestAlgorithm.Algorithm); if (RT_SUCCESS(rc)) { RTCrDigestRelease(*phDigest); *phDigest = hDigest; /* ASSUMES that the attributes are encoded according to DER. */ uint8_t const *pbData = (uint8_t const *)RTASN1CORE_GET_RAW_ASN1_PTR(&pSignerInfo->AuthenticatedAttributes.SetCore.Asn1Core); uint32_t cbData = RTASN1CORE_GET_RAW_ASN1_SIZE(&pSignerInfo->AuthenticatedAttributes.SetCore.Asn1Core); uint8_t bSetOfTag = ASN1_TAG_SET | ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED; rc = RTCrDigestUpdate(hDigest, &bSetOfTag, sizeof(bSetOfTag)); /* Replace the implict tag with a SET-OF tag. */ if (RT_SUCCESS(rc)) rc = RTCrDigestUpdate(hDigest, pbData + sizeof(bSetOfTag), cbData - sizeof(bSetOfTag)); /* Skip the implicit tag. */ if (RT_SUCCESS(rc)) rc = RTCrDigestFinal(hDigest, NULL, 0); } return rc; }
/** * Initializes a file object but does *not* open the file on the guest * yet. This is done in the dedidcated openFile call. * * @return IPRT status code. * @param pConsole Pointer to console object. * @param pSession Pointer to session object. * @param uFileID Host-based file ID (part of the context ID). * @param openInfo File opening information. */ int GuestFile::init(Console *pConsole, GuestSession *pSession, ULONG uFileID, const GuestFileOpenInfo &openInfo) { LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n", pConsole, pSession, uFileID, openInfo.mFileName.c_str())); AssertPtrReturn(pConsole, VERR_INVALID_POINTER); AssertPtrReturn(pSession, VERR_INVALID_POINTER); /* Enclose the state transition NotReady->InInit->Ready. */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */); if (RT_SUCCESS(vrc)) { mSession = pSession; mData.mID = uFileID; mData.mInitialSize = 0; mData.mStatus = FileStatus_Undefined; mData.mOpenInfo = openInfo; unconst(mEventSource).createObject(); HRESULT hr = mEventSource->init(); if (FAILED(hr)) vrc = VERR_COM_UNEXPECTED; } if (RT_SUCCESS(vrc)) { try { GuestFileListener *pListener = new GuestFileListener(); ComObjPtr<GuestFileListenerImpl> thisListener; HRESULT hr = thisListener.createObject(); if (SUCCEEDED(hr)) hr = thisListener->init(pListener, this); if (SUCCEEDED(hr)) { com::SafeArray <VBoxEventType_T> eventTypes; eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged); eventTypes.push_back(VBoxEventType_OnGuestFileRead); eventTypes.push_back(VBoxEventType_OnGuestFileWrite); hr = mEventSource->RegisterListener(thisListener, ComSafeArrayAsInParam(eventTypes), TRUE /* Active listener */); if (SUCCEEDED(hr)) { vrc = baseInit(); if (RT_SUCCESS(vrc)) { mLocalListener = thisListener; } } else vrc = VERR_COM_UNEXPECTED; } else vrc = VERR_COM_UNEXPECTED; } catch(std::bad_alloc &) { vrc = VERR_NO_MEMORY; } } if (RT_SUCCESS(vrc)) { /* Confirm a successful initialization when it's the case. */ autoInitSpan.setSucceeded(); } else autoInitSpan.setFailed(); LogFlowFuncLeaveRC(vrc); return vrc; }
STDMETHODIMP Session::AssignRemoteMachine(IMachine *aMachine, IConsole *aConsole) { LogFlowThisFuncEnter(); LogFlowThisFunc(("aMachine=%p, aConsole=%p\n", aMachine, aConsole)); AssertReturn(aMachine && aConsole, E_INVALIDARG); AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Unlocked || mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE); HRESULT rc = E_FAIL; /* query IInternalMachineControl interface */ mControl = aMachine; AssertReturn(!!mControl, E_FAIL); /// @todo (dmik) // currently, the remote session returns the same machine and // console objects as the direct session, thus giving the // (remote) client full control over the direct session. For the // console, it is the desired behavior (the ability to control // VM execution is a must for the remote session). What about // the machine object, we may want to prevent the remote client // from modifying machine data. In this case, we must: // 1) assign the Machine object (instead of the SessionMachine // object that is passed to this method) to mRemoteMachine; // 2) remove GetMachine() property from the IConsole interface // because it always returns the SessionMachine object // (alternatively, we can supply a separate IConsole // implementation that will return the Machine object in // response to GetMachine()). mRemoteMachine = aMachine; mRemoteConsole = aConsole; /* * Reference the VirtualBox object to ensure the server is up * until the session is closed */ rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam()); if (SUCCEEDED(rc)) { /* * RemoteSession type can be already set by AssignMachine() when its * argument is NULL (a special case) */ if (mType != SessionType_Remote) mType = SessionType_Shared; else Assert(mState == SessionState_Spawning); mState = SessionState_Locked; } else { /* some cleanup */ mControl.setNull(); mRemoteMachine.setNull(); mRemoteConsole.setNull(); } LogFlowThisFunc(("rc=%08X\n", rc)); LogFlowThisFuncLeave(); return rc; }
/* return a failure if the session already transitioned to Closing * but the server hasn't processed Machine::OnSessionEnd() yet. */ if (mState != SessionState_Locked) return VBOX_E_INVALID_VM_STATE; mConsole.queryInterfaceTo(aConsole); LogFlowThisFuncLeave(); return S_OK; #else /* VBOX_COM_INPROC_API_CLIENT */ AssertFailed(); return VBOX_E_INVALID_OBJECT_STATE; #endif /* VBOX_COM_INPROC_API_CLIENT */ } #ifndef VBOX_WITH_GENERIC_SESSION_WATCHER STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType, IN_BSTR aTokenId) #else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType, IToken *aToken) #endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ { LogFlowThisFuncEnter(); LogFlowThisFunc(("aMachine=%p\n", aMachine)); AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), autoCaller.rc()); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); AssertReturn(mState == SessionState_Unlocked, VBOX_E_INVALID_VM_STATE); if (!aMachine) { /* * A special case: the server informs us that this session has been * passed to IMachine::launchVMProcess() so this session will become * remote (but not existing) when AssignRemoteMachine() is called. */ AssertReturn(mType == SessionType_Null, VBOX_E_INVALID_OBJECT_STATE); mType = SessionType_Remote; mState = SessionState_Spawning; LogFlowThisFuncLeave(); return S_OK; } /* query IInternalMachineControl interface */ mControl = aMachine; AssertReturn(!!mControl, E_FAIL); #ifndef VBOX_COM_INPROC_API_CLIENT HRESULT rc = mConsole.createObject(); AssertComRCReturn(rc, rc); rc = mConsole->init(aMachine, mControl, aLockType); AssertComRCReturn(rc, rc); #else HRESULT rc = S_OK; mRemoteMachine = aMachine; #endif #ifndef VBOX_WITH_GENERIC_SESSION_WATCHER Utf8Str strTokenId(aTokenId); Assert(!strTokenId.isEmpty()); #else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ AssertPtr(aToken); #endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ /* create the machine client token */ try { #ifndef VBOX_WITH_GENERIC_SESSION_WATCHER mClientTokenHolder = new ClientTokenHolder(strTokenId); #else /* VBOX_WITH_GENERIC_SESSION_WATCHER */ mClientTokenHolder = new ClientTokenHolder(aToken); #endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */ if (!mClientTokenHolder->isReady()) { delete mClientTokenHolder; mClientTokenHolder = NULL; rc = E_FAIL; } } catch (std::bad_alloc &) { rc = E_OUTOFMEMORY; } /* * Reference the VirtualBox object to ensure the server is up * until the session is closed */ if (SUCCEEDED(rc)) rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam()); if (SUCCEEDED(rc)) { mType = SessionType_WriteLock; mState = SessionState_Locked; } else { /* some cleanup */ mControl.setNull(); #ifndef VBOX_COM_INPROC_API_CLIENT if (!mConsole.isNull()) { mConsole->uninit(); mConsole.setNull(); } #endif } LogFlowThisFunc(("rc=%08X\n", rc)); LogFlowThisFuncLeave(); return rc; }
/** * Walk through pasteboard items and report currently available item types. * * @param pPasteboard Reference to guest Pasteboard. * @returns Available formats bit field. */ uint32_t vbclClipboardGetAvailableFormats(PasteboardRef pPasteboard) { uint32_t fFormats = 0; ItemCount cItems = 0; ItemCount iItem; OSStatus rc; #define VBOXCL_ADD_FORMAT_IF_PRESENT(a_kDarwinFmt, a_fVBoxFmt) \ if (PasteboardCopyItemFlavorData(pPasteboard, iItemID, a_kDarwinFmt, &flavorData) == noErr) \ { \ fFormats |= (uint32_t)a_fVBoxFmt; \ CFRelease(flavorData); \ } rc = PasteboardGetItemCount(pPasteboard, &cItems); AssertReturn((rc == noErr) && (cItems > 0), fFormats); for (iItem = 1; iItem <= cItems; iItem++) { PasteboardItemID iItemID; CFDataRef flavorData; rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID); if (rc == noErr) { VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeUTF16PlainText, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeUTF8PlainText, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT); VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeBMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP ); VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeHTML, VBOX_SHARED_CLIPBOARD_FMT_HTML ); #ifdef CLIPBOARD_DUMP_CONTENT_FORMATS CFArrayRef flavorTypeArray; CFIndex flavorCount; CFStringRef flavorType; rc = PasteboardCopyItemFlavors(pPasteboard, iItemID, &flavorTypeArray); if (rc == noErr) { VBoxClientVerbose(3, "SCAN..\n"); flavorCount = CFArrayGetCount(flavorTypeArray); VBoxClientVerbose(3, "SCAN (%d)..\n", (int)flavorCount); for(CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++) { VBoxClientVerbose(3, "SCAN #%d..\n", (int)flavorIndex); flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex); CFDataRef flavorData1; rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, flavorType, &flavorData1); if (rc == noErr) { VBoxClientVerbose(3, "Found: %s, size: %d\n", (char *)CFStringGetCStringPtr(flavorType, kCFStringEncodingMacRoman), (int)CFDataGetLength(flavorData1)); CFRelease(flavorData1); } } VBoxClientVerbose(3, "SCAN COMPLETE\n"); CFRelease(flavorTypeArray); } #endif /* CLIPBOARD_DUMP_CONTENT_FORMATS */ } } #undef VBOXCL_ADD_FORMAT_IF_PRESENT return fFormats; }
RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) { IPRT_LINUX_SAVE_EFL_AC(); int rc; RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER; AssertReturn(idCpu1 != idCpu2, VERR_INVALID_PARAMETER); AssertReturn(!(fFlags & RTMPON_F_VALID_MASK), VERR_INVALID_FLAGS); /* * Check that both CPUs are online before doing the broadcast call. */ RTThreadPreemptDisable(&PreemptState); if ( RTMpIsCpuOnline(idCpu1) && RTMpIsCpuOnline(idCpu2)) { /* * Use the smp_call_function variant taking a cpu mask where available, * falling back on broadcast with filter. Slight snag if one of the * CPUs is the one we're running on, we must do the call and the post * call wait ourselves. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) cpumask_t DstCpuMask; #endif RTCPUID idCpuSelf = RTMpCpuId(); bool const fCallSelf = idCpuSelf == idCpu1 || idCpuSelf == idCpu2; RTMPARGS Args; Args.pfnWorker = pfnWorker; Args.pvUser1 = pvUser1; Args.pvUser2 = pvUser2; Args.idCpu = idCpu1; Args.idCpu2 = idCpu2; Args.cHits = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) cpumask_clear(&DstCpuMask); cpumask_set_cpu(idCpu1, &DstCpuMask); cpumask_set_cpu(idCpu2, &DstCpuMask); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) cpus_clear(DstCpuMask); cpu_set(idCpu1, DstCpuMask); cpu_set(idCpu2, DstCpuMask); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) smp_call_function_many(&DstCpuMask, rtmpLinuxWrapperPostInc, &Args, !fCallSelf /* wait */); rc = 0; #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) rc = smp_call_function_mask(DstCpuMask, rtmpLinuxWrapperPostInc, &Args, !fCallSelf /* wait */); #else /* older kernels */ rc = smp_call_function(rtMpLinuxOnPairWrapper, &Args, 0 /* retry */, !fCallSelf /* wait */); #endif /* older kernels */ Assert(rc == 0); /* Call ourselves if necessary and wait for the other party to be done. */ if (fCallSelf) { uint32_t cLoops = 0; rtmpLinuxWrapper(&Args); while (ASMAtomicReadU32(&Args.cHits) < 2) { if ((cLoops & 0x1ff) == 0 && !RTMpIsCpuOnline(idCpuSelf == idCpu1 ? idCpu2 : idCpu1)) break; cLoops++; ASMNopPause(); } } Assert(Args.cHits <= 2); if (Args.cHits == 2) rc = VINF_SUCCESS; else if (Args.cHits == 1) rc = VERR_NOT_ALL_CPUS_SHOWED; else if (Args.cHits == 0) rc = VERR_CPU_OFFLINE; else rc = VERR_CPU_IPE_1; } /* * A CPU must be present to be considered just offline. */ else if ( RTMpIsCpuPresent(idCpu1) && RTMpIsCpuPresent(idCpu2)) rc = VERR_CPU_OFFLINE; else rc = VERR_CPU_NOT_FOUND; RTThreadPreemptRestore(&PreemptState);; IPRT_LINUX_RESTORE_EFL_AC(); return rc; }
RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t cbBuf) { AssertPtrReturn(pszBuf, VERR_INVALID_POINTER); AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER); *pszBuf = '\0'; AssertReturn(enmString > RTSYSDMISTR_INVALID && enmString < RTSYSDMISTR_END, VERR_INVALID_PARAMETER); /* * Figure the property name before we start. */ const char *pszPropName; switch (enmString) { case RTSYSDMISTR_PRODUCT_NAME: pszPropName = "Name"; break; case RTSYSDMISTR_PRODUCT_VERSION: pszPropName = "Version"; break; case RTSYSDMISTR_PRODUCT_UUID: pszPropName = "UUID"; break; case RTSYSDMISTR_PRODUCT_SERIAL: pszPropName = "IdentifyingNumber"; break; case RTSYSDMISTR_MANUFACTURER: pszPropName = "Vendor"; break; default: return VERR_NOT_SUPPORTED; } /* * Before we do anything with COM, we have to initialize it. */ bool fUninit = true; HRESULT hrc = rtSystemDmiWinInitialize(); if (hrc == RPC_E_CHANGED_MODE) fUninit = false; /* don't fail if already initialized */ else if (FAILED(hrc)) return VERR_NOT_SUPPORTED; int rc = VERR_NOT_SUPPORTED; BSTR pBstrPropName = rtSystemWinBstrFromUtf8(pszPropName); if (pBstrPropName) { /* * Instantiate the IWbemLocator, whatever that is and connect to the * DMI serve. */ IWbemLocator *pLoc; hrc = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc); if (SUCCEEDED(hrc)) { IWbemServices *pServices; hrc = rtSystemDmiWinConnectToServer(pLoc, "ROOT\\CIMV2", &pServices); if (SUCCEEDED(hrc)) { /* * Enumerate whatever it is we're looking at and try get * the desired property. */ BSTR pBstrFilter = rtSystemWinBstrFromUtf8("Win32_ComputerSystemProduct"); if (pBstrFilter) { IEnumWbemClassObject *pEnum; hrc = pServices->CreateInstanceEnum(pBstrFilter, 0, NULL, &pEnum); if (SUCCEEDED(hrc)) { do { IWbemClassObject *pObj; ULONG cObjRet; hrc = pEnum->Next(WBEM_INFINITE, 1, &pObj, &cObjRet); if ( SUCCEEDED(hrc) && cObjRet >= 1) { VARIANT Var; VariantInit(&Var); hrc = pObj->Get(pBstrPropName, 0, &Var, 0, 0); if ( SUCCEEDED(hrc) && V_VT(&Var) == VT_BSTR) { /* * Convert the BSTR to UTF-8 and copy it * into the return buffer. */ char *pszValue; rc = RTUtf16ToUtf8(Var.bstrVal, &pszValue); if (RT_SUCCESS(rc)) { rc = RTStrCopy(pszBuf, cbBuf, pszValue); RTStrFree(pszValue); hrc = WBEM_S_FALSE; } } VariantClear(&Var); pObj->Release(); } } while (hrc != WBEM_S_FALSE); pEnum->Release(); } SysFreeString(pBstrFilter); } else hrc = E_OUTOFMEMORY; pServices->Release(); } pLoc->Release(); } SysFreeString(pBstrPropName); } else hrc = E_OUTOFMEMORY; if (fUninit) rtSystemDmiWinTerminate(); if (FAILED(hrc) && rc == VERR_NOT_SUPPORTED) rc = VERR_NOT_SUPPORTED; return rc; }
/** * Registers a new shared module for the VM * * @returns VBox status code. * @param pVM Pointer to the VM. * @param enmGuestOS Guest OS type. * @param pszModuleName Module name. * @param pszVersion Module version. * @param GCBaseAddr Module base address. * @param cbModule Module size. * @param cRegions Number of shared region descriptors. * @param paRegions Shared region(s). * * @todo This should be a GMMR3 call. No need to involve GMM here. */ VMMR3DECL(int) PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule, uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions) { Log(("PGMR3SharedModuleRegister family=%d name=%s version=%s base=%RGv size=%x cRegions=%d\n", enmGuestOS, pszModuleName, pszVersion, GCBaseAddr, cbModule, cRegions)); /* * Sanity check. */ AssertReturn(cRegions <= VMMDEVSHAREDREGIONDESC_MAX, VERR_INVALID_PARAMETER); /* * Allocate and initialize a GMM request. */ PGMMREGISTERSHAREDMODULEREQ pReq; pReq = (PGMMREGISTERSHAREDMODULEREQ)RTMemAllocZ(RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[cRegions])); AssertReturn(pReq, VERR_NO_MEMORY); pReq->enmGuestOS = enmGuestOS; pReq->GCBaseAddr = GCBaseAddr; pReq->cbModule = cbModule; pReq->cRegions = cRegions; for (uint32_t i = 0; i < cRegions; i++) pReq->aRegions[i] = paRegions[i]; int rc = RTStrCopy(pReq->szName, sizeof(pReq->szName), pszModuleName); if (RT_SUCCESS(rc)) { rc = RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion); if (RT_SUCCESS(rc)) { /* * Issue the request. In strict builds, do some local tracking. */ pgmR3PhysAssertSharedPageChecksums(pVM); rc = GMMR3RegisterSharedModule(pVM, pReq); if (RT_SUCCESS(rc)) rc = pReq->rc; AssertMsg(rc == VINF_SUCCESS || rc == VINF_GMM_SHARED_MODULE_ALREADY_REGISTERED, ("%Rrc\n", rc)); # ifdef VBOX_STRICT if ( rc == VINF_SUCCESS && g_cSharedModules < RT_ELEMENTS(g_apSharedModules)) { unsigned i; for (i = 0; i < RT_ELEMENTS(g_apSharedModules); i++) if (g_apSharedModules[i] == NULL) { size_t const cbSharedModule = RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[cRegions]); g_apSharedModules[i] = (PGMMREGISTERSHAREDMODULEREQ)RTMemDup(pReq, cbSharedModule); g_cSharedModules++; break; } Assert(i < RT_ELEMENTS(g_apSharedModules)); } # endif /* VBOX_STRICT */ if (RT_SUCCESS(rc)) rc = VINF_SUCCESS; } } RTMemFree(pReq); return rc; }
/** * Reads one segment. * * @returns IPRT status code. * @param pThis The gzip I/O stream instance data. * @param pvBuf Where to put the read bytes. * @param cbToRead The number of bytes to read. * @param fBlocking Whether to block or not. * @param pcbRead Where to store the number of bytes actually read. */ static int rtZipGzip_ReadOneSeg(PRTZIPGZIPSTREAM pThis, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead) { /* * This simplifies life a wee bit below. */ if (pThis->fEndOfStream) return pcbRead ? VINF_EOF : VERR_EOF; /* * Set up the output buffer. */ pThis->Zlib.next_out = (Bytef *)pvBuf; pThis->Zlib.avail_out = (uInt)cbToRead; AssertReturn(pThis->Zlib.avail_out == cbToRead, VERR_OUT_OF_RANGE); /* * Be greedy reading input, even if no output buffer is left. It's possible * that it's just the end of stream marker which needs to be read. Happens * for incompressible blocks just larger than the input buffer size. */ int rc = VINF_SUCCESS; while ( pThis->Zlib.avail_out > 0 || pThis->Zlib.avail_in == 0 /* greedy */) { /* * Read more input? * * N.B. The assertions here validate the RTVfsIoStrmSgRead behavior * since the API is new and untested. They could be removed later * but, better leaving them in. */ if (pThis->Zlib.avail_in == 0) { size_t cbReadIn = ~(size_t)0; rc = RTVfsIoStrmSgRead(pThis->hVfsIos, &pThis->SgBuf, fBlocking, &cbReadIn); if (rc != VINF_SUCCESS) { AssertMsg(RT_FAILURE(rc) || rc == VINF_TRY_AGAIN || rc == VINF_EOF, ("%Rrc\n", rc)); if (rc == VERR_INTERRUPTED) { Assert(cbReadIn == 0); continue; } if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN || cbReadIn == 0) { Assert(cbReadIn == 0); break; } AssertMsg(rc == VINF_EOF, ("%Rrc\n", rc)); } AssertMsgBreakStmt(cbReadIn > 0 && cbReadIn <= sizeof(pThis->abBuffer), ("%zu %Rrc\n", cbReadIn, rc), rc = VERR_INTERNAL_ERROR_4); pThis->Zlib.avail_in = (uInt)cbReadIn; pThis->Zlib.next_in = &pThis->abBuffer[0]; } /* * Pass it on to zlib. */ rc = inflate(&pThis->Zlib, Z_NO_FLUSH); if (rc != Z_OK && rc != Z_BUF_ERROR) { if (rc == Z_STREAM_END) { pThis->fEndOfStream = true; if (pThis->Zlib.avail_out == 0) rc = VINF_SUCCESS; else rc = pcbRead ? VINF_EOF : VERR_EOF; } else rc = rtZipGzipConvertErrFromZlib(pThis, rc); break; } rc = VINF_SUCCESS; } /* * Update the read counters before returning. */ size_t const cbRead = cbToRead - pThis->Zlib.avail_out; pThis->offStream += cbRead; if (pcbRead) *pcbRead = cbRead; return rc; }
int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename) { pImage->idSolMod = -1; pImage->pSolModCtl = NULL; # if 1 /* This approach requires _init/_fini/_info stubs. */ /* * Construct a filename that escapes the module search path and let us * specify a root path. */ /** @todo change this to use modctl and use_path=0. */ const char *pszName = RTPathFilename(pszFilename); AssertReturn(pszName, VERR_INVALID_PARAMETER); char *pszSubDir = RTStrAPrintf2("../../../../../../../../../../..%.*s", pszName - pszFilename - 1, pszFilename); if (!pszSubDir) return VERR_NO_STR_MEMORY; int idMod = modload(pszSubDir, pszName); if (idMod == -1) { /* This is an horrible hack for avoiding the mod-present check in modrload on S10. Fortunately, nobody else seems to be using that variable... */ extern int swaploaded; int saved_swaploaded = swaploaded; swaploaded = 0; idMod = modload(pszSubDir, pszName); swaploaded = saved_swaploaded; } RTStrFree(pszSubDir); if (idMod == -1) { LogRel(("modload(,%s): failed, could be anything...\n", pszFilename)); return VERR_LDR_GENERAL_FAILURE; } modctl_t *pModCtl = mod_hold_by_id(idMod); if (!pModCtl) { LogRel(("mod_hold_by_id(,%s): failed, weird.\n", pszFilename)); /* No point in calling modunload. */ return VERR_LDR_GENERAL_FAILURE; } pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD | MOD_NOUNLOAD; /* paranoia */ # else const int idMod = -1; modctl_t *pModCtl = mod_hold_by_name(pszFilename); if (!pModCtl) { LogRel(("mod_hold_by_name failed for '%s'\n", pszFilename)); return VERR_LDR_GENERAL_FAILURE; } int rc = kobj_load_module(pModCtl, 0 /*use_path*/); if (rc != 0) { LogRel(("kobj_load_module failed with rc=%d for '%s'\n", rc, pszFilename)); mod_release_mod(pModCtl); return RTErrConvertFromErrno(rc); } # endif /* * Get the module info. * * Note! The text section is actually not at mi_base, but and the next * alignment boundrary and there seems to be no easy way of * getting at this address. This sabotages supdrvOSLdrLoad. * Bastards! */ struct modinfo ModInfo; kobj_getmodinfo(pModCtl->mod_mp, &ModInfo); pImage->pvImage = ModInfo.mi_base; pImage->idSolMod = idMod; pImage->pSolModCtl = pModCtl; mod_release_mod(pImage->pSolModCtl); LogRel(("supdrvOSLdrOpen: succeeded for '%s' (mi_base=%p mi_size=%#x), id=%d ctl=%p\n", pszFilename, ModInfo.mi_base, ModInfo.mi_size, idMod, pModCtl)); return VINF_SUCCESS; }
RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSIOSTREAM phVfsIosOut) { AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE); AssertReturn(!(fFlags & ~RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR), VERR_INVALID_PARAMETER); AssertPtrReturn(phVfsIosOut, VERR_INVALID_POINTER); uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn); AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE); /* * Create the decompression I/O stream. */ RTVFSIOSTREAM hVfsIos; PRTZIPGZIPSTREAM pThis; int rc = RTVfsNewIoStream(&g_rtZipGzipOps, sizeof(RTZIPGZIPSTREAM), RTFILE_O_READ, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsIos, (void **)&pThis); if (RT_SUCCESS(rc)) { pThis->hVfsIos = hVfsIosIn; pThis->offStream = 0; pThis->fDecompress = true; pThis->SgSeg.pvSeg = &pThis->abBuffer[0]; pThis->SgSeg.cbSeg = sizeof(pThis->abBuffer); RTSgBufInit(&pThis->SgBuf, &pThis->SgSeg, 1); memset(&pThis->Zlib, 0, sizeof(pThis->Zlib)); pThis->Zlib.opaque = pThis; rc = inflateInit2(&pThis->Zlib, fFlags & RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR ? MAX_WBITS : MAX_WBITS + 16 /* autodetect gzip header */); if (rc >= 0) { /* * Read the gzip header from the input stream to check that it's * a gzip stream as specified by the user. * * Note!. Since we've told zlib to check for the gzip header, we * prebuffer what we read in the input buffer so it can * be handed on to zlib later on. */ rc = RTVfsIoStrmRead(pThis->hVfsIos, pThis->abBuffer, sizeof(RTZIPGZIPHDR), true /*fBlocking*/, NULL /*pcbRead*/); if (RT_SUCCESS(rc)) { /* Validate the header and make a copy of it. */ PCRTZIPGZIPHDR pHdr = (PCRTZIPGZIPHDR)pThis->abBuffer; if ( pHdr->bId1 == RTZIPGZIPHDR_ID1 && pHdr->bId2 == RTZIPGZIPHDR_ID2 && !(pHdr->fFlags & ~RTZIPGZIPHDR_FLG_VALID_MASK)) { if (pHdr->bCompressionMethod == RTZIPGZIPHDR_CM_DEFLATE) rc = VINF_SUCCESS; else rc = VERR_ZIP_UNSUPPORTED_METHOD; } else if ( (fFlags & RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR) && (RT_MAKE_U16(pHdr->bId2, pHdr->bId1) % 31) == 0 && (pHdr->bId1 & 0xf) == RTZIPGZIPHDR_CM_DEFLATE ) { pHdr = NULL; rc = VINF_SUCCESS; } else rc = VERR_ZIP_BAD_HEADER; if (RT_SUCCESS(rc)) { pThis->Zlib.avail_in = sizeof(RTZIPGZIPHDR); pThis->Zlib.next_in = &pThis->abBuffer[0]; if (pHdr) { pThis->Hdr = *pHdr; /* Parse on if there are names or comments. */ if (pHdr->fFlags & (RTZIPGZIPHDR_FLG_NAME | RTZIPGZIPHDR_FLG_COMMENT)) { /** @todo Can implement this when someone needs the * name or comment for something useful. */ } } if (RT_SUCCESS(rc)) { *phVfsIosOut = hVfsIos; return VINF_SUCCESS; } } } } else rc = rtZipGzipConvertErrFromZlib(pThis, rc); /** @todo cleaning up in this situation is going to go wrong. */ RTVfsIoStrmRelease(hVfsIos); } else RTVfsIoStrmRelease(hVfsIosIn); return rc; }
RTDECL(int) RTSemSpinMutexRequest(RTSEMSPINMUTEX hSpinMtx) { RTSEMSPINMUTEXINTERNAL *pThis = hSpinMtx; RTNATIVETHREAD hSelf = RTThreadNativeSelf(); RTSEMSPINMUTEXSTATE State; bool fRc; int rc; Assert(hSelf != NIL_RTNATIVETHREAD); RTSEMSPINMUTEX_VALIDATE_RETURN(pThis); /* * Check context, disable preemption and save flags if necessary. */ rc = rtSemSpinMutexEnter(&State, pThis); if (RT_FAILURE(rc)) return rc; /* * Try take the ownership. */ ASMAtomicIncS32(&pThis->cLockers); ASMAtomicCmpXchgHandle(&pThis->hOwner, hSelf, NIL_RTNATIVETHREAD, fRc); if (!fRc) { uint32_t cSpins; /* * It's busy. Check if it's an attempt at nested access. */ if (RT_UNLIKELY(pThis->hOwner == hSelf)) { AssertMsgFailed(("%p attempt at nested access\n")); rtSemSpinMutexLeave(&State); return VERR_SEM_NESTED; } /* * Return if we're in interrupt context and the semaphore isn't * configure to be interrupt safe. */ if (rc == VINF_SEM_BAD_CONTEXT) { rtSemSpinMutexLeave(&State); return VERR_SEM_BAD_CONTEXT; } /* * Ok, we have to wait. */ if (State.fSpin) { for (cSpins = 0; ; cSpins++) { ASMAtomicCmpXchgHandle(&pThis->hOwner, hSelf, NIL_RTNATIVETHREAD, fRc); if (fRc) break; ASMNopPause(); if (RT_UNLIKELY(pThis->u32Magic != RTSEMSPINMUTEX_MAGIC)) { rtSemSpinMutexLeave(&State); return VERR_SEM_DESTROYED; } /* * "Yield" once in a while. This may lower our IRQL/PIL which * may preempting us, and it will certainly stop the hammering * of hOwner for a little while. */ if ((cSpins & 0x7f) == 0x1f) { rtSemSpinMutexLeave(&State); rtSemSpinMutexEnter(&State, pThis); Assert(State.fSpin); } } } else { for (cSpins = 0;; cSpins++) { ASMAtomicCmpXchgHandle(&pThis->hOwner, hSelf, NIL_RTNATIVETHREAD, fRc); if (fRc) break; ASMNopPause(); if (RT_UNLIKELY(pThis->u32Magic != RTSEMSPINMUTEX_MAGIC)) { rtSemSpinMutexLeave(&State); return VERR_SEM_DESTROYED; } if ((cSpins & 15) == 15) /* spin a bit before going sleep (again). */ { rtSemSpinMutexLeave(&State); rc = RTSemEventWait(pThis->hEventSem, RT_INDEFINITE_WAIT); ASMCompilerBarrier(); if (RT_SUCCESS(rc)) AssertReturn(pThis->u32Magic == RTSEMSPINMUTEX_MAGIC, VERR_SEM_DESTROYED); else if (rc == VERR_INTERRUPTED) AssertRC(rc); /* shouldn't happen */ else { AssertRC(rc); return rc; } rc = rtSemSpinMutexEnter(&State, pThis); AssertRCReturn(rc, rc); Assert(!State.fSpin); } } } } /* * We're the semaphore owner. */ pThis->SavedState = State; Assert(pThis->hOwner == hSelf); return VINF_SUCCESS; }
DECL_FORCE_INLINE(int) rtCritSectEnter(PRTCRITSECT pCritSect, PCRTLOCKVALSRCPOS pSrcPos) { AssertPtr(pCritSect); AssertReturn(pCritSect->u32Magic == RTCRITSECT_MAGIC, VERR_SEM_DESTROYED); /* * Return straight away if NOP. */ if (pCritSect->fFlags & RTCRITSECT_FLAGS_NOP) return VINF_SUCCESS; /* * How is calling and is the order right? */ RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf(); #ifdef RTCRITSECT_STRICT RTTHREAD hThreadSelf = pCritSect->pValidatorRec ? RTThreadSelfAutoAdopt() : RTThreadSelf(); int rc9; if (pCritSect->pValidatorRec) /* (bootstap) */ { rc9 = RTLockValidatorRecExclCheckOrder(pCritSect->pValidatorRec, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT); if (RT_FAILURE(rc9)) return rc9; } #endif /* * Increment the waiter counter. * This becomes 0 when the section is free. */ if (ASMAtomicIncS32(&pCritSect->cLockers) > 0) { /* * Nested? */ if (pCritSect->NativeThreadOwner == NativeThreadSelf) { if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING)) { #ifdef RTCRITSECT_STRICT rc9 = RTLockValidatorRecExclRecursion(pCritSect->pValidatorRec, pSrcPos); if (RT_FAILURE(rc9)) { ASMAtomicDecS32(&pCritSect->cLockers); return rc9; } #endif pCritSect->cNestings++; return VINF_SUCCESS; } AssertBreakpoint(); /* don't do normal assertion here, the logger uses this code too. */ ASMAtomicDecS32(&pCritSect->cLockers); return VERR_SEM_NESTED; } /* * Wait for the current owner to release it. */ #ifndef RTCRITSECT_STRICT RTTHREAD hThreadSelf = RTThreadSelf(); #endif for (;;) { #ifdef RTCRITSECT_STRICT rc9 = RTLockValidatorRecExclCheckBlocking(pCritSect->pValidatorRec, hThreadSelf, pSrcPos, !(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING), RT_INDEFINITE_WAIT, RTTHREADSTATE_CRITSECT, false); if (RT_FAILURE(rc9)) { ASMAtomicDecS32(&pCritSect->cLockers); return rc9; } #else RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT, false); #endif int rc = RTSemEventWait(pCritSect->EventSem, RT_INDEFINITE_WAIT); RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT); if (pCritSect->u32Magic != RTCRITSECT_MAGIC) return VERR_SEM_DESTROYED; if (rc == VINF_SUCCESS) break; AssertMsg(rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc)); } AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner)); } /* * First time */ pCritSect->cNestings = 1; ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf); #ifdef RTCRITSECT_STRICT RTLockValidatorRecExclSetOwner(pCritSect->pValidatorRec, hThreadSelf, pSrcPos, true); #endif return VINF_SUCCESS; }
/** * Tries to parse the next upcoming pair block within the internal * buffer. * * Returns VERR_NO_DATA is no data is in internal buffer or buffer has been * completely parsed already. * * Returns VERR_MORE_DATA if current block was parsed (with zero or more pairs * stored in stream block) but still contains incomplete (unterminated) * data. * * Returns VINF_SUCCESS if current block was parsed until the next upcoming * block (with zero or more pairs stored in stream block). * * @return IPRT status code. * @param streamBlock Reference to guest stream block to fill. * */ int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock) { if ( !m_pbBuffer || !m_cbSize) { return VERR_NO_DATA; } AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER); if (m_cbOffset == m_cbSize) return VERR_NO_DATA; int rc = VINF_SUCCESS; char *pszOff = (char*)&m_pbBuffer[m_cbOffset]; char *pszStart = pszOff; uint32_t uDistance; while (*pszStart) { size_t pairLen = strlen(pszStart); uDistance = (pszStart - pszOff); if (m_cbOffset + uDistance + pairLen + 1 >= m_cbSize) { rc = VERR_MORE_DATA; break; } else { char *pszSep = strchr(pszStart, '='); char *pszVal = NULL; if (pszSep) pszVal = pszSep + 1; if (!pszSep || !pszVal) { rc = VERR_MORE_DATA; break; } /* Terminate the separator so that we can * use pszStart as our key from now on. */ *pszSep = '\0'; rc = streamBlock.SetValue(pszStart, pszVal); if (RT_FAILURE(rc)) return rc; } /* Next pair. */ pszStart += pairLen + 1; } /* If we did not do any movement but we have stuff left * in our buffer just skip the current termination so that * we can try next time. */ uDistance = (pszStart - pszOff); if ( !uDistance && *pszStart == '\0' && m_cbOffset < m_cbSize) { uDistance++; } m_cbOffset += uDistance; return rc; }
static int shaOpenCallback(void *pvUser, const char *pszLocation, uint32_t fOpen, PFNVDCOMPLETED pfnCompleted, void **ppInt) { /* Validate input. */ AssertPtrReturn(pvUser, VERR_INVALID_PARAMETER); AssertPtrReturn(pszLocation, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER); AssertPtrReturn(ppInt, VERR_INVALID_POINTER); AssertReturn((fOpen & RTFILE_O_READWRITE) != RTFILE_O_READWRITE, VERR_INVALID_PARAMETER); /* No read/write allowed */ PSHASTORAGE pShaStorage = (PSHASTORAGE)pvUser; PVDINTERFACEIO pIfIo = VDIfIoGet(pShaStorage->pVDImageIfaces); AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER); DEBUG_PRINT_FLOW(); PSHASTORAGEINTERNAL pInt = (PSHASTORAGEINTERNAL)RTMemAllocZ(sizeof(SHASTORAGEINTERNAL)); if (!pInt) return VERR_NO_MEMORY; int rc = VINF_SUCCESS; do { pInt->pfnCompleted = pfnCompleted; pInt->pShaStorage = pShaStorage; pInt->fEOF = false; pInt->fOpenMode = fOpen; pInt->u32Status = STATUS_WAIT; /* Circular buffer in the read case. */ rc = RTCircBufCreate(&pInt->pCircBuf, _1M * 2); if (RT_FAILURE(rc)) break; if (fOpen & RTFILE_O_WRITE) { /* The zero buffer is used for appending empty parts at the end of the * file (or our buffer) in setSize or when uOffset in writeSync is * increased in steps bigger than a byte. */ pInt->cbZeroBuf = _1K; pInt->pvZeroBuf = RTMemAllocZ(pInt->cbZeroBuf); if (!pInt->pvZeroBuf) { rc = VERR_NO_MEMORY; break; } } /* Create an event semaphore to indicate a state change for the worker * thread. */ rc = RTSemEventCreate(&pInt->newStatusEvent); if (RT_FAILURE(rc)) break; /* Create an event semaphore to indicate a finished calculation of the worker thread. */ rc = RTSemEventCreate(&pInt->workFinishedEvent); if (RT_FAILURE(rc)) break; /* Create the worker thread. */ rc = RTThreadCreate(&pInt->pWorkerThread, shaCalcWorkerThread, pInt, 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, RTTHREADFLAGS_WAITABLE, "SHA-Worker"); if (RT_FAILURE(rc)) break; if (pShaStorage->fCreateDigest) { /* Create a SHA1/SHA256 context the worker thread will work with. */ if (pShaStorage->fSha256) RTSha256Init(&pInt->ctx.Sha256); else RTSha1Init(&pInt->ctx.Sha1); } /* Open the file. */ rc = vdIfIoFileOpen(pIfIo, pszLocation, fOpen, pInt->pfnCompleted, &pInt->pvStorage); if (RT_FAILURE(rc)) break; if (fOpen & RTFILE_O_READ) { /* Immediately let the worker thread start the reading. */ rc = shaSignalManifestThread(pInt, STATUS_READ); } } while(0); if (RT_FAILURE(rc)) { if (pInt->pWorkerThread) { shaSignalManifestThread(pInt, STATUS_END); RTThreadWait(pInt->pWorkerThread, RT_INDEFINITE_WAIT, 0); } 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); } else *ppInt = pInt; return rc; }
/** * Adds data to the internal parser buffer. Useful if there * are multiple rounds of adding data needed. * * @return IPRT status code. * @param pbData Pointer to data to add. * @param cbData Size (in bytes) of data to add. */ int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData) { AssertPtrReturn(pbData, VERR_INVALID_POINTER); AssertReturn(cbData, VERR_INVALID_PARAMETER); int rc = VINF_SUCCESS; /* Rewind the buffer if it's empty. */ size_t cbInBuf = m_cbSize - m_cbOffset; bool const fAddToSet = cbInBuf == 0; if (fAddToSet) m_cbSize = m_cbOffset = 0; /* Try and see if we can simply append the data. */ if (cbData + m_cbSize <= m_cbAllocated) { memcpy(&m_pbBuffer[m_cbSize], pbData, cbData); m_cbSize += cbData; } else { /* Move any buffered data to the front. */ cbInBuf = m_cbSize - m_cbOffset; if (cbInBuf == 0) m_cbSize = m_cbOffset = 0; else if (m_cbOffset) /* Do we have something to move? */ { memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf); m_cbSize = cbInBuf; m_cbOffset = 0; } /* Do we need to grow the buffer? */ if (cbData + m_cbSize > m_cbAllocated) { size_t cbAlloc = m_cbSize + cbData; cbAlloc = RT_ALIGN_Z(cbAlloc, _64K); void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc); if (pvNew) { m_pbBuffer = (uint8_t *)pvNew; m_cbAllocated = cbAlloc; } else rc = VERR_NO_MEMORY; } /* Finally, copy the data. */ if (RT_SUCCESS(rc)) { if (cbData + m_cbSize <= m_cbAllocated) { memcpy(&m_pbBuffer[m_cbSize], pbData, cbData); m_cbSize += cbData; } else rc = VERR_BUFFER_OVERFLOW; } } return rc; }
RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, signed int cchDigits, char chSep) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(cbSize, VERR_BUFFER_OVERFLOW); AssertReturn(cchDigits > 0, VERR_INVALID_PARAMETER); /* Check that there is sufficient space. */ char *pszEnd = RTStrEnd(pszPath, cbSize); AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW); AssertReturn(cbSize - 1 - (pszEnd - pszPath) >= (size_t)cchDigits + (chSep ? 1 : 0), VERR_BUFFER_OVERFLOW); size_t cbLeft = cbSize - (pszEnd - pszPath); /* First try is to create the path without any numbers. */ int rc = RTDirCreate(pszPath, fMode, 0); if ( RT_SUCCESS(rc) || rc != VERR_ALREADY_EXISTS) return rc; /* If the separator value isn't zero, add it. */ if (chSep != '\0') { cbLeft--; *pszEnd++ = chSep; *pszEnd = '\0'; } /* How many tries? Stay within somewhat sane limits. */ uint32_t cMaxTries; if (cchDigits >= 8) cMaxTries = 100 * _1M; else { cMaxTries = 10; for (int a = 0; a < cchDigits - 1; ++a) cMaxTries *= 10; } /* Try cMaxTries - 1 times to create a directory with appended numbers. */ uint32_t i = 1; while (i < cMaxTries) { /* Format the number with leading zero's. */ ssize_t rc2 = RTStrFormatU32(pszEnd, cbLeft, i, 10, cchDigits, 0, RTSTR_F_WIDTH | RTSTR_F_ZEROPAD); if (RT_FAILURE((int) rc2)) { *pszPath = '\0'; return (int)rc2; } rc = RTDirCreate(pszPath, fMode, 0); if (RT_SUCCESS(rc)) return rc; ++i; } /* We've given up. */ *pszPath = '\0'; return VERR_ALREADY_EXISTS; }
/** * Search for content of specified type in guest clipboard buffer and put * it into newly allocated buffer. * * @param pPasteboard Guest PasteBoard reference. * @param fFormat Data formats we are looking for. * @param ppvData Where to return pointer to the received data. M * @param pcbData Where to return the size of the data. * @param pcbAlloc Where to return the size of the memory block * *ppvData pointes to. (Usually greater than *cbData * because the allocation is page aligned.) * @returns IPRT status code. */ static int vbclClipboardReadGuestData(PasteboardRef pPasteboard, CFStringRef sFormat, void **ppvData, uint32_t *pcbData, uint32_t *pcbAlloc) { ItemCount cItems, iItem; OSStatus rc; void *pvData = NULL; uint32_t cbData = 0; uint32_t cbAlloc = 0; AssertPtrReturn(ppvData, VERR_INVALID_POINTER); AssertPtrReturn(pcbData, VERR_INVALID_POINTER); AssertPtrReturn(pcbAlloc, VERR_INVALID_POINTER); rc = PasteboardGetItemCount(pPasteboard, &cItems); AssertReturn(rc == noErr, VERR_INVALID_PARAMETER); AssertReturn(cItems > 0, VERR_INVALID_PARAMETER); /* Walk through all the items in PasteBoard in order to find that one that correcponds to requested data format. */ for (iItem = 1; iItem <= cItems; iItem++) { PasteboardItemID iItemID; CFDataRef flavorData; /* Now, get the item's flavors that corresponds to requested type. */ rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID); AssertReturn(rc == noErr, VERR_INVALID_PARAMETER); rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, sFormat, &flavorData); if (rc == noErr) { void *flavorDataPtr = (void *)CFDataGetBytePtr(flavorData); cbData = CFDataGetLength(flavorData); if (flavorDataPtr && cbData > 0) { cbAlloc = RT_ALIGN_32(cbData, PAGE_SIZE); pvData = RTMemPageAllocZ(cbAlloc); if (pvData) memcpy(pvData, flavorDataPtr, cbData); } CFRelease(flavorData); /* Found first matching item, no more search. */ break; } } /* Found match */ if (pvData) { *ppvData = pvData; *pcbData = cbData; *pcbAlloc = cbAlloc; return VINF_SUCCESS; } return VERR_INVALID_PARAMETER; }
static DECLCALLBACK(int) gimDevR3DbgRecvThread(RTTHREAD hThreadSelf, void *pvUser) { RT_NOREF1(hThreadSelf); /* * Validate. */ PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser; AssertReturn(pDevIns, VERR_INVALID_PARAMETER); PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); PGIMDEV pThis = PDMINS_2_DATA(pDevIns, PGIMDEV); AssertReturn(pThis, VERR_INVALID_POINTER); AssertReturn(pThis->DbgSetup.cbDbgRecvBuf, VERR_INTERNAL_ERROR); AssertReturn(pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENTMULTI, VERR_INTERNAL_ERROR_2); AssertReturn(pThis->Dbg.pvDbgRecvBuf, VERR_INTERNAL_ERROR_3); PVM pVM = PDMDevHlpGetVM(pDevIns); AssertReturn(pVM, VERR_INVALID_POINTER); PPDMISTREAM pDbgDrvStream = pThis->Dbg.pDbgDrvStream; AssertReturn(pDbgDrvStream, VERR_INVALID_POINTER); for (;;) { /* * Read incoming debug data. */ size_t cbRead = pThis->DbgSetup.cbDbgRecvBuf; int rc = pDbgDrvStream->pfnRead(pDbgDrvStream, pThis->Dbg.pvDbgRecvBuf, &cbRead); if ( RT_SUCCESS(rc) && cbRead > 0) { /* * Notify the consumer thread. */ if (ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == false) { if (pThis->DbgSetup.pfnDbgRecvBufAvail) pThis->DbgSetup.pfnDbgRecvBufAvail(pVM); pThis->Dbg.cbDbgRecvBufRead = cbRead; RTSemEventMultiReset(pThis->Dbg.hDbgRecvThreadSem); ASMAtomicWriteBool(&pThis->Dbg.fDbgRecvBufRead, true); } /* * Wait until the consumer thread has acknowledged reading of the * current buffer or we're asked to shut down. * * It is important that we do NOT re-invoke 'pfnRead' before the * current buffer is consumed, otherwise we risk data corruption. */ while ( ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == true && !pThis->fDbgRecvThreadShutdown) { RTSemEventMultiWait(pThis->Dbg.hDbgRecvThreadSem, RT_INDEFINITE_WAIT); } } #ifdef RT_OS_LINUX else if (rc == VERR_NET_CONNECTION_REFUSED) { /* * With the current, simplistic PDMISTREAM interface, this is the best we can do. * Even using RTSocketSelectOne[Ex] on Linux returns immediately with 'ready-to-read' * on localhost UDP sockets that are not connected on the other end. */ /** @todo Fix socket waiting semantics on localhost Linux unconnected UDP sockets. */ RTThreadSleep(400); } #endif else if ( rc != VINF_TRY_AGAIN && rc != VERR_TRY_AGAIN && rc != VERR_NET_CONNECTION_RESET_BY_PEER) { LogRel(("GIMDev: Debug thread terminating with rc=%Rrc\n", rc)); break; } if (pThis->fDbgRecvThreadShutdown) { LogRel(("GIMDev: Debug thread shutting down\n")); break; } } return VINF_SUCCESS; }
RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) { int rc; /* * Validate input. */ AssertPtrReturn(pDir, VERR_INVALID_POINTER); AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE); AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER); AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); size_t cbDirEntry = sizeof(*pDirEntry); if (pcbDirEntry) { cbDirEntry = *pcbDirEntry; AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]), ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])), VERR_INVALID_PARAMETER); } /* * Fetch data? */ if (!pDir->fDataUnread) { rc = rtDirNtFetchMore(pDir); if (RT_FAILURE(rc)) return rc; } /* * Convert the filename to UTF-8. */ rc = rtDirNtConvertCurName(pDir); if (RT_FAILURE(rc)) return rc; /* * Check if we've got enough space to return the data. */ const char *pszName = pDir->pszName; const size_t cchName = pDir->cchName; const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName; if (pcbDirEntry) *pcbDirEntry = cbRequired; if (cbRequired > cbDirEntry) return VERR_BUFFER_OVERFLOW; /* * Setup the returned data. */ PFILE_BOTH_DIR_INFORMATION pBoth = pDir->uCurData.pBoth; pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName); memcpy(pDirEntry->szName, pszName, cchName + 1); memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName)); #ifdef IPRT_WITH_NT_PATH_PASSTHRU if (pDir->enmInfoClass != FileMaximumInformation) #endif { uint8_t cbShort = pBoth->ShortNameLength; if (cbShort > 0) { AssertStmt(cbShort < sizeof(pDirEntry->wszShortName), cbShort = sizeof(pDirEntry->wszShortName) - 2); memcpy(pDirEntry->wszShortName, pBoth->ShortName, cbShort); pDirEntry->cwcShortName = cbShort / 2; } else pDirEntry->cwcShortName = 0; pDirEntry->Info.cbObject = pBoth->EndOfFile.QuadPart; pDirEntry->Info.cbAllocated = pBoth->AllocationSize.QuadPart; Assert(sizeof(uint64_t) == sizeof(pBoth->CreationTime)); RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, pBoth->CreationTime.QuadPart); RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, pBoth->LastAccessTime.QuadPart); RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, pBoth->LastWriteTime.QuadPart); RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, pBoth->ChangeTime.QuadPart); pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pBoth->FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, pszName, cchName); } #ifdef IPRT_WITH_NT_PATH_PASSTHRU else { pDirEntry->cwcShortName = 0; pDirEntry->Info.cbObject = 0; pDirEntry->Info.cbAllocated = 0; RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, 0); RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, 0); RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, 0); RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, 0); if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, RT_STR_TUPLE("Directory"))) pDirEntry->Info.Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777; else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, RT_STR_TUPLE("SymbolicLink"))) pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777; else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length, RT_STR_TUPLE("Device"))) pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666; else pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666; } #endif /* * Requested attributes (we cannot provide anything actually). */ switch (enmAdditionalAttribs) { case RTFSOBJATTRADD_EASIZE: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; #ifdef IPRT_WITH_NT_PATH_PASSTHRU if (pDir->enmInfoClass == FileMaximumInformation) pDirEntry->Info.Attr.u.EASize.cb = 0; else #endif pDirEntry->Info.Attr.u.EASize.cb = pBoth->EaSize; break; case RTFSOBJATTRADD_UNIX: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX; pDirEntry->Info.Attr.u.Unix.uid = ~0U; pDirEntry->Info.Attr.u.Unix.gid = ~0U; pDirEntry->Info.Attr.u.Unix.cHardlinks = 1; pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */ pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */ pDirEntry->Info.Attr.u.Unix.fFlags = 0; pDirEntry->Info.Attr.u.Unix.GenerationId = 0; pDirEntry->Info.Attr.u.Unix.Device = 0; break; case RTFSOBJATTRADD_NOTHING: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; break; case RTFSOBJATTRADD_UNIX_OWNER: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U; pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ break; case RTFSOBJATTRADD_UNIX_GROUP: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U; pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0'; break; default: AssertMsgFailed(("Impossible!\n")); return VERR_INTERNAL_ERROR; } /* * Follow links if requested. */ if ( (fFlags & RTPATH_F_FOLLOW_LINK) && RTFS_IS_SYMLINK(fFlags)) { /** @todo Symlinks: Find[First|Next]FileW will return info about the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */ } /* * Finally advance the buffer. */ return rtDirNtAdvanceBuffer(pDir); }