]> arthur.barton.de Git - bup.git/blob - t/test-meta.sh
meta-cmd.py: actually respond to recursion options.
[bup.git] / t / test-meta.sh
1 #!/usr/bin/env bash
2 . wvtest.sh
3 . t/lib.sh
4
5 TOP="$(pwd)"
6 export BUP_DIR="$TOP/buptest.tmp"
7
8 bup()
9 {
10     "$TOP/bup" "$@"
11 }
12
13 hardlink-sets()
14 {
15     "$TOP/t/hardlink-sets" "$@"
16 }
17
18 id-other-than()
19 {
20     "$TOP/t/id-other-than" "$@"
21 }
22
23 # Very simple metadata tests -- create a test tree then check that bup
24 # meta can reproduce the metadata correctly (according to bup xstat)
25 # via create, extract, start-extract, and finish-extract.  The current
26 # tests are crude, and this does not fully test devices, varying
27 # users/groups, acls, attrs, etc.
28
29 genstat()
30 {
31     (
32         export PATH="$TOP:$PATH" # pick up bup
33         # Skip atime (test elsewhere) to avoid the observer effect.
34         find . | sort | xargs bup xstat --exclude-fields ctime,atime,size
35     )
36 }
37
38 test-src-create-extract()
39 {
40     # Test bup meta create/extract for ./src -> ./src-restore.
41     # Also writes to ./src-stat and ./src-restore-stat.
42     (
43         (cd src && WVPASS genstat) > src-stat
44         WVPASS bup meta --create --recurse --file src.meta src
45         # Test extract.
46         force-delete src-restore
47         mkdir src-restore
48         cd src-restore
49         WVPASS bup meta --extract --file ../src.meta
50         WVPASS test -d src
51         (cd src && genstat >../../src-restore-stat) || WVFAIL
52         WVPASS diff -U5 ../src-stat ../src-restore-stat
53         # Test start/finish extract.
54         force-delete src
55         WVPASS bup meta --start-extract --file ../src.meta
56         WVPASS test -d src
57         WVPASS bup meta --finish-extract --file ../src.meta
58         (cd src && genstat >../../src-restore-stat) || WVFAIL
59         WVPASS diff -U5 ../src-stat ../src-restore-stat
60     )
61 }
62
63 test-src-save-restore()
64 {
65     # Test bup save/restore metadata for ./src -> ./src-restore.  Also
66     # writes to ./src.bup.  Note that for now this just tests the
67     # restore below src/, in order to avoid having to worry about
68     # operations that require root (like chown /home).
69     (
70         set -x
71         rm -rf src.bup
72         mkdir src.bup
73         export BUP_DIR=$(pwd)/src.bup
74         WVPASS bup init
75         WVPASS bup index src
76         WVPASS bup save -t -n src src
77         # Test extract.
78         force-delete src-restore
79         mkdir src-restore
80         WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
81         WVPASS test -d src-restore/src
82         WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
83         rm -rf src.bup
84         set +x
85     )
86 }
87
88 universal-cleanup()
89 {
90     if [ $(t/root-status) != root ]; then return 0; fi
91     cd "$TOP"
92     umount "$TOP/bupmeta.tmp/testfs" || true
93     umount "$TOP/bupmeta.tmp/testfs-limited" || true
94 }
95
96 universal-cleanup
97 trap universal-cleanup EXIT
98
99 setup-test-tree()
100 (
101     set -e
102     force-delete "$BUP_DIR"
103     force-delete "$TOP/bupmeta.tmp"
104     mkdir -p "$TOP/bupmeta.tmp/src"
105     cp -pPR Documentation cmd lib t "$TOP/bupmeta.tmp"/src
106
107     # Add some hard links for the general tests.
108     (
109         cd "$TOP/bupmeta.tmp"/src
110         touch hardlink-target
111         ln hardlink-target hardlink-1
112         ln hardlink-target hardlink-2
113         ln hardlink-target hardlink-3
114     )
115
116     # Add some trivial files for the index, modify, save tests.
117     (
118         cd "$TOP/bupmeta.tmp"/src
119         mkdir volatile
120         touch volatile/{1,2,3}
121     )
122
123     # Regression test for metadata sort order.  Previously, these two
124     # entries would sort in the wrong order because the metadata
125     # entries were being sorted by mangled name, but the index isn't.
126     dd if=/dev/zero of="$TOP/bupmeta.tmp"/src/foo bs=1k count=33
127     touch -t 201111111111 "$TOP/bupmeta.tmp"/src/foo
128     touch -t 201112121111 "$TOP/bupmeta.tmp"/src/foo-bar
129
130     t/mksock "$TOP/bupmeta.tmp/src/test-socket" || true
131 ) || WVFAIL
132
133 # Use the test tree to check bup meta.
134 WVSTART 'meta --create/--extract'
135 (
136     setup-test-tree
137     cd "$TOP/bupmeta.tmp"
138     test-src-create-extract
139
140     # Test a top-level file (not dir).
141     touch src-file
142     WVPASS bup meta -cf src-file.meta src-file
143     mkdir dest
144     cd dest
145     WVPASS bup meta -xf ../src-file.meta
146 )
147
148 # Use the test tree to check bup save/restore metadata.
149 WVSTART 'metadata save/restore (general)'
150 (
151     setup-test-tree
152     cd "$TOP/bupmeta.tmp"
153     test-src-save-restore
154
155     # Test a deeper subdir/ to make sure top-level non-dir metadata is
156     # restored correctly.  We need at least one dir and one non-dir at
157     # the "top-level".
158     WVPASS test -f src/lib/__init__.py
159     WVPASS test -d src/lib/bup
160     rm -rf src.bup
161     mkdir src.bup
162     export BUP_DIR=$(pwd)/src.bup
163     WVPASS bup init
164     touch -t 201111111111 src-restore # Make sure the top won't match.
165     WVPASS bup index src
166     WVPASS bup save -t -n src src
167     force-delete src-restore
168     WVPASS bup restore -C src-restore "/src/latest$(pwd)/src/lib/"
169     touch -t 201211111111 src-restore # Make sure the top won't match.
170     # Check that the only difference is the top dir.
171     $TOP/t/compare-trees -c src/lib/ src-restore/ > tmp-compare-trees
172     WVPASSEQ $(cat tmp-compare-trees | wc -l) 2
173     tail -n +2 tmp-compare-trees | WVPASS grep -qE '^\.d[^ ]+ \./$'
174 ) || WVFAIL
175
176 # Test that we pull the index (not filesystem) metadata for any
177 # unchanged files whenever we're saving other files in a given
178 # directory.
179 WVSTART 'metadata save/restore (using index metadata)'
180 (
181     setup-test-tree
182     cd "$TOP/bupmeta.tmp"
183
184     # ...for now -- might be a problem with hardlink restores that was
185     # causing noise wrt this test.
186     rm -rf src/hardlink*
187
188     # Pause here to keep the filesystem changes far enough away from
189     # the first index run that bup won't cap their index timestamps
190     # (see "bup help index" for more information).  Without this
191     # sleep, the compare-trees test below "Bup should *not* pick up
192     # these metadata..." may fail.
193     sleep 1
194
195     set -x
196     rm -rf src.bup
197     mkdir src.bup
198     export BUP_DIR=$(pwd)/src.bup
199     WVPASS bup init
200     WVPASS bup index src
201     WVPASS bup save -t -n src src
202
203     force-delete src-restore-1
204     mkdir src-restore-1
205     WVPASS bup restore -C src-restore-1 "/src/latest$(pwd)/"
206     WVPASS test -d src-restore-1/src
207     WVPASS "$TOP/t/compare-trees" -c src/ src-restore-1/src/
208
209     echo "blarg" > src/volatile/1
210     cp -a src/volatile/1 src-restore-1/src/volatile/
211     WVPASS bup index src
212
213     # Bup should *not* pick up these metadata changes.
214     touch src/volatile/2
215
216     WVPASS bup save -t -n src src
217
218     force-delete src-restore-2
219     mkdir src-restore-2
220     WVPASS bup restore -C src-restore-2 "/src/latest$(pwd)/"
221     WVPASS test -d src-restore-2/src
222     WVPASS "$TOP/t/compare-trees" -c src-restore-1/src/ src-restore-2/src/
223
224     rm -rf src.bup
225     set +x
226 )
227
228 setup-hardlink-test()
229 {
230     (
231         cd "$TOP/bupmeta.tmp"
232         rm -rf src src.bup
233         mkdir src src.bup
234         WVPASS bup init
235     )
236 }
237
238 hardlink-test-run-restore()
239 {
240     force-delete src-restore
241     mkdir src-restore
242     WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
243     WVPASS test -d src-restore/src
244 }
245
246 # Test hardlinks more carefully.
247 WVSTART 'metadata save/restore (hardlinks)'
248 (
249     set -e
250     set -x
251     export BUP_DIR="$TOP/bupmeta.tmp/src.bup"
252     force-delete "$TOP/bupmeta.tmp"
253     mkdir -p "$TOP/bupmeta.tmp"
254
255     cd "$TOP/bupmeta.tmp"
256
257     # Test trivial case - single hardlink.
258     setup-hardlink-test
259     (
260         cd "$TOP/bupmeta.tmp"/src
261         touch hardlink-target
262         ln hardlink-target hardlink-1
263     )
264     WVPASS bup index src
265     WVPASS bup save -t -n src src
266     hardlink-test-run-restore
267     WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
268
269     # Test the case where the hardlink hasn't changed, but the tree
270     # needs to be saved again. i.e. the save-cmd.py "if hashvalid:"
271     # case.
272     (
273         cd "$TOP/bupmeta.tmp"/src
274         echo whatever > something-new
275     )
276     WVPASS bup index src
277     WVPASS bup save -t -n src src
278     hardlink-test-run-restore
279     WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
280
281     # Test hardlink changes between index runs.
282     #
283     setup-hardlink-test
284     cd "$TOP/bupmeta.tmp"/src
285     touch hardlink-target-a
286     touch hardlink-target-b
287     ln hardlink-target-a hardlink-b-1
288     ln hardlink-target-a hardlink-a-1
289     cd ..
290     WVPASS bup index -vv src
291     rm src/hardlink-b-1
292     ln src/hardlink-target-b src/hardlink-b-1
293     WVPASS bup index -vv src
294     WVPASS bup save -t -n src src
295     hardlink-test-run-restore
296     echo ./src/hardlink-a-1 > hardlink-sets.expected
297     echo ./src/hardlink-target-a >> hardlink-sets.expected
298     echo >> hardlink-sets.expected
299     echo ./src/hardlink-b-1 >> hardlink-sets.expected
300     echo ./src/hardlink-target-b >> hardlink-sets.expected
301     (cd src-restore && hardlink-sets .) > hardlink-sets.restored
302     WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
303
304     # Test hardlink changes between index and save -- hardlink set [a
305     # b c d] changes to [a b] [c d].  At least right now bup should
306     # notice and recreate the latter.
307     setup-hardlink-test
308     cd "$TOP/bupmeta.tmp"/src
309     touch a
310     ln a b
311     ln a c
312     ln a d
313     cd ..
314     WVPASS bup index -vv src
315     rm src/c src/d
316     touch src/c
317     ln src/c src/d
318     WVPASS bup save -t -n src src
319     hardlink-test-run-restore
320     echo ./src/a > hardlink-sets.expected
321     echo ./src/b >> hardlink-sets.expected
322     echo >> hardlink-sets.expected
323     echo ./src/c >> hardlink-sets.expected
324     echo ./src/d >> hardlink-sets.expected
325     (cd src-restore && hardlink-sets .) > hardlink-sets.restored
326     WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
327
328     # Test that we don't link outside restore tree.
329     setup-hardlink-test
330     cd "$TOP/bupmeta.tmp"
331     mkdir src/a src/b
332     touch src/a/1
333     ln src/a/1 src/b/1
334     WVPASS bup index -vv src
335     WVPASS bup save -t -n src src
336     force-delete src-restore
337     mkdir src-restore
338     WVPASS bup restore -C src-restore "/src/latest$(pwd)/src/a/"
339     WVPASS test -e src-restore/1
340     echo -n > hardlink-sets.expected
341     (cd src-restore && hardlink-sets .) > hardlink-sets.restored
342     WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
343
344     # Test that we do link within separate sub-trees.
345     setup-hardlink-test
346     cd "$TOP/bupmeta.tmp"
347     mkdir src/a src/b
348     touch src/a/1
349     ln src/a/1 src/b/1
350     WVPASS bup index -vv src/a src/b
351     WVPASS bup save -t -n src src/a src/b
352     hardlink-test-run-restore
353     echo ./src/a/1 > hardlink-sets.expected
354     echo ./src/b/1 >> hardlink-sets.expected
355     (cd src-restore && hardlink-sets .) > hardlink-sets.restored
356     WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
357 )
358
359 WVSTART 'meta --edit'
360 (
361     force-delete "$TOP/bupmeta.tmp"
362     mkdir "$TOP/bupmeta.tmp"
363     cd "$TOP/bupmeta.tmp"
364     mkdir src
365     WVPASS bup meta -cf src.meta src
366
367     WVPASS bup meta --edit --set-uid 0 src.meta | WVPASS bup meta -tvvf - \
368         | WVPASS grep -qE '^uid: 0'
369     WVPASS bup meta --edit --set-uid 1000 src.meta | WVPASS bup meta -tvvf - \
370         | WVPASS grep -qE '^uid: 1000'
371
372     WVPASS bup meta --edit --set-gid 0 src.meta | WVPASS bup meta -tvvf - \
373         | WVPASS grep -qE '^gid: 0'
374     WVPASS bup meta --edit --set-gid 1000 src.meta | WVPASS bup meta -tvvf - \
375         | WVPASS grep -qE '^gid: 1000'
376
377     WVPASS bup meta --edit --set-user foo src.meta | WVPASS bup meta -tvvf - \
378         | WVPASS grep -qE '^user: foo'
379     WVPASS bup meta --edit --set-user bar src.meta | WVPASS bup meta -tvvf - \
380         | WVPASS grep -qE '^user: bar'
381     WVPASS bup meta --edit --unset-user src.meta | WVPASS bup meta -tvvf - \
382         | WVPASS grep -qE '^user:'
383     WVPASS bup meta --edit --set-user bar --unset-user src.meta \
384         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user:'
385     WVPASS bup meta --edit --unset-user --set-user bar src.meta \
386         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user: bar'
387
388     WVPASS bup meta --edit --set-group foo src.meta | WVPASS bup meta -tvvf - \
389         | WVPASS grep -qE '^group: foo'
390     WVPASS bup meta --edit --set-group bar src.meta | WVPASS bup meta -tvvf - \
391         | WVPASS grep -qE '^group: bar'
392     WVPASS bup meta --edit --unset-group src.meta | WVPASS bup meta -tvvf - \
393         | WVPASS grep -qE '^group:'
394     WVPASS bup meta --edit --set-group bar --unset-group src.meta \
395         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^group:'
396     WVPASS bup meta --edit --unset-group --set-group bar src.meta \
397         | WVPASS bup meta -tvvf - | grep -qE '^group: bar'
398 )
399
400 WVSTART 'meta --no-recurse'
401 (
402     set +e
403     WVPASS force-delete "$TOP/bupmeta.tmp"
404     WVPASS mkdir "$TOP/bupmeta.tmp"
405     WVPASS cd "$TOP/bupmeta.tmp"
406     WVPASS mkdir src
407     WVPASS mkdir src/foo
408     WVPASS touch src/foo/{1,2,3}
409     WVPASS bup meta -cf src.meta src
410     WVPASSEQ "$(LC_ALL=C; bup meta -tf src.meta | sort)" "src/
411 src/foo/
412 src/foo/1
413 src/foo/2
414 src/foo/3"
415     WVPASS bup meta --no-recurse -cf src.meta src
416     WVPASSEQ "$(LC_ALL=C; bup meta -tf src.meta | sort)" "src/"
417 ) || exit $?
418
419 # Test ownership restoration (when not root or fakeroot).
420 (
421     if [ $(t/root-status) != none ]; then
422         exit 0
423     fi
424
425     WVSTART 'metadata (restoration of ownership)'
426     force-delete "$TOP/bupmeta.tmp"
427     mkdir "$TOP/bupmeta.tmp"
428     cd "$TOP/bupmeta.tmp"
429     touch src
430     WVPASS bup meta -cf src.meta src
431
432     mkdir dest
433     cd dest
434     # Make sure we don't change (or try to change) the user when not root.
435     WVPASS bup meta --edit --set-user root ../src.meta | WVPASS bup meta -x
436     WVPASS bup xstat src | WVPASS grep -qvE '^user: root'
437     rm -rf src
438     WVPASS bup meta --edit --unset-user --set-uid 0 ../src.meta \
439         | WVPASS bup meta -x
440     WVPASS bup xstat src | grep -qvE '^user: root'
441
442     # Make sure we can restore one of the user's groups.
443     last_group="$(python -c 'import os,grp; \
444       print grp.getgrgid(os.getgroups()[0])[0]')"
445     rm -rf src
446     WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
447         | WVPASS bup meta -x
448     WVPASS bup xstat src | WVPASS grep -qE "^group: $last_group"
449
450     # Make sure we can restore one of the user's gids.
451     user_gids="$(id -G)"
452     last_gid="$(echo ${user_gids/* /})"
453     rm -rf src
454     WVPASS bup meta --edit --unset-group --set-gid "$last_gid" ../src.meta \
455         | WVPASS bup meta -x
456     WVPASS bup xstat src | WVPASS grep -qE "^gid: $last_gid"
457
458     # Test --numeric-ids (gid).
459     rm -rf src
460     current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
461     WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
462         | WVPASS bup meta -x --numeric-ids
463     new_gidx=$(bup xstat src | grep -e '^gid:')
464     WVPASSEQ "$current_gidx" "$new_gidx"
465
466     # Test that restoring an unknown user works.
467     unknown_user=$("$TOP"/t/unknown-owner --user)
468     rm -rf src
469     current_uidx=$(bup meta -tvvf ../src.meta | grep -e '^uid:')
470     WVPASS bup meta --edit --set-user "$unknown_user" ../src.meta \
471         | WVPASS bup meta -x
472     new_uidx=$(bup xstat src | grep -e '^uid:')
473     WVPASSEQ "$current_uidx" "$new_uidx"
474
475     # Test that restoring an unknown group works.
476     unknown_group=$("$TOP"/t/unknown-owner --group)
477     rm -rf src
478     current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
479     WVPASS bup meta --edit --set-group "$unknown_group" ../src.meta \
480         | WVPASS bup meta -x
481     new_gidx=$(bup xstat src | grep -e '^gid:')
482     WVPASSEQ "$current_gidx" "$new_gidx"
483 )
484
485 # Test ownership restoration (when root or fakeroot).
486 (
487     if [ $(t/root-status) == none ]; then
488         exit 0
489     fi
490
491     WVSTART 'metadata (restoration of ownership as root)'
492     force-delete "$TOP/bupmeta.tmp"
493     mkdir "$TOP/bupmeta.tmp"
494     cd "$TOP/bupmeta.tmp"
495     touch src
496     chown 0:0 src # In case the parent dir is sgid, etc.
497     WVPASS bup meta -cf src.meta src
498
499     mkdir dest
500     chmod 700 dest # so we can't accidentally do something insecure
501     cd dest
502
503     other_uinfo="$(id-other-than --user "$(id -un)")"
504     other_user="${other_uinfo%%:*}"
505     other_uid="${other_uinfo##*:}"
506
507     other_ginfo="$(id-other-than --group "$(id -gn)")"
508     other_group="${other_ginfo%%:*}"
509     other_gid="${other_ginfo##*:}"
510
511     # Make sure we can restore a uid (must be in /etc/passwd b/c cygwin).
512     WVPASS bup meta --edit --unset-user --set-uid "$other_uid" ../src.meta \
513         | WVPASS bup meta -x
514     WVPASS bup xstat src | WVPASS grep -qE "^uid: $other_uid"
515
516     # Make sure we can restore a gid (must be in /etc/group b/c cygwin).
517     WVPASS bup meta --edit --unset-group --set-gid "$other_gid" ../src.meta \
518         | WVPASS bup meta -x
519     WVPASS bup xstat src | WVPASS grep -qE "^gid: $other_gid"
520
521     other_uinfo2="$(id-other-than --user "$(id -un)" "$other_user")"
522     other_user2="${other_uinfo2%%:*}"
523     other_uid2="${other_uinfo2##*:}"
524
525     other_ginfo2="$(id-other-than --group "$(id -gn)" "$other_group")"
526     other_group2="${other_ginfo2%%:*}"
527     other_gid2="${other_ginfo2##*:}"
528
529     # Try to restore a user (and see that user trumps uid when uid is not 0).
530     WVPASS bup meta --edit \
531         --set-uid "$other_uid2" --set-user "$some_user" ../src.meta \
532         | WVPASS bup meta -x
533     WVPASS bup xstat src | WVPASS grep -qE "^user: $some_user"
534
535     # Try to restore a group (and see that group trumps gid when gid is not 0).
536     WVPASS bup meta --edit \
537         --set-gid "$other_gid2" --set-group "$some_group" ../src.meta \
538         | WVPASS bup meta -x
539     WVPASS bup xstat src | WVPASS grep -qE "^group: $some_user"
540
541     # Test --numeric-ids (uid).  Note the name 'root' is not handled
542     # specially, so we use that here as the test user name.  We assume
543     # that the root user's uid is never 42.
544     rm -rf src
545     WVPASS bup meta --edit --set-user root --set-uid "$other_uid" ../src.meta \
546         | WVPASS bup meta -x --numeric-ids
547     new_uidx=$(bup xstat src | grep -e '^uid:')
548     WVPASSEQ "$new_uidx" "uid: $other_uid"
549
550     # Test --numeric-ids (gid).  Note the name 'root' is not handled
551     # specially, so we use that here as the test group name.  We
552     # assume that the root group's gid is never 42.
553     rm -rf src
554     WVPASS bup meta --edit --set-group root --set-gid "$other_gid" ../src.meta \
555         | WVPASS bup meta -x --numeric-ids
556     new_gidx=$(bup xstat src | grep -e '^gid:')
557     WVPASSEQ "$new_gidx" "gid: $other_gid"
558
559     # Test that restoring an unknown user works.
560     unknown_user=$("$TOP"/t/unknown-owners --user)
561     rm -rf src
562     WVPASS bup meta --edit \
563         --set-uid "$other_uid" --set-user "$unknown_user" ../src.meta \
564         | WVPASS bup meta -x
565     new_uidx=$(bup xstat src | grep -e '^uid:')
566     WVPASSEQ "$new_uidx" "uid: $other_uid"
567
568     # Test that restoring an unknown group works.
569     unknown_group=$("$TOP"/t/unknown-owners --group)
570     rm -rf src
571     WVPASS bup meta --edit \
572         --set-gid "$other_gid" --set-group "$unknown_group" ../src.meta \
573         | WVPASS bup meta -x
574     new_gidx=$(bup xstat src | grep -e '^gid:')
575     WVPASSEQ "$new_gidx" "gid: $other_gid"
576
577     if ! [[ $(uname) =~ CYGWIN ]]; then
578         # For now, skip these on Cygwin because it doesn't allow
579         # restoring an unknown uid/gid.
580
581         # Make sure a uid of 0 trumps a non-root user.
582         WVPASS bup meta --edit --set-user "$some_user" ../src.meta \
583             | WVPASS bup meta -x
584         WVPASS bup xstat src | WVPASS grep -qvE "^user: $some_user"
585         WVPASS bup xstat src | WVPASS grep -qE "^uid: 0"
586
587         # Make sure a gid of 0 trumps a non-root group.
588         WVPASS bup meta --edit --set-group "$some_user" ../src.meta \
589             | WVPASS bup meta -x
590         WVPASS bup xstat src | WVPASS grep -qvE "^group: $some_group"
591         WVPASS bup xstat src | WVPASS grep -qE "^gid: 0"
592     fi
593 )
594
595 # Root-only tests that require an FS with all the trimmings: ACLs,
596 # Linux attr, Linux xattr, etc.
597 if [ $(t/root-status) == root ]; then
598     (
599         set -e
600         # Some cleanup handled in universal-cleanup() above.
601         # These tests are only likely to work under Linux for now
602         # (patches welcome).
603         [[ $(uname) =~ Linux ]] || exit 0
604
605         WVSTART 'meta - general (as root)'
606         setup-test-tree
607         cd "$TOP/bupmeta.tmp"
608
609         umount testfs || true
610         dd if=/dev/zero of=testfs.img bs=1M count=32
611         mke2fs -F -j -m 0 testfs.img
612         mkdir testfs
613         mount -o loop,acl,user_xattr testfs.img testfs
614         # Hide, so that tests can't create risks.
615         chown root:root testfs
616         chmod 0700 testfs
617
618         umount testfs-limited || true
619         dd if=/dev/zero of=testfs-limited.img bs=1M count=32
620         mkfs -t vfat testfs-limited.img
621         mkdir testfs-limited
622         mount -o loop,uid=root,gid=root,umask=0077 \
623             testfs-limited.img testfs-limited
624
625         #cp -a src testfs/src
626         cp -pPR src testfs/src
627         (cd testfs && test-src-create-extract)
628
629         WVSTART 'meta - atime (as root)'
630         force-delete testfs/src
631         mkdir testfs/src
632         (
633             mkdir testfs/src/foo
634             touch testfs/src/bar
635             PYTHONPATH="$TOP/lib" \
636                 python -c "from bup import xstat; \
637                 x = xstat.timespec_to_nsecs((42, 0));\
638                    xstat.utime('testfs/src/foo', (x, x));\
639                    xstat.utime('testfs/src/bar', (x, x));"
640             cd testfs
641             WVPASS bup meta -v --create --recurse --file src.meta src
642             bup meta -tvf src.meta
643             # Test extract.
644             force-delete src-restore
645             mkdir src-restore
646             cd src-restore
647             WVPASS bup meta --extract --file ../src.meta
648             WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
649             WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
650             # Test start/finish extract.
651             force-delete src
652             WVPASS bup meta --start-extract --file ../src.meta
653             WVPASS test -d src
654             WVPASS bup meta --finish-extract --file ../src.meta
655             WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
656             WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
657         )
658
659         WVSTART 'meta - Linux attr (as root)'
660         force-delete testfs/src
661         mkdir testfs/src
662         (
663             touch testfs/src/foo
664             mkdir testfs/src/bar
665             chattr +acdeijstuADST testfs/src/foo
666             chattr +acdeijstuADST testfs/src/bar
667             (cd testfs && test-src-create-extract)
668             # Test restoration to a limited filesystem (vfat).
669             (
670                 WVPASS bup meta --create --recurse --file testfs/src.meta \
671                     testfs/src
672                 force-delete testfs-limited/src-restore
673                 mkdir testfs-limited/src-restore
674                 cd testfs-limited/src-restore
675                 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
676                     | WVPASS grep -e '^Linux chattr:' \
677                     | WVPASS python -c \
678                       'import sys; exit(not len(sys.stdin.readlines()) == 2)'
679             )
680         )
681
682         WVSTART 'meta - Linux xattr (as root)'
683         force-delete testfs/src
684         mkdir testfs/src
685         (
686             touch testfs/src/foo
687             mkdir testfs/src/bar
688             attr -s foo -V bar testfs/src/foo
689             attr -s foo -V bar testfs/src/bar
690             (cd testfs && test-src-create-extract)
691
692             # Test restoration to a limited filesystem (vfat).
693             (
694                 WVPASS bup meta --create --recurse --file testfs/src.meta \
695                     testfs/src
696                 force-delete testfs-limited/src-restore
697                 mkdir testfs-limited/src-restore
698                 cd testfs-limited/src-restore
699                 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
700                     | WVPASS grep -e '^xattr\.set:' \
701                     | WVPASS python -c \
702                       'import sys; exit(not len(sys.stdin.readlines()) == 2)'
703             )
704         )
705
706         WVSTART 'meta - POSIX.1e ACLs (as root)'
707         force-delete testfs/src
708         mkdir testfs/src
709         (
710             touch testfs/src/foo
711             mkdir testfs/src/bar
712             setfacl -m u:root:r testfs/src/foo
713             setfacl -m u:root:r testfs/src/bar
714             (cd testfs && test-src-create-extract)
715
716             # Test restoration to a limited filesystem (vfat).
717             (
718                 WVPASS bup meta --create --recurse --file testfs/src.meta \
719                     testfs/src
720                 force-delete testfs-limited/src-restore
721                 mkdir testfs-limited/src-restore
722                 cd testfs-limited/src-restore
723                 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
724                     | WVPASS grep -e '^POSIX1e ACL applyto:' \
725                     | WVPASS python -c \
726                       'import sys; exit(not len(sys.stdin.readlines()) == 2)'
727             )
728         )
729     )
730 fi
731
732 exit 0