/** * 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; }
/** * 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; }