]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
Reorganize CmdFileHash 1104/head
authorCheng-Ling Lai <jameslai.tech@gmail.com>
Tue, 17 Mar 2026 06:05:28 +0000 (14:05 +0800)
committerCheng-Ling Lai <jameslai.tech@gmail.com>
Tue, 17 Mar 2026 06:18:16 +0000 (14:18 +0800)
client/snbk/CmdFileHash.cc
client/snbk/CmdFileHash.h
client/snbk/TheBigThing.cc

index a857c1b2f9cc15ce6b6033cb1f75f549d0ee0626..e8b67ffb1f64f2dd8dd8e999213f32c1f2b9c574 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <boost/algorithm/string.hpp>
 
+#include <snapper/AppUtil.h>
 #include <snapper/Exception.h>
 #include <snapper/LoggerImpl.h>
 #include <snapper/SystemCmd.h>
@@ -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<string> 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<string> 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<string>& lines)
-    {
-       for (const string& line : lines)
-       {
-           vector<string> 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';
index 8325dbc007ae0301336607324d837e50fe05b434..0a6dacc75aa768bc51a6b4e856f952d0c015c886 100644 (file)
@@ -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<string>& lines);
     };
 
 
index 4d20e5c6697bff5b508ecd02b4c91e3929b88d18..5effad66547284925122a9a348af032a5b037a6f 100644 (file)
@@ -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 &&