/** * Opens the output file. * * @returns Command exit, error messages written using RTMsg*. * * @param pszFile The input filename. * @param pOpts The options, szOutput will be filled in by this * function on success. * @param phVfsIos Where to return the output stream handle. * * @remarks This is actually not quite the way we need to do things. * * First of all, we need a GZIP file system stream for a real GZIP * implementation, since there may be more than one file in the gzipped * file. * * Second, we need to open the output files as we encounter files in the input * file system stream. The gzip format contains timestamp and usually a * filename, the default is to use this name (see the --no-name * option). */ static RTEXITCODE gzipOpenOutput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos) { int rc; if (!strcmp(pszFile, "-") || pOpts->fStdOut) { strcpy(pOpts->szOutput, "-"); if ( !pOpts->fForce && !pOpts->fDecompress && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT)) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Yeah, right. I'm not writing any compressed data to the terminal without --force.\n"); rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, true /*fLeaveOpen*/, phVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard output: %Rrc", rc); } else { Assert(!RTVfsChainIsSpec(pszFile)); /* Construct an output filename. */ rc = RTStrCopy(pOpts->szOutput, sizeof(pOpts->szOutput), pszFile); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc); if (pOpts->fDecompress) { /** @todo take filename from archive? */ size_t cchSuff = strlen(pOpts->pszSuff); Assert(cchSuff > 0); size_t cch = strlen(pOpts->szOutput); if ( cch <= cchSuff || strcmp(&pOpts->szOutput[cch - cchSuff], pOpts->pszSuff)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Input file does not end with: '%s'", pOpts->pszSuff); pOpts->szOutput[cch - cchSuff] = '\0'; if (!RTPathFilename(pOpts->szOutput)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: Input file name is all suffix."); } else { rc = RTStrCat(pOpts->szOutput, sizeof(pOpts->szOutput), pOpts->pszSuff); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc); } /* Open the output file. */ uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE; if (pOpts->fForce) fOpen |= RTFILE_O_CREATE_REPLACE; else fOpen |= RTFILE_O_CREATE; rc = RTVfsIoStrmOpenNormal(pOpts->szOutput, fOpen, phVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening output file '%s': %Rrc", pOpts->szOutput, rc); } return RTEXITCODE_SUCCESS; }
int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod) { /* * We only try the System32 directory. */ WCHAR wszSysDir[MAX_PATH]; UINT cwcSysDir = GetSystemDirectoryW(wszSysDir, MAX_PATH); if (cwcSysDir >= MAX_PATH) return VERR_FILENAME_TOO_LONG; char szPath[RTPATH_MAX]; char *pszPath = szPath; int rc = RTUtf16ToUtf8Ex(wszSysDir, RTSTR_MAX, &pszPath, sizeof(szPath), NULL); if (RT_SUCCESS(rc)) { rc = RTPathAppend(szPath, sizeof(szPath), pszFilename); if (pszExt && RT_SUCCESS(rc)) rc = RTStrCat(szPath, sizeof(szPath), pszExt); if (RT_SUCCESS(rc)) { if (RTFileExists(szPath)) rc = RTLdrLoadEx(szPath, phLdrMod, fFlags, NULL); else rc = VERR_MODULE_NOT_FOUND; } } return rc; }
STDMETHODIMP SystemProperties::COMGETTER(DefaultVRDEExtPack)(BSTR *aExtPack) { CheckComArgOutPointerValid(aExtPack); AutoCaller autoCaller(this); HRESULT hrc = autoCaller.rc(); if (SUCCEEDED(hrc)) { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); Utf8Str strExtPack(m->strDefaultVRDEExtPack); if (strExtPack.isNotEmpty()) { if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME)) hrc = S_OK; else #ifdef VBOX_WITH_EXTPACK hrc = mParent->getExtPackManager()->checkVrdeExtPack(&strExtPack); #else hrc = setError(E_FAIL, tr("The extension pack '%s' does not exist"), strExtPack.c_str()); #endif } else { #ifdef VBOX_WITH_EXTPACK hrc = mParent->getExtPackManager()->getDefaultVrdeExtPack(&strExtPack); #endif if (strExtPack.isEmpty()) { /* * Klugde - check if VBoxVRDP.dll/.so/.dylib is installed. * This is hardcoded uglyness, sorry. */ char szPath[RTPATH_MAX]; int vrc = RTPathAppPrivateArch(szPath, sizeof(szPath)); if (RT_SUCCESS(vrc)) vrc = RTPathAppend(szPath, sizeof(szPath), "VBoxVRDP"); if (RT_SUCCESS(vrc)) vrc = RTStrCat(szPath, sizeof(szPath), RTLdrGetSuff()); if (RT_SUCCESS(vrc) && RTFileExists(szPath)) { /* Illegal extpack name, so no conflict. */ strExtPack = VBOXVRDP_KLUDGE_EXTPACK_NAME; } } } if (SUCCEEDED(hrc)) strExtPack.cloneTo(aExtPack); } return S_OK; }
RTDECL(int) RTErrInfoAdd(PRTERRINFO pErrInfo, int rc, const char *pszMsg) { if (pErrInfo) { AssertPtr(pErrInfo); if (pErrInfo->fFlags & RTERRINFO_FLAGS_SET) RTStrCat(pErrInfo->pszMsg, pErrInfo->cbMsg, pszMsg); else { while (*pszMsg == ' ') pszMsg++; return RTErrInfoSet(pErrInfo, rc, pszMsg); } } return rc; }
/** * Adds a file to the cache. * * @returns IPRT status code. * @param pszSrcPath Path to the source file. * @param pszDstName The name of the destionation file (no path stuff). * @param pszExtraSuff Optional extra suffix. Mach-O dSYM hack. * @param pszDstSubDir The subdirectory to file it under. This is the * stringification of a relatively unique identifier of * the file in question. * @param pAddToUuidMap Optional file UUID that is used to create a UUID map * entry. * @param pszUuidMapDir The UUID map subdirectory in the cache, if this is * wanted, otherwise NULL. * @param pCfg The configuration. */ static int rtDbgSymCacheAddOneFile(const char *pszSrcPath, const char *pszDstName, const char *pszExtraStuff, const char *pszDstSubDir, PRTUUID pAddToUuidMap, const char *pszUuidMapDir, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Build and create the destination path, step by step. */ char szDstPath[RTPATH_MAX]; int rc = RTPathJoin(szDstPath, sizeof(szDstPath), pCfg->pszCache, pszDstName); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); if (!RTDirExists(szDstPath)) { rc = RTDirCreate(szDstPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error creating '%s': %Rrc", szDstPath, rc); } rc = RTPathAppend(szDstPath, sizeof(szDstPath), pszDstSubDir); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); if (!RTDirExists(szDstPath)) { rc = RTDirCreate(szDstPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error creating '%s': %Rrc", szDstPath, rc); } rc = RTPathAppend(szDstPath, sizeof(szDstPath), pszDstName); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); if (pszExtraStuff) { rc = RTStrCat(szDstPath, sizeof(szDstPath), pszExtraStuff); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc); } /* * If the file exists, we compare the two and throws an error if the doesn't match. */ if (RTPathExists(szDstPath)) { rc = RTFileCompare(pszSrcPath, szDstPath); if (RT_SUCCESS(rc)) { RTMsgInfo("%s is already in the cache.", pszSrcPath); if (pAddToUuidMap && pszUuidMapDir) return rtDbgSymCacheAddCreateUuidMapping(szDstPath, pAddToUuidMap, pszUuidMapDir, pCfg); return VINF_SUCCESS; } if (rc == VERR_NOT_EQUAL) RTMsgInfo("Cache conflict with existing entry '%s' when inserting '%s'.", szDstPath, pszSrcPath); else RTMsgInfo("Error comparing '%s' with '%s': %Rrc", pszSrcPath, szDstPath, rc); if (!pCfg->fOverwriteOnConflict) return rc; } /* * The file doesn't exist or we should overwrite it, */ RTMsgInfo("Copying '%s' to '%s'...", pszSrcPath, szDstPath); rc = RTFileCopy(pszSrcPath, szDstPath); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error copying '%s' to '%s': %Rrc", pszSrcPath, szDstPath, rc); if (pAddToUuidMap && pszUuidMapDir) return rtDbgSymCacheAddCreateUuidMapping(szDstPath, pAddToUuidMap, pszUuidMapDir, pCfg); 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; }
/** * Parses and validates the first TAR header of a archive/file/dir/whatever. * * @returns IPRT status code. * @param pThis The TAR reader stat. * @param pTar The TAR header that has been read. * @param fFirst Set if this is the first header, otherwise * clear. */ static int rtZipTarReaderParseNextHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr, bool fFirst) { int rc; /* * Basic header validation and detection first. */ RTZIPTARTYPE enmType; rc = rtZipTarHdrValidate(pHdr, &enmType); if (RT_FAILURE_NP(rc)) { if (rc == VERR_TAR_ZERO_HEADER) { pThis->cZeroHdrs = 1; pThis->enmState = RTZIPTARREADERSTATE_ZERO; return VINF_SUCCESS; } return rc; } if (fFirst) pThis->enmType = enmType; /* * Handle the header by type. */ switch (pHdr->Common.typeflag) { case RTZIPTAR_TF_OLDNORMAL: case RTZIPTAR_TF_NORMAL: case RTZIPTAR_TF_CONTIG: case RTZIPTAR_TF_LINK: case RTZIPTAR_TF_SYMLINK: case RTZIPTAR_TF_CHR: case RTZIPTAR_TF_BLK: case RTZIPTAR_TF_FIFO: case RTZIPTAR_TF_DIR: /* * Extract the name first. */ if (!pHdr->Common.name[0]) return VERR_TAR_EMPTY_NAME; if (pThis->enmType == RTZIPTARTYPE_POSIX) { Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0'); pThis->szName[0] = '\0'; if (pHdr->Posix.prefix[0]) { rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Posix.prefix, sizeof(pHdr->Posix.prefix)); AssertRC(rc); /* shall not fail */ rc = RTStrCat(pThis->szName, sizeof(pThis->szName), "/"); AssertRC(rc); /* ditto */ } rc = RTStrCatEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name)); AssertRCReturn(rc, rc); } else if (pThis->enmType == RTZIPTARTYPE_GNU) { if (!pThis->szName[0]) { rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name)); AssertRCReturn(rc, rc); } } else { /* Old TAR */ Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0'); rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name)); AssertRCReturn(rc, rc); } /* * Extract the link target. */ if ( pHdr->Common.typeflag == RTZIPTAR_TF_LINK || pHdr->Common.typeflag == RTZIPTAR_TF_SYMLINK) { if ( pThis->enmType == RTZIPTARTYPE_POSIX || pThis->enmType == RTZIPTARTYPE_ANCIENT || (pThis->enmType == RTZIPTARTYPE_GNU && pThis->szTarget[0] == '\0') ) { Assert(pThis->szTarget[0] == '\0'); rc = RTStrCopyEx(pThis->szTarget, sizeof(pThis->szTarget), pHdr->Common.linkname, sizeof(pHdr->Common.linkname)); AssertRCReturn(rc, rc); } } else pThis->szTarget[0] = '\0'; pThis->Hdr = *pHdr; break; case RTZIPTAR_TF_X_HDR: case RTZIPTAR_TF_X_GLOBAL: /** @todo implement PAX */ return VERR_TAR_UNSUPPORTED_PAX_TYPE; case RTZIPTAR_TF_SOLARIS_XHDR: /** @todo implement solaris / pax attribute lists. */ return VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE; /* * A GNU long name or long link is a dummy record followed by one or * more 512 byte string blocks holding the long name/link. The name * lenght is encoded in the size field, null terminator included. If * it is a symlink or hard link the long name may be followed by a * long link sequence. */ case RTZIPTAR_TF_GNU_LONGNAME: case RTZIPTAR_TF_GNU_LONGLINK: { if (strcmp(pHdr->Gnu.name, "././@LongLink")) return VERR_TAR_MALFORMED_GNU_LONGXXXX; int64_t cb64; rc = rtZipTarHdrFieldToNum(pHdr->Gnu.size, sizeof(pHdr->Gnu.size), false /*fOctalOnly*/, &cb64); if (RT_FAILURE(rc) || cb64 < 0 || cb64 > _1M) return VERR_TAR_MALFORMED_GNU_LONGXXXX; uint32_t cb = (uint32_t)cb64; if (cb >= sizeof(pThis->szName)) return VERR_TAR_NAME_TOO_LONG; pThis->cbGnuLongExpect = cb; pThis->offGnuLongCur = 0; pThis->enmState = pHdr->Common.typeflag == RTZIPTAR_TF_GNU_LONGNAME ? RTZIPTARREADERSTATE_GNU_LONGNAME : RTZIPTARREADERSTATE_GNU_LONGLINK; break; } case RTZIPTAR_TF_GNU_DUMPDIR: case RTZIPTAR_TF_GNU_MULTIVOL: case RTZIPTAR_TF_GNU_SPARSE: case RTZIPTAR_TF_GNU_VOLDHR: /** @todo Implement or skip GNU headers */ return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE; default: return VERR_TAR_UNKNOWN_TYPE_FLAG; } return VINF_SUCCESS; }
static void testCat1(RTTEST hTest) { RTTestISub("RTStrCat"); char *pszBuf4H = (char *)RTTestGuardedAllocHead(hTest, 4); char *pszBuf4T = (char *)RTTestGuardedAllocTail(hTest, 4); memset(pszBuf4T, 0xff, 4); *pszBuf4T = '\0'; RTTESTI_CHECK_RC(RTStrCat(pszBuf4H, 4, "abc"), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4H, "abc") == 0); memset(pszBuf4H, 0xff, 4); *pszBuf4H = '\0'; RTTESTI_CHECK_RC(RTStrCat(pszBuf4T, 4, "abc"), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4T, "abc") == 0); memset(pszBuf4T, 0xff, 4); strcpy(pszBuf4T, "a"); memset(pszBuf4H, 0xff, 4); strcpy(pszBuf4H, "a"); RTTESTI_CHECK_RC(RTStrCat(pszBuf4H, 4, "bc"), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4H, "abc") == 0); RTTESTI_CHECK_RC(RTStrCat(pszBuf4T, 4, "bc"), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4T, "abc") == 0); memset(pszBuf4T, 0xff, 4); strcpy(pszBuf4T, "ab"); memset(pszBuf4H, 0xff, 4); strcpy(pszBuf4H, "ab"); RTTESTI_CHECK_RC(RTStrCat(pszBuf4H, 4, "c"), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4H, "abc") == 0); RTTESTI_CHECK_RC(RTStrCat(pszBuf4T, 4, "c"), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4T, "abc") == 0); memset(pszBuf4T, 0xff, 4); strcpy(pszBuf4T, "abc"); memset(pszBuf4H, 0xff, 4); strcpy(pszBuf4H, "abc"); RTTESTI_CHECK_RC(RTStrCat(pszBuf4H, 4, ""), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4H, "abc") == 0); RTTESTI_CHECK_RC(RTStrCat(pszBuf4T, 4, ""), VINF_SUCCESS); RTTESTI_CHECK(strcmp(pszBuf4T, "abc") == 0); memset(pszBuf4T, 0xff, 4); strcpy(pszBuf4T, ""); memset(pszBuf4H, 0xff, 4); strcpy(pszBuf4H, ""); RTTESTI_CHECK_RC(RTStrCat(pszBuf4H, 4, "abcd"), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK(strcmp(pszBuf4H, "abc") == 0); RTTESTI_CHECK_RC(RTStrCat(pszBuf4T, 4, "abcd"), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK(strcmp(pszBuf4T, "abc") == 0); memset(pszBuf4T, 0xff, 4); strcpy(pszBuf4T, "ab"); memset(pszBuf4H, 0xff, 4); strcpy(pszBuf4H, "ab"); RTTESTI_CHECK_RC(RTStrCat(pszBuf4H, 4, "cd"), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK(strcmp(pszBuf4H, "abc") == 0); RTTESTI_CHECK_RC(RTStrCat(pszBuf4T, 4, "cd"), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK(strcmp(pszBuf4T, "abc") == 0); memset(pszBuf4T, 0xff, 4); strcpy(pszBuf4T, "abc"); memset(pszBuf4H, 0xff, 4); strcpy(pszBuf4H, "abc"); RTTESTI_CHECK_RC(RTStrCat(pszBuf4H, 4, "d"), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK(strcmp(pszBuf4H, "abc") == 0); RTTESTI_CHECK_RC(RTStrCat(pszBuf4T, 4, "d"), VERR_BUFFER_OVERFLOW); RTTESTI_CHECK(strcmp(pszBuf4T, "abc") == 0); }