]> arthur.barton.de Git - bup.git/commitdiff
save: skip/balk if an entry changed type since indexing
authorJohannes Berg <johannes@sipsolutions.net>
Sat, 2 Jan 2021 19:58:44 +0000 (20:58 +0100)
committerRob Browning <rlb@defaultvalue.org>
Sat, 15 May 2021 18:57:24 +0000 (13:57 -0500)
If an entry changed file type (link, regular file, ...) since
indexing, then all kinds of weird things can happen. Skip the
item in such cases and record an error.

This also requires adjusting the test that actually provokes
a failure in metadata read - now we don't store the file at
all, so modify the test to account for that behaviour in the
check.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Reviewed-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
lib/bup/cmd/save.py
test/ext/test-save-errors

index e0897dd1bb51a6cbc922d4158fa0e0b438f0afea..2a142d3db425043d46aab802730f77c25741eda9 100755 (executable)
@@ -409,6 +409,29 @@ def main(argv):
             metalists[-1].append((sort_key, meta))
         else:
             id = None
+            hlink = find_hardlink_target(hlink_db, ent)
+            try:
+                meta = metadata.from_path(ent.name, hardlink_target=hlink,
+                                          normalized=True)
+            except (OSError, IOError) as e:
+                add_error(e)
+                lastskip_name = ent.name
+                continue
+            if stat.S_IFMT(ent.mode) != stat.S_IFMT(meta.mode):
+                # The mode changed since we indexed the file, this is bad.
+                # This can cause two issues:
+                # 1) We e.g. think the file is a regular file, but now it's
+                #    something else (a device, socket, FIFO or symlink, etc.)
+                #    and _read_ from it when we shouldn't.
+                # 2) We then record it as valid, but don't update the index
+                #    metadata, and on a subsequent save it has 'hashvalid'
+                #    but is recorded as the file type from the index, when
+                #    the content is something else ...
+                # Avoid all of these consistency issues by just skipping such
+                # things - it really ought to not happen anyway.
+                add_error("%s: mode changed since indexing, skipping." % path_msg(ent.name))
+                lastskip_name = ent.name
+                continue
             if stat.S_ISREG(ent.mode):
                 try:
                     with hashsplit.open_noatime(ent.name) as f:
@@ -441,14 +464,6 @@ def main(argv):
                 git_info = (mode, git_name, id)
                 shalists[-1].append(git_info)
                 sort_key = git.shalist_item_sort_key((ent.mode, file, id))
-                hlink = find_hardlink_target(hlink_db, ent)
-                try:
-                    meta = metadata.from_path(ent.name, hardlink_target=hlink,
-                                              normalized=True)
-                except (OSError, IOError) as e:
-                    add_error(e)
-                    lastskip_name = ent.name
-                    meta = metadata.Metadata()
                 metalists[-1].append((sort_key, meta))
 
         if exists and wasmissing:
index 78daeb3d01ef6cd98f5bec23df1eb2f5a89a5f97..3181f2719fe9df7ab3cdc9570ffe905a722f402f 100755 (executable)
@@ -56,8 +56,8 @@ for f in 1 2 3 4   6 7 8 9 ; do
     fi
 done
 # and ensure we actually failed, and the above script/hack didn't break
-if ! echo "$lsout" | grep "1970-01-01 00:00 5" ; then
-    WVFAIL echo unexpected date for file 5
+if echo "$lsout" | grep " 5$" ; then
+    WVFAIL echo unexpectedly stored data for file 5
 fi