diff --git a/include/dwarfs/util.h b/include/dwarfs/util.h index 2290381e..89072ecb 100644 --- a/include/dwarfs/util.h +++ b/include/dwarfs/util.h @@ -83,4 +83,6 @@ int get_current_umask(); void install_signal_handlers(); +std::tm safe_localtime(std::time_t t); + } // namespace dwarfs diff --git a/src/history.cpp b/src/history.cpp index a96390ec..5804e91d 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -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()))}, }; } diff --git a/src/reader/internal/metadata_v2.cpp b/src/reader/internal/metadata_v2.cpp index 3fe22c06..465aa5ad 100644 --- a/src/reader/internal/metadata_v2.cpp +++ b/src/reader/internal/metadata_v2.cpp @@ -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)) { diff --git a/src/util.cpp b/src/util.cpp index eca634a5..71140c10 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -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 diff --git a/test/tool_main_test.cpp b/test/tool_main_test.cpp index 2068d605..a13221c0 100644 --- a/test/tool_main_test.cpp +++ b/test/tool_main_test.cpp @@ -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 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) { diff --git a/tools/src/dwarfsck_main.cpp b/tools/src/dwarfsck_main.cpp index 5dc409a1..3d4aa04f 100644 --- a/tools/src/dwarfsck_main.cpp +++ b/tools/src/dwarfsck_main.cpp @@ -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"; }