+WVSTART 'meta --create/--extract'
+(
+ tmpdir="$(WVPASS wvmktempdir)" || exit $?
+ export BUP_DIR="$tmpdir/bup"
+ WVPASS setup-test-tree
+ WVPASS cd "$tmpdir"
+ WVPASS test-src-create-extract
+
+ # Test a top-level file (not dir).
+ WVPASS touch src-file
+ WVPASS bup meta -cf src-file.meta src-file
+ WVPASS mkdir dest
+ WVPASS cd dest
+ WVPASS bup meta -xf ../src-file.meta
+ WVPASS rm -r "$tmpdir"
+) || exit $?
+
+# Use the test tree to check bup save/restore metadata.
+WVSTART 'metadata save/restore (general)'
+(
+ tmpdir="$(WVPASS wvmktempdir)" || exit $?
+ export BUP_DIR="$tmpdir/bup"
+ WVPASS setup-test-tree
+ WVPASS cd "$tmpdir"
+ WVPASS test-src-save-restore
+
+ # Test a deeper subdir/ to make sure top-level non-dir metadata is
+ # restored correctly. We need at least one dir and one non-dir at
+ # the "top-level".
+ WVPASS test -d src/bin
+ WVPASS test -f src/bin/bup
+ WVPASS rm -rf "$BUP_DIR"
+ WVPASS bup init
+ WVPASS touch -t 201111111111 src-restore # Make sure the top won't match.
+ WVPASS bup index src
+ WVPASS bup save -t -n src src
+ WVPASS force-delete src-restore
+ WVPASS bup restore -C src-restore "/src/latest$(pwd)/src/lib/"
+ WVPASS touch -t 201211111111 src-restore # Make sure the top won't match.
+ # Check that the only difference is the top dir.
+ WVFAIL $TOP/t/compare-trees -c src/lib/ src-restore/ > tmp-compare-trees
+ WVPASSEQ $(cat tmp-compare-trees | wc -l) 2
+ WVPASS tail -n +2 tmp-compare-trees | WVPASS grep -qE '^\.d[^ ]+ \./$'
+ WVPASS rm -r "$tmpdir"
+) || exit $?
+
+# Test that we pull the index (not filesystem) metadata for any
+# unchanged files whenever we're saving other files in a given
+# directory.
+WVSTART 'metadata save/restore (using index metadata)'
+(
+ tmpdir="$(WVPASS wvmktempdir)" || exit $?
+ export BUP_DIR="$tmpdir/bup"
+ WVPASS setup-test-tree
+ WVPASS cd "$tmpdir"
+
+ # ...for now -- might be a problem with hardlink restores that was
+ # causing noise wrt this test.
+ WVPASS rm -rf src/hardlink*
+
+ # Pause here to keep the filesystem changes far enough away from
+ # the first index run that bup won't cap their index timestamps
+ # (see "bup help index" for more information). Without this
+ # sleep, the compare-trees test below "Bup should *not* pick up
+ # these metadata..." may fail.
+ WVPASS sleep 1
+
+ WVPASS rm -rf "$BUP_DIR"
+ WVPASS bup init
+ WVPASS bup index src
+ WVPASS bup save -t -n src src
+
+ WVPASS force-delete src-restore-1
+ WVPASS mkdir src-restore-1
+ WVPASS bup restore -C src-restore-1 "/src/latest$(pwd)/"
+ WVPASS test -d src-restore-1/src
+ WVPASS "$TOP/t/compare-trees" -c src/ src-restore-1/src/
+
+ WVPASS echo "blarg" > src/volatile/1
+ WVPASS cp -a src/volatile/1 src-restore-1/src/volatile/
+ WVPASS bup index src
+
+ # Bup should *not* pick up these metadata changes.
+ WVPASS touch src/volatile/2
+
+ WVPASS bup save -t -n src src
+
+ WVPASS force-delete src-restore-2
+ WVPASS mkdir src-restore-2
+ WVPASS bup restore -C src-restore-2 "/src/latest$(pwd)/"
+ WVPASS test -d src-restore-2/src
+ WVPASS "$TOP/t/compare-trees" -c src-restore-1/src/ src-restore-2/src/
+
+ WVPASS rm -r "$tmpdir"
+
+) || exit $?
+
+
+setup-hardlink-test()
+{
+ WVPASS rm -rf "$tmpdir/src" "$BUP_DIR"
+ WVPASS bup init
+ WVPASS mkdir "$tmpdir/src"
+}
+
+hardlink-test-run-restore()
+{
+ WVPASS force-delete src-restore
+ WVPASS mkdir src-restore
+ WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
+ WVPASS test -d src-restore/src
+}
+
+# Test hardlinks more carefully.
+WVSTART 'metadata save/restore (hardlinks)'
+(
+ tmpdir="$(WVPASS wvmktempdir)" || exit $?
+ export BUP_DIR="$tmpdir/bup"
+
+ WVPASS setup-hardlink-test
+ WVPASS cd "$tmpdir"
+
+ # Test trivial case - single hardlink.
+ (
+ WVPASS cd src
+ WVPASS touch hardlink-target
+ WVPASS ln hardlink-target hardlink-1
+ ) || exit $?
+ WVPASS bup index src
+ WVPASS bup save -t -n src src
+ WVPASS hardlink-test-run-restore
+ WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
+
+ # Test the case where the hardlink hasn't changed, but the tree
+ # needs to be saved again. i.e. the save-cmd.py "if hashvalid:"
+ # case.
+ (
+ WVPASS cd src
+ WVPASS echo whatever > something-new
+ ) || exit $?
+ WVPASS bup index src
+ WVPASS bup save -t -n src src
+ WVPASS hardlink-test-run-restore
+ WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
+
+ # Test hardlink changes between index runs.
+ #
+ WVPASS setup-hardlink-test
+ WVPASS cd src
+ WVPASS touch hardlink-target-a
+ WVPASS touch hardlink-target-b
+ WVPASS ln hardlink-target-a hardlink-b-1
+ WVPASS ln hardlink-target-a hardlink-a-1
+ WVPASS cd ..
+ WVPASS bup index -vv src
+ WVPASS rm src/hardlink-b-1
+ WVPASS ln src/hardlink-target-b src/hardlink-b-1
+ WVPASS bup index -vv src
+ WVPASS bup save -t -n src src
+ WVPASS hardlink-test-run-restore
+ WVPASS echo ./src/hardlink-a-1 > hardlink-sets.expected
+ WVPASS echo ./src/hardlink-target-a >> hardlink-sets.expected
+ WVPASS echo >> hardlink-sets.expected
+ WVPASS echo ./src/hardlink-b-1 >> hardlink-sets.expected
+ WVPASS echo ./src/hardlink-target-b >> hardlink-sets.expected
+ (WVPASS cd src-restore; WVPASS hardlink-sets .) > hardlink-sets.restored \
+ || exit $?
+ WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
+
+ # Test hardlink changes between index and save -- hardlink set [a
+ # b c d] changes to [a b] [c d]. At least right now bup should
+ # notice and recreate the latter.
+ WVPASS setup-hardlink-test
+ WVPASS cd "$tmpdir"/src
+ WVPASS touch a
+ WVPASS ln a b
+ WVPASS ln a c
+ WVPASS ln a d
+ WVPASS cd ..
+ WVPASS bup index -vv src
+ WVPASS rm src/c src/d
+ WVPASS touch src/c
+ WVPASS ln src/c src/d
+ WVPASS bup save -t -n src src
+ WVPASS hardlink-test-run-restore
+ WVPASS echo ./src/a > hardlink-sets.expected
+ WVPASS echo ./src/b >> hardlink-sets.expected
+ WVPASS echo >> hardlink-sets.expected
+ WVPASS echo ./src/c >> hardlink-sets.expected
+ WVPASS echo ./src/d >> hardlink-sets.expected
+ (WVPASS cd src-restore; WVPASS hardlink-sets .) > hardlink-sets.restored \
+ || exit $?
+ WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
+
+ # Test that we don't link outside restore tree.
+ WVPASS setup-hardlink-test
+ WVPASS cd "$tmpdir"
+ WVPASS mkdir src/a src/b
+ WVPASS touch src/a/1
+ WVPASS ln src/a/1 src/b/1
+ WVPASS bup index -vv src
+ WVPASS bup save -t -n src src
+ WVPASS force-delete src-restore
+ WVPASS mkdir src-restore
+ WVPASS bup restore -C src-restore "/src/latest$(pwd)/src/a/"
+ WVPASS test -e src-restore/1
+ WVPASS echo -n > hardlink-sets.expected
+ (WVPASS cd src-restore; WVPASS hardlink-sets .) > hardlink-sets.restored \
+ || exit $?
+ WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
+
+ # Test that we do link within separate sub-trees.
+ WVPASS setup-hardlink-test
+ WVPASS cd "$tmpdir"
+ WVPASS mkdir src/a src/b
+ WVPASS touch src/a/1
+ WVPASS ln src/a/1 src/b/1
+ WVPASS bup index -vv src/a src/b
+ WVPASS bup save -t -n src src/a src/b
+ WVPASS hardlink-test-run-restore
+ WVPASS echo ./src/a/1 > hardlink-sets.expected
+ WVPASS echo ./src/b/1 >> hardlink-sets.expected
+ (WVPASS cd src-restore; WVPASS hardlink-sets .) > hardlink-sets.restored \
+ || exit $?
+ WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
+
+ WVPASS rm -r "$tmpdir"
+
+) || exit $?
+
+WVSTART 'meta --edit'
+(
+ tmpdir="$(WVPASS wvmktempdir)" || exit $?
+ WVPASS cd "$tmpdir"
+ WVPASS mkdir src
+
+ WVPASS bup meta -cf src.meta src
+
+ WVPASS bup meta --edit --set-uid 0 src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^uid: 0'
+ WVPASS bup meta --edit --set-uid 1000 src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^uid: 1000'
+
+ WVPASS bup meta --edit --set-gid 0 src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^gid: 0'
+ WVPASS bup meta --edit --set-gid 1000 src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^gid: 1000'
+
+ WVPASS bup meta --edit --set-user foo src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^user: foo'
+ WVPASS bup meta --edit --set-user bar src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^user: bar'
+ WVPASS bup meta --edit --unset-user src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^user:'
+ WVPASS bup meta --edit --set-user bar --unset-user src.meta \
+ | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user:'
+ WVPASS bup meta --edit --unset-user --set-user bar src.meta \
+ | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user: bar'
+
+ WVPASS bup meta --edit --set-group foo src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^group: foo'
+ WVPASS bup meta --edit --set-group bar src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^group: bar'
+ WVPASS bup meta --edit --unset-group src.meta | WVPASS bup meta -tvvf - \
+ | WVPASS grep -qE '^group:'
+ WVPASS bup meta --edit --set-group bar --unset-group src.meta \
+ | WVPASS bup meta -tvvf - | WVPASS grep -qE '^group:'
+ WVPASS bup meta --edit --unset-group --set-group bar src.meta \
+ | WVPASS bup meta -tvvf - | grep -qE '^group: bar'
+
+ WVPASS rm -r "$tmpdir"
+
+) || exit $?
+
+WVSTART 'meta --no-recurse'
+(
+ tmpdir="$(WVPASS wvmktempdir)" || exit $?
+ WVPASS cd "$tmpdir"
+ WVPASS mkdir src
+ WVPASS mkdir src/foo
+ WVPASS touch src/foo/{1,2,3}
+ WVPASS bup meta -cf src.meta src
+ WVPASSEQ "$(LC_ALL=C; bup meta -tf src.meta | sort)" "src/
+src/foo/
+src/foo/1
+src/foo/2
+src/foo/3"
+ WVPASS bup meta --no-recurse -cf src.meta src
+ WVPASSEQ "$(LC_ALL=C; bup meta -tf src.meta | sort)" "src/"
+ WVPASS rm -r "$tmpdir"
+) || exit $?
+
+# Test ownership restoration (when not root or fakeroot).
+(
+ if [ "$root_status" != none ]; then
+ exit 0
+ fi
+
+ tmpdir="$(WVPASS wvmktempdir)" || exit $?
+
+ first_group="$(WVPASS python -c 'import os,grp; \
+ print grp.getgrgid(os.getgroups()[0])[0]')" || exit $?
+ last_group="$(python -c 'import os,grp; \
+ print grp.getgrgid(os.getgroups()[-1])[0]')" || exit $?
+ last_group_erx="$(escape-erx "$last_group")"
+
+ WVSTART 'metadata (restoration of ownership)'
+ WVPASS cd "$tmpdir"
+ WVPASS touch src
+ # Some systems always assign the parent dir group to new paths
+ # (sgid). Make sure the group is one we're in.
+ WVPASS chgrp -R "$first_group" src
+
+ WVPASS bup meta -cf src.meta src
+
+ WVPASS mkdir dest
+ WVPASS cd dest
+ # Make sure we don't change (or try to change) the user when not root.
+ WVPASS bup meta --edit --set-user root ../src.meta | WVPASS bup meta -x
+ WVPASS bup xstat src | WVPASS grep -qvE '^user: root'
+ WVPASS rm -rf src
+ WVPASS bup meta --edit --unset-user --set-uid 0 ../src.meta \
+ | WVPASS bup meta -x
+ WVPASS bup xstat src | WVPASS grep -qvE '^user: root'
+
+ # Make sure we can restore one of the user's groups.
+ WVPASS rm -rf src
+ WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
+ | WVPASS bup meta -x
+ WVPASS bup xstat src | WVPASS grep -qE "^group: $last_group_erx"
+
+ # Make sure we can restore one of the user's gids.
+ user_gids="$(id -G)" || exit $?
+ last_gid="$(echo ${user_gids/* /})" || exit $?
+ WVPASS rm -rf src
+ WVPASS bup meta --edit --unset-group --set-gid "$last_gid" ../src.meta \
+ | WVPASS bup meta -x
+ WVPASS bup xstat src | WVPASS grep -qE "^gid: $last_gid"
+
+ # Test --numeric-ids (gid).
+ WVPASS rm -rf src
+ current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:') || exit $?
+ WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
+ | WVPASS bup meta -x --numeric-ids
+ new_gidx=$(bup xstat src | grep -e '^gid:') || exit $?
+ WVPASSEQ "$current_gidx" "$new_gidx"
+
+ # Test that restoring an unknown user works.
+ unknown_user=$("$TOP"/t/unknown-owner --user) || exit $?
+ WVPASS rm -rf src
+ current_uidx=$(bup meta -tvvf ../src.meta | grep -e '^uid:') || exit $?
+ WVPASS bup meta --edit --set-user "$unknown_user" ../src.meta \
+ | WVPASS bup meta -x
+ new_uidx=$(bup xstat src | grep -e '^uid:') || exit $?
+ WVPASSEQ "$current_uidx" "$new_uidx"
+
+ # Test that restoring an unknown group works.
+ unknown_group=$("$TOP"/t/unknown-owner --group) || exit $?
+ WVPASS rm -rf src
+ current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:') || exit $?
+ WVPASS bup meta --edit --set-group "$unknown_group" ../src.meta \
+ | WVPASS bup meta -x
+ new_gidx=$(bup xstat src | grep -e '^gid:') || exit $?
+ WVPASSEQ "$current_gidx" "$new_gidx"
+
+ WVPASS rm -r "$tmpdir"
+
+) || exit $?
+
+# Test ownership restoration (when root or fakeroot).