int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVBox, IHostNetworkInterface **aHostNetworkInterface, IProgress **aProgress, const char *pcszName) { #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) /* create a progress object */ ComObjPtr<Progress> progress; progress.createObject(); ComPtr<IHost> host; HRESULT hrc = pVBox->COMGETTER(Host)(host.asOutParam()); if (SUCCEEDED(hrc)) { hrc = progress->init(pVBox, host, Bstr("Creating host only network interface").raw(), FALSE /* aCancelable */); if (SUCCEEDED(hrc)) { progress.queryInterfaceTo(aProgress); char szAdpCtl[RTPATH_MAX]; int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " add")); if (RT_FAILURE(rc)) { progress->notifyComplete(E_FAIL, COM_IIDOF(IHostNetworkInterface), HostNetworkInterface::getStaticComponentName(), "Failed to get program path, rc=%Rrc\n", rc); return rc; } strcat(szAdpCtl, "/" VBOXNETADPCTL_NAME " "); if (pcszName && strlen(pcszName) <= RTPATH_MAX - strlen(szAdpCtl) - sizeof(" add")) { strcat(szAdpCtl, pcszName); strcat(szAdpCtl, " add"); } else strcat(szAdpCtl, "add"); FILE *fp = popen(szAdpCtl, "r"); if (fp) { char szBuf[VBOXNET_MAX_SHORT_NAME]; if (fgets(szBuf, sizeof(szBuf), fp)) { char *pLast = szBuf + strlen(szBuf) - 1; if (pLast >= szBuf && *pLast == '\n') *pLast = 0; size_t cbNameLen = strlen(szBuf) + 1; PNETIFINFO pInfo = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen])); if (!pInfo) rc = VERR_NO_MEMORY; else { strcpy(pInfo->szShortName, szBuf); strcpy(pInfo->szName, szBuf); rc = NetIfGetConfigByName(pInfo); if (RT_FAILURE(rc)) { progress->notifyComplete(E_FAIL, COM_IIDOF(IHostNetworkInterface), HostNetworkInterface::getStaticComponentName(), "Failed to get config info for %s (as reported by '" VBOXNETADPCTL_NAME " add')\n", szBuf); } else { Bstr IfName(szBuf); /* create a new uninitialized host interface object */ ComObjPtr<HostNetworkInterface> iface; iface.createObject(); iface->init(IfName, HostNetworkInterfaceType_HostOnly, pInfo); iface->setVirtualBox(pVBox); iface.queryInterfaceTo(aHostNetworkInterface); } RTMemFree(pInfo); } } if ((rc = pclose(fp)) != 0) { progress->notifyComplete(E_FAIL, COM_IIDOF(IHostNetworkInterface), HostNetworkInterface::getStaticComponentName(), "Failed to execute '"VBOXNETADPCTL_NAME " add' (exit status: %d)", rc); rc = VERR_INTERNAL_ERROR; } } if (RT_SUCCESS(rc)) progress->notifyComplete(rc); } } return hrc; #else NOREF(pVBox); NOREF(aHostNetworkInterface); NOREF(aProgress); return VERR_NOT_IMPLEMENTED; #endif }
/** * Verifies the manifest and its signature. * * @returns VBox status code, failures with message. * @param hOurManifest The manifest we compiled. * @param hManifestFile The manifest file in the extension pack. * @param hSignatureFile The manifest signature file. * @param pszError Where to store an error message on failure. * @param cbError The size of the buffer @a pszError points to. */ static int vboxExtPackVerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile, char *pszError, size_t cbError) { /* * Read the manifest from the extension pack. */ int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsFileSeek failed: %Rrc", rc); RTMANIFEST hTheirManifest; rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest); if (RT_FAILURE(rc)) return vboxExtPackReturnError(rc, pszError, cbError, "RTManifestCreate failed: %Rrc", rc); RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile); rc = RTManifestReadStandard(hTheirManifest, hVfsIos); RTVfsIoStrmRelease(hVfsIos); if (RT_SUCCESS(rc)) { /* * Compare the manifests. */ static const char *s_apszIgnoreEntries[] = { VBOX_EXTPACK_MANIFEST_NAME, VBOX_EXTPACK_SIGNATURE_NAME, "./" VBOX_EXTPACK_MANIFEST_NAME, "./" VBOX_EXTPACK_SIGNATURE_NAME, NULL }; char szError[RTPATH_MAX]; rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL, RTMANIFEST_EQUALS_IGN_MISSING_ATTRS /*fFlags*/, szError, sizeof(szError)); if (RT_SUCCESS(rc)) { /* * Validate the manifest file signature. */ /** @todo implement signature stuff */ NOREF(hSignatureFile); } else if (rc == VERR_NOT_EQUAL && szError[0]) vboxExtPackSetError(pszError, cbError, "Manifest mismatch: %s", szError); else vboxExtPackSetError(pszError, cbError, "RTManifestEqualsEx failed: %Rrc", rc); #if 0 RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM; RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut); RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL); RTManifestWriteStandard(hOurManifest, hVfsIosStdOut); RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL); RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut); #endif } else vboxExtPackSetError(pszError, cbError, "Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc); RTManifestRelease(hTheirManifest); return rc; }
RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER); AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs), VERR_INVALID_PARAMETER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Query file info. */ WIN32_FILE_ATTRIBUTE_DATA Data; PRTUTF16 pwszPath; int rc = RTStrToUtf16(pszPath, &pwszPath); if (RT_FAILURE(rc)) return rc; if (!GetFileAttributesExW(pwszPath, GetFileExInfoStandard, &Data)) { /* Fallback to FindFileFirst in case of sharing violation. */ if (GetLastError() == ERROR_SHARING_VIOLATION) { WIN32_FIND_DATAW FindData; HANDLE hDir = FindFirstFileW(pwszPath, &FindData); if (hDir == INVALID_HANDLE_VALUE) { rc = RTErrConvertFromWin32(GetLastError()); RTUtf16Free(pwszPath); return rc; } FindClose(hDir); Data.dwFileAttributes = FindData.dwFileAttributes; Data.ftCreationTime = FindData.ftCreationTime; Data.ftLastAccessTime = FindData.ftLastAccessTime; Data.ftLastWriteTime = FindData.ftLastWriteTime; Data.nFileSizeHigh = FindData.nFileSizeHigh; Data.nFileSizeLow = FindData.nFileSizeLow; } else { rc = RTErrConvertFromWin32(GetLastError()); RTUtf16Free(pwszPath); return rc; } } /* * Getting the information for the link target is a bit annoying and * subject to the same access violation mess as above.. :/ */ /** @todo we're too lazy wrt to error paths here... */ if ( (fFlags & RTPATH_F_FOLLOW_LINK) && (Data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { HANDLE hFinal = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFinal != INVALID_HANDLE_VALUE) { BY_HANDLE_FILE_INFORMATION FileData; if (GetFileInformationByHandle(hFinal, &FileData)) { Data.dwFileAttributes = FileData.dwFileAttributes; Data.ftCreationTime = FileData.ftCreationTime; Data.ftLastAccessTime = FileData.ftLastAccessTime; Data.ftLastWriteTime = FileData.ftLastWriteTime; Data.nFileSizeHigh = FileData.nFileSizeHigh; Data.nFileSizeLow = FileData.nFileSizeLow; } CloseHandle(hFinal); } else if (GetLastError() != ERROR_SHARING_VIOLATION) { rc = RTErrConvertFromWin32(GetLastError()); RTUtf16Free(pwszPath); return rc; } } RTUtf16Free(pwszPath); /* * Setup the returned data. */ pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32) | (uint64_t)Data.nFileSizeLow; pObjInfo->cbAllocated = pObjInfo->cbObject; Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime)); RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime); pObjInfo->ChangeTime = pObjInfo->ModificationTime; pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, pszPath, strlen(pszPath)); /* * Requested attributes (we cannot provide anything actually). */ switch (enmAdditionalAttribs) { case RTFSOBJATTRADD_NOTHING: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; break; case RTFSOBJATTRADD_UNIX: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX; pObjInfo->Attr.u.Unix.uid = ~0U; pObjInfo->Attr.u.Unix.gid = ~0U; pObjInfo->Attr.u.Unix.cHardlinks = 1; pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /** @todo use volume serial number */ pObjInfo->Attr.u.Unix.INodeId = 0; /** @todo use fileid (see GetFileInformationByHandle). */ pObjInfo->Attr.u.Unix.fFlags = 0; pObjInfo->Attr.u.Unix.GenerationId = 0; pObjInfo->Attr.u.Unix.Device = 0; break; case RTFSOBJATTRADD_UNIX_OWNER: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; pObjInfo->Attr.u.UnixOwner.uid = ~0U; pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ break; case RTFSOBJATTRADD_UNIX_GROUP: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; pObjInfo->Attr.u.UnixGroup.gid = ~0U; pObjInfo->Attr.u.UnixGroup.szName[0] = '\0'; break; case RTFSOBJATTRADD_EASIZE: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; pObjInfo->Attr.u.EASize.cb = 0; break; default: AssertMsgFailed(("Impossible!\n")); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }
static int rtCrPkcs7SignedData_CheckSanityExtra(PCRTCRPKCS7SIGNEDDATA pSignedData, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag) { bool const fAuthenticode = RT_BOOL(fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE); //RTAsn1Dump(&pSignedData->SeqCore.Asn1Core, 0, 0, RTAsn1DumpStrmPrintfV, g_pStdOut); if ( RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V1) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V3) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V4) != 0 && RTAsn1Integer_UnsignedCompareWithU32(&pSignedData->Version, RTCRPKCS7SIGNEDDATA_V5) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNED_DATA_VERSION, "SignedData version is %llu, expected %u", pSignedData->Version.uValue.u, RTCRPKCS7SIGNEDDATA_V1); /* * DigestAlgorithms. */ if (pSignedData->DigestAlgorithms.cItems == 0) /** @todo this might be too strict */ return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_SIGNED_DATA_NO_DIGEST_ALGOS, "SignedData.DigestAlgorithms is empty"); if (pSignedData->DigestAlgorithms.cItems != 1 && fAuthenticode) return RTErrInfoSetF(pErrInfo, VERR_CR_SPC_NOT_EXACTLY_ONE_DIGEST_ALGO, "SignedData.DigestAlgorithms has more than one algorithm (%u)", pSignedData->DigestAlgorithms.cItems); if (fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH) for (uint32_t i = 0; i < pSignedData->DigestAlgorithms.cItems; i++) { if (RTCrX509AlgorithmIdentifier_QueryDigestType(&pSignedData->DigestAlgorithms.paItems[i]) == RTDIGESTTYPE_INVALID) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_UNKNOWN_DIGEST_ALGORITHM, "SignedData.DigestAlgorithms[%i] is not known: %s", i, pSignedData->DigestAlgorithms.paItems[i].Algorithm.szObjId); if (pSignedData->DigestAlgorithms.paItems[i].Parameters.enmType != RTASN1TYPE_NULL) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_PARAMS_NOT_IMPL, "SignedData.DigestAlgorithms[%i] has parameters: tag=%u", i, pSignedData->DigestAlgorithms.paItems[i].Parameters.u.Core.uTag); } /* * Certificates. */ if ( (fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT) && pSignedData->Certificates.cItems == 0) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_NO_CERTIFICATES, "SignedData.Certifcates is empty, expected at least one certificate"); /* * Crls. */ if (fAuthenticode && RTAsn1Core_IsPresent(&pSignedData->Crls)) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_EXPECTED_NO_CRLS, "SignedData.Crls is not empty as expected for authenticode."); /** @todo check Crls when they become important. */ /* * SignerInfos. */ if (pSignedData->SignerInfos.cItems == 0) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_NO_SIGNER_INFOS, "SignedData.SignerInfos is empty?"); if (fAuthenticode && pSignedData->SignerInfos.cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_EXPECTED_ONE_SIGNER_INFO, "SignedData.SignerInfos should have one entry for authenticode: %u", pSignedData->SignerInfos.cItems); for (uint32_t i = 0; i < pSignedData->SignerInfos.cItems; i++) { PCRTCRPKCS7SIGNERINFO pSignerInfo = &pSignedData->SignerInfos.paItems[i]; if (RTAsn1Integer_UnsignedCompareWithU32(&pSignerInfo->Version, RTCRPKCS7SIGNERINFO_V1) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_INFO_VERSION, "SignedData.SignerInfos[%u] version is %llu, expected %u", i, pSignerInfo->Version.uValue.u, RTCRPKCS7SIGNERINFO_V1); /* IssuerAndSerialNumber. */ int rc = RTCrX509Name_CheckSanity(&pSignerInfo->IssuerAndSerialNumber.Name, 0, pErrInfo, "SignedData.SignerInfos[#].IssuerAndSerialNumber.Name"); if (RT_FAILURE(rc)) return rc; if (pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.cb == 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_INFO_NO_ISSUER_SERIAL_NO, "SignedData.SignerInfos[%u].IssuerAndSerialNumber.SerialNumber is missing (zero length)", i); PCRTCRX509CERTIFICATE pCert; pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSignedData->Certificates, &pSignerInfo->IssuerAndSerialNumber.Name, &pSignerInfo->IssuerAndSerialNumber.SerialNumber); if (!pCert && (fFlags & RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT)) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_CERT_NOT_SHIPPED, "SignedData.SignerInfos[%u].IssuerAndSerialNumber not found in T0.Certificates", i); /* DigestAlgorithm */ uint32_t j = 0; while ( j < pSignedData->DigestAlgorithms.cItems && RTCrX509AlgorithmIdentifier_Compare(&pSignedData->DigestAlgorithms.paItems[j], &pSignerInfo->DigestAlgorithm) != 0) j++; if (j >= pSignedData->DigestAlgorithms.cItems) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_ALGO_NOT_FOUND_IN_LIST, "SignedData.SignerInfos[%u].DigestAlgorithm (%s) not found in SignedData.DigestAlgorithms", i, pSignerInfo->DigestAlgorithm.Algorithm.szObjId); /* Digest encryption algorithm. */ #if 0 /** @todo Unimportant: Seen timestamp signatures specifying pkcs1-Sha256WithRsaEncryption in SignerInfo and just RSA in the certificate. Figure out how to compare the two. */ if ( pCert && RTCrX509AlgorithmIdentifier_Compare(&pSignerInfo->DigestEncryptionAlgorithm, &pCert->TbsCertificate.SubjectPublicKeyInfo.Algorithm) != 0) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_SIGNER_INFO_DIGEST_ENCRYPT_MISMATCH, "SignedData.SignerInfos[%u].DigestEncryptionAlgorithm (%s) mismatch with certificate (%s)", i, pSignerInfo->DigestEncryptionAlgorithm.Algorithm.szObjId, pCert->TbsCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm.szObjId); #endif /* Authenticated attributes we know. */ if (RTCrPkcs7Attributes_IsPresent(&pSignerInfo->AuthenticatedAttributes)) { bool fFoundContentInfo = false; bool fFoundMessageDigest = false; for (j = 0; j < pSignerInfo->AuthenticatedAttributes.cItems; j++) { PCRTCRPKCS7ATTRIBUTE pAttrib = &pSignerInfo->AuthenticatedAttributes.paItems[j]; if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_CONTENT_TYPE_OID) == 0) { if (fFoundContentInfo) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB, "Multiple authenticated content-type attributes."); fFoundContentInfo = true; AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS, VERR_INTERNAL_ERROR_3); if (pAttrib->uValues.pObjIds->cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB, "Expected exactly one value for content-type attrib, found: %u", pAttrib->uValues.pObjIds->cItems); } else if (RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_MESSAGE_DIGEST_OID) == 0) { if (fFoundMessageDigest) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB, "Multiple authenticated message-digest attributes."); fFoundMessageDigest = true; AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS, VERR_INTERNAL_ERROR_3); if (pAttrib->uValues.pOctetStrings->cItems != 1) return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB, "Expected exactly one value for message-digest attrib, found: %u", pAttrib->uValues.pOctetStrings->cItems); } else AssertReturn(pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_UNKNOWN, VERR_INTERNAL_ERROR_3); } if (!fFoundContentInfo) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB, "Missing authenticated content-type attribute."); if (!fFoundMessageDigest) return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_MESSAGE_DIGEST_ATTRIB, "Missing authenticated message-digest attribute."); } } return VINF_SUCCESS; }
/** * Validates the extension pack tarball prior to unpacking. * * Operations performed: * - Mandatory files. * - Manifest check. * - Manifest seal check. * - XML check, match name. * * @returns VBox status code, failures with message. * @param hTarballFile The handle to open the @a pszTarball file. * @param pszExtPackName The name of the extension pack name. NULL if * the name is not fixed. * @param pszTarball The name of the tarball in case we have to * complain about something. * @param pszTarballDigest The SHA-256 digest of the tarball. Empty string * if no digest available. * @param pszError Where to store an error message on failure. * @param cbError The size of the buffer @a pszError points to. * @param phValidManifest Where to optionally return the handle to fully * validated the manifest for the extension pack. * This includes all files. * @param phXmlFile Where to optionally return the memorized XML * file. * @param pStrDigest Where to return the digest of the file. * Optional. */ int VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName, const char *pszTarball, const char *pszTarballDigest, char *pszError, size_t cbError, PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile, RTCString *pStrDigest) { /* * Clear return values. */ if (phValidManifest) *phValidManifest = NIL_RTMANIFEST; if (phXmlFile) *phXmlFile = NIL_RTVFSFILE; Assert(cbError > 1); *pszError = '\0'; NOREF(pszTarball); /* * Open the tar.gz filesystem stream and set up an manifest in-memory file. */ RTMANIFEST hFileManifest; RTVFSFSSTREAM hTarFss; int rc = VBoxExtPackOpenTarFss(hTarballFile, pszError, cbError, &hTarFss, &hFileManifest); if (RT_FAILURE(rc)) return rc; RTMANIFEST hOurManifest; rc = RTManifestCreate(0 /*fFlags*/, &hOurManifest); if (RT_SUCCESS(rc)) { /* * Process the tarball (would be nice to move this to a function). */ RTVFSFILE hXmlFile = NIL_RTVFSFILE; RTVFSFILE hManifestFile = NIL_RTVFSFILE; RTVFSFILE hSignatureFile = NIL_RTVFSFILE; for (;;) { /* * Get the next stream object. */ char *pszName; RTVFSOBJ hVfsObj; RTVFSOBJTYPE enmType; rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj); if (RT_FAILURE(rc)) { if (rc != VERR_EOF) vboxExtPackSetError(pszError, cbError, "RTVfsFsStrmNext failed: %Rrc", rc); else rc = VINF_SUCCESS; break; } const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName; /* * Check the type & name validity, performing special tests on * standard extension pack member files. * * N.B. We will always reach the end of the loop before breaking on * failure - cleanup reasons. */ rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, pszError, cbError); if (RT_SUCCESS(rc)) { PRTVFSFILE phVfsFile = NULL; if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME)) phVfsFile = &hXmlFile; else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME)) phVfsFile = &hManifestFile; else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME)) phVfsFile = &hSignatureFile; else if (!strncmp(pszAdjName, VBOX_EXTPACK_LICENSE_NAME_PREFIX, sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX) - 1)) rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, NULL, pszError, cbError); if (phVfsFile) rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, phVfsFile, pszError, cbError); } /* * Add any I/O stream to the manifest */ if ( RT_SUCCESS(rc) && ( enmType == RTVFSOBJTYPE_FILE || enmType == RTVFSOBJTYPE_IO_STREAM)) { RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); rc = RTManifestEntryAddIoStream(hOurManifest, hVfsIos, pszAdjName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256); if (RT_FAILURE(rc)) vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszAdjName, rc); RTVfsIoStrmRelease(hVfsIos); } /* * Clean up and break out on failure. */ RTVfsObjRelease(hVfsObj); RTStrFree(pszName); if (RT_FAILURE(rc)) break; } /* * Check the integrity of the tarball file. */ if (RT_SUCCESS(rc)) { RTVfsFsStrmRelease(hTarFss); hTarFss = NIL_RTVFSFSSTREAM; rc = vboxExtPackVerifyFileDigest(hFileManifest, pszTarballDigest, pStrDigest, pszError, cbError); } /* * If we've successfully processed the tarball, verify that the * mandatory files are present. */ if (RT_SUCCESS(rc)) { if (hXmlFile == NIL_RTVFSFILE) rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME); if (hManifestFile == NIL_RTVFSFILE) rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME); if (hSignatureFile == NIL_RTVFSFILE) rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME); } /* * Check the manifest and it's signature. */ if (RT_SUCCESS(rc)) rc = vboxExtPackVerifyManifestAndSignature(hOurManifest, hManifestFile, hSignatureFile, pszError, cbError); /* * Check the XML. */ if (RT_SUCCESS(rc)) rc = vboxExtPackVerifyXml(hXmlFile, pszExtPackName, pszError, cbError); /* * Returns objects. */ if (RT_SUCCESS(rc)) { if (phValidManifest) { RTManifestRetain(hOurManifest); *phValidManifest = hOurManifest; } if (phXmlFile) { RTVfsFileRetain(hXmlFile); *phXmlFile = hXmlFile; } } /* * Release our object references. */ RTManifestRelease(hOurManifest); RTVfsFileRelease(hXmlFile); RTVfsFileRelease(hManifestFile); RTVfsFileRelease(hSignatureFile); } else vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc); RTVfsFsStrmRelease(hTarFss); RTManifestRelease(hFileManifest); return rc; }
/** * The PDM thread function. * * @returns return from pfnThread. * * @param Thread The thread handle. * @param pvUser Pointer to the PDMTHREAD structure. */ static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser) { PPDMTHREAD pThread = (PPDMTHREAD)pvUser; Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread))); pThread->Thread = Thread; PUVM pUVM = pThread->Internal.s.pVM->pUVM; if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtInit) pUVM->pVmm2UserMethods->pfnNotifyPdmtInit(pUVM->pVmm2UserMethods, pUVM); /* * The run loop. * * It handles simple thread functions which returns when they see a suspending * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning * parts to us. */ int rc; for (;;) { switch (pThread->Internal.s.enmType) { case PDMTHREADTYPE_DEVICE: rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread); break; case PDMTHREADTYPE_USB: rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread); break; case PDMTHREADTYPE_DRIVER: rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread); break; case PDMTHREADTYPE_INTERNAL: rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread); break; case PDMTHREADTYPE_EXTERNAL: rc = pThread->u.Ext.pfnThread(pThread); break; default: AssertMsgFailed(("%d\n", pThread->Internal.s.enmType)); rc = VERR_PDM_THREAD_IPE_1; break; } if (RT_FAILURE(rc)) break; /* * If this is a simple thread function, the state will be suspending * or initializing now. If it isn't we're supposed to terminate. */ if ( pThread->enmState != PDMTHREADSTATE_SUSPENDING && pThread->enmState != PDMTHREADSTATE_INITIALIZING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmSuspending(pThread); if (RT_FAILURE(rc)) break; if (pThread->enmState != PDMTHREADSTATE_RESUMING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmRunning(pThread); if (RT_FAILURE(rc)) break; } if (RT_FAILURE(rc)) LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc)); /* * Advance the state to terminating and then on to terminated. */ for (;;) { PDMTHREADSTATE enmState = pThread->enmState; if ( enmState == PDMTHREADSTATE_TERMINATING || pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) break; } ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED); int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2); if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm) pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm(pUVM->pVmm2UserMethods, pUVM); Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc)); return rc; }
/** * Creates a diff of the changes between the streams @a pLeft and @a pRight. * * This currently only implements the simplest diff format, so no contexts. * * Also, note that we won't detect differences in the final newline of the * streams. * * @returns The number of differences. * @param pszFilename The filename. * @param pLeft The left side stream. * @param pRight The right side stream. * @param fIgnoreEol Whether to ignore end of line markers. * @param fIgnoreLeadingWhite Set if leading white space should be ignored. * @param fIgnoreTrailingWhite Set if trailing white space should be ignored. * @param fSpecialChars Whether to print special chars in a human * readable form or not. * @param cchTab The tab size. * @param pDiff Where to write the diff. */ size_t ScmDiffStreams(const char *pszFilename, PSCMSTREAM pLeft, PSCMSTREAM pRight, bool fIgnoreEol, bool fIgnoreLeadingWhite, bool fIgnoreTrailingWhite, bool fSpecialChars, size_t cchTab, PRTSTREAM pDiff) { #ifdef RT_STRICT ScmStreamCheckItegrity(pLeft); ScmStreamCheckItegrity(pRight); #endif /* * Set up the diff state. */ SCMDIFFSTATE State; State.cDiffs = 0; State.pszFilename = pszFilename; State.pLeft = pLeft; State.pRight = pRight; State.fIgnoreEol = fIgnoreEol; State.fIgnoreLeadingWhite = fIgnoreLeadingWhite; State.fIgnoreTrailingWhite = fIgnoreTrailingWhite; State.fSpecialChars = fSpecialChars; State.cchTab = cchTab; State.pDiff = pDiff; /* * Compare them line by line. */ ScmStreamRewindForReading(pLeft); ScmStreamRewindForReading(pRight); const char *pchLeft; const char *pchRight; for (;;) { SCMEOL enmEolLeft; size_t cchLeft; pchLeft = ScmStreamGetLine(pLeft, &cchLeft, &enmEolLeft); SCMEOL enmEolRight; size_t cchRight; pchRight = ScmStreamGetLine(pRight, &cchRight, &enmEolRight); if (!pchLeft || !pchRight) break; if (!scmDiffCompare(&State, pchLeft, cchLeft, enmEolLeft, pchRight, cchRight, enmEolRight)) scmDiffSynchronize(&State, 3); } /* * Deal with any remaining differences. */ if (pchLeft) scmDiffReport(&State, 0, ScmStreamTellLine(pLeft) - 1, ~(size_t)0, ScmStreamTellLine(pRight), 0); else if (pchRight) scmDiffReport(&State, 0, ScmStreamTellLine(pLeft), 0, ScmStreamTellLine(pRight) - 1, ~(size_t)0); /* * Report any errors. */ if (RT_FAILURE(ScmStreamGetStatus(pLeft))) RTMsgError("Left diff stream error: %Rrc\n", ScmStreamGetStatus(pLeft)); if (RT_FAILURE(ScmStreamGetStatus(pRight))) RTMsgError("Right diff stream error: %Rrc\n", ScmStreamGetStatus(pRight)); return State.cDiffs; }
/** * Recursively delete a directory. * * @returns IPRT status code, errors go via rtPathRmError. * @param pOpts The RM options. * @param pszPath Pointer to a writable buffer holding the path to * the directory. * @param cchPath The length of the path (avoid strlen). * @param pDirEntry Pointer to a directory entry buffer that is * RTPATHRM_DIR_MAX_ENTRY_SIZE bytes big. */ static int rtPathRmRecursive(PRTPATHRMCMDOPTS pOpts, char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry) { /* * Make sure the path ends with a slash. */ if (!cchPath || !RTPATH_IS_SLASH(pszPath[cchPath - 1])) { if (cchPath + 1 >= RTPATH_MAX) return rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Buffer overflow fixing up '%s'.\n", pszPath); pszPath[cchPath++] = RTPATH_SLASH; pszPath[cchPath] = '\0'; } /* * Traverse the directory. */ PRTDIR hDir; int rc = RTDirOpen(&hDir, pszPath); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, "Error opening directory '%s': %Rrc", pszPath, rc); int rcRet = VINF_SUCCESS; for (;;) { /* * Read the next entry, constructing an full path for it. */ size_t cbEntry = RTPATHRM_DIR_MAX_ENTRY_SIZE; rc = RTDirReadEx(hDir, pDirEntry, &cbEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); if (rc == VERR_NO_MORE_FILES) { /* * Reached the end of the directory. */ pszPath[cchPath] = '\0'; rc = RTDirClose(hDir); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, "Error closing directory '%s': %Rrc", pszPath, rc); /* Delete the directory. */ int rc2 = rtPathRmOneDir(pOpts, pszPath); if (RT_FAILURE(rc2) && RT_SUCCESS(rcRet)) return rc2; return rcRet; } if (RT_FAILURE(rc)) { rc = rtPathRmError(pOpts, pszPath, rc, "Error reading directory '%s': %Rrc", pszPath, rc); break; } /* Skip '.' and '..'. */ if ( pDirEntry->szName[0] == '.' && ( pDirEntry->cbName == 1 || ( pDirEntry->cbName == 2 && pDirEntry->szName[1] == '.'))) continue; /* Construct full path. */ if (cchPath + pDirEntry->cbName >= RTPATH_MAX) { pszPath[cchPath] = '\0'; rc = rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Path buffer overflow in directory '%s'.", pszPath); break; } memcpy(pszPath + cchPath, pDirEntry->szName, pDirEntry->cbName + 1); /* * Take action according to the type. */ switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) { case RTFS_TYPE_FILE: rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info); break; case RTFS_TYPE_DIRECTORY: rc = rtPathRmRecursive(pOpts, pszPath, cchPath + pDirEntry->cbName, pDirEntry); break; case RTFS_TYPE_SYMLINK: rc = rtPathRmOneSymlink(pOpts, pszPath); break; case RTFS_TYPE_FIFO: case RTFS_TYPE_DEV_CHAR: case RTFS_TYPE_DEV_BLOCK: case RTFS_TYPE_SOCKET: rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info); break; case RTFS_TYPE_WHITEOUT: default: rc = rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE, "Object '%s' has an unknown file type: %o\n", pszPath, pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK); break; } if (RT_FAILURE(rc) && RT_SUCCESS(rcRet)) rcRet = rc; } /* * Some error occured, close and return. */ RTDirClose(hDir); return rc; }
/** * Remove one user specified file or directory. * * @returns IPRT status code, errors go via rtPathRmError. * @param pOpts The RM options. * @param pszPath The path to the file, directory, whatever. */ static int rtPathRmOne(PRTPATHRMCMDOPTS pOpts, const char *pszPath) { /* * RM refuses to delete some directories. */ int rc = rtPathRmOneValidate(pOpts, pszPath); if (RT_FAILURE(rc)) return rc; /* * Query file system object info. */ RTFSOBJINFO ObjInfo; rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); if (RT_FAILURE(rc)) { if (pOpts->fForce && (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)) return VINF_SUCCESS; return rtPathRmError(pOpts, pszPath, rc, "Error deleting '%s': %Rrc", pszPath, rc); } /* * Take type specific action. */ switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK) { case RTFS_TYPE_FILE: return rtPathRmOneFile(pOpts, pszPath, &ObjInfo); case RTFS_TYPE_DIRECTORY: if (pOpts->fRecursive) { char szPath[RTPATH_MAX]; rc = RTPathAbs(pszPath, szPath, sizeof(szPath)); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, "RTPathAbs failed on '%s': %Rrc\n", pszPath, rc); union { RTDIRENTRYEX Core; uint8_t abPadding[RTPATHRM_DIR_MAX_ENTRY_SIZE]; } DirEntry; return rtPathRmRecursive(pOpts, szPath, strlen(szPath), &DirEntry.Core); } if (pOpts->fDirsAndOther) return rtPathRmOneDir(pOpts, pszPath); return rtPathRmError(pOpts, pszPath, VERR_IS_A_DIRECTORY, "Cannot remove '%s': %Rrc\n", pszPath, VERR_IS_A_DIRECTORY); case RTFS_TYPE_SYMLINK: return rtPathRmOneSymlink(pOpts, pszPath); case RTFS_TYPE_FIFO: case RTFS_TYPE_DEV_CHAR: case RTFS_TYPE_DEV_BLOCK: case RTFS_TYPE_SOCKET: return rtPathRmOneFile(pOpts, pszPath, &ObjInfo); case RTFS_TYPE_WHITEOUT: default: return rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE, "Object '%s' has an unknown file type: %o\n", pszPath, ObjInfo.Attr.fMode & RTFS_TYPE_MASK); } }
/** * Device I/O Control entry point. * * @param pFilp Associated file pointer. * @param uCmd The function specified to ioctl(). * @param ulArg The argument specified to ioctl(). */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) static int VBoxNetAdpLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg) #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) */ static long VBoxNetAdpLinuxIOCtlUnlocked(struct file *pFilp, unsigned int uCmd, unsigned long ulArg) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) */ { VBOXNETADPREQ Req; PVBOXNETADP pAdp; int rc; char *pszName = NULL; Log(("VBoxNetAdpLinuxIOCtl: param len %#x; uCmd=%#x; add=%#x\n", _IOC_SIZE(uCmd), uCmd, VBOXNETADP_CTL_ADD)); if (RT_UNLIKELY(_IOC_SIZE(uCmd) != sizeof(Req))) /* paranoia */ { Log(("VBoxNetAdpLinuxIOCtl: bad ioctl sizeof(Req)=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", sizeof(Req), _IOC_SIZE(uCmd), uCmd)); return -EINVAL; } switch (uCmd) { case VBOXNETADP_CTL_ADD: Log(("VBoxNetAdpLinuxIOCtl: _IOC_DIR(uCmd)=%#x; IOC_OUT=%#x\n", _IOC_DIR(uCmd), IOC_OUT)); if (RT_UNLIKELY(copy_from_user(&Req, (void *)ulArg, sizeof(Req)))) { Log(("VBoxNetAdpLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd)); return -EFAULT; } Log(("VBoxNetAdpLinuxIOCtl: Add %s\n", Req.szName)); if (Req.szName[0]) { pAdp = vboxNetAdpFindByName(Req.szName); if (pAdp) { Log(("VBoxNetAdpLinuxIOCtl: '%s' already exists\n", Req.szName)); return -EINVAL; } pszName = Req.szName; } rc = vboxNetAdpCreate(&pAdp, pszName); if (RT_FAILURE(rc)) { Log(("VBoxNetAdpLinuxIOCtl: vboxNetAdpCreate -> %Rrc\n", rc)); return -(rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL); } Assert(strlen(pAdp->szName) < sizeof(Req.szName)); strncpy(Req.szName, pAdp->szName, sizeof(Req.szName) - 1); Req.szName[sizeof(Req.szName) - 1] = '\0'; if (RT_UNLIKELY(copy_to_user((void *)ulArg, &Req, sizeof(Req)))) { /* this is really bad! */ /** @todo remove the adapter again? */ printk(KERN_ERR "VBoxNetAdpLinuxIOCtl: copy_to_user(%#lx,,%#zx); uCmd=%#x!\n", ulArg, sizeof(Req), uCmd); return -EFAULT; } Log(("VBoxNetAdpLinuxIOCtl: Successfully added '%s'\n", Req.szName)); break; case VBOXNETADP_CTL_REMOVE: if (RT_UNLIKELY(copy_from_user(&Req, (void *)ulArg, sizeof(Req)))) { Log(("VBoxNetAdpLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd)); return -EFAULT; } Log(("VBoxNetAdpLinuxIOCtl: Remove %s\n", Req.szName)); pAdp = vboxNetAdpFindByName(Req.szName); if (!pAdp) { Log(("VBoxNetAdpLinuxIOCtl: '%s' not found\n", Req.szName)); return -EINVAL; } rc = vboxNetAdpDestroy(pAdp); if (RT_FAILURE(rc)) { Log(("VBoxNetAdpLinuxIOCtl: vboxNetAdpDestroy('%s') -> %Rrc\n", Req.szName, rc)); return -EINVAL; } Log(("VBoxNetAdpLinuxIOCtl: Successfully removed '%s'\n", Req.szName)); break; default: printk(KERN_ERR "VBoxNetAdpLinuxIOCtl: unknown command %x.\n", uCmd); return -EINVAL; } return 0; }
/** * Worker that removes a file. * * Currently used to delete both regular and special files. * * @returns IPRT status code, errors go via rtPathRmError. * @param pOpts The RM options. * @param pszPath The path to the file. * @param pObjInfo The FS object info for the file. */ static int rtPathRmOneFile(PRTPATHRMCMDOPTS pOpts, const char *pszPath, PRTFSOBJINFO pObjInfo) { int rc; if (pOpts->fVerbose) rtPathRmVerbose(pOpts, pszPath); /* * Wipe the file if requested and possible. */ if (pOpts->fSafeDelete && RTFS_IS_FILE(pObjInfo->Attr.fMode)) { /* Lazy init of the 0xff buffer. */ if (g_ab0xFF[0] != 0xff || g_ab0xFF[sizeof(g_ab0xFF) - 1] != 0xff) memset(g_ab0xFF, 0xff, sizeof(g_ab0xFF)); RTFILE hFile; rc = RTFileOpen(&hFile, pszPath, RTFILE_O_WRITE); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, "Opening '%s' for overwriting: %Rrc\n", pszPath, rc); for (unsigned iPass = 0; iPass < 3; iPass++) { uint8_t const *pabFiller = iPass == 1 ? g_abZeros : g_ab0xFF; size_t const cbFiller = iPass == 1 ? sizeof(g_abZeros) : sizeof(g_ab0xFF); rc = RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { rc = rtPathRmError(pOpts, pszPath, rc, "Error seeking to start of '%s': %Rrc\n", pszPath, rc); break; } for (RTFOFF cbLeft = pObjInfo->cbObject; cbLeft > 0; cbLeft -= cbFiller) { size_t cbToWrite = cbFiller; if (cbLeft < (RTFOFF)cbToWrite) cbToWrite = (size_t)cbLeft; rc = RTFileWrite(hFile, pabFiller, cbToWrite, NULL); if (RT_FAILURE(rc)) { rc = rtPathRmError(pOpts, pszPath, rc, "Error writing to '%s': %Rrc\n", pszPath, rc); break; } } } int rc2 = RTFileClose(hFile); if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) return rtPathRmError(pOpts, pszPath, rc2, "Closing '%s' failed: %Rrc\n", pszPath, rc); if (RT_FAILURE(rc)) return rc; } /* * Remove the file. */ rc = RTFileDelete(pszPath); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, RTFS_IS_FILE(pObjInfo->Attr.fMode) ? "Error removing regular file '%s': %Rrc\n" : "Error removing special file '%s': %Rrc\n", pszPath, rc); return rc; }
static int vboxvfs_mount(struct mount *mp, struct thread *td) { int rc; char *pszShare; int cbShare, cbOption; int uid = 0, gid = 0; struct sf_glob_info *pShFlGlobalInfo; SHFLSTRING *pShFlShareName = NULL; int cbShFlShareName; printf("%s: Enter\n", __FUNCTION__); if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) return EOPNOTSUPP; if (vfs_filteropt(mp->mnt_optnew, vboxvfs_opts)) { vfs_mount_error(mp, "%s", "Invalid option"); return EINVAL; } rc = vfs_getopt(mp->mnt_optnew, "from", (void **)&pszShare, &cbShare); if (rc || pszShare[cbShare-1] != '\0' || cbShare > 0xfffe) return EINVAL; rc = vfs_getopt(mp->mnt_optnew, "gid", (void **)&gid, &cbOption); if ((rc != ENOENT) && (rc || cbOption != sizeof(gid))) return EINVAL; rc = vfs_getopt(mp->mnt_optnew, "uid", (void **)&uid, &cbOption); if ((rc != ENOENT) && (rc || cbOption != sizeof(uid))) return EINVAL; pShFlGlobalInfo = RTMemAllocZ(sizeof(struct sf_glob_info)); if (!pShFlGlobalInfo) return ENOMEM; cbShFlShareName = offsetof (SHFLSTRING, String.utf8) + cbShare + 1; pShFlShareName = RTMemAllocZ(cbShFlShareName); if (!pShFlShareName) return VERR_NO_MEMORY; pShFlShareName->u16Length = cbShare; pShFlShareName->u16Size = cbShare + 1; memcpy (pShFlShareName->String.utf8, pszShare, cbShare + 1); rc = VbglR0SfMapFolder (&g_vboxSFClient, pShFlShareName, &pShFlGlobalInfo->map); RTMemFree(pShFlShareName); if (RT_FAILURE (rc)) { RTMemFree(pShFlGlobalInfo); printf("VbglR0SfMapFolder failed rc=%d\n", rc); return EPROTO; } pShFlGlobalInfo->uid = uid; pShFlGlobalInfo->gid = gid; mp->mnt_data = pShFlGlobalInfo; /** @todo root vnode. */ vfs_getnewfsid(mp); vfs_mountedfrom(mp, pszShare); printf("%s: Leave rc=0\n", __FUNCTION__); return 0; }
/** * @copydoc USBPROXYBACK::pfnUrbQueue */ static DECLCALLBACK(int) usbProxyFreeBSDUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb) { PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD); PUSBENDPOINTFBSD pEndpointFBSD; struct usb_fs_endpoint *pXferEndpoint; struct usb_fs_start UsbFsStart; unsigned cFrames; uint8_t *pbData; int index; int ep_num; int rc; LogFlow(("usbProxyFreeBSDUrbQueue: pUrb=%p EndPt=%u Dir=%u\n", pUrb, (unsigned)pUrb->EndPt, (unsigned)pUrb->enmDir)); ep_num = pUrb->EndPt; if ((pUrb->enmType != VUSBXFERTYPE_MSG) && (pUrb->enmDir == VUSBDIRECTION_IN)) { /* set IN-direction bit */ ep_num |= 0x80; } index = 0; retry: index = usbProxyFreeBSDEndpointOpen(pProxyDev, ep_num, (pUrb->enmType == VUSBXFERTYPE_ISOC), index); if (index < 0) return VERR_INVALID_PARAMETER; pEndpointFBSD = &pDevFBSD->aSwEndpoint[index]; pXferEndpoint = &pDevFBSD->aHwEndpoint[index]; pbData = pUrb->abData; switch (pUrb->enmType) { case VUSBXFERTYPE_MSG: { pEndpointFBSD->apvData[0] = pbData; pEndpointFBSD->acbData[0] = 8; /* check wLength */ if (pbData[6] || pbData[7]) { pEndpointFBSD->apvData[1] = pbData + 8; pEndpointFBSD->acbData[1] = pbData[6] | (pbData[7] << 8); cFrames = 2; } else { pEndpointFBSD->apvData[1] = NULL; pEndpointFBSD->acbData[1] = 0; cFrames = 1; } LogFlow(("usbProxyFreeBSDUrbQueue: pUrb->cbData=%u, 0x%02x, " "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", pUrb->cbData, pbData[0], pbData[1], pbData[2], pbData[3], pbData[4], pbData[5], pbData[6], pbData[7])); pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE; pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK; break; } case VUSBXFERTYPE_ISOC: { unsigned i; for (i = 0; i < pUrb->cIsocPkts; i++) { if (i >= pEndpointFBSD->cMaxFrames) break; pEndpointFBSD->apvData[i] = pbData + pUrb->aIsocPkts[i].off; pEndpointFBSD->acbData[i] = pUrb->aIsocPkts[i].cb; } /* Timeout handling will be done during reap. */ pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE; pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK; cFrames = i; break; } default: { pEndpointFBSD->apvData[0] = pbData; pEndpointFBSD->cbData0 = pUrb->cbData; /* XXX maybe we have to loop */ if (pUrb->cbData > pEndpointFBSD->cMaxIo) pEndpointFBSD->acbData[0] = pEndpointFBSD->cMaxIo; else pEndpointFBSD->acbData[0] = pUrb->cbData; /* Timeout handling will be done during reap. */ pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE; pXferEndpoint->flags = pUrb->fShortNotOk ? 0 : USB_FS_FLAG_MULTI_SHORT_OK; cFrames = 1; break; } } /* store number of frames */ pXferEndpoint->nFrames = cFrames; /* zero-default */ memset(&UsbFsStart, 0, sizeof(UsbFsStart)); /* Start the transfer */ UsbFsStart.ep_index = index; rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_START, &UsbFsStart, true); LogFlow(("usbProxyFreeBSDUrbQueue: USB_FS_START returned rc=%d " "len[0]=%u len[1]=%u cbData=%u index=%u ep_num=%u\n", rc, (unsigned)pEndpointFBSD->acbData[0], (unsigned)pEndpointFBSD->acbData[1], (unsigned)pUrb->cbData, (unsigned)index, (unsigned)ep_num)); if (RT_FAILURE(rc)) { if (rc == VERR_RESOURCE_BUSY) { index++; goto retry; } return rc; } pUrb->Dev.pvPrivate = (void *)(long)(index + 1); pEndpointFBSD->pUrb = pUrb; return rc; }
static int usbProxyFreeBSDEndpointOpen(PUSBPROXYDEV pProxyDev, int Endpoint, bool fIsoc, int index) { PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD); PUSBENDPOINTFBSD pEndpointFBSD = NULL; /* shut up gcc */ struct usb_fs_endpoint *pXferEndpoint; struct usb_fs_open UsbFsOpen; int rc; LogFlow(("usbProxyFreeBSDEndpointOpen: pProxyDev=%p Endpoint=%d\n", (void *)pProxyDev, Endpoint)); for (; index < USBFBSD_MAXENDPOINTS; index++) { pEndpointFBSD = &pDevFBSD->aSwEndpoint[index]; if (pEndpointFBSD->fCancelling) continue; if ( pEndpointFBSD->fOpen && !pEndpointFBSD->pUrb && (int)pEndpointFBSD->iEpNum == Endpoint) return index; } if (index == USBFBSD_MAXENDPOINTS) { for (index = 0; index != USBFBSD_MAXENDPOINTS; index++) { pEndpointFBSD = &pDevFBSD->aSwEndpoint[index]; if (pEndpointFBSD->fCancelling) continue; if (!pEndpointFBSD->fOpen) break; } if (index == USBFBSD_MAXENDPOINTS) return -1; } /* set ppBuffer and pLength */ pXferEndpoint = &pDevFBSD->aHwEndpoint[index]; pXferEndpoint->ppBuffer = &pEndpointFBSD->apvData[0]; pXferEndpoint->pLength = &pEndpointFBSD->acbData[0]; LogFlow(("usbProxyFreeBSDEndpointOpen: ep_index=%d ep_num=%d\n", index, Endpoint)); memset(&UsbFsOpen, 0, sizeof(UsbFsOpen)); UsbFsOpen.ep_index = index; UsbFsOpen.ep_no = Endpoint; UsbFsOpen.max_bufsize = 256 * 1024; /* Hardcoded assumption about the URBs we get. */ UsbFsOpen.max_frames = fIsoc ? USBFBSD_MAXFRAMES : 2; rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_OPEN, &UsbFsOpen, true); if (RT_FAILURE(rc)) { if (rc == VERR_RESOURCE_BUSY) LogFlow(("usbProxyFreeBSDEndpointOpen: EBUSY\n")); return -1; } pEndpointFBSD->fOpen = true; pEndpointFBSD->pUrb = NULL; pEndpointFBSD->iEpNum = Endpoint; pEndpointFBSD->cMaxIo = UsbFsOpen.max_bufsize; pEndpointFBSD->cMaxFrames = UsbFsOpen.max_frames; return index; }
/** * Entry point. */ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp) { RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); RTPrintf(TESTCASE ": TESTING...\n"); RTStrmFlush(g_pStdOut); /* * Create empty VM. */ PUVM pUVM; int rc = VMR3Create(1, NULL, NULL, NULL, tstVMREQConfigConstructor, NULL, NULL, &pUVM); if (RT_SUCCESS(rc)) { /* * Do testing. */ uint64_t u64StartTS = RTTimeNanoTS(); RTTHREAD Thread0; rc = RTThreadCreate(&Thread0, Thread, pUVM, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "REQ1"); if (RT_SUCCESS(rc)) { RTTHREAD Thread1; rc = RTThreadCreate(&Thread1, Thread, pUVM, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "REQ1"); if (RT_SUCCESS(rc)) { int rcThread1; rc = RTThreadWait(Thread1, RT_INDEFINITE_WAIT, &rcThread1); if (RT_FAILURE(rc)) { RTPrintf(TESTCASE ": RTThreadWait(Thread1,,) failed, rc=%Rrc\n", rc); g_cErrors++; } if (RT_FAILURE(rcThread1)) g_cErrors++; } else { RTPrintf(TESTCASE ": RTThreadCreate(&Thread1,,,,) failed, rc=%Rrc\n", rc); g_cErrors++; } int rcThread0; rc = RTThreadWait(Thread0, RT_INDEFINITE_WAIT, &rcThread0); if (RT_FAILURE(rc)) { RTPrintf(TESTCASE ": RTThreadWait(Thread1,,) failed, rc=%Rrc\n", rc); g_cErrors++; } if (RT_FAILURE(rcThread0)) g_cErrors++; } else { RTPrintf(TESTCASE ": RTThreadCreate(&Thread0,,,,) failed, rc=%Rrc\n", rc); g_cErrors++; } uint64_t u64ElapsedTS = RTTimeNanoTS() - u64StartTS; RTPrintf(TESTCASE ": %llu ns elapsed\n", u64ElapsedTS); RTStrmFlush(g_pStdOut); /* * Print stats. */ STAMR3Print(pUVM, "/VM/Req/*"); /* * Testing va_list fun. */ RTPrintf(TESTCASE ": va_list argument test...\n"); RTStrmFlush(g_pStdOut); PassVA(pUVM, "hello %s", "world"); VMR3AtRuntimeErrorRegister(pUVM, MyAtRuntimeError, (void *)"user argument"); VMSetRuntimeError(VMR3GetVM(pUVM), 0 /*fFlags*/, "enum", "some %s string", "error"); /* * Cleanup. */ rc = VMR3PowerOff(pUVM); if (!RT_SUCCESS(rc)) { RTPrintf(TESTCASE ": error: failed to power off vm! rc=%Rrc\n", rc); g_cErrors++; } rc = VMR3Destroy(pUVM); if (!RT_SUCCESS(rc)) { RTPrintf(TESTCASE ": error: failed to destroy vm! rc=%Rrc\n", rc); g_cErrors++; } VMR3ReleaseUVM(pUVM); } else { RTPrintf(TESTCASE ": fatal error: failed to create vm! rc=%Rrc\n", rc); g_cErrors++; } /* * Summary and return. */ if (!g_cErrors) RTPrintf(TESTCASE ": SUCCESS\n"); else RTPrintf(TESTCASE ": FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; }
RTDECL(RTEXITCODE) RTPathRmCmd(unsigned cArgs, char **papszArgs) { /* * Parse the command line. */ static const RTGETOPTDEF s_aOptions[] = { /* operations */ { "--dirs-and-more", 'd', RTGETOPT_REQ_NOTHING }, { "--force", 'f', RTGETOPT_REQ_NOTHING }, { "--prompt", 'i', RTGETOPT_REQ_NOTHING }, { "--prompt-once", 'I', RTGETOPT_REQ_NOTHING }, { "--interactive", RTPATHRMCMD_OPT_INTERACTIVE, RTGETOPT_REQ_STRING }, { "--one-file-system", RTPATHRMCMD_OPT_ONE_FILE_SYSTEM, RTGETOPT_REQ_NOTHING }, { "--preserve-root", RTPATHRMCMD_OPT_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING }, { "--no-preserve-root", RTPATHRMCMD_OPT_NO_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING }, { "--recursive", 'R', RTGETOPT_REQ_NOTHING }, { "--recursive", 'r', RTGETOPT_REQ_NOTHING }, { "--safe-delete", 'P', RTGETOPT_REQ_NOTHING }, { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, /* IPRT extensions */ { "--machine-readable", RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING }, { "--machinereadable", RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING }, /* bad long option style */ }; RTGETOPTSTATE GetState; int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc); RTPATHRMCMDOPTS Opts; RT_ZERO(Opts); Opts.fPreserveRoot = true; Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE; RTGETOPTUNION ValueUnion; while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0 && rc != VINF_GETOPT_NOT_OPTION) { switch (rc) { case 'd': Opts.fDirsAndOther = true; break; case 'f': Opts.fForce = true; Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE; break; case 'i': Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL; break; case 'I': Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE; break; case RTPATHRMCMD_OPT_INTERACTIVE: if (!strcmp(ValueUnion.psz, "always")) Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL; else if (!strcmp(ValueUnion.psz, "once")) Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE; else return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown --interactive option value: '%s'\n", ValueUnion.psz); break; case RTPATHRMCMD_OPT_ONE_FILE_SYSTEM: Opts.fOneFileSystem = true; break; case RTPATHRMCMD_OPT_PRESERVE_ROOT: Opts.fPreserveRoot = true; break; case RTPATHRMCMD_OPT_NO_PRESERVE_ROOT: Opts.fPreserveRoot = false; break; case 'R': case 'r': Opts.fRecursive = true; Opts.fDirsAndOther = true; break; case 'P': Opts.fSafeDelete = true; break; case 'v': Opts.fVerbose = true; break; case RTPATHRMCMD_OPT_MACHINE_READABLE: Opts.fMachineReadable = true; break; case 'h': RTPrintf("Usage: to be written\nOption dump:\n"); for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++) if (RT_C_IS_PRINT(s_aOptions[i].iShort)) RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong); else RTPrintf(" %s\n", s_aOptions[i].pszLong); return RTEXITCODE_SUCCESS; case 'V': RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision()); return RTEXITCODE_SUCCESS; default: return RTGetOptPrintError(rc, &ValueUnion); } } /* * Options we don't support. */ if (Opts.fOneFileSystem) return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --one-file-system option is not yet implemented.\n"); if (Opts.enmInteractive != RTPATHRMCMDINTERACTIVE_NONE) return RTMsgErrorExit(RTEXITCODE_FAILURE, "The -i, -I and --interactive options are not implemented yet.\n"); /* * No files means error. */ if (rc != VINF_GETOPT_NOT_OPTION && !Opts.fForce) return RTMsgErrorExit(RTEXITCODE_FAILURE, "No files or directories specified.\n"); /* * Machine readable init + header. */ if (Opts.fMachineReadable) { rc = RTStrmSetMode(g_pStdOut, true /*fBinary*/, false /*fCurrentCodeSet*/); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmSetMode failed: %Rrc.\n", rc); static const char s_achHeader[] = "hdr_id=rm\0hdr_ver=1"; RTStrmWrite(g_pStdOut, s_achHeader, sizeof(s_achHeader)); } /* * Delete the specified files/dirs/whatever. */ RTEXITCODE rcExit = RTEXITCODE_SUCCESS; while (rc == VINF_GETOPT_NOT_OPTION) { rc = rtPathRmOne(&Opts, ValueUnion.psz); if (RT_FAILURE(rc)) rcExit = RTEXITCODE_FAILURE; /* next */ rc = RTGetOpt(&GetState, &ValueUnion); } if (rc != 0) rcExit = RTGetOptPrintError(rc, &ValueUnion); /* * Terminate the machine readable stuff. */ if (Opts.fMachineReadable) { RTStrmWrite(g_pStdOut, "\0\0\0", 4); rc = RTStrmFlush(g_pStdOut); if (RT_FAILURE(rc) && rcExit == RTEXITCODE_SUCCESS) rcExit = RTEXITCODE_FAILURE; } return rcExit; }
int CollectorWin::preCollect(const CollectorHints& hints, uint64_t /* iTick */) { LogFlowThisFuncEnter(); uint64_t user, kernel, idle, total; int rc = getRawHostCpuLoad(&user, &kernel, &idle); if (RT_FAILURE(rc)) return rc; total = user + kernel + idle; DWORD dwError; const CollectorHints::ProcessList& processes = hints.getProcessFlags(); CollectorHints::ProcessList::const_iterator it; mProcessStats.clear(); for (it = processes.begin(); it != processes.end() && RT_SUCCESS(rc); ++it) { RTPROCESS process = it->first; HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process); if (!h) { dwError = GetLastError(); Log (("OpenProcess() -> 0x%x\n", dwError)); rc = RTErrConvertFromWin32(dwError); break; } VMProcessStats vmStats; RT_ZERO(vmStats); if ((it->second & COLLECT_CPU_LOAD) != 0) { FILETIME ftCreate, ftExit, ftKernel, ftUser; if (!GetProcessTimes(h, &ftCreate, &ftExit, &ftKernel, &ftUser)) { dwError = GetLastError(); Log (("GetProcessTimes() -> 0x%x\n", dwError)); rc = RTErrConvertFromWin32(dwError); } else { vmStats.cpuKernel = FILETTIME_TO_100NS(ftKernel); vmStats.cpuUser = FILETTIME_TO_100NS(ftUser); vmStats.cpuTotal = total; } } if (RT_SUCCESS(rc) && (it->second & COLLECT_RAM_USAGE) != 0) { PROCESS_MEMORY_COUNTERS pmc; if (!GetProcessMemoryInfo(h, &pmc, sizeof(pmc))) { dwError = GetLastError(); Log (("GetProcessMemoryInfo() -> 0x%x\n", dwError)); rc = RTErrConvertFromWin32(dwError); } else vmStats.ramUsed = pmc.WorkingSetSize; } CloseHandle(h); mProcessStats[process] = vmStats; } LogFlowThisFuncLeave(); return rc; }
RTDECL(int) RTGetOptArgvFromString(char ***ppapszArgv, int *pcArgs, const char *pszCmdLine, uint32_t fFlags, const char *pszSeparators) { /* * Some input validation. */ AssertPtr(pszCmdLine); AssertPtr(pcArgs); AssertPtr(ppapszArgv); AssertReturn( fFlags == RTGETOPTARGV_CNV_QUOTE_BOURNE_SH || fFlags == RTGETOPTARGV_CNV_QUOTE_MS_CRT, VERR_INVALID_FLAGS); if (!pszSeparators) pszSeparators = " \t\n\r"; else AssertPtr(pszSeparators); size_t const cchSeparators = strlen(pszSeparators); AssertReturn(cchSeparators > 0, VERR_INVALID_PARAMETER); /* * Parse the command line and chop off it into argv individual argv strings. */ int rc = VINF_SUCCESS; const char *pszSrc = pszCmdLine; char *pszDup = (char *)RTMemAlloc(strlen(pszSrc) + 1); char *pszDst = pszDup; if (!pszDup) return VERR_NO_STR_MEMORY; char **papszArgs = NULL; unsigned iArg = 0; while (*pszSrc) { /* Skip stuff */ rc = rtGetOptSkipDelimiters(&pszSrc, pszSeparators, cchSeparators); if (RT_FAILURE(rc)) break; if (!*pszSrc) break; /* Start a new entry. */ if ((iArg % 32) == 0) { void *pvNew = RTMemRealloc(papszArgs, (iArg + 33) * sizeof(char *)); if (!pvNew) { rc = VERR_NO_MEMORY; break; } papszArgs = (char **)pvNew; } papszArgs[iArg++] = pszDst; /* * Parse and copy the string over. */ RTUNICP Cp; if ((fFlags & RTGETOPTARGV_CNV_QUOTE_MASK) == RTGETOPTARGV_CNV_QUOTE_BOURNE_SH) { /* * Bourne shell style. */ RTUNICP CpQuote = 0; for (;;) { rc = RTStrGetCpEx(&pszSrc, &Cp); if (RT_FAILURE(rc) || !Cp) break; if (!CpQuote) { if (Cp == '"' || Cp == '\'') CpQuote = Cp; else if (rtGetOptIsCpInSet(Cp, pszSeparators, cchSeparators)) break; else if (Cp != '\\') pszDst = RTStrPutCp(pszDst, Cp); else { /* escaped char */ rc = RTStrGetCpEx(&pszSrc, &Cp); if (RT_FAILURE(rc) || !Cp) break; pszDst = RTStrPutCp(pszDst, Cp); } } else if (CpQuote != Cp) { if (Cp != '\\' || CpQuote == '\'') pszDst = RTStrPutCp(pszDst, Cp); else { /* escaped char */ rc = RTStrGetCpEx(&pszSrc, &Cp); if (RT_FAILURE(rc) || !Cp) break; pszDst = RTStrPutCp(pszDst, Cp); } } else CpQuote = 0; } } else { /* * Microsoft CRT style. */ Assert((fFlags & RTGETOPTARGV_CNV_QUOTE_MASK) == RTGETOPTARGV_CNV_QUOTE_MS_CRT); bool fInQuote = false; for (;;) { rc = RTStrGetCpEx(&pszSrc, &Cp); if (RT_FAILURE(rc) || !Cp) break; if (Cp == '"') fInQuote = !fInQuote; else if (!fInQuote && rtGetOptIsCpInSet(Cp, pszSeparators, cchSeparators)) break; else if (Cp != '\\') pszDst = RTStrPutCp(pszDst, Cp); else { /* A backslash sequence is only relevant if followed by a double quote, then it will work like an escape char. */ size_t cQuotes = 1; while (*pszSrc == '\\') { cQuotes++; pszSrc++; } if (*pszSrc != '"') /* Not an escape sequence. */ while (cQuotes-- > 0) pszDst = RTStrPutCp(pszDst, '\\'); else { /* Escape sequence. Output half of the slashes. If odd number, output the escaped double quote . */ while (cQuotes >= 2) { pszDst = RTStrPutCp(pszDst, '\\'); cQuotes -= 2; } if (!cQuotes) fInQuote = !fInQuote; else pszDst = RTStrPutCp(pszDst, '"'); pszSrc++; } } } } *pszDst++ = '\0'; if (RT_FAILURE(rc) || !Cp) break; } if (RT_FAILURE(rc)) { RTMemFree(pszDup); RTMemFree(papszArgs); return rc; } /* * Terminate the array. * Check for empty string to make sure we've got an array. */ if (iArg == 0) { RTMemFree(pszDup); papszArgs = (char **)RTMemAlloc(1 * sizeof(char *)); if (!papszArgs) return VERR_NO_MEMORY; } papszArgs[iArg] = NULL; *pcArgs = iArg; *ppapszArgv = papszArgs; return VINF_SUCCESS; }
int main(int argc, char **argv) { /* * Init IPRT. */ int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); /* * Locate a native DTrace command binary. */ bool fIsNativeDTrace = false; char szDTraceCmd[RTPATH_MAX]; szDTraceCmd[0] = '\0'; #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) /* * 1. Try native first on platforms where it's applicable. */ static const char * const s_apszNativeDTrace[] = { "/usr/sbin/dtrace", "/sbin/dtrace", "/usr/bin/dtrace", "/bin/dtrace", "/usr/local/sbin/dtrace", "/usr/local/bin/dtrace" }; if (!RTEnvExist("VBOX_DTRACE_NO_NATIVE")) for (uint32_t i = 0; i < RT_ELEMENTS(s_apszNativeDTrace); i++) if (RTFileExists(s_apszNativeDTrace[i])) { fIsNativeDTrace = true; strcpy(szDTraceCmd, s_apszNativeDTrace[i]); # ifdef RT_OS_LINUX /** @todo Warn if the dtrace modules haven't been loaded or vboxdrv isn't * compiled against them. */ # endif break; } if (szDTraceCmd[0] == '\0') #endif { /* * 2. VBoxDTrace extension pack installed? * * Note! We cannot use the COM API here because this program is usually * run thru sudo or directly as root, even if the target * VirtualBox process is running as regular user. This is due to * the privileges required to run dtrace scripts on a host. */ rc = RTPathAppPrivateArch(szDTraceCmd, sizeof(szDTraceCmd)); if (RT_SUCCESS(rc)) rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), VBOX_EXTPACK_INSTALL_DIR RTPATH_SLASH_STR VBOX_EXTPACK_VBOXDTRACE_MANGLED_NAME); if (RT_SUCCESS(rc)) rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), RTBldCfgTargetDotArch()); if (RT_SUCCESS(rc)) rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), "VBoxDTraceCmd"); if (RT_SUCCESS(rc)) rc = RTStrCat(szDTraceCmd, sizeof(szDTraceCmd), RTLdrGetSuff()); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing extension pack path: %Rrc", rc); if (!RTFileExists(szDTraceCmd)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unable to find a DTrace implementation. VBoxDTrace Extension Pack installed?"); fIsNativeDTrace = false; } /* * Construct a new command line that includes our libary. */ char szDTraceLibDir[RTPATH_MAX]; rc = RTPathAppPrivateNoArch(szDTraceLibDir, sizeof(szDTraceLibDir)); if (RT_SUCCESS(rc)) rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), "dtrace" RTPATH_SLASH_STR "lib"); if (RT_SUCCESS(rc)) rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), RTBldCfgTargetArch()); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing dtrace library path for VBox: %Rrc", rc); char **papszArgs = (char **)RTMemAlloc((argc + 3) * sizeof(char *)); if (!papszArgs) return RTMsgErrorExit(RTEXITCODE_FAILURE, "No memory for argument list."); int cArgs = 1; papszArgs[0] = fIsNativeDTrace ? szDTraceCmd : argv[0]; if (argc > 1) { papszArgs[cArgs++] = (char *)"-L"; papszArgs[cArgs++] = szDTraceLibDir; } for (int i = 1; i < argc; i++) papszArgs[cArgs++] = argv[i]; papszArgs[cArgs] = NULL; Assert(cArgs <= argc + 3); /* * The native DTrace we execute as a sub-process and wait for. */ RTEXITCODE rcExit; if (fIsNativeDTrace) { RTPROCESS hProc; rc = RTProcCreate(szDTraceCmd, papszArgs, RTENV_DEFAULT, 0, &hProc); if (RT_SUCCESS(rc)) { RTPROCSTATUS Status; rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &Status); if (RT_SUCCESS(rc)) { if (Status.enmReason == RTPROCEXITREASON_NORMAL) rcExit = (RTEXITCODE)Status.iStatus; else rcExit = RTEXITCODE_FAILURE; } else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error waiting for child process: %Rrc", rc); } else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error executing '%s': %Rrc", szDTraceCmd, rc); } /* * While the VBoxDTrace we load and call the main function of. */ else { RTERRINFOSTATIC ErrInfo; RTLDRMOD hMod; rc = SUPR3HardenedLdrLoadPlugIn(szDTraceCmd, &hMod, RTErrInfoInitStatic(&ErrInfo)); if (RT_SUCCESS(rc)) { PFNVBOXDTRACEMAIN pfnVBoxDTraceMain; rc = RTLdrGetSymbol(hMod, "VBoxDTraceMain", (void **)&pfnVBoxDTraceMain); if (RT_SUCCESS(rc)) rcExit = (RTEXITCODE)pfnVBoxDTraceMain(cArgs, papszArgs); else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error locating 'VBoxDTraceMain' in '%s': %Rrc", szDTraceCmd, rc); } else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading '%s': %Rrc (%s)", szDTraceCmd, rc, ErrInfo.szMsg); } return rcExit; }
static LRESULT vboxClipboardProcessMsg(VBOXCLIPBOARDCONTEXT *pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT rc = 0; switch (msg) { case WM_CHANGECBCHAIN: { HWND hwndRemoved = (HWND)wParam; HWND hwndNext = (HWND)lParam; Log(("VBoxTray: vboxClipboardProcessMsg: WM_CHANGECBCHAIN: hwndRemoved %p, hwndNext %p, hwnd %p\n", hwndRemoved, hwndNext, pCtx->hwnd)); if (hwndRemoved == pCtx->hwndNextInChain) { /* The window that was next to our in the chain is being removed. * Relink to the new next window. */ pCtx->hwndNextInChain = hwndNext; } else { if (pCtx->hwndNextInChain) { /* Pass the message further. */ DWORD_PTR dwResult; rc = SendMessageTimeout(pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult); if (!rc) rc = (LRESULT) dwResult; } } } break; case WM_DRAWCLIPBOARD: { Log(("VBoxTray: vboxClipboardProcessMsg: WM_DRAWCLIPBOARD, hwnd %p\n", pCtx->hwnd)); if (GetClipboardOwner () != hwnd) { /* Clipboard was updated by another application. */ /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */ int vboxrc = vboxClipboardChanged(pCtx); if (RT_FAILURE(vboxrc)) Log(("VBoxTray: vboxClipboardProcessMsg: vboxClipboardChanged failed, rc = %Rrc\n", vboxrc)); } /* Pass the message to next windows in the clipboard chain. */ SendMessageTimeout(pCtx->hwndNextInChain, msg, wParam, lParam, 0, CBCHAIN_TIMEOUT, NULL); } break; case WM_TIMER: { HWND hViewer = GetClipboardViewer(); /* Re-register ourselves in the clipboard chain if our last ping * timed out or there seems to be no valid chain. */ if (!hViewer || pCtx->fCBChainPingInProcess) { removeFromCBChain(pCtx); addToCBChain(pCtx); } /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be * processed by ourselves to the chain. */ pCtx->fCBChainPingInProcess = TRUE; hViewer = GetClipboardViewer(); if (hViewer) SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pCtx->hwndNextInChain, (LPARAM)pCtx->hwndNextInChain, CBChainPingProc, (ULONG_PTR) pCtx); } break; case WM_CLOSE: { /* Do nothing. Ignore the message. */ } break; case WM_RENDERFORMAT: { /* Insert the requested clipboard format data into the clipboard. */ uint32_t u32Format = 0; UINT format = (UINT)wParam; Log(("VBoxTray: vboxClipboardProcessMsg: WM_RENDERFORMAT, format = %x\n", format)); switch (format) { case CF_UNICODETEXT: u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; break; case CF_DIB: u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP; break; default: if (format >= 0xC000) { TCHAR szFormatName[256]; int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR)); if (cActual) { if (strcmp (szFormatName, "HTML Format") == 0) { u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML; } } } break; } if (u32Format == 0) { /* Unsupported clipboard format is requested. */ Log(("VBoxTray: vboxClipboardProcessMsg: Unsupported clipboard format requested: %ld\n", u32Format)); EmptyClipboard(); } else { const uint32_t cbPrealloc = 4096; /* @todo r=andy Make it dynamic for supporting larger text buffers! */ uint32_t cb = 0; /* Preallocate a buffer, most of small text transfers will fit into it. */ HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc); Log(("VBoxTray: vboxClipboardProcessMsg: Preallocated handle hMem = %p\n", hMem)); if (hMem) { void *pMem = GlobalLock(hMem); Log(("VBoxTray: vboxClipboardProcessMsg: Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cbPrealloc, &cb); Log(("VBoxTray: vboxClipboardProcessMsg: VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc)); if (RT_SUCCESS(vboxrc)) { if (cb == 0) { /* 0 bytes returned means the clipboard is empty. * Deallocate the memory and set hMem to NULL to get to * the clipboard empty code path. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else if (cb > cbPrealloc) { GlobalUnlock(hMem); /* The preallocated buffer is too small, adjust the size. */ hMem = GlobalReAlloc(hMem, cb, 0); Log(("VBoxTray: vboxClipboardProcessMsg: Reallocated hMem = %p\n", hMem)); if (hMem) { pMem = GlobalLock(hMem); Log(("VBoxTray: vboxClipboardProcessMsg: Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ uint32_t cbNew = 0; vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cb, &cbNew); Log(("VBoxTray: VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew)); if (RT_SUCCESS (vboxrc) && cbNew <= cb) { cb = cbNew; } else { GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } } else { GlobalFree(hMem); hMem = NULL; } } } if (hMem) { /* pMem is the address of the data. cb is the size of returned data. */ /* Verify the size of returned text, the memory block for clipboard * must have the exact string size. */ if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { size_t cbActual = 0; HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual); if (FAILED (hrc)) { /* Discard invalid data. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else { /* cbActual is the number of bytes, excluding those used * for the terminating null character. */ cb = (uint32_t)(cbActual + 2); } } } if (hMem) { GlobalUnlock(hMem); hMem = GlobalReAlloc(hMem, cb, 0); Log(("VBoxTray: vboxClipboardProcessMsg: Reallocated hMem = %p\n", hMem)); if (hMem) { /* 'hMem' contains the host clipboard data. * size is 'cb' and format is 'format'. */ HANDLE hClip = SetClipboardData(format, hMem); Log(("VBoxTray: vboxClipboardProcessMsg: WM_RENDERFORMAT hClip = %p\n", hClip)); if (hClip) { /* The hMem ownership has gone to the system. Finish the processing. */ break; } /* Cleanup follows. */ } } } if (hMem) GlobalUnlock(hMem); } if (hMem) GlobalFree(hMem); } /* Something went wrong. */ EmptyClipboard(); } } break; case WM_RENDERALLFORMATS: { /* Do nothing. The clipboard formats will be unavailable now, because the * windows is to be destroyed and therefore the guest side becomes inactive. */ if (OpenClipboard(hwnd)) { EmptyClipboard(); CloseClipboard(); } } break; case WM_USER: { /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */ uint32_t u32Formats = (uint32_t)lParam; if (FALSE == OpenClipboard(hwnd)) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError())); } else { EmptyClipboard(); HANDLE hClip = NULL; if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n")); hClip = SetClipboardData(CF_UNICODETEXT, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n")); hClip = SetClipboardData(CF_DIB, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format)); if (format != 0) { hClip = SetClipboardData(format, NULL); } } CloseClipboard(); Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: hClip = %p, err = %ld\n", hClip, GetLastError ())); } } break; case WM_USER + 1: { /* Send data in the specified format to the host. */ uint32_t u32Formats = (uint32_t)lParam; HANDLE hClip = NULL; if (FALSE == OpenClipboard(hwnd)) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError())); } else { int vboxrc; if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { hClip = GetClipboardData(CF_DIB); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_DIB\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { hClip = GetClipboardData(CF_UNICODETEXT); if (hClip != NULL) { LPWSTR uniString = (LPWSTR)GlobalLock(hClip); if (uniString != NULL) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_UNICODETEXT\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); if (format != 0) { hClip = GetClipboardData(format); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_HTML\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } } CloseClipboard(); } if (hClip == NULL) { /* Requested clipboard format is not available, send empty data. */ VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0); } } break; default: { rc = DefWindowProc(hwnd, msg, wParam, lParam); } } Log(("VBoxTray: vboxClipboardProcessMsg returned with rc = %ld\n", rc)); return rc; }
RTDECL(int) RTGetOptArgvFromString(char ***ppapszArgv, int *pcArgs, const char *pszCmdLine, const char *pszSeparators) { /* * Some input validation. */ AssertPtr(pszCmdLine); AssertPtr(pcArgs); AssertPtr(ppapszArgv); if (!pszSeparators) pszSeparators = " \t\n\r"; else AssertPtr(pszSeparators); size_t const cchSeparators = strlen(pszSeparators); AssertReturn(cchSeparators > 0, VERR_INVALID_PARAMETER); /* * Parse the command line and chop off it into argv individual argv strings. */ int rc = VINF_SUCCESS; const char *pszSrc = pszCmdLine; char *pszDup = (char *)RTMemAlloc(strlen(pszSrc) + 1); char *pszDst = pszDup; if (!pszDup) return VERR_NO_STR_MEMORY; char **papszArgs = NULL; unsigned iArg = 0; while (*pszSrc) { /* Skip stuff */ rc = rtGetOptSkipDelimiters(&pszSrc, pszSeparators, cchSeparators); if (RT_FAILURE(rc)) break; if (!*pszSrc) break; /* Start a new entry. */ if ((iArg % 32) == 0) { void *pvNew = RTMemRealloc(papszArgs, (iArg + 33) * sizeof(char *)); if (!pvNew) { rc = VERR_NO_MEMORY; break; } papszArgs = (char **)pvNew; } papszArgs[iArg++] = pszDst; /* Parse and copy the string over. */ RTUNICP CpQuote = 0; RTUNICP Cp; for (;;) { rc = RTStrGetCpEx(&pszSrc, &Cp); if (RT_FAILURE(rc) || !Cp) break; if (!CpQuote) { if (Cp == '"' || Cp == '\'') CpQuote = Cp; else if (rtGetOptIsCpInSet(Cp, pszSeparators, cchSeparators)) break; else pszDst = RTStrPutCp(pszDst, Cp); } else if (CpQuote != Cp) pszDst = RTStrPutCp(pszDst, Cp); else CpQuote = 0; } *pszDst++ = '\0'; if (RT_FAILURE(rc) || !Cp) break; } if (RT_FAILURE(rc)) { RTMemFree(pszDup); RTMemFree(papszArgs); return rc; } /* * Terminate the array. * Check for empty string to make sure we've got an array. */ if (iArg == 0) { RTMemFree(pszDup); papszArgs = (char **)RTMemAlloc(1 * sizeof(char *)); if (!papszArgs) return VERR_NO_MEMORY; } papszArgs[iArg] = NULL; *pcArgs = iArg; *ppapszArgv = papszArgs; return VINF_SUCCESS; }
unsigned __stdcall VBoxClipboardThread(void *pInstance) { Log(("VBoxTray: VBoxClipboardThread\n")); VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pInstance; AssertPtr(pCtx); /* The thread waits for incoming messages from the host. */ for (;;) { uint32_t u32Msg; uint32_t u32Formats; int rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats); if (RT_FAILURE(rc)) { Log(("VBoxTray: VBoxClipboardThread: Failed to call the driver for host message! rc = %Rrc\n", rc)); if (rc == VERR_INTERRUPTED) { /* Wait for termination event. */ WaitForSingleObject(pCtx->pEnv->hStopEvent, INFINITE); break; } /* Wait a bit before retrying. */ AssertPtr(pCtx->pEnv); if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0) { break; } continue; } else { Log(("VBoxTray: VBoxClipboardThread: VbglR3ClipboardGetHostMsg u32Msg = %ld, u32Formats = %ld\n", u32Msg, u32Formats)); switch (u32Msg) { case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS: { /* The host has announced available clipboard formats. * Forward the information to the window, so it can later * respond to WM_RENDERFORMAT message. */ ::PostMessage (pCtx->hwnd, WM_USER, 0, u32Formats); } break; case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA: { /* The host needs data in the specified format. */ ::PostMessage (pCtx->hwnd, WM_USER + 1, 0, u32Formats); } break; case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT: { /* The host is terminating. */ rc = VERR_INTERRUPTED; } break; default: { Log(("VBoxTray: VBoxClipboardThread: Unsupported message from host! Message = %ld\n", u32Msg)); } } } } return 0; }
/** * Rewinds the tarball file handle and creates a gunzip | tar chain that * results in a filesystem stream. * * @returns VBox status code, failures with message. * @param hTarballFile The handle to the tarball file. * @param pszError Where to store an error message on failure. * @param cbError The size of the buffer @a pszError points to. * @param phTarFss Where to return the filesystem stream handle. * @param phFileManifest Where to return a manifest where the tarball is * gettting hashed. The entry will be called * "extpack" and be ready when the file system * stream is at an end. Optional. */ int VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss, PRTMANIFEST phFileManifest) { Assert(cbError > 0); *pszError = '\0'; *phTarFss = NIL_RTVFSFSSTREAM; /* * Rewind the file and set up a VFS chain for it. */ int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) return vboxExtPackReturnError(rc, pszError, cbError, "Failed seeking to the start of the tarball: %Rrc", rc); RTVFSIOSTREAM hTarballIos; rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/, &hTarballIos); if (RT_FAILURE(rc)) return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsIoStrmFromRTFile failed: %Rrc", rc); RTMANIFEST hFileManifest = NIL_RTMANIFEST; rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest); if (RT_SUCCESS(rc)) { RTVFSIOSTREAM hPtIos; rc = RTManifestEntryAddPassthruIoStream(hFileManifest, hTarballIos, "extpack", RTMANIFEST_ATTR_SHA256, true /*read*/, &hPtIos); if (RT_SUCCESS(rc)) { RTVFSIOSTREAM hGunzipIos; rc = RTZipGzipDecompressIoStream(hPtIos, 0 /*fFlags*/, &hGunzipIos); if (RT_SUCCESS(rc)) { RTVFSFSSTREAM hTarFss; rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss); if (RT_SUCCESS(rc)) { RTVfsIoStrmRelease(hPtIos); RTVfsIoStrmRelease(hGunzipIos); RTVfsIoStrmRelease(hTarballIos); *phTarFss = hTarFss; if (phFileManifest) *phFileManifest = hFileManifest; else RTManifestRelease(hFileManifest); return VINF_SUCCESS; } vboxExtPackSetError(pszError, cbError, "RTZipTarFsStreamFromIoStream failed: %Rrc", rc); RTVfsIoStrmRelease(hGunzipIos); } else vboxExtPackSetError(pszError, cbError, "RTZipGzipDecompressIoStream failed: %Rrc", rc); RTVfsIoStrmRelease(hPtIos); } else vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddPassthruIoStream failed: %Rrc", rc); RTManifestRelease(hFileManifest); } else vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc); RTVfsIoStrmRelease(hTarballIos); return rc; }
int main(int argc, char **argv) { int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); static const RTGETOPTDEF s_aOptions[] = { { "--samples-per-sec", 's', RTGETOPT_REQ_UINT32 }, { "--period-in-samples", 'p', RTGETOPT_REQ_UINT32 }, { "--bufsize-in-samples", 'b', RTGETOPT_REQ_UINT32 }, { "--total-duration-in-secs", 'd', RTGETOPT_REQ_UINT32 } }; RTGETOPTSTATE State; RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); RTGETOPTUNION ValueUnion; int chOpt; while ((chOpt = RTGetOpt(&State, &ValueUnion)) != 0) { switch (chOpt) { case 's': g_cSamplesPerSec = ValueUnion.u32; break; case 'p': g_cSamplesPerPeriod = ValueUnion.u32; break; case 'b': g_cSamplesInBuffer = ValueUnion.u32; break; case 'd': g_rdSecDuration = ValueUnion.u32; break; case 'h': RTPrintf("usage: ntPlayToneWaveX.exe\n" "[-s|--samples-per-sec]\n" "[-p|--period-in-samples]\n" "[-b|--bufsize-in-samples]\n" "[-d|--total-duration-in-secs]\n" "\n" "Plays sine tone using ancient waveX API\n"); return 0; default: return RTGetOptPrintError(chOpt, &ValueUnion); } } WAVEFORMATEX waveFormatEx = { 0 }; MMRESULT mmresult; waveFormatEx.wFormatTag = WAVE_FORMAT_PCM; waveFormatEx.nChannels = 2; waveFormatEx.nSamplesPerSec = g_cSamplesPerSec; waveFormatEx.wBitsPerSample = 16; waveFormatEx.nBlockAlign = g_cbSample = waveFormatEx.nChannels * waveFormatEx.wBitsPerSample / 8; waveFormatEx.nAvgBytesPerSec = waveFormatEx.nBlockAlign * waveFormatEx.nSamplesPerSec; waveFormatEx.cbSize = 0; g_hWavEvent = CreateEvent(NULL, FALSE, FALSE, NULL); mmresult = waveOutOpen(&g_hWaveOut, WAVE_MAPPER, &waveFormatEx, (DWORD_PTR)g_hWavEvent, NULL, CALLBACK_EVENT); if (mmresult != MMSYSERR_NOERROR) { RTMsgError("waveOutOpen failed with 0x%X\n", mmresult); return -1; } uint32_t ui32SamplesToPlayTotal = (uint32_t)(g_rdSecDuration * g_cSamplesPerSec); uint32_t ui32SamplesToPlay = ui32SamplesToPlayTotal; uint32_t ui32SamplesPlayed = 0; uint32_t ui32SamplesForWavBuf; WAVEHDR waveHdr1 = {0}, waveHdr2 = {0}, *pWaveHdr, *pWaveHdrPlaying, *pWaveHdrWaiting; uint32_t i, k; DWORD res; int16_t *i16Samples1 = (int16_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, g_cSamplesInBuffer * g_cbSample); int16_t *i16Samples2 = (int16_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, g_cSamplesInBuffer * g_cbSample); k = 0; // This is discrete time really!!! for (i = 0; i < g_cSamplesInBuffer; i++, k++) { i16Samples1[2 * i] = (uint16_t)(10000.0 * sin(2.0 * M_PI * k / g_cSamplesPerPeriod)); i16Samples1[2 * i + 1] = i16Samples1[2 * i]; } ui32SamplesForWavBuf = min(ui32SamplesToPlay, g_cSamplesInBuffer); waveHdr1.lpData = (LPSTR)i16Samples1; waveHdr1.dwBufferLength = ui32SamplesForWavBuf * g_cbSample; waveHdr1.dwFlags = 0; waveHdr1.dwLoops = 0; ui32SamplesToPlay -= ui32SamplesForWavBuf; ui32SamplesPlayed += ui32SamplesForWavBuf; pWaveHdrPlaying = &waveHdr1; mmresult = waveOutPrepareHeader(g_hWaveOut, pWaveHdrPlaying, sizeof(WAVEHDR)); mmresult = waveOutWrite(g_hWaveOut, pWaveHdrPlaying, sizeof(WAVEHDR)); //RTMsgInfo("waveOutWrite completes with %d\n", mmresult); res = WaitForSingleObject(g_hWavEvent, INFINITE); //RTMsgInfo("WaitForSingleObject completes with %d\n\n", res); waveHdr2.lpData = (LPSTR)i16Samples2; waveHdr2.dwBufferLength = 0; waveHdr2.dwFlags = 0; waveHdr2.dwLoops = 0; pWaveHdrWaiting = &waveHdr2; while (ui32SamplesToPlay > 0) { int16_t *i16Samples = (int16_t *)pWaveHdrWaiting->lpData; for (i = 0; i < g_cSamplesInBuffer; i++, k++) { i16Samples[2 * i] = (uint16_t)(10000.0 * sin(2.0 * M_PI * k / g_cSamplesPerPeriod)); i16Samples[2 * i + 1] = i16Samples[2 * i]; } ui32SamplesForWavBuf = min(ui32SamplesToPlay, g_cSamplesInBuffer); pWaveHdrWaiting->dwBufferLength = ui32SamplesForWavBuf * g_cbSample; pWaveHdrWaiting->dwFlags = 0; pWaveHdrWaiting->dwLoops = 0; ui32SamplesToPlay -= ui32SamplesForWavBuf; ui32SamplesPlayed += ui32SamplesForWavBuf; mmresult = waveOutPrepareHeader(g_hWaveOut, pWaveHdrWaiting, sizeof(WAVEHDR)); mmresult = waveOutWrite(g_hWaveOut, pWaveHdrWaiting, sizeof(WAVEHDR)); //RTMsgInfo("waveOutWrite completes with %d\n", mmresult); res = WaitForSingleObject(g_hWavEvent, INFINITE); //RTMsgInfo("WaitForSingleObject completes with %d\n\n", res); mmresult = waveOutUnprepareHeader(g_hWaveOut, pWaveHdrPlaying, sizeof(WAVEHDR)); //RTMsgInfo("waveOutUnprepareHeader completes with %d\n", mmresult); pWaveHdr = pWaveHdrWaiting; pWaveHdrWaiting = pWaveHdrPlaying; pWaveHdrPlaying = pWaveHdr; } while (mmresult = waveOutUnprepareHeader(g_hWaveOut, pWaveHdrPlaying, sizeof(WAVEHDR))) { //Expecting WAVERR_STILLPLAYING //RTMsgInfo("waveOutUnprepareHeader failed with 0x%X\n", mmresult); Sleep(100); } if (mmresult == MMSYSERR_NOERROR) { waveOutClose(g_hWaveOut); } HeapFree(GetProcessHeap(), 0, i16Samples1); HeapFree(GetProcessHeap(), 0, i16Samples2); }
/** * Reads the extension pack descriptor. * * @returns NULL on success, pointer to an error message on failure (caller * deletes it). * @param a_pszDir The directory containing the description file. * @param a_pExtPackDesc Where to store the extension pack descriptor. * @param a_pObjInfo Where to store the object info for the file (unix * attribs). Optional. */ RTCString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo) { vboxExtPackClearDesc(a_pExtPackDesc); /* * Query the object info. */ RTFSOBJINFO ObjInfo; int rc = RTVfsFileQueryInfo(hVfsFile, &ObjInfo, RTFSOBJATTRADD_UNIX); if (RT_FAILURE(rc)) return &(new RTCString)->printf("RTVfsFileQueryInfo failed: %Rrc", rc); if (a_pObjInfo) *a_pObjInfo = ObjInfo; /* * The simple approach, read the whole thing into memory and pass this to * the XML parser. */ /* Check the file size. */ if (ObjInfo.cbObject > _1M || ObjInfo.cbObject < 0) return &(new RTCString)->printf("The XML file is too large (%'RU64 bytes)", ObjInfo.cbObject); size_t const cbFile = (size_t)ObjInfo.cbObject; /* Rewind to the start of the file. */ rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) return &(new RTCString)->printf("RTVfsFileSeek(,0,BEGIN) failed: %Rrc", rc); /* Allocate memory and read the file content into it. */ void *pvFile = RTMemTmpAlloc(cbFile); if (!pvFile) return &(new RTCString)->printf("RTMemTmpAlloc(%zu) failed", cbFile); RTCString *pstrErr = NULL; rc = RTVfsFileRead(hVfsFile, pvFile, cbFile, NULL); if (RT_FAILURE(rc)) pstrErr = &(new RTCString)->printf("RTVfsFileRead failed: %Rrc", rc); /* * Parse the file. */ xml::Document Doc; if (RT_SUCCESS(rc)) { xml::XmlMemParser Parser; RTCString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME; try { Parser.read(pvFile, cbFile, strFileName, Doc); } catch (xml::XmlError Err) { pstrErr = new RTCString(Err.what()); rc = VERR_PARSE_ERROR; } } RTMemTmpFree(pvFile); /* * Hand the xml doc over to the common code. */ if (RT_SUCCESS(rc)) pstrErr = vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc); return pstrErr; }
RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue) { AssertPtrReturn(pszVar, VERR_INVALID_POINTER); AssertReturn(*pszVar, VERR_INVALID_PARAMETER); AssertPtrReturn(pszValue, VERR_INVALID_POINTER); int rc; if (Env == RTENV_DEFAULT) { /* * Since RTEnvPut isn't UTF-8 clean and actually expects the strings * to be in the current code page (codeset), we'll do the necessary * conversions here. */ char *pszVarOtherCP; rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar); if (RT_SUCCESS(rc)) { char *pszValueOtherCP; rc = RTStrUtf8ToCurrentCP(&pszValueOtherCP, pszValue); if (RT_SUCCESS(rc)) { rc = RTEnvSet(pszVarOtherCP, pszValueOtherCP); RTStrFree(pszValueOtherCP); } RTStrFree(pszVarOtherCP); } } else { PRTENVINTERNAL pIntEnv = Env; AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); /* * Create the variable string. */ const size_t cchVar = strlen(pszVar); const size_t cchValue = strlen(pszValue); char *pszEntry = (char *)RTMemAlloc(cchVar + cchValue + 2); if (pszEntry) { memcpy(pszEntry, pszVar, cchVar); pszEntry[cchVar] = '='; memcpy(&pszEntry[cchVar + 1], pszValue, cchValue + 1); RTENV_LOCK(pIntEnv); /* * Find the location of the variable. (iVar = cVars if new) */ rc = VINF_SUCCESS; size_t iVar; for (iVar = 0; iVar < pIntEnv->cVars; iVar++) if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar) && pIntEnv->papszEnv[iVar][cchVar] == '=') break; if (iVar < pIntEnv->cVars) { /* * Replace the current entry. Simple. */ RTMemFree(pIntEnv->papszEnv[iVar]); pIntEnv->papszEnv[iVar] = pszEntry; } else { /* * Adding a new variable. Resize the array if required * and then insert the new value at the end. */ if (pIntEnv->cVars + 2 > pIntEnv->cAllocated) { void *pvNew = RTMemRealloc(pIntEnv->papszEnv, sizeof(char *) * (pIntEnv->cAllocated + RTENV_GROW_SIZE)); if (!pvNew) rc = VERR_NO_MEMORY; else { pIntEnv->papszEnv = (char **)pvNew; pIntEnv->cAllocated += RTENV_GROW_SIZE; for (size_t iNewVar = pIntEnv->cVars; iNewVar < pIntEnv->cAllocated; iNewVar++) pIntEnv->papszEnv[iNewVar] = NULL; } } if (RT_SUCCESS(rc)) { pIntEnv->papszEnv[iVar] = pszEntry; pIntEnv->papszEnv[iVar + 1] = NULL; /* this isn't really necessary, but doesn't hurt. */ pIntEnv->cVars++; Assert(pIntEnv->cVars == iVar + 1); } } RTENV_UNLOCK(pIntEnv); if (RT_FAILURE(rc)) RTMemFree(pszEntry); } else rc = VERR_NO_MEMORY; } return rc; }
/** * Construct a host parallel driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvHostParallelConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL); LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Init basic data members and interfaces. * * Must be done before returning any failure because we've got a destructor. */ pThis->hFileDevice = NIL_RTFILE; #ifndef VBOX_WITH_WIN_PARPORT_SUP pThis->hWakeupPipeR = NIL_RTPIPE; pThis->hWakeupPipeW = NIL_RTPIPE; #else pThis->hWinFileDevice = NIL_RTFILE; #endif pThis->pDrvInsR3 = pDrvIns; #ifdef VBOX_WITH_DRVINTNET_IN_R0 pThis->pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns); #endif /* IBase. */ pDrvIns->IBase.pfnQueryInterface = drvHostParallelQueryInterface; /* IHostParallelConnector. */ pThis->IHostParallelConnectorR3.pfnWrite = drvHostParallelWrite; pThis->IHostParallelConnectorR3.pfnRead = drvHostParallelRead; pThis->IHostParallelConnectorR3.pfnSetPortDirection = drvHostParallelSetPortDirection; pThis->IHostParallelConnectorR3.pfnWriteControl = drvHostParallelWriteControl; pThis->IHostParallelConnectorR3.pfnReadControl = drvHostParallelReadControl; pThis->IHostParallelConnectorR3.pfnReadStatus = drvHostParallelReadStatus; /* * Validate the config. */ if (!CFGMR3AreValuesValid(pCfg, "DevicePath\0")) return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, N_("Unknown host parallel configuration option, only supports DevicePath")); /* * Query configuration. */ /* Device */ int rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc)); return rc; } /* * Open the device */ rc = RTFileOpen(&pThis->hFileDevice, pThis->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Parallel#%d could not open '%s'"), pDrvIns->iInstance, pThis->pszDevicePath); #ifndef VBOX_WITH_WIN_PARPORT_SUP /* * Try to get exclusive access to parallel port */ rc = ioctl(RTFileToNative(pThis->hFileDevice), PPEXCL); if (rc < 0) return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("Parallel#%d could not get exclusive access for parallel port '%s'" "Be sure that no other process or driver accesses this port"), pDrvIns->iInstance, pThis->pszDevicePath); /* * Claim the parallel port */ rc = ioctl(RTFileToNative(pThis->hFileDevice), PPCLAIM); if (rc < 0) return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("Parallel#%d could not claim parallel port '%s'" "Be sure that no other process or driver accesses this port"), pDrvIns->iInstance, pThis->pszDevicePath); /* * Get the IHostParallelPort interface of the above driver/device. */ pThis->pDrvHostParallelPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTPARALLELPORT); if (!pThis->pDrvHostParallelPort) return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Parallel#%d has no parallel port interface above"), pDrvIns->iInstance); /* * Create wakeup pipe. */ rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/); AssertRCReturn(rc, rc); /* * Start in SPP mode. */ pThis->enmModeCur = PDM_PARALLEL_PORT_MODE_INVALID; rc = drvHostParallelSetMode(pThis, PDM_PARALLEL_PORT_MODE_SPP); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostParallel#%d cannot change mode of parallel mode to SPP"), pDrvIns->iInstance); /* * Start waiting for interrupts. */ rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostParallelMonitorThread, drvHostParallelWakeupMonitorThread, 0, RTTHREADTYPE_IO, "ParMon"); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostParallel#%d cannot create monitor thread"), pDrvIns->iInstance); #else /* VBOX_WITH_WIN_PARPORT_SUP */ pThis->fParportAvail = false; pThis->u32LptAddr = 0; pThis->u32LptAddrControl = 0; pThis->u32LptAddrStatus = 0; rc = drvWinHostGetparportAddr(pThis); /* If we have the char port availabe use it , else I am not getting exclusive access to parallel port. Read and write will be done only if addresses are available */ if (pThis->szParportName) { rc = RTFileOpen(&pThis->hWinFileDevice, (char *)pThis->szParportName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); } #endif return VINF_SUCCESS; }
RTDECL(int) RTEnvQueryUtf16Block(RTENV hEnv, PRTUTF16 *ppwszzBlock) { RTENV hClone = NIL_RTENV; PRTENVINTERNAL pIntEnv; int rc; /* * Validate / simplify input. */ if (hEnv == RTENV_DEFAULT) { rc = RTEnvClone(&hClone, RTENV_DEFAULT); if (RT_FAILURE(rc)) return rc; pIntEnv = hClone; } else { pIntEnv = hEnv; AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); rc = VINF_SUCCESS; } RTENV_LOCK(pIntEnv); /* * Sort it first. */ RTSortApvShell((void **)pIntEnv->papszEnv, pIntEnv->cVars, rtEnvSortCompare, pIntEnv); /* * Calculate the size. */ size_t cwc; size_t cwcTotal = 2; for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++) { rc = RTStrCalcUtf16LenEx(pIntEnv->papszEnv[iVar], RTSTR_MAX, &cwc); AssertRCBreak(rc); cwcTotal += cwc + 1; } PRTUTF16 pwszzBlock = NULL; if (RT_SUCCESS(rc)) { /* * Perform the conversion. */ PRTUTF16 pwszz = pwszzBlock = (PRTUTF16)RTMemAlloc(cwcTotal * sizeof(RTUTF16)); if (pwszz) { size_t cwcLeft = cwcTotal; for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++) { rc = RTStrToUtf16Ex(pIntEnv->papszEnv[iVar], RTSTR_MAX, &pwszz, cwcTotal - (pwszz - pwszzBlock), &cwc); AssertRCBreak(rc); pwszz += cwc + 1; cwcLeft -= cwc + 1; AssertBreakStmt(cwcLeft >= 2, rc = VERR_INTERNAL_ERROR_3); } AssertStmt(cwcLeft == 2 || RT_FAILURE(rc), rc = VERR_INTERNAL_ERROR_2); if (RT_SUCCESS(rc)) { pwszz[0] = '\0'; pwszz[1] = '\0'; } else { RTMemFree(pwszzBlock); pwszzBlock = NULL; } } else rc = VERR_NO_MEMORY; } RTENV_UNLOCK(pIntEnv); if (hClone != NIL_RTENV) RTEnvDestroy(hClone); if (RT_SUCCESS(rc)) *ppwszzBlock = pwszzBlock; return rc; }
int main() { char szPath[RTPATH_MAX]; /* * Init RT+Test. */ RTTEST hTest; int rc = RTTestInitAndCreate("tstRTPath", &hTest); if (rc) return rc; RTTestBanner(hTest); RTTestSub(hTest, "Environment"); #if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) RTTESTI_CHECK(RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS); # if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS # else RTTestIFailed("#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS"); # endif RTTESTI_CHECK(strcmp(RTPATH_SLASH_STR, "\\") == 0); RTTESTI_CHECK(RTPATH_SLASH == '\\'); RTTESTI_CHECK(RTPATH_IS_SEP('/')); RTTESTI_CHECK(RTPATH_IS_SEP('\\')); RTTESTI_CHECK(RTPATH_IS_SEP(':')); #else RTTESTI_CHECK(RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX); # if RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX # else RTTestIFailed("#if RTPATH_STYLE == RTPATH_STR_F_STYLE_UNIX"); # endif RTTESTI_CHECK(strcmp(RTPATH_SLASH_STR, "/") == 0); RTTESTI_CHECK(RTPATH_SLASH == '/'); RTTESTI_CHECK(RTPATH_IS_SEP('/')); RTTESTI_CHECK(!RTPATH_IS_SEP('\\')); RTTESTI_CHECK(!RTPATH_IS_SEP(':')); #endif /* * RTPathExecDir, RTPathUserHome and RTProcGetExecutablePath. */ RTTestSub(hTest, "RTPathExecDir"); RTTESTI_CHECK_RC(rc = RTPathExecDir(szPath, sizeof(szPath)), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTestIPrintf(RTTESTLVL_INFO, "ExecDir={%s}\n", szPath); RTTestSub(hTest, "RTProcGetExecutablePath"); if (RTProcGetExecutablePath(szPath, sizeof(szPath)) == szPath) RTTestIPrintf(RTTESTLVL_INFO, "ExecutableName={%s}\n", szPath); else RTTestIFailed("RTProcGetExecutablePath -> NULL"); RTTestSub(hTest, "RTPathUserHome"); RTTESTI_CHECK_RC(rc = RTPathUserHome(szPath, sizeof(szPath)), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTestIPrintf(RTTESTLVL_INFO, "UserHome={%s}\n", szPath); RTTestSub(hTest, "RTPathUserDocuments"); RTTESTI_CHECK_RC(rc = RTPathUserDocuments(szPath, sizeof(szPath)), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTestIPrintf(RTTESTLVL_INFO, "UserDocuments={%s}\n", szPath); RTTestSub(hTest, "RTPathTemp"); RTTESTI_CHECK_RC(rc = RTPathTemp(szPath, sizeof(szPath)), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTestIPrintf(RTTESTLVL_INFO, "PathTemp={%s}\n", szPath); size_t cch = strlen(szPath); RTTESTI_CHECK_RC(RTPathTemp(szPath, cch), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK_RC(RTPathTemp(szPath, cch+1), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPathTemp(szPath, cch+2), VINF_SUCCESS); /* * RTPathAbsEx */ RTTestSub(hTest, "RTPathAbsEx"); static const struct { const char *pcszInputBase; const char *pcszInputPath; int rc; const char *pcszOutput; } s_aRTPathAbsExTests[] = { #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) { NULL, "", VERR_INVALID_PARAMETER, NULL }, { NULL, ".", VINF_SUCCESS, "%p" }, { NULL, "\\", VINF_SUCCESS, "%d\\" }, { NULL, "\\..", VINF_SUCCESS, "%d\\" }, { NULL, "/absolute/..", VINF_SUCCESS, "%d\\" }, { NULL, "/absolute\\\\../..", VINF_SUCCESS, "%d\\" }, { NULL, "/absolute//../path\\", VINF_SUCCESS, "%d\\path" }, { NULL, "/absolute/../../path", VINF_SUCCESS, "%d\\path" }, { NULL, "relative/../dir\\.\\.\\.\\file.txt", VINF_SUCCESS, "%p\\dir\\file.txt" }, { NULL, "\\data\\", VINF_SUCCESS, "%d\\data" }, { "relative_base/dir\\", "\\from_root", VINF_SUCCESS, "%d\\from_root" }, { "relative_base/dir/", "relative_also", VINF_SUCCESS, "%p\\relative_base\\dir\\relative_also" }, #else { NULL, "", VERR_INVALID_PARAMETER, NULL }, { NULL, ".", VINF_SUCCESS, "%p" }, { NULL, "/", VINF_SUCCESS, "/" }, { NULL, "/..", VINF_SUCCESS, "/" }, { NULL, "/absolute/..", VINF_SUCCESS, "/" }, { NULL, "/absolute\\\\../..", VINF_SUCCESS, "/" }, { NULL, "/absolute//../path/", VINF_SUCCESS, "/path" }, { NULL, "/absolute/../../path", VINF_SUCCESS, "/path" }, { NULL, "relative/../dir/./././file.txt", VINF_SUCCESS, "%p/dir/file.txt" }, { NULL, "relative/../dir\\.\\.\\.\\file.txt", VINF_SUCCESS, "%p/dir\\.\\.\\.\\file.txt" }, /* linux-specific */ { NULL, "/data/", VINF_SUCCESS, "/data" }, { "relative_base/dir/", "/from_root", VINF_SUCCESS, "/from_root" }, { "relative_base/dir/", "relative_also", VINF_SUCCESS, "%p/relative_base/dir/relative_also" }, #endif #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) { NULL, "C:\\", VINF_SUCCESS, "C:\\" }, { "C:\\", "..", VINF_SUCCESS, "C:\\" }, { "C:\\temp", "..", VINF_SUCCESS, "C:\\" }, { "C:\\VirtualBox/Machines", "..\\VirtualBox.xml", VINF_SUCCESS, "C:\\VirtualBox\\VirtualBox.xml" }, { "C:\\MustDie", "\\from_root/dir/..", VINF_SUCCESS, "C:\\from_root" }, { "C:\\temp", "D:\\data", VINF_SUCCESS, "D:\\data" }, { NULL, "\\\\server\\..\\share", VINF_SUCCESS, "\\\\server\\..\\share" /* kind of strange */ }, { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server\\" }, { NULL, "\\\\", VINF_SUCCESS, "\\\\" }, { NULL, "\\\\\\something", VINF_SUCCESS, "\\\\\\something" /* kind of strange */ }, { "\\\\server\\share_as_base", "/from_root", VINF_SUCCESS, "\\\\server\\from_root" }, { "\\\\just_server", "/from_root", VINF_SUCCESS, "\\\\just_server\\from_root" }, { "\\\\server\\share_as_base", "relative\\data", VINF_SUCCESS, "\\\\server\\share_as_base\\relative\\data" }, { "base", "\\\\?\\UNC\\relative/edwef/..", VINF_SUCCESS, "\\\\?\\UNC\\relative" }, { "\\\\?\\UNC\\base", "/from_root", VERR_INVALID_NAME, NULL }, #else { "/temp", "..", VINF_SUCCESS, "/" }, { "/VirtualBox/Machines", "../VirtualBox.xml", VINF_SUCCESS, "/VirtualBox/VirtualBox.xml" }, { "/MustDie", "/from_root/dir/..", VINF_SUCCESS, "/from_root" }, { "\\temp", "\\data", VINF_SUCCESS, "%p/\\temp/\\data" }, #endif }; for (unsigned i = 0; i < RT_ELEMENTS(s_aRTPathAbsExTests); ++ i) { rc = RTPathAbsEx(s_aRTPathAbsExTests[i].pcszInputBase, s_aRTPathAbsExTests[i].pcszInputPath, szPath, sizeof(szPath)); if (rc != s_aRTPathAbsExTests[i].rc) { RTTestIFailed("unexpected result code!\n" " input base: '%s'\n" " input path: '%s'\n" " output: '%s'\n" " rc: %Rrc\n" " expected rc: %Rrc", s_aRTPathAbsExTests[i].pcszInputBase, s_aRTPathAbsExTests[i].pcszInputPath, szPath, rc, s_aRTPathAbsExTests[i].rc); continue; } char szTmp[RTPATH_MAX]; char *pszExpected = NULL; if (s_aRTPathAbsExTests[i].pcszOutput != NULL) { if (s_aRTPathAbsExTests[i].pcszOutput[0] == '%') { RTTESTI_CHECK_RC(rc = RTPathGetCurrent(szTmp, sizeof(szTmp)), VINF_SUCCESS); if (RT_FAILURE(rc)) break; pszExpected = szTmp; if (s_aRTPathAbsExTests[i].pcszOutput[1] == 'p') { cch = strlen(szTmp); if (cch + strlen(s_aRTPathAbsExTests[i].pcszOutput) - 2 <= sizeof(szTmp)) strcpy(szTmp + cch, s_aRTPathAbsExTests[i].pcszOutput + 2); } #if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) else if (s_aRTPathAbsExTests[i].pcszOutput[1] == 'd') { if (2 + strlen(s_aRTPathAbsExTests[i].pcszOutput) - 2 <= sizeof(szTmp)) strcpy(szTmp + 2, s_aRTPathAbsExTests[i].pcszOutput + 2); } #endif } else { strcpy(szTmp, s_aRTPathAbsExTests[i].pcszOutput); pszExpected = szTmp; } if (strcmp(szPath, pszExpected)) { RTTestIFailed("Unexpected result\n" " input base: '%s'\n" " input path: '%s'\n" " output: '%s'\n" " expected: '%s'", s_aRTPathAbsExTests[i].pcszInputBase, s_aRTPathAbsExTests[i].pcszInputPath, szPath, s_aRTPathAbsExTests[i].pcszOutput); } } } /* * RTPathStripFilename */ RTTestSub(hTest, "RTPathStripFilename"); static const char *s_apszStripFilenameTests[] = { "/usr/include///", "/usr/include//", "/usr/include/", "/usr/include", "/usr/include", "/usr", "/usr", "/", "usr", ".", #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) "c:/windows", "c:/", "c:/", "c:/", "D:", "D:", "C:\\OS2\\DLLS", "C:\\OS2", #endif }; for (unsigned i = 0; i < RT_ELEMENTS(s_apszStripFilenameTests); i += 2) { const char *pszInput = s_apszStripFilenameTests[i]; const char *pszExpect = s_apszStripFilenameTests[i + 1]; strcpy(szPath, pszInput); RTPathStripFilename(szPath); if (strcmp(szPath, pszExpect)) { RTTestIFailed("Unexpected result\n" " input: '%s'\n" " output: '%s'\n" "expected: '%s'", pszInput, szPath, pszExpect); } } /* * RTPathAppend. */ RTTestSub(hTest, "RTPathAppend"); static const char *s_apszAppendTests[] = { /* base append result */ "/", "", "/", "", "/", "/", "/", "/", "/", "/x", "", "/x", "/x", "/", "/x/", "/", "x", "/x", "dir", "file", "dir/file", "dir", "/file", "dir/file", "dir", "//file", "dir/file", "dir", "///file", "dir/file", "dir/", "/file", "dir/file", "dir/", "//file", "dir/file", "dir/", "///file", "dir/file", "dir//", "file", "dir/file", "dir//", "/file", "dir/file", "dir//", "//file", "dir/file", "dir///", "///file", "dir/file", "/bin/testcase", "foo.r0", "/bin/testcase/foo.r0", #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) "/", "\\", "/", "\\", "/", "\\", "\\\\srv\\shr", "dir//", "\\\\srv\\shr/dir//", "\\\\srv\\shr", "dir//file", "\\\\srv\\shr/dir//file", "\\\\srv\\shr", "//dir//", "\\\\srv\\shr/dir//", "\\\\srv\\shr", "/\\dir//", "\\\\srv\\shr\\dir//", "\\\\", "not-srv/not-shr/file", "\\not-srv/not-shr/file", "C:", "autoexec.bat", "C:autoexec.bat", "C:", "/autoexec.bat", "C:/autoexec.bat", "C:", "\\autoexec.bat", "C:\\autoexec.bat", "C:\\", "/autoexec.bat", "C:\\autoexec.bat", "C:\\\\", "autoexec.bat", "C:\\autoexec.bat", "E:\\bin\\testcase", "foo.r0", "E:\\bin\\testcase/foo.r0", #endif }; for (unsigned i = 0; i < RT_ELEMENTS(s_apszAppendTests); i += 3) { const char *pszInput = s_apszAppendTests[i]; const char *pszAppend = s_apszAppendTests[i + 1]; const char *pszExpect = s_apszAppendTests[i + 2]; strcpy(szPath, pszInput); RTTESTI_CHECK_RC(rc = RTPathAppend(szPath, sizeof(szPath), pszAppend), VINF_SUCCESS); if (RT_FAILURE(rc)) continue; if (strcmp(szPath, pszExpect)) { RTTestIFailed("Unexpected result\n" " input: '%s'\n" " append: '%s'\n" " output: '%s'\n" "expected: '%s'", pszInput, pszAppend, szPath, pszExpect); } else { size_t const cchResult = strlen(szPath); strcpy(szPath, pszInput); RTTESTI_CHECK_RC(rc = RTPathAppend(szPath, cchResult + 2, pszAppend), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || !strcmp(szPath, pszExpect)); strcpy(szPath, pszInput); RTTESTI_CHECK_RC(rc = RTPathAppend(szPath, cchResult + 1, pszAppend), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || !strcmp(szPath, pszExpect)); if (strlen(pszInput) < cchResult) { strcpy(szPath, pszInput); RTTESTI_CHECK_RC(RTPathAppend(szPath, cchResult, pszAppend), VERR_BUFFER_OVERFLOW); } } } /* * RTPathJoin - reuse the append tests. */ RTTestSub(hTest, "RTPathJoin"); for (unsigned i = 0; i < RT_ELEMENTS(s_apszAppendTests); i += 3) { const char *pszInput = s_apszAppendTests[i]; const char *pszAppend = s_apszAppendTests[i + 1]; const char *pszExpect = s_apszAppendTests[i + 2]; memset(szPath, 'a', sizeof(szPath)); szPath[sizeof(szPath) - 1] = '\0'; RTTESTI_CHECK_RC(rc = RTPathJoin(szPath, sizeof(szPath), pszInput, pszAppend), VINF_SUCCESS); if (RT_FAILURE(rc)) continue; if (strcmp(szPath, pszExpect)) { RTTestIFailed("Unexpected result\n" " input: '%s'\n" " append: '%s'\n" " output: '%s'\n" "expected: '%s'", pszInput, pszAppend, szPath, pszExpect); } else { size_t const cchResult = strlen(szPath); memset(szPath, 'a', sizeof(szPath)); szPath[sizeof(szPath) - 1] = '\0'; RTTESTI_CHECK_RC(rc = RTPathJoin(szPath, cchResult + 2, pszInput, pszAppend), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || !strcmp(szPath, pszExpect)); memset(szPath, 'a', sizeof(szPath)); szPath[sizeof(szPath) - 1] = '\0'; RTTESTI_CHECK_RC(rc = RTPathJoin(szPath, cchResult + 1, pszInput, pszAppend), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || !strcmp(szPath, pszExpect)); RTTESTI_CHECK_RC(rc = RTPathJoin(szPath, cchResult, pszInput, pszAppend), VERR_BUFFER_OVERFLOW); } } /* * RTPathJoinA - reuse the append tests. */ RTTestSub(hTest, "RTPathJoinA"); for (unsigned i = 0; i < RT_ELEMENTS(s_apszAppendTests); i += 3) { const char *pszInput = s_apszAppendTests[i]; const char *pszAppend = s_apszAppendTests[i + 1]; const char *pszExpect = s_apszAppendTests[i + 2]; char *pszPathDst; RTTESTI_CHECK(pszPathDst = RTPathJoinA(pszInput, pszAppend)); if (!pszPathDst) continue; if (strcmp(pszPathDst, pszExpect)) { RTTestIFailed("Unexpected result\n" " input: '%s'\n" " append: '%s'\n" " output: '%s'\n" "expected: '%s'", pszInput, pszAppend, pszPathDst, pszExpect); } RTStrFree(pszPathDst); } /* * RTPathStripTrailingSlash */ static const char *s_apszStripTrailingSlash[] = { /* input result */ "/", "/", "//", "/", "////////////////////", "/", "/tmp", "/tmp", "/tmp////////////////", "/tmp", "tmp", "tmp", "tmp////////////////", "tmp", "./", ".", #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) "////////////////////", "/", "D:", "D:", "D:/", "D:/", "D:\\", "D:\\", "D:\\/\\", "D:\\", "D:/\\/\\", "D:/", "C:/Temp", "C:/Temp", "C:/Temp/", "C:/Temp", "C:/Temp\\/", "C:/Temp", #endif }; for (unsigned i = 0; i < RT_ELEMENTS(s_apszStripTrailingSlash); i += 2) { const char *pszInput = s_apszStripTrailingSlash[i]; const char *pszExpect = s_apszStripTrailingSlash[i + 1]; strcpy(szPath, pszInput); cch = RTPathStripTrailingSlash(szPath); if (strcmp(szPath, pszExpect)) RTTestIFailed("Unexpected result\n" " input: '%s'\n" " output: '%s'\n" "expected: '%s'", pszInput, szPath, pszExpect); else RTTESTI_CHECK(cch == strlen(szPath)); } /* * RTPathCountComponents */ RTTestSub(hTest, "RTPathCountComponents"); RTTESTI_CHECK(RTPathCountComponents("") == 0); RTTESTI_CHECK(RTPathCountComponents("/") == 1); RTTESTI_CHECK(RTPathCountComponents("//") == 1); RTTESTI_CHECK(RTPathCountComponents("//////////////") == 1); RTTESTI_CHECK(RTPathCountComponents("//////////////bin") == 2); RTTESTI_CHECK(RTPathCountComponents("//////////////bin/") == 2); RTTESTI_CHECK(RTPathCountComponents("//////////////bin/////") == 2); RTTESTI_CHECK(RTPathCountComponents("..") == 1); RTTESTI_CHECK(RTPathCountComponents("../") == 1); RTTESTI_CHECK(RTPathCountComponents("../..") == 2); RTTESTI_CHECK(RTPathCountComponents("../../") == 2); #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) RTTESTI_CHECK(RTPathCountComponents("d:") == 1); RTTESTI_CHECK(RTPathCountComponents("d:/") == 1); RTTESTI_CHECK(RTPathCountComponents("d:/\\") == 1); RTTESTI_CHECK(RTPathCountComponents("d:\\") == 1); RTTESTI_CHECK(RTPathCountComponents("c:\\config.sys") == 2); RTTESTI_CHECK(RTPathCountComponents("c:\\windows") == 2); RTTESTI_CHECK(RTPathCountComponents("c:\\windows\\") == 2); RTTESTI_CHECK(RTPathCountComponents("c:\\windows\\system32") == 3); RTTESTI_CHECK(RTPathCountComponents("//./C$") == 1); RTTESTI_CHECK(RTPathCountComponents("\\\\.\\C$") == 1); RTTESTI_CHECK(RTPathCountComponents("/\\.\\C$") == 1); RTTESTI_CHECK(RTPathCountComponents("//myserver") == 1); RTTESTI_CHECK(RTPathCountComponents("//myserver/") == 1); RTTESTI_CHECK(RTPathCountComponents("//myserver/share") == 1); RTTESTI_CHECK(RTPathCountComponents("//myserver/share/") == 1); RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\") == 1); RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\x") == 2); RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\x\\y") == 3); RTTESTI_CHECK(RTPathCountComponents("//myserver/share\\x\\y\\") == 3); #endif /* * RTPathCopyComponents */ struct { const char *pszSrc; size_t cComponents; const char *pszResult; } s_aCopyComponents[] = { { "", 0, "" }, { "", 5, "" }, { "/", 0, "" }, { "/", 1, "/" }, { "/", 2, "/" }, { "/usr/bin/sed", 0, "" }, { "/usr/bin/sed", 1, "/" }, { "/usr/bin/sed", 2, "/usr/" }, { "/usr/bin/sed", 3, "/usr/bin/" }, { "/usr/bin/sed", 4, "/usr/bin/sed" }, { "/usr/bin/sed", 5, "/usr/bin/sed" }, { "/usr/bin/sed", 6, "/usr/bin/sed" }, { "/usr///bin/sed", 2, "/usr///" }, }; for (unsigned i = 0; i < RT_ELEMENTS(s_aCopyComponents); i++) { const char *pszInput = s_aCopyComponents[i].pszSrc; size_t cComponents = s_aCopyComponents[i].cComponents; const char *pszResult = s_aCopyComponents[i].pszResult; memset(szPath, 'a', sizeof(szPath)); rc = RTPathCopyComponents(szPath, sizeof(szPath), pszInput, cComponents); RTTESTI_CHECK_RC(rc, VINF_SUCCESS); if (RT_SUCCESS(rc) && strcmp(szPath, pszResult)) RTTestIFailed("Unexpected result\n" " input: '%s' cComponents=%u\n" " output: '%s'\n" "expected: '%s'", pszInput, cComponents, szPath, pszResult); else if (RT_SUCCESS(rc)) { RTTESTI_CHECK_RC(RTPathCopyComponents(szPath, strlen(pszResult) + 1, pszInput, cComponents), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPathCopyComponents(szPath, strlen(pszResult), pszInput, cComponents), VERR_BUFFER_OVERFLOW); } } /* * RTPathStripSuffix */ RTTestSub(hTest, "RTPathStripSuffix"); struct { const char *pszSrc; const char *pszResult; } s_aStripExt[] = { { "filename.ext", "filename" }, { "filename.ext1.ext2.ext3", "filename.ext1.ext2" }, { "filename..ext", "filename." }, { "filename.ext.", "filename.ext." }, }; for (unsigned i = 0; i < RT_ELEMENTS(s_aStripExt); i++) { const char *pszInput = s_aStripExt[i].pszSrc; const char *pszResult = s_aStripExt[i].pszResult; strcpy(szPath, pszInput); RTPathStripSuffix(szPath); if (strcmp(szPath, pszResult)) RTTestIFailed("Unexpected result\n" " input: '%s'\n" " output: '%s'\n" "expected: '%s'", pszInput, szPath, pszResult); } /* * RTPathCalcRelative */ RTTestSub(hTest, "RTPathCalcRelative"); struct { const char *pszFrom; const char *pszTo; int rc; const char *pszExpected; } s_aRelPath[] = { { "/home/test.ext", "/home/test2.ext", VINF_SUCCESS, "test2.ext"}, { "/dir/test.ext", "/dir/dir2/test2.ext", VINF_SUCCESS, "dir2/test2.ext"}, { "/dir/dir2/test.ext", "/dir/test2.ext", VINF_SUCCESS, ".." RTPATH_SLASH_STR "test2.ext"}, { "/dir/dir2/test.ext", "/dir/dir3/test2.ext", VINF_SUCCESS, ".." RTPATH_SLASH_STR "dir3/test2.ext"}, #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) { "\\\\server\\share\\test.ext", "\\\\server\\share2\\test2.ext", VERR_NOT_SUPPORTED, ""}, { "c:\\dir\\test.ext", "f:\\dir\\test.ext", VERR_NOT_SUPPORTED, ""} #endif }; for (unsigned i = 0; i < RT_ELEMENTS(s_aRelPath); i++) { const char *pszFrom = s_aRelPath[i].pszFrom; const char *pszTo = s_aRelPath[i].pszTo; rc = RTPathCalcRelative(szPath, sizeof(szPath), pszFrom, pszTo); if (rc != s_aRelPath[i].rc) RTTestIFailed("Unexpected return code\n" " got: %Rrc\n" "expected: %Rrc", rc, s_aRelPath[i].rc); else if ( RT_SUCCESS(rc) && strcmp(szPath, s_aRelPath[i].pszExpected)) RTTestIFailed("Unexpected result\n" " from: '%s'\n" " to: '%s'\n" " output: '%s'\n" "expected: '%s'", pszFrom, pszTo, szPath, s_aRelPath[i].pszExpected); } testParserAndSplitter(hTest); /* * Summary. */ return RTTestSummaryAndDestroy(hTest); }
bool writeQuoted(enum ENMFORMAT enmFormat, const char *pcszQuoted) { /* Was the last character seen a back slash? */ bool fEscaped = false; /* Was the last character seen an argument separator (an unescaped space)? */ bool fNextArgument = false; if (enmFormat == FORMAT_SHELL) if (!outputCharacter('\'')) return false; for (; *pcszQuoted; ++pcszQuoted) { if (fEscaped) { bool fRc = true; const char (*pachEscapes)[2]; fEscaped = false; /* One-letter escapes. */ for (pachEscapes = aachEscapes; (*pachEscapes)[0]; ++pachEscapes) if (*pcszQuoted == (*pachEscapes)[0]) { if (!escapeAndOutputCharacter(enmFormat, (*pachEscapes)[1])) return false; break; } if ((*pachEscapes)[0]) continue; /* Octal. */ if (*pcszQuoted >= '0' && *pcszQuoted <= '7') { uint8_t cNum; char *pchNext; char achDigits[4]; int rc; RTStrCopy(achDigits, sizeof(achDigits), pcszQuoted); rc = RTStrToUInt8Ex(achDigits, &pchNext, 8, &cNum); if (rc == VWRN_NUMBER_TOO_BIG) { RTStrmPrintf(g_pStdErr, "Invalid octal sequence at \"%.16s\"\n", pcszQuoted - 1); return false; } if (!escapeAndOutputCharacter(enmFormat, cNum)) return false; pcszQuoted += pchNext - achDigits - 1; continue; } /* Hexadecimal. */ if (*pcszQuoted == 'x') { uint8_t cNum; char *pchNext; char achDigits[3]; int rc; RTStrCopy(achDigits, sizeof(achDigits), pcszQuoted + 1); rc = RTStrToUInt8Ex(achDigits, &pchNext, 16, &cNum); if ( rc == VWRN_NUMBER_TOO_BIG || rc == VWRN_NEGATIVE_UNSIGNED || RT_FAILURE(rc)) { RTStrmPrintf(g_pStdErr, "Invalid hexadecimal sequence at \"%.16s\"\n", pcszQuoted - 1); return false; } if (!escapeAndOutputCharacter(enmFormat, cNum)) return false; pcszQuoted += pchNext - achDigits; continue; } /* Output anything else non-zero as is. */ if (*pcszQuoted) { if (!escapeAndOutputCharacter(enmFormat, *pcszQuoted)) return false; continue; } RTStrmPrintf(g_pStdErr, "Trailing back slash in argument.\n"); return false; } /* Argument separator. */ if (*pcszQuoted == ' ') { if (!fNextArgument && !outputArgumentSeparator(enmFormat)) return false; fNextArgument = true; continue; } else fNextArgument = false; /* Start of escape sequence. */ if (*pcszQuoted == '\\') { fEscaped = true; continue; } /* Anything else. */ if (!outputCharacter(*pcszQuoted)) return false; } if (enmFormat == FORMAT_SHELL) if (!outputCharacter('\'')) return false; return true; }