]> arthur.barton.de Git - bup.git/commitdiff
Fix path ownership restoration problems on Cygwin.
authorRob Browning <rlb@defaultvalue.org>
Sat, 14 Sep 2013 18:47:23 +0000 (13:47 -0500)
committerRob Browning <rlb@defaultvalue.org>
Mon, 16 Sep 2013 21:49:56 +0000 (16:49 -0500)
It turns out that Cygwin won't allow you to chown() a path to an
unknown uid or gid, even when "root".

For now, make that a deferred error on Cygwin, rework the tests to
avoid it when possible, and disable the tests (on Cygwin) that require
it.

For the record, it appears that tar doesn't normally hit this problem
on Cygwin because it uses "geteuid() == 0" to detect super-user
status, which won't be true in the normal case, even if the user is an
administrator.

Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Documentation/bup-restore.md
lib/bup/metadata.py
t/id-other-than [new file with mode: 0755]
t/some-owner [deleted file]
t/test-meta.sh

index ab98c00b9e402d054f3096efa9c895cad7a796f2..5208b30e3e5018ee7ddf802058c7e355f6926f0d 100644 (file)
@@ -56,7 +56,9 @@ metadata contains a user or group name that doesn't exist on the
 current system.  The use of user and group names can be disabled via
 `--numeric-ids` (which can be important when restoring a chroot, for
 example), and as a special case, a uid or gid of 0 will never be
-remapped by name.
+remapped by name.  Additionally, some systems don't allow setting a
+uid/gid that doesn't correspond with a known user/group.  On those
+systems, bup will log an error for each relevant path.
 
 Hardlinks will also be restored when possible, but at least currently,
 no links will be made to targets outside the restore tree, and if the
index 7f51cfd53300cc069985c1db8812aab2cefab626..81c234fa2e2dcec7123ffe64dc68e4b9a712d248 100644 (file)
@@ -394,6 +394,10 @@ class Metadata:
             except OSError, e:
                 if e.errno == errno.EPERM:
                     add_error('lchown: %s' %  e)
+                elif sys.platform.startswith('cygwin') \
+                   and e.errno == errno.EINVAL:
+                    add_error('lchown: unknown uid/gid (%d/%d) for %s'
+                              %  (uid, gid, path))
                 else:
                     raise
 
diff --git a/t/id-other-than b/t/id-other-than
new file mode 100755 (executable)
index 0000000..25e7fbf
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+import grp
+import pwd
+import sys
+
+def usage():
+    print >> sys.stderr, "Usage: id-other-than ID [ID ...]"
+
+if len(sys.argv) < 2:
+    usage()
+    sys.exit(1)
+
+def is_integer(x):
+    try:
+        int(x)
+        return True
+    except ValueError, e:
+        return False
+
+excluded_ids = frozenset(int(x) for x in sys.argv[2:] if is_integer(x))
+excluded_names = frozenset(x for x in sys.argv[2:] if not is_integer(x))
+
+if sys.argv[1] == '--user':
+    for x in pwd.getpwall():
+        if x.pw_name not in excluded_names and x.pw_uid not in excluded_ids:
+            print x.pw_name + ':' + str(x.pw_uid)
+            sys.exit(0)
+elif sys.argv[1] == '--group':
+    for x in grp.getgrall():
+        if x.gr_name not in excluded_names and x.gr_gid not in excluded_ids:
+            print x.gr_name + ':' + str(x.gr_gid)
+            sys.exit(0)
+else:
+    usage()
+    sys.exit(1)
diff --git a/t/some-owner b/t/some-owner
deleted file mode 100755 (executable)
index e200fae..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-
-import grp
-import pwd
-import sys
-
-def usage():
-    print >> sys.stderr, "Usage: some-owners (--user | --group)"
-
-if len(sys.argv) != 2:
-    usage()
-    sys.exit(1)
-
-if sys.argv[1] == '--user':
-    non_root_users = [x.pw_name for x in pwd.getpwall() if x.pw_name != 'root']
-    print non_root_users[0]
-elif sys.argv[1] == '--group':
-    non_root_groups = [x.gr_name for x in grp.getgrall() if x.gr_name != 'root']
-    print non_root_groups[0]
-else:
-    usage()
-    sys.exit(1)
index 1d7e467bafe2b243327dddb26256345ecef98901..6f28cd09169c9bd7a60039c67d7dd0019df6c2a7 100755 (executable)
@@ -15,6 +15,11 @@ hardlink-sets()
     "$TOP/t/hardlink-sets" "$@"
 }
 
