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