From f050dd08f5e4b145f0365c28da7310f65322694d Mon Sep 17 00:00:00 2001 From: Cheng-Ling Lai Date: Tue, 17 Mar 2026 14:05:28 +0800 Subject: [PATCH] Reorganize CmdFileHash --- client/snbk/CmdFileHash.cc | 73 ++++++++++++++++++++++++-------------- client/snbk/CmdFileHash.h | 8 ++--- client/snbk/TheBigThing.cc | 9 ++--- 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/client/snbk/CmdFileHash.cc b/client/snbk/CmdFileHash.cc index a857c1b2..e8b67ffb 100644 --- a/client/snbk/CmdFileHash.cc +++ b/client/snbk/CmdFileHash.cc @@ -22,6 +22,7 @@ #include +#include #include #include #include @@ -36,23 +37,59 @@ namespace snapper CmdFileHash::CmdFileHash(const Shell& shell, const string& chksum_bin, - const string& path) + const string& path, bool allow_failure) : path(path) { SystemCmd::Args cmd_args = { chksum_bin, "--", path }; SystemCmd cmd(shellify(shell, cmd_args)); - if (cmd.retcode() != 0) + try { - y2err("command '" << cmd.cmd() << "' failed: " << cmd.retcode()); - for (const string& tmp : cmd.get_stdout()) - y2err(tmp); - for (const string& tmp : cmd.get_stderr()) - y2err(tmp); + if (cmd.retcode() != 0) + { + y2err("command '" << cmd.cmd() << "' failed: " << cmd.retcode()); + for (const string& tmp : cmd.get_stdout()) + y2err(tmp); + for (const string& tmp : cmd.get_stderr()) + y2err(tmp); + + SN_THROW(Exception(_("Failed to compute file hash."))); + } + else + { + // Check if the hash utility returns 1 line exactly + vector cmd_outputs = cmd.get_stdout(); + if (cmd_outputs.size() != 1) + { + y2err(sformat("Expected 1 line, but %lu lines were received from %s.", + cmd_outputs.size(), chksum_bin.c_str())); + SN_THROW(Exception(_("Unexpected output from the hash utility."))); + } + + // Parse the hash output + vector parts; + const string& line = cmd_outputs[0]; + boost::split(parts, line, boost::is_any_of(" "), + boost::token_compress_on); + if (parts.size() != 2) + { + y2err("Invalid hash string: " << line); + SN_THROW(Exception(_("Invalid hash output format."))); + } + + hash = parts[0]; + } } - else + catch (const Exception& e) { - parse(cmd.get_stdout()); + if (!allow_failure) + { + SN_THROW(e); + } + else + { + y2err(e); + } } y2mil(*this); @@ -61,24 +98,6 @@ namespace snapper const string& CmdFileHash::get_hash() const { return hash; } - void CmdFileHash::parse(const vector& lines) - { - for (const string& line : lines) - { - vector parts; - boost::split(parts, line, boost::is_any_of(" "), boost::token_compress_on); - if (parts.size() != 2) - { - y2err("Invalid hash string: " << line); - SN_THROW(Exception(_("Invalid hash output format."))); - } - - hash = parts[0]; - break; - } - } - - std::ostream& operator<<(std::ostream& s, const CmdFileHash& cmd_filehash) { s << "path: " << cmd_filehash.path << " hash: " << cmd_filehash.hash << '\n'; diff --git a/client/snbk/CmdFileHash.h b/client/snbk/CmdFileHash.h index 8325dbc0..0a6dacc7 100644 --- a/client/snbk/CmdFileHash.h +++ b/client/snbk/CmdFileHash.h @@ -34,13 +34,15 @@ namespace snapper /** * Find the hash of the file at the given path. - * If an error occurs, the hash is set to an empty string. + * If `allow_failure` is `true`, errors are ignored and the hash is set to an empty + * string. */ class CmdFileHash { public: - CmdFileHash(const Shell& shell, const string& chksum_bin, const string& path); + CmdFileHash(const Shell& shell, const string& chksum_bin, const string& path, + bool allow_failure); const string& get_hash() const; @@ -50,8 +52,6 @@ namespace snapper const string path; string hash; - - void parse(const std::vector& lines); }; diff --git a/client/snbk/TheBigThing.cc b/client/snbk/TheBigThing.cc index 4d20e5c6..5effad66 100644 --- a/client/snbk/TheBigThing.cc +++ b/client/snbk/TheBigThing.cc @@ -518,7 +518,8 @@ namespace snapper // Find the hash of info.xml CmdFileHash cmd_filehash(shell_source, SHA256SUM_BIN, - source_snapshot_dir(snapper, num) + "/info.xml"); + source_snapshot_dir(snapper, num) + "/info.xml", + false); the_big_thing.source_meta_hash = cmd_filehash.get_hash(); the_big_things.push_back(the_big_thing); @@ -618,9 +619,9 @@ namespace snapper it->target_creation_time = extra.get_creation_time(); // Find the hash of info.xml - CmdFileHash cmd_filehash(shell_target, backup_config.target_sha256sum_bin, - target_snapshot_dir(backup_config, num) + - "/info.xml"); + CmdFileHash cmd_filehash( + shell_target, backup_config.target_sha256sum_bin, + target_snapshot_dir(backup_config, num) + "/info.xml", true); it->target_meta_hash = cmd_filehash.get_hash(); if (it->source_state == TheBigThing::SourceState::READ_ONLY && -- 2.47.3