Stat::Stat(StatFunction stat_function,
const std::string& path,
- Stat::OnError on_error)
+ Stat::LogOnError log_on_error)
: m_path(path)
{
int result = stat_function(path.c_str(), &m_stat);
m_errno = 0;
} else {
m_errno = errno;
- if (on_error == OnError::throw_error) {
- throw core::Error(FMT("failed to stat {}: {}", path, strerror(errno)));
- }
- if (on_error == OnError::log) {
+ if (log_on_error == LogOnError::yes) {
LOG("Failed to stat {}: {}", path, strerror(errno));
}
}
Stat
-Stat::stat(const std::string& path, OnError on_error)
+Stat::stat(const std::string& path, LogOnError log_on_error)
{
return Stat(
#ifdef _WIN32
::stat,
#endif
path,
- on_error);
+ log_on_error);
}
Stat
-Stat::lstat(const std::string& path, OnError on_error)
+Stat::lstat(const std::string& path, LogOnError log_on_error)
{
return Stat(
#ifdef _WIN32
::lstat,
#endif
path,
- on_error);
+ log_on_error);
}
class Stat
{
public:
- enum class OnError {
- // Ignore any error (including missing file) from the underlying stat call.
- // On error, error_number() will return the error number (AKA errno) and
- // the query functions will return 0 or false.
- ignore,
- // Like above but log an error message as well.
- log,
- // Throw Error on errors (including missing file).
- throw_error,
- };
+ enum class LogOnError { no, yes };
#if defined(_WIN32)
struct stat_t
// error_number() will return -1 and other accessors will return false or 0.
Stat();
- // Run stat(2).
- //
- // Arguments:
- // - path: Path to stat.
- // - on_error: What to do on errors (including missing file).
- static Stat stat(const std::string& path, OnError on_error = OnError::ignore);
-
- // Run lstat(2) if available, otherwise stat(2).
- //
- // Arguments:
- // - path: Path to (l)stat.
- // - on_error: What to do on errors (including missing file).
+ // Run stat(2) on `path`.
+ static Stat stat(const std::string& path,
+ LogOnError log_on_error = LogOnError::no);
+
+ // Run lstat(2) on `path` if available, otherwise stat(2).
static Stat lstat(const std::string& path,
- OnError on_error = OnError::ignore);
+ LogOnError log_on_error = LogOnError::no);
// Return true if the file could be (l)stat-ed (i.e., the file exists),
// otherwise false.
protected:
using StatFunction = int (*)(const char*, stat_t*);
- Stat(StatFunction stat_function, const std::string& path, OnError on_error);
+ Stat(StatFunction stat_function,
+ const std::string& path,
+ LogOnError log_on_error);
private:
std::string m_path;
}
#endif
- auto st = Stat::stat(path, Stat::OnError::log);
+ auto st = Stat::stat(path, Stat::LogOnError::yes);
if (!st) {
return false;
}
// hash pch.sum instead of pch when it exists
// to prevent hashing a very large .pch file every time
std::string pch_sum_path = FMT("{}.sum", path);
- if (Stat::stat(pch_sum_path, Stat::OnError::log)) {
+ if (Stat::stat(pch_sum_path, Stat::LogOnError::yes)) {
path = std::move(pch_sum_path);
using_pch_sum = true;
LOG("Using pch.sum file {}", path);
const bool added = ctx.manifest.add_result(
result_key, ctx.included_files, [&](const std::string& path) {
- auto stat = Stat::stat(path, Stat::OnError::log);
+ auto stat = Stat::stat(path, Stat::LogOnError::yes);
bool cache_time =
save_timestamp
&& ctx.time_of_compilation > std::max(stat.mtime(), stat.ctime());
} else {
std::string path = find_executable(ctx, compiler, ctx.orig_args[0]);
if (!path.empty()) {
- auto st = Stat::stat(path, Stat::OnError::log);
+ auto st = Stat::stat(path, Stat::LogOnError::yes);
TRY(hash_compiler(ctx, hash, st, ccbin, false));
}
}
const std::string compiler_path = args[0];
#endif
- auto st = Stat::stat(compiler_path, Stat::OnError::log);
+ auto st = Stat::stat(compiler_path, Stat::LogOnError::yes);
if (!st) {
return tl::unexpected(Statistic::could_not_find_compiler);
}
} else {
path = args[i].substr(eq_pos + 1);
}
- auto st = Stat::stat(path, Stat::OnError::log);
+ auto st = Stat::stat(path, Stat::LogOnError::yes);
if (st) {
// If given an explicit specs file, then hash that file, but don't
// include the path to it in the hash.
}
if (util::starts_with(args[i], "-fplugin=")) {
- auto st = Stat::stat(&args[i][9], Stat::OnError::log);
+ auto st = Stat::stat(&args[i][9], Stat::LogOnError::yes);
if (st) {
hash.hash_delimiter("plugin");
TRY(hash_compiler(ctx, hash, st, &args[i][9], false));
if (args[i] == "-Xclang" && i + 3 < args.size() && args[i + 1] == "-load"
&& args[i + 2] == "-Xclang") {
- auto st = Stat::stat(args[i + 3], Stat::OnError::log);
+ auto st = Stat::stat(args[i + 3], Stat::LogOnError::yes);
if (st) {
hash.hash_delimiter("plugin");
TRY(hash_compiler(ctx, hash, st, args[i + 3], false));
new_cache_file.write(
core::CacheEntry::serialize(header, cache_entry.payload()));
new_cache_file.commit();
- new_stat = Stat::lstat(stat.path(), Stat::OnError::log);
+ new_stat = Stat::lstat(stat.path(), Stat::LogOnError::yes);
}
// Restore mtime/atime to keep cache LRU cleanup working as expected:
const bool store_raw =
is_file_entry && should_store_raw_file(m_config, entry.file_type);
const uint64_t file_size =
- is_file_entry ? Stat::stat(std::get<std::string>(entry.data),
- Stat::OnError::throw_error)
- .size()
- : std::get<nonstd::span<const uint8_t>>(entry.data).size();
+ is_file_entry
+ ? Stat::stat(std::get<std::string>(entry.data), Stat::LogOnError::yes)
+ .size()
+ : std::get<nonstd::span<const uint8_t>>(entry.data).size();
LOG("Storing {} entry #{} {} ({} bytes){}",
store_raw ? "raw" : "embedded",
throw Error("Raw entry for non-local result");
}
const auto raw_file_path = (*m_get_raw_file_path)(file_number);
- const auto st = Stat::stat(raw_file_path, Stat::OnError::throw_error);
+ const auto st = Stat::stat(raw_file_path, Stat::LogOnError::yes);
+ if (!st) {
+ throw Error(
+ FMT("Failed to stat {}: {}", raw_file_path, strerror(st.error_number())));
+ }
if (st.size() != file_size) {
throw Error(FMT("Bad file size of {} (actual {} bytes, expected {} bytes)",
raw_file_path,
}
const auto raw_file_path =
m_ctx.storage.local.get_raw_file_path(*m_result_key, file_number);
- const auto st = Stat::stat(raw_file_path, Stat::OnError::throw_error);
+ const auto st = Stat::stat(raw_file_path, Stat::LogOnError::yes);
+ if (!st) {
+ throw Error(
+ FMT("Failed to stat {}: {}", raw_file_path, strerror(st.error_number())));
+ }
if (st.size() != file_size) {
throw core::Error(
FMT("Bad file size of {} (actual {} bytes, expected {} bytes)",
}
Statistics statistics(StatsLog(config.stats_log()).read());
const auto timestamp =
- Stat::stat(config.stats_log(), Stat::OnError::log).mtime();
+ Stat::stat(config.stats_log(), Stat::LogOnError::yes).mtime();
PRINT_RAW(
stdout,
statistics.format_human_readable(config, timestamp, verbosity, true));
increment_statistic(Statistic::local_storage_write);
- const auto new_stat = Stat::stat(cache_file.path, Stat::OnError::log);
+ const auto new_stat = Stat::stat(cache_file.path, Stat::LogOnError::yes);
if (!new_stat) {
return;
}
if (is_dir) {
return;
}
- const auto st = Stat::lstat(path, Stat::OnError::log);
+ const auto st = Stat::lstat(path, Stat::LogOnError::yes);
if (st && st.mtime() + k_tempdir_cleanup_interval < now) {
util::remove(path);
}
TEST_CASE("Named constructors")
{
CHECK(!Stat::stat("does_not_exist"));
- CHECK(!Stat::stat("does_not_exist", Stat::OnError::ignore));
- CHECK(!Stat::stat("does_not_exist", Stat::OnError::log));
- CHECK_THROWS_WITH(Stat::stat("does_not_exist", Stat::OnError::throw_error),
- "failed to stat does_not_exist: No such file or directory");
+ CHECK(!Stat::stat("does_not_exist", Stat::LogOnError::no));
+ CHECK(!Stat::stat("does_not_exist", Stat::LogOnError::yes));
}
TEST_CASE("Same i-node as")
SUBCASE("file lstat")
{
- auto stat = Stat::lstat("file", Stat::OnError::ignore);
+ auto stat = Stat::lstat("file", Stat::LogOnError::no);
CHECK(stat);
CHECK(stat.error_number() == 0);
CHECK(!stat.is_directory());
SUBCASE("file stat")
{
- auto stat = Stat::stat("file", Stat::OnError::ignore);
+ auto stat = Stat::stat("file", Stat::LogOnError::no);
CHECK(stat);
CHECK(stat.error_number() == 0);
CHECK(!stat.is_directory());
SUBCASE("symlink lstat")
{
- auto stat = Stat::lstat("symlink", Stat::OnError::ignore);
+ auto stat = Stat::lstat("symlink", Stat::LogOnError::no);
CHECK(stat);
CHECK(stat.error_number() == 0);
CHECK(!stat.is_directory());
SUBCASE("symlink stat")
{
- auto stat = Stat::stat("symlink", Stat::OnError::ignore);
+ auto stat = Stat::stat("symlink", Stat::LogOnError::no);
CHECK(stat);
CHECK(stat.error_number() == 0);
CHECK(!stat.is_directory());