1#!/bin/sh
2# Ensure that mv, cp -a and cp --preserve=xattr(all) options do work
3# as expected on file systems without their support and do show correct
4# diagnostics when required
5
6# Copyright (C) 2009-2023 Free Software Foundation, Inc.
7
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
21. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
22print_ver_ cp mv
23
24require_root_
25
26cwd=$(pwd)
27cleanup_() { cd /; umount "$cwd/noxattr"; umount "$cwd/xattr"; }
28
29skip=0
30
31# Mount an ext2 loopback file system at $WHERE with $OPTS
32make_fs() {
33  where="$1"
34  opts="$2"
35
36  fs="$where.bin"
37
38  dd if=/dev/zero of="$fs" bs=8192 count=200 > /dev/null 2>&1 \
39                                                 || skip=1
40  mkdir "$where"                                 || skip=1
41  mkfs -t ext2 -F "$fs" ||
42    skip_ "failed to create ext2 file system"
43  mount -oloop,$opts "$fs" "$where"              || skip=1
44  echo test > "$where"/f                         || skip=1
45  test -s "$where"/f                             || skip=1
46
47  test $skip = 1 &&
48    skip_ "insufficient mount/ext2 support"
49}
50
51make_fs noxattr nouser_xattr
52make_fs xattr   user_xattr
53
54# testing xattr name-value pair
55xattr_name="user.foo"
56xattr_value="bar"
57xattr_pair="$xattr_name=\"$xattr_value\""
58
59echo test > xattr/a || framework_failure_
60getfattr -d xattr/a >out_a || skip_ "failed to get xattr of file"
61grep -F "$xattr_pair" out_a >/dev/null && framework_failure_
62setfattr -n "$xattr_name" -v "$xattr_value" xattr/a >out_a \
63  || skip_ "failed to set xattr of file"
64getfattr -d xattr/a >out_a || skip_ "failed to get xattr of file"
65grep -F "$xattr_pair" out_a >/dev/null \
66  || skip_ "failed to set xattr of file"
67
68
69# This should pass without diagnostics
70cp -a xattr/a noxattr/ 2>err || fail=1
71test -s noxattr/a   || fail=1  # destination file must not be empty
72compare /dev/null err || fail=1
73
74rm -f err noxattr/a
75
76# This should pass without diagnostics (new file)
77cp --preserve=all xattr/a noxattr/ 2>err || fail=1
78test -s noxattr/a   || fail=1  # destination file must not be empty
79compare /dev/null err || fail=1
80
81# This should pass without diagnostics (existing file)
82cp --preserve=all xattr/a noxattr/ 2>err || fail=1
83test -s noxattr/a   || fail=1  # destination file must not be empty
84compare /dev/null err || fail=1
85
86rm -f err noxattr/a
87
88# This should fail with corresponding diagnostics
89cp -a --preserve=xattr xattr/a noxattr/ 2>err && fail=1
90if grep '^#define USE_XATTR 1' $CONFIG_HEADER > /dev/null; then
91cat <<\EOF > exp
92cp: setting attributes for 'noxattr/a': Operation not supported
93EOF
94else
95cat <<\EOF > exp
96cp: cannot preserve extended attributes, cp is built without xattr support
97EOF
98fi
99
100compare exp err     || fail=1
101
102rm -f err noxattr/a
103
104# This should pass without diagnostics
105mv xattr/a noxattr/ 2>err || fail=1
106test -s noxattr/a         || fail=1  # destination file must not be empty
107compare /dev/null err || fail=1
108
109# This should pass and copy xattrs of the symlink
110# since the xattrs used here are not in the 'user.' namespace.
111# Up to and including coreutils-8.22 xattrs of symlinks
112# were not copied across file systems.
113ln -s 'foo' xattr/symlink || framework_failure_
114# Note 'user.' namespace is only supported on regular files/dirs
115# so use the 'trusted.' namespace here
116txattr='trusted.overlay.whiteout'
117if setfattr -hn "$txattr" -v y xattr/symlink; then
118  # Note only root can read the 'trusted.' namespace
119  if getfattr -h -m- -d xattr/symlink | grep -F "$txattr"; then
120    mv xattr/symlink noxattr/ 2>err || fail=1
121    if grep '^#define USE_XATTR 1' $CONFIG_HEADER > /dev/null; then
122      getfattr -h -m- -d noxattr/symlink | grep -F "$txattr" || fail=1
123    fi
124    compare /dev/null err || fail=1
125  else
126    echo "failed to get '$txattr' xattr. skipping symlink check" >&2
127  fi
128else
129  echo "failed to set '$txattr' xattr. skipping symlink check" >&2
130fi
131
132Exit $fail
133