fix(persist): use non-throwing directory_iterator increment in pruneDryRun

Replace range-based for over fs::directory_iterator with manual
it.increment(ec) form. Mid-iteration failures now break to a
best-effort partial list instead of throwing filesystem_error
across REAPER's C ABI. Split shared fec into reg_ec/sz_ec.
This commit is contained in:
2026-07-26 18:25:28 -04:00
parent c1473c42e1
commit 1f0efe6db6
+11 -6
View File
@@ -281,18 +281,23 @@ PruneReport ReaSamplerSession::pruneDryRun() const {
// and the manifest. Non-recursive: the bank folder is flat (capture writes files // and the manifest. Non-recursive: the bank folder is flat (capture writes files
// directly here); skip any subdirectory. Size is stat'd here and cached by relative // directly here); skip any subdirectory. Size is stat'd here and cached by relative
// path so the report's byte tally reuses the same on-disk read. // path so the report's byte tally reuses the same on-disk read.
// Manual iterator form (it.increment(ec)) keeps the loop non-throwing: a mid-iteration
// failure (file removed, permission flip) breaks out with a best-effort partial list
// rather than propagating std::filesystem_error across REAPER's C ABI.
std::vector<std::string> present; std::vector<std::string> present;
std::unordered_map<std::string, std::uint64_t> sizeByRel; std::unordered_map<std::string, std::uint64_t> sizeByRel;
for (const auto& entry : fs::directory_iterator(bankDir, ec)) { fs::directory_iterator it(bankDir, ec);
if (ec) break; for (; !ec && it != fs::directory_iterator{}; it.increment(ec)) {
std::error_code fec; const auto& entry = *it;
if (!entry.is_regular_file(fec)) continue; // skip subdirs / specials std::error_code reg_ec;
if (!entry.is_regular_file(reg_ec)) continue; // skip subdirs / specials
const std::string name = entry.path().filename().string(); const std::string name = entry.path().filename().string();
const std::string rel = bankRelativeForName(name); const std::string rel = bankRelativeForName(name);
if (rel.empty()) continue; if (rel.empty()) continue;
present.push_back(rel); present.push_back(rel);
const std::uintmax_t sz = entry.file_size(fec); std::error_code sz_ec;
sizeByRel[rel] = fec ? 0 : static_cast<std::uint64_t>(sz); const std::uintmax_t sz = entry.file_size(sz_ec);
sizeByRel[rel] = sz_ec ? 0 : static_cast<std::uint64_t>(sz);
} }
// The decision lives in the pure core — read-only inputs from the session's book and // The decision lives in the pure core — read-only inputs from the session's book and