refactor: introduce and use safe_localtime()

This commit is contained in:
Marcus Holland-Moritz 2025-05-13 13:35:56 +02:00
parent 4b277a0507
commit 7b0b1cdc0c
6 changed files with 40 additions and 27 deletions

View File

@ -83,4 +83,6 @@ int get_current_umask();
void install_signal_handlers();
std::tm safe_localtime(std::time_t t);
} // namespace dwarfs

View File

@ -37,6 +37,7 @@
#include <dwarfs/history.h>
#include <dwarfs/library_dependencies.h>
#include <dwarfs/malloc_byte_buffer.h>
#include <dwarfs/util.h>
#include <dwarfs/version.h>
#include <dwarfs/gen-cpp2/history_types.h>
@ -105,10 +106,9 @@ void history::dump(std::ostream& os) const {
for (auto const& histent : *history_->entries()) {
os << " " << fmt::format("{:>{}}:", i++, iwidth);
if (histent.timestamp().has_value()) {
os << " "
<< fmt::format("[{:%Y-%m-%d %H:%M:%S}]",
fmt::localtime(histent.timestamp().value()));
if (auto ts = histent.timestamp(); ts.has_value()) {
os << " [" << fmt::format("{:%F %T}", safe_localtime(ts.value()))
<< "]";
}
auto const& version = histent.version().value();
@ -172,11 +172,10 @@ nlohmann::json history::as_json() const {
}
}
if (histent.timestamp().has_value()) {
if (auto ts = histent.timestamp(); ts.has_value()) {
entry["timestamp"] = {
{"epoch", histent.timestamp().value()},
{"local", fmt::format("{:%Y-%m-%dT%H:%M:%S}",
fmt::localtime(histent.timestamp().value()))},
{"epoch", ts.value()},
{"local", fmt::format("%FT%T", safe_localtime(ts.value()))},
};
}

View File

@ -1335,8 +1335,7 @@ metadata_v2_data::info_as_json(fsinfo_options const& opts,
}
if (auto ts = meta_.create_timestamp()) {
info["created_on"] =
fmt::format("{:%Y-%m-%dT%H:%M:%S}", fmt::localtime(ts.value()));
info["created_on"] = fmt::format("{:%FT%T}", safe_localtime(ts.value()));
}
if (opts.features.has(fsinfo_feature::metadata_summary)) {
@ -1468,11 +1467,8 @@ void metadata_v2_data::dump(
}
if (auto ts = meta_.create_timestamp()) {
time_t tp = *ts;
std::string str(32, '\0');
str.resize(
std::strftime(str.data(), str.size(), "%F %T", std::localtime(&tp)));
os << "created on: " << str << "\n";
os << "created on: " << fmt::format("{:%F %T}", safe_localtime(*ts))
<< "\n";
}
if (opts.features.has(fsinfo_feature::metadata_summary)) {

View File

@ -556,4 +556,19 @@ void install_signal_handlers() {
#endif
}
std::tm safe_localtime(std::time_t t) {
std::tm buf{};
#ifdef _WIN32
if (auto r = ::localtime_s(&buf, &t); r != 0) {
DWARFS_THROW(runtime_error, fmt::format("localtime_s: error code {}", r));
}
#else
if (!::localtime_r(&t, &buf)) {
DWARFS_THROW(runtime_error,
fmt::format("localtime_r: error code {}", errno));
}
#endif
return buf;
}
} // namespace dwarfs

View File

@ -2631,16 +2631,17 @@ TEST(dwarfsck_test, list_files_verbose) {
auto num_lines = std::count(out.begin(), out.end(), '\n');
EXPECT_EQ(12, num_lines);
auto format_time = [](time_t t) {
return fmt::format("{:%F %H:%M}", safe_localtime(t));
};
std::vector<std::string> expected_re{
fmt::format("drwxrwxrwx\\s+1000/100\\s+8\\s+{:%Y-%m-%d %H:%M}\\s*\n",
fmt::localtime(2)),
fmt::format(
"-rw-------\\s+1337/ 0\\s+{:L}\\s+{:%Y-%m-%d %H:%M}\\s+baz.pl\n",
23456, fmt::localtime(8002)),
fmt::format("lrwxrwxrwx\\s+1000/100\\s+16\\s+{:%Y-%m-%d "
"%H:%M}\\s+somelink -> somedir/ipsum.py\n",
fmt::localtime(2002)),
fmt::format("drwxrwxrwx\\s+1000/100\\s+8\\s+{}\\s*\n", format_time(2)),
fmt::format("-rw-------\\s+1337/ 0\\s+{:L}\\s+{}\\s+baz.pl\n", 23456,
format_time(8002)),
fmt::format("lrwxrwxrwx\\s+1000/100\\s+16\\s+{}\\s+somelink -> "
"somedir/ipsum.py\n",
format_time(2002)),
};
for (auto const& str : expected_re) {

View File

@ -103,10 +103,10 @@ void do_list_files(reader::filesystem_v2& fs, iolayer const& iol,
auto st = fs.getattr(iv);
iol.out << fmt::format(
"{3} {4:{0}}/{5:{1}} {6:{2}L} {7:%Y-%m-%d %H:%M} {8}\n", uid_width,
gid_width, inode_size_width, iv.mode_string(), iv.getuid(),
iv.getgid(), st.size(), fmt::localtime(st.mtime()), name);
iol.out << fmt::format("{3} {4:{0}}/{5:{1}} {6:{2}L} {7:%F %H:%M} {8}\n",
uid_width, gid_width, inode_size_width,
iv.mode_string(), iv.getuid(), iv.getgid(),
st.size(), safe_localtime(st.mtime()), name);
} else if (!name.empty()) {
iol.out << name << "\n";
}