/** * Adds a file or directory. * * @returns Program exit code. * @param pszPath The user supplied path to the file or directory. * @param pszCache The path to the cache. * @param fRecursive Whether to process directories recursively. * @param fOverwriteOnConflict Whether to overwrite existing cache entry on * conflict, or just leave it. */ static RTEXITCODE rtDbgSymCacheAddFileOrDir(const char *pszPath, const char *pszCache, bool fRecursive, bool fOverwriteOnConflict) { RT_NOREF1(fOverwriteOnConflict); RTDBGSYMCACHEADDCFG Cfg; Cfg.fRecursive = fRecursive; Cfg.pszCache = pszCache; Cfg.pszFilter = NULL; int rc; RTDBGSYMCACHEFILETYPE enmType = rtDbgSymCacheFigureType(pszPath); switch (enmType) { default: case RTDBGSYMCACHEFILETYPE_INVALID: return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid: '%s'", pszPath); case RTDBGSYMCACHEFILETYPE_DIR_FILTER: Cfg.pszFilter = RTPathFilename(pszPath); /* fall thru */ case RTDBGSYMCACHEFILETYPE_DIR: rc = rtDbgSymCacheAddDir(pszPath, &Cfg); break; case RTDBGSYMCACHEFILETYPE_DEBUG_FILE: rc = rtDbgSymCacheAddDebugFile(pszPath, &Cfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_FILE: rc = rtDbgSymCacheAddImageFile(pszPath, NULL /*pszExtraSuff*/, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, &Cfg); break; case RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE: case RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE: { size_t cchPath = strlen(pszPath); size_t cchFilename = strlen(RTPathFilename(pszPath)); char szPathBuf[RTPATH_MAX]; if (cchPath < sizeof(szPathBuf)) { memcpy(szPathBuf, pszPath, cchPath + 1); if (enmType == RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE) rc = rtDbgSymCacheAddDebugBundle(szPathBuf, cchPath - cchFilename, cchFilename, &Cfg); else { RTDIRENTRYEX DirEntry; rc = rtDbgSymCacheAddImageBundle(szPathBuf, cchPath - cchFilename, cchFilename, &DirEntry, &Cfg); } } else rc = RTMsgErrorRc(VERR_FILENAME_TOO_LONG, "Filename too long: '%s'", pszPath); break; } case RTDBGSYMCACHEFILETYPE_IGNORE: rc = RTMsgErrorRc(VERR_INVALID_PARAMETER, "Invalid file: '%s'", pszPath); break; } return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; }
/** * @interface_method_impl{TXSTRANSPORT,pfnOption} */ static DECLCALLBACK(int) txsTcpOption(int ch, PCRTGETOPTUNION pVal) { int rc; switch (ch) { case TXSTCPOPT_MODE: if (!strcmp(pVal->psz, "both")) g_enmTcpMode = TXSTCPMODE_BOTH; else if (!strcmp(pVal->psz, "client")) g_enmTcpMode = TXSTCPMODE_CLIENT; else if (!strcmp(pVal->psz, "server")) g_enmTcpMode = TXSTCPMODE_SERVER; else return RTMsgErrorRc(VERR_INVALID_PARAMETER, "Invalid TCP mode: '%s'\n", pVal->psz); break; case TXSTCPOPT_BIND_ADDRESS: rc = RTStrCopy(g_szTcpBindAddr, sizeof(g_szTcpBindAddr), pVal->psz); if (RT_FAILURE(rc)) return RTMsgErrorRc(VERR_INVALID_PARAMETER, "TCP bind address is too long (%Rrc)", rc); return VINF_SUCCESS; case TXSTCPOPT_BIND_PORT: g_uTcpBindPort = pVal->u16 == 0 ? TXS_TCP_DEF_BIND_PORT : pVal->u16; break; case TXSTCPOPT_LEGACY_CONNECT: g_enmTcpMode = TXSTCPMODE_CLIENT; /* fall thru */ case TXSTCPOPT_CONNECT_ADDRESS: rc = RTStrCopy(g_szTcpConnectAddr, sizeof(g_szTcpConnectAddr), pVal->psz); if (RT_FAILURE(rc)) return RTMsgErrorRc(VERR_INVALID_PARAMETER, "TCP connect address is too long (%Rrc)", rc); if (!g_szTcpConnectAddr[0]) strcpy(g_szTcpConnectAddr, TXS_TCP_DEF_CONNECT_ADDRESS); return VINF_SUCCESS; case TXSTCPOPT_CONNECT_PORT: g_uTcpConnectPort = pVal->u16 == 0 ? TXS_TCP_DEF_CONNECT_PORT : pVal->u16; break; case TXSTCPOPT_LEGACY_PORT: if (pVal->u16 == 0) { g_uTcpBindPort = TXS_TCP_DEF_BIND_PORT; g_uTcpConnectPort = TXS_TCP_DEF_CONNECT_PORT; } else { g_uTcpBindPort = pVal->u16; g_uTcpConnectPort = pVal->u16; } return VINF_SUCCESS; } return VERR_TRY_AGAIN; }
/** * Adds a debug file to the cache. * * @returns IPRT status code * @param pszPath The path to the debug file in question. * @param pCfg The configuration. */ static int rtDbgSymCacheAddDebugFile(const char *pszPath, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Need to extract an identifier of sorts here in order to put them in * the right place in the cache. Currently only implemnted for Mach-O * files since these use executable containers. * * We take a look at the file header in hope to figure out what to do * with the file. */ RTFILE hFile; int rc = RTFileOpen(&hFile, pszPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error opening '%s': %Rrc", pszPath, rc); union { uint64_t au64[16]; uint32_t au32[16]; uint16_t au16[32]; uint8_t ab[64]; } uBuf; rc = RTFileRead(hFile, &uBuf, sizeof(uBuf), NULL); if (RT_SUCCESS(rc)) { /* * Look for magics and call workers. */ if (!memcmp(uBuf.ab, RT_STR_TUPLE("Microsoft C/C++ MSF 7.00"))) rc = rtDbgSymCacheAddDebugPdb(pszPath, pCfg, hFile); else if ( uBuf.au32[0] == IMAGE_FAT_SIGNATURE || uBuf.au32[0] == IMAGE_FAT_SIGNATURE_OE || uBuf.au32[0] == IMAGE_MACHO32_SIGNATURE || uBuf.au32[0] == IMAGE_MACHO64_SIGNATURE || uBuf.au32[0] == IMAGE_MACHO32_SIGNATURE_OE || uBuf.au32[0] == IMAGE_MACHO64_SIGNATURE_OE) rc = rtDbgSymCacheAddDebugMachO(pszPath, pCfg); else rc = RTMsgErrorRc(VERR_INVALID_MAGIC, "Unsupported debug file '%s' magic: %#010x", pszPath, uBuf.au32[0]); } else rc = RTMsgErrorRc(rc, "Error reading '%s': %Rrc", pszPath, rc); /* close the file. */ int rc2 = RTFileClose(hFile); if (RT_FAILURE(rc2)) { RTMsgError("Error closing '%s': %Rrc", pszPath, rc2); if (RT_SUCCESS(rc)) rc = rc2; } return rc; }
/** * Worker for rtDbgSymCacheAddDebugFile that adds a Mach-O debug file to the * cache. * * @returns IPRT status code * @param pszPath The path to the PDB file. * @param pCfg The configuration. * @param hFile Handle to the file. */ static int rtDbgSymCacheAddDebugMachO(const char *pszPath, PCRTDBGSYMCACHEADDCFG pCfg) { /* This shouldn't happen, figure out what to do if it does. */ return RTMsgErrorRc(VERR_NOT_IMPLEMENTED, "'%s' is an OS X image file, did you point me to a file inside a .dSYM or .sym file?", pszPath); }
/** * Constructs the path to the file instide the bundle that we're keen on. * * @returns IPRT status code. * @param pszPath Path to the bundle on input, on successful * return it's the path to the desired file. This * a RTPATH_MAX size buffer. * @param cchPath The length of the path up to the bundle name. * @param cchName The length of the bundle name. * @param pszSubDir The bundle subdirectory the file lives in. * @param papszSuffixes Pointer to an array of bundle suffixes. */ static int rtDbgSymCacheConstructBundlePath(char *pszPath, size_t cchPath, size_t cchName, const char *pszSubDir, const char * const *papszSuffixes) { int rc = RTPathAppend(pszPath, RTPATH_MAX, pszSubDir); if (RT_SUCCESS(rc)) { /* Strip off the bundle suffix. */ const char *pszEnd = &pszPath[cchPath + cchName]; for (unsigned i = 0; papszSuffixes[i]; i++) { Assert(papszSuffixes[i][0] == '.'); size_t cchSuff = strlen(papszSuffixes[i]); if ( cchSuff < cchName && !memcmp(&pszEnd[-(ssize_t)cchSuff], papszSuffixes[i], cchSuff)) { cchName -= cchSuff; break; } } /* Add the name. */ rc = RTPathAppendEx(pszPath, RTPATH_MAX, &pszPath[cchPath], cchName); } if (RT_FAILURE(rc)) { pszPath[cchPath + cchName] = '\0'; return RTMsgErrorRc(rc, "Error constructing image bundle path for '%s': %Rrc", pszPath, rc); } return VINF_SUCCESS; }
/** * Worker that add the image file to the right place. * * @returns IPRT status code. * @param pszPath Path to the image file. * @param pCfg Configuration data. * @param hLdrMod Image handle. * @param pszExtraSuff Optional extra suffix. Mach-O dSYM hack. * @param pszUuidMapDir Optional UUID map cache directory if the image * should be mapped by UUID. * The map is a Mac OS X debug feature supported by * the two native debuggers gdb and lldb. Look for * descriptions of DBGFileMappedPaths in the * com.apple.DebugSymbols in the user defaults. */ static int rtDbgSymCacheAddImageFileWorker(const char *pszPath, PCRTDBGSYMCACHEADDCFG pCfg, RTLDRMOD hLdrMod, const char *pszExtrSuff, const char *pszUuidMapDir) { /* * Determine which subdirectory to put the files in. */ RTUUID Uuid; PRTUUID pUuid = NULL; int rc; char szSubDir[48]; RTLDRFMT enmFmt = RTLdrGetFormat(hLdrMod); switch (enmFmt) { case RTLDRFMT_MACHO: { rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_UUID, &Uuid, sizeof(Uuid)); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error quering image UUID from image '%s': %Rrc", pszPath, rc); rc = RTUuidToStr(&Uuid, szSubDir, sizeof(szSubDir)); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error convering UUID for image '%s' to string: %Rrc", pszPath, rc); pUuid = &Uuid; break; } case RTLDRFMT_PE: { uint32_t uTimestamp; rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uTimestamp)); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error quering timestamp from image '%s': %Rrc", pszPath, rc); size_t cbImage = RTLdrSize(hLdrMod); if (cbImage == ~(size_t)0) return RTMsgErrorRc(rc, "Error quering size of image '%s': %Rrc", pszPath, rc); RTStrPrintf(szSubDir, sizeof(szSubDir), "%08X%x", uTimestamp, cbImage); break; } case RTLDRFMT_AOUT: return RTMsgErrorRc(VERR_NOT_SUPPORTED, "Caching of a.out image has not yet been implemented: %s", pszPath); case RTLDRFMT_ELF: return RTMsgErrorRc(VERR_NOT_SUPPORTED, "Caching of ELF image has not yet been implemented: %s", pszPath); case RTLDRFMT_LX: return RTMsgErrorRc(VERR_NOT_SUPPORTED, "Caching of LX image has not yet been implemented: %s", pszPath); default: return RTMsgErrorRc(VERR_NOT_SUPPORTED, "Unknown loader format for '%s': %d", pszPath, enmFmt); } /* * Now add it. */ return rtDbgSymCacheAddOneFile(pszPath, RTPathFilename(pszPath), pszExtrSuff, szSubDir, pUuid, pszUuidMapDir, pCfg); }
/** * Constructs the path to the file instide the bundle that we're keen on. * * @returns IPRT status code. * @param pszPath Path to the bundle on input, on successful * return it's the path to the desired file. This * a RTPATH_MAX size buffer. * @param cchPath The length of the path up to the bundle name. * @param cchName The length of the bundle name. * @param pszSubDir The bundle subdirectory the file lives in. * @param papszSuffixes Pointer to an array of bundle suffixes. */ static int rtDbgSymCacheConstructBundlePath(char *pszPath, size_t cchPath, size_t cchName, const char *pszSubDir, const char * const *papszSuffixes) { /* * Calc the name without the bundle extension. */ size_t const cchOrgName = cchName; const char *pszEnd = &pszPath[cchPath + cchName]; for (unsigned i = 0; papszSuffixes[i]; i++) { Assert(papszSuffixes[i][0] == '.'); size_t cchSuff = strlen(papszSuffixes[i]); if ( cchSuff < cchName && !memcmp(&pszEnd[-(ssize_t)cchSuff], papszSuffixes[i], cchSuff)) { cchName -= cchSuff; break; } } /* * Check the immediate directory first, in case it's layed out like * IOPCIFamily.kext. */ int rc = RTPathAppendEx(pszPath, RTPATH_MAX, &pszPath[cchPath], cchName); if (RT_FAILURE(rc) || !RTFileExists(pszPath)) { /* * Not there, ok then try the given subdirectory + name. */ pszPath[cchPath + cchOrgName] = '\0'; rc = RTPathAppend(pszPath, RTPATH_MAX, pszSubDir); if (RT_SUCCESS(rc)) rc = RTPathAppendEx(pszPath, RTPATH_MAX, &pszPath[cchPath], cchName); if (RT_FAILURE(rc)) { pszPath[cchPath + cchOrgName] = '\0'; return RTMsgErrorRc(rc, "Error constructing image bundle path for '%s': %Rrc", pszPath, rc); } } return VINF_SUCCESS; }
/** * Recursive worker for rtDbgSymCacheAddDir, for minimal stack wasting. * * @returns IPRT status code (fully bitched). * @param pszPath Pointer to a RTPATH_MAX size buffer containing * the path to the current directory ending with a * slash. * @param cchPath The size of the current directory path. * @param pDirEntry Pointer to the RTDIRENTRYEX structure to use. * @param pCfg The configuration. */ static int rtDbgSymCacheAddDirWorker(char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Open the directory. */ PRTDIR pDir; int rc, rc2; if (pCfg->pszFilter) { rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX - cchPath, pCfg->pszFilter); if (RT_FAILURE(rc)) { pszPath[cchPath] = '\0'; return RTMsgErrorRc(rc, "Filename too long (%Rrc): '%s" RTPATH_SLASH_STR "%s'", rc, pszPath, pCfg->pszFilter); } rc = RTDirOpenFiltered(&pDir, pszPath, RTDIRFILTER_WINNT, 0 /*fFlags*/); } else rc = RTDirOpen(&pDir, pszPath); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "RTDirOpen%s failed on '%s': %Rrc", pCfg->pszFilter ? "Filtered" : "", pszPath, rc); /* * Enumerate the files. */ for (;;) { rc2 = RTDirReadEx(pDir, pDirEntry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK); if (RT_FAILURE(rc2)) { pszPath[cchPath] = '\0'; if (rc2 != VERR_NO_MORE_FILES) { RTMsgError("RTDirReadEx failed in '%s': %Rrc\n", pszPath, rc2); rc = rc2; } break; } /* Skip dot and dot-dot. */ if (RTDirEntryExIsStdDotLink(pDirEntry)) continue; /* Construct a full path. */ rc = RTStrCopy(&pszPath[cchPath], RTPATH_MAX, pDirEntry->szName); if (RT_FAILURE(rc)) { pszPath[cchPath] = '\0'; RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc); break; } switch (rtDbgSymCacheFigureType2(pszPath, &pDirEntry->Info)) { case RTDBGSYMCACHEFILETYPE_DIR: if (!pCfg->fRecursive) RTMsgInfo("Skipping directory '%s'...", pszPath); else { if (cchPath + pDirEntry->cbName + 3 <= RTPATH_MAX) { pszPath[cchPath + pDirEntry->cbName] = RTPATH_SLASH; pszPath[cchPath + pDirEntry->cbName + 1] = '\0'; rc2 = rtDbgSymCacheAddDirWorker(pszPath, cchPath + pDirEntry->cbName + 1, pDirEntry, pCfg); } else { RTMsgError("File name too long in '%s': '%s' (%Rrc)", pszPath, pDirEntry->szName, rc); rc2 = VERR_FILENAME_TOO_LONG; } } break; case RTDBGSYMCACHEFILETYPE_DEBUG_FILE: rc2 = rtDbgSymCacheAddDebugFile(pszPath, pCfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_FILE: rc2 = rtDbgSymCacheAddImageFile(pszPath, NULL /*pszExtraSuff*/, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, pCfg); break; case RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE: rc2 = rtDbgSymCacheAddDebugBundle(pszPath, cchPath, pDirEntry->cbName, pCfg); break; case RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE: rc2 = rtDbgSymCacheAddImageBundle(pszPath, cchPath, pDirEntry->cbName, pDirEntry, pCfg); break; case RTDBGSYMCACHEFILETYPE_DIR_FILTER: case RTDBGSYMCACHEFILETYPE_INVALID: rc2 = RTMsgErrorRc(VERR_INTERNAL_ERROR_2, "Invalid: '%s'", pszPath); break; case RTDBGSYMCACHEFILETYPE_IGNORE: rc2 = VINF_SUCCESS; break; } if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; } /* * Clean up. */ rc2 = RTDirClose(pDir); if (RT_FAILURE(rc2)) { RTMsgError("RTDirClose failed in '%s': %Rrc", pszPath, rc); rc = rc2; } return rc; }
/** * Worker for rtDbgSymCacheAddDebugFile that adds PDBs to the cace. * * @returns IPRT status code * @param pszPath The path to the PDB file. * @param pCfg The configuration. * @param hFile Handle to the file. */ static int rtDbgSymCacheAddDebugPdb(const char *pszPath, PCRTDBGSYMCACHEADDCFG pCfg, RTFILE hFile) { return RTMsgErrorRc(VERR_NOT_IMPLEMENTED, "PDB support not implemented: '%s'", pszPath); }
/** * Adds what we think is an image file to the cache. * * @returns IPRT status code. * @param pszPath Path to the image file. * @param pszExtraSuff Optional extra suffix. Mach-O dSYM hack. * @param pszUuidMapDir The UUID map subdirectory in the cache, if this is * wanted, otherwise NULL. * @param pCfg Configuration data. */ static int rtDbgSymCacheAddImageFile(const char *pszPath, const char *pszExtraSuff, const char *pszUuidMapDir, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Use the loader to open the alleged image file. We need to open it with * arch set to amd64 and x86_32 in order to handle FAT images from the mac * guys (we should actually enumerate archs, but that's currently not * implemented nor necessary for our current use). */ /* Open it as AMD64. */ RTLDRMOD hLdrMod64; int rc = RTLdrOpen(pszPath, RTLDR_O_FOR_DEBUG, RTLDRARCH_AMD64, &hLdrMod64); if (RT_FAILURE(rc)) { if (rc != VERR_LDR_ARCH_MISMATCH) { if (rc != VERR_INVALID_EXE_SIGNATURE) return RTMsgErrorRc(rc, "RTLdrOpen failed opening '%s' [arch=amd64]: %Rrc", pszPath, rc); RTMsgInfo("Skipping '%s', no a recognizable image file...", pszPath); return VINF_SUCCESS; } hLdrMod64 = NIL_RTLDRMOD; } /* Open it as X86. */ RTLDRMOD hLdrMod32; rc = RTLdrOpen(pszPath, RTLDR_O_FOR_DEBUG, RTLDRARCH_X86_32, &hLdrMod32); if (RT_FAILURE(rc)) { if (rc != VERR_LDR_ARCH_MISMATCH) { RTLdrClose(hLdrMod32); return RTMsgErrorRc(rc, "RTLdrOpen failed opening '%s' [arch=x86]: %Rrc", pszPath, rc); } hLdrMod32 = NIL_RTLDRMOD; } /* * Add the file. */ if (hLdrMod32 == NIL_RTLDRMOD) rc = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod64, pszExtraSuff, pszUuidMapDir); else if (hLdrMod64 == NIL_RTLDRMOD) rc = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod32, pszExtraSuff, pszUuidMapDir); else { /* * Do we need to add it once or twice? */ RTLDRFMT enmFmt = RTLdrGetFormat(hLdrMod32); bool fSame = enmFmt == RTLdrGetFormat(hLdrMod64); if (fSame && enmFmt == RTLDRFMT_MACHO) { RTUUID Uuid32, Uuid64; int rc32 = RTLdrQueryProp(hLdrMod32, RTLDRPROP_UUID, &Uuid32, sizeof(Uuid32)); int rc64 = RTLdrQueryProp(hLdrMod64, RTLDRPROP_UUID, &Uuid64, sizeof(Uuid64)); fSame = RT_SUCCESS(rc32) == RT_SUCCESS(rc64); if (fSame && RT_SUCCESS(rc32)) fSame = RTUuidCompare(&Uuid32, &Uuid64) == 0; } else if (fSame && enmFmt == RTLDRFMT_PE) { fSame = RTLdrSize(hLdrMod32) == RTLdrSize(hLdrMod64); if (fSame) { uint32_t uTimestamp32, uTimestamp64; int rc32 = RTLdrQueryProp(hLdrMod32, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp32, sizeof(uTimestamp32)); int rc64 = RTLdrQueryProp(hLdrMod64, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp64, sizeof(uTimestamp64)); fSame = RT_SUCCESS(rc32) == RT_SUCCESS(rc64); if (fSame && RT_SUCCESS(rc32)) fSame = uTimestamp32 == uTimestamp64; } } rc = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod64, pszExtraSuff, pszUuidMapDir); if (!fSame) { /** @todo should symlink or hardlink this second copy. */ int rc2 = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod32, pszExtraSuff, pszUuidMapDir); if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; } } RTLdrClose(hLdrMod32); RTLdrClose(hLdrMod64); return VINF_SUCCESS; }
/** * 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; }
/** * Creates a UUID mapping for the file. * * @returns IPRT status code. * @param pszCacheFile The path to the file in the cache. * @param pFileUuid The UUID of the file. * @param pszUuidMapDir The UUID map subdirectory in the cache, if this is * wanted, otherwise NULL. * @param pCfg The configuration. */ static int rtDbgSymCacheAddCreateUuidMapping(const char *pszCacheFile, PRTUUID pFileUuid, const char *pszUuidMapDir, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Create the UUID map entry first, deep. */ char szMapPath[RTPATH_MAX]; int rc = RTPathJoin(szMapPath, sizeof(szMapPath) - sizeof("/xxxx/yyyy/xxxx/yyyy/xxxx/zzzzzzzzzzzz") + 1, pCfg->pszCache, pszUuidMapDir); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing UUID map path (RTPathJoin): %Rrc", rc); size_t cch = strlen(szMapPath); szMapPath[cch] = '-'; rc = RTUuidToStr(pFileUuid, &szMapPath[cch + 2], sizeof(szMapPath) - cch); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Error constructing UUID map path (RTUuidToStr): %Rrc", rc); /* Uppercase the whole lot. */ RTStrToUpper(&szMapPath[cch + 2]); /* Split the first dword in two. */ szMapPath[cch + 1] = szMapPath[cch + 2]; szMapPath[cch + 2] = szMapPath[cch + 3]; szMapPath[cch + 3] = szMapPath[cch + 4]; szMapPath[cch + 4] = szMapPath[cch + 5]; szMapPath[cch + 5] = '-'; /* * Create the directories in the path. */ char chSaved = RTPATH_SLASH; for (unsigned i = 0; i < 6; i++, cch += 5) { Assert(szMapPath[cch] == '-'); szMapPath[cch] = '\0'; if (!RTDirExists(szMapPath)) { rc = RTDirCreate(szMapPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "RTDirCreate failed on '%s' (UUID map path): %Rrc", szMapPath, rc); } szMapPath[cch] = RTPATH_SLASH; } cch -= 5; /* * Calculate a relative path from there to the actual file. */ char szLinkTarget[RTPATH_MAX]; //szMapPath[cch] = '\0'; rc = RTPathCalcRelative(szLinkTarget, sizeof(szLinkTarget), szMapPath, pszCacheFile); //szMapPath[cch] = RTPATH_SLASH; if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Failed to calculate relative path from '%s' to '%s': %Rrc", szMapPath, pszCacheFile, rc); /* * If there is already a link there, check if it matches or whether * perhaps it's target doesn't exist. */ RTFSOBJINFO ObjInfo; rc = RTPathQueryInfoEx(szMapPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); if (RT_SUCCESS(rc)) { if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) { rc = RTPathQueryInfoEx(szMapPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK); if (RT_SUCCESS(rc)) { char *pszCurTarget = NULL; rc = RTSymlinkReadA(szMapPath, &pszCurTarget); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "UUID map: failed to read existing symlink '%s': %Rrc", szMapPath, rc); if (RTPathCompare(pszCurTarget, szLinkTarget) == 0) RTMsgInfo("UUID map: existing link '%s' has the same target ('%s').", szMapPath, pszCurTarget); else { RTMsgError("UUID map: Existing mapping '%s' pointing to '%s' insted of '%s'", szMapPath, pszCurTarget, szLinkTarget); rc = VERR_ALREADY_EXISTS; } RTStrFree(pszCurTarget); return rc; } else RTMsgInfo("UUID map: replacing dangling link '%s'", szMapPath); RTSymlinkDelete(szMapPath, 0 /*fFlags*/); } else if (RTFS_IS_FILE(ObjInfo.Attr.fMode)) return RTMsgErrorRc(VERR_IS_A_FILE, "UUID map: found file at '%s', expect symbolic link or nothing.", szMapPath); else if (RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode)) return RTMsgErrorRc(VERR_IS_A_DIRECTORY, "UUID map: found directory at '%s', expect symbolic link or nothing.", szMapPath); else return RTMsgErrorRc(VERR_NOT_SYMLINK, "UUID map: Expected symbolic link or nothing at '%s', found: fMode=%#x", szMapPath, ObjInfo.Attr.fMode); } /* * Create the symbolic link. */ rc = RTSymlinkCreate(szMapPath, szLinkTarget, RTSYMLINKTYPE_FILE, 0); if (RT_FAILURE(rc)) return RTMsgErrorRc(rc, "Failed to create UUID map symlink '%s' to '%s': %Rrc", szMapPath, szLinkTarget, rc); RTMsgInfo("UUID map: %s => %s", szMapPath, szLinkTarget); return VINF_SUCCESS; }