+id-other-than()
+{
+    "$TOP/t/id-other-than" "$@"
+}
+
 # Very simple metadata tests -- create a test tree then check that bup
 # meta can reproduce the metadata correctly (according to bup xstat)
 # via create, extract, start-extract, and finish-extract.  The current
@@ -456,75 +461,96 @@ WVSTART 'meta --edit'
     chmod 700 dest # so we can't accidentally do something insecure
     cd dest
 
-    # Make sure we can restore a uid.
-    WVPASS bup meta --edit --unset-user --set-uid 42 ../src.meta \
+    other_uinfo="$(id-other-than --user "$(id -un)")"
+    other_user="${other_uinfo%%:*}"
+    other_uid="${other_uinfo##*:}"
+
+    other_ginfo="$(id-other-than --group "$(id -gn)")"
+    other_group="${other_ginfo%%:*}"
+    other_gid="${other_ginfo##*:}"
+
+    # Make sure we can restore a uid (must be in /etc/passwd b/c cygwin).
+    WVPASS bup meta --edit --unset-user --set-uid "$other_uid" ../src.meta \
         | WVPASS bup meta -x
-    WVPASS bup xstat src | WVPASS grep -qE '^uid: 42'
+    WVPASS bup xstat src | WVPASS grep -qE "^uid: $other_uid"
 
-    # Make sure we can restore a gid.
-    WVPASS bup meta --edit --unset-group --set-gid 42 ../src.meta \
+    # Make sure we can restore a gid (must be in /etc/group b/c cygwin).
+    WVPASS bup meta --edit --unset-group --set-gid "$other_gid" ../src.meta \
         | WVPASS bup meta -x
-    WVPASS bup xstat src | WVPASS grep -qE '^gid: 42'
+    WVPASS bup xstat src | WVPASS grep -qE "^gid: $other_gid"
+
+    other_uinfo2="$(id-other-than --user "$(id -un)" "$other_user")"
+    other_user2="${other_uinfo2%%:*}"
+    other_uid2="${other_uinfo2##*:}"
 
-    some_user=$("$TOP"/t/some-owner --user)
-    some_group=$("$TOP"/t/some-owner --group)
+    other_ginfo2="$(id-other-than --group "$(id -gn)" "$other_group")"
+    other_group2="${other_ginfo2%%:*}"
+    other_gid2="${other_ginfo2##*:}"
 
     # Try to restore a user (and see that user trumps uid when uid is not 0).
-    WVPASS bup meta --edit --set-uid 42 --set-user "$some_user" ../src.meta \
+    WVPASS bup meta --edit \
+        --set-uid "$other_uid2" --set-user "$some_user" ../src.meta \
         | WVPASS bup meta -x
     WVPASS bup xstat src | WVPASS grep -qE "^user: $some_user"
 
     # Try to restore a group (and see that group trumps gid when gid is not 0).
-    WVPASS bup meta --edit --set-gid 42 --set-group "$some_group" ../src.meta \
+    WVPASS bup meta --edit \
+        --set-gid "$other_gid2" --set-group "$some_group" ../src.meta \
         | WVPASS bup meta -x
     WVPASS bup xstat src | WVPASS grep -qE "^group: $some_user"
 
-    # Make sure a uid of 0 trumps a non-root user.
-    WVPASS bup meta --edit --set-user "$some_user" ../src.meta \
-        | WVPASS bup meta -x
-    WVPASS bup xstat src | WVPASS grep -qvE "^user: $some_user"
-    WVPASS bup xstat src | WVPASS grep -qE "^uid: 0"
-
-    # Make sure a gid of 0 trumps a non-root group.
-    WVPASS bup meta --edit --set-group "$some_user" ../src.meta \
-        | WVPASS bup meta -x
-    WVPASS bup xstat src | WVPASS grep -qvE "^group: $some_group"
-    WVPASS bup xstat src | WVPASS grep -qE "^gid: 0"
+    # Test --numeric-ids (uid).  Note the name 'root' is not handled
+    # specially, so we use that here as the test user name.  We assume
+    # that the root user's uid is never 42.
+    rm -rf src
+    WVPASS bup meta --edit --set-user root --set-uid "$other_uid" ../src.meta \
+        | WVPASS bup meta -x --numeric-ids
+    new_uidx=$(bup xstat src | grep -e '^uid:')
+    WVPASSEQ "$new_uidx" "uid: $other_uid"
 
     # Test --numeric-ids (gid).  Note the name 'root' is not handled
     # specially, so we use that here as the test group name.  We
     # assume that the root group's gid is never 42.
     rm -rf src
-    WVPASS bup meta --edit --set-group root --set-gid 42 ../src.meta \
+    WVPASS bup meta --edit --set-group root --set-gid "$other_gid" ../src.meta \
         | WVPASS bup meta -x --numeric-ids
     new_gidx=$(bup xstat src | grep -e '^gid:')
-    WVPASSEQ "$new_gidx" 'gid: 42'
-
-    # Test --numeric-ids (uid).  Note the name 'root' is not handled
-    # specially, so we use that here as the test user name.  We assume
-    # that the root user's uid is never 42.
-    rm -rf src
-    WVPASS bup meta --edit --set-user root --set-uid 42 ../src.meta \
-        | WVPASS bup meta -x --numeric-ids
-    new_uidx=$(bup xstat src | grep -e '^uid:')
-    WVPASSEQ "$new_uidx" 'uid: 42'
+    WVPASSEQ "$new_gidx" "gid: $other_gid"
 
     # Test that restoring an unknown user works.
     unknown_user=$("$TOP"/t/unknown-owners --user)
     rm -rf src
-    WVPASS bup meta --edit --set-uid 42 --set-user "$unknown_user" ../src.meta \
+    WVPASS bup meta --edit \
+        --set-uid "$other_uid" --set-user "$unknown_user" ../src.meta \
         | WVPASS bup meta -x
     new_uidx=$(bup xstat src | grep -e '^uid:')
-    WVPASSEQ "$new_uidx" 'uid: 42'
+    WVPASSEQ "$new_uidx" "uid: $other_uid"
 
     # Test that restoring an unknown group works.
     unknown_group=$("$TOP"/t/unknown-owners --group)
     rm -rf src
     WVPASS bup meta --edit \
-        --set-gid 42 --set-group "$unknown_group" ../src.meta \
+        --set-gid "$other_gid" --set-group "$unknown_group" ../src.meta \
         | WVPASS bup meta -x
     new_gidx=$(bup xstat src | grep -e '^gid:')
-    WVPASSEQ "$new_gidx" 'gid: 42'
+    WVPASSEQ "$new_gidx" "gid: $other_gid"
+
+    if ! [[ $(uname) =~ CYGWIN ]]; then
+        # For now, skip these on Cygwin because it doesn't allow
+        # restoring an unknown uid/gid.
+
+        # Make sure a uid of 0 trumps a non-root user.
+        WVPASS bup meta --edit --set-user "$some_user" ../src.meta \
+            | WVPASS bup meta -x
+        WVPASS bup xstat src | WVPASS grep -qvE "^user: $some_user"
+        WVPASS bup xstat src | WVPASS grep -qE "^uid: 0"
+
+        # Make sure a gid of 0 trumps a non-root group.
+        WVPASS bup meta --edit --set-group "$some_user" ../src.meta \
+            | WVPASS bup meta -x
+        WVPASS bup xstat src | WVPASS grep -qvE "^group: $some_group"
+        WVPASS bup xstat src | WVPASS grep -qE "^gid: 0"
+    fi
 )
 
 # Root-only tests that require an FS with all the trimmings: ACLs,