summaryrefslogtreecommitdiffstats
path: root/tests/du
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:11:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:11:47 +0000
commit758f820bcc0f68aeebac1717e537ca13a320b909 (patch)
tree48111ece75cf4f98316848b37a7e26356e00669e /tests/du
parentInitial commit. (diff)
downloadcoreutils-758f820bcc0f68aeebac1717e537ca13a320b909.tar.xz
coreutils-758f820bcc0f68aeebac1717e537ca13a320b909.zip
Adding upstream version 9.1.upstream/9.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/du')
-rwxr-xr-xtests/du/2g.sh71
-rwxr-xr-xtests/du/8gb.sh54
-rwxr-xr-xtests/du/basic.sh89
-rwxr-xr-xtests/du/bigtime.sh52
-rwxr-xr-xtests/du/bind-mount-dir-cycle-v2.sh38
-rwxr-xr-xtests/du/bind-mount-dir-cycle.sh37
-rwxr-xr-xtests/du/deref-args.sh48
-rwxr-xr-xtests/du/deref.sh48
-rwxr-xr-xtests/du/exclude.sh58
-rwxr-xr-xtests/du/fd-leak.sh43
-rwxr-xr-xtests/du/files0-from-dir.sh39
-rwxr-xr-xtests/du/files0-from.pl94
-rwxr-xr-xtests/du/hard-link.sh64
-rwxr-xr-xtests/du/inacc-dest.sh56
-rwxr-xr-xtests/du/inacc-dir.sh42
-rwxr-xr-xtests/du/inaccessible-cwd.sh40
-rwxr-xr-xtests/du/inodes.sh140
-rwxr-xr-xtests/du/long-from-unreadable.sh74
-rwxr-xr-xtests/du/long-sloop.sh72
-rwxr-xr-xtests/du/max-depth.sh39
-rwxr-xr-xtests/du/move-dir-while-traversing.sh99
-rwxr-xr-xtests/du/no-deref.sh33
-rwxr-xr-xtests/du/no-x.sh49
-rwxr-xr-xtests/du/one-file-system.sh57
-rwxr-xr-xtests/du/restore-wd.sh31
-rwxr-xr-xtests/du/slash.sh33
-rwxr-xr-xtests/du/threshold.sh362
-rwxr-xr-xtests/du/trailing-slash.sh47
-rwxr-xr-xtests/du/two-args.sh40
29 files changed, 1949 insertions, 0 deletions
diff --git a/tests/du/2g.sh b/tests/du/2g.sh
new file mode 100755
index 0000000..adee756
--- /dev/null
+++ b/tests/du/2g.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Ensure that du can handle a 2GB file (i.e., a file of size 2^31 bytes)
+# Before coreutils-5.93, on systems with a signed, 32-bit stat.st_blocks
+# one of du's computations would overflow.
+
+# Copyright (C) 2005-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Creating a 2GB file counts as 'very expensive'.
+very_expensive_
+
+# Get number of free kilobytes on current partition, so we can
+# skip this test if there is insufficient free space.
+free_kb=$(df -k --output=avail . | tail -n1)
+case "$free_kb" in
+ [0-9]*) ;;
+ *) skip_ "invalid size from df: $free_kb";;
+esac
+
+# Require about 3GB free.
+min_kb=3000000
+test $min_kb -lt $free_kb ||
+{
+ skip_ \
+ "too little free space on current partition: $free_kb (need $min_kb KB)"
+}
+
+big=big
+
+if ! fallocate -l2G $big; then
+ rm -f $big
+ {
+ is_local_dir_ . || skip_ 'Not writing 2GB data to remote'
+ for i in $(seq 100); do
+ # Note: 2147483648 == 2^31. Print floor(2^31/100) per iteration.
+ printf %21474836s x || fail=1
+ done
+ # After the final iteration, append the remaining 48 bytes.
+ printf %48s x || fail=1
+ } > $big || fail=1
+fi
+
+# The allocation may be done asynchronously (BTRFS for example)
+sync $big || framework_failure_
+
+du -k $big > out1 || fail=1
+rm -f $big
+sed 's/^2[0-9][0-9][0-9][0-9][0-9][0-9] '$big'$/~2M/' out1 > out
+
+cat <<\EOF > exp || framework_failure_
+~2M
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/8gb.sh b/tests/du/8gb.sh
new file mode 100755
index 0000000..7d067e5
--- /dev/null
+++ b/tests/du/8gb.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Ensure that du does not rely on narrow types like size_t for
+# file sizes or sums.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_sparse_support_
+
+# timeout to avoid hang on GNU/Hurd from 2019
+timeout 10 dd bs=1 seek=8G of=big < /dev/null 2> /dev/null
+if test $? != 0; then
+ skip_ 'cannot create a file large enough for this test; possibly
+because file offsets are only 32 bits on this file system'
+fi
+
+# FIXME: this should be a test of dd.
+# On some systems (at least linux-2.4.18 + NFS to Solaris system)
+# the 'dd' command above mistakenly creates a file of length '0', yet
+# doesn't fail. The root of that failure is that the ftruncate call
+# returns zero but doesn't do its job. Detect this failure.
+set x $(ls -gG big)
+size=$4
+if test "$size" = 0; then
+ skip_ "cannot create a file large enough for this test
+possibly because this system's NFS support is buggy
+Consider rerunning this test on a different file system."
+fi
+
+
+# This would print '0 big' with coreutils-4.5.8.
+du -ab big > out || fail=1
+
+cat <<\EOF > exp
+8589934592 big
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/basic.sh b/tests/du/basic.sh
new file mode 100755
index 0000000..a81e895
--- /dev/null
+++ b/tests/du/basic.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+# Compare actual numbers from du, assuming block size matches mine.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b d d/sub || framework_failure_
+
+# Ensure that these files contain more than 64 bytes, so that we don't
+# immediately disqualify file systems (e.g., NetApp) on which smaller
+# files take up zero file system blocks.
+printf '%*s' 257 make-sure-the-file-is-non-empty > a/b/F || framework_failure_
+printf %4096s x > d/1
+cp d/1 d/sub/2
+
+
+B=$(stat --format=%B a/b/F)
+
+du --block-size=$B -a a > out || fail=1
+echo === >> out
+du --block-size=$B -a -S a >> out || fail=1
+echo === >> out
+du --block-size=$B -s a >> out || fail=1
+
+f=$(stat --format=%b a/b/F)
+b=$(stat --format=%b a/b)
+a=$(stat --format=%b a)
+bf=$(expr $b + $f)
+tot=$(expr $bf + $a)
+
+cat <<EOF | sed 's/ *#.*//' > exp
+$f a/b/F
+$bf a/b
+$tot a
+===
+$f a/b/F # size of file, a/b/F
+$bf a/b # size of dir entry, a/b, + size of file, a/b/F
+$a a # size of dir entry, a
+===
+$tot a
+EOF
+
+compare exp out || fail=1
+
+# Perform this test only if "." is on a local file system.
+# Otherwise, it would fail e.g., on an NFS-mounted Solaris ZFS file system.
+if is_local_dir_ .; then
+ rm -f out exp
+ du --block-size=$B -a d | sort -r -k2,2 > out || fail=1
+ echo === >> out
+ du --block-size=$B -S d | sort -r -k2,2 >> out || fail=1
+
+ t2=$(stat --format=%b d/sub/2)
+ ts=$(stat --format=%b d/sub)
+ t1=$(stat --format=%b d/1)
+ td=$(stat --format=%b d)
+ tot=$(expr $t1 + $t2 + $ts + $td)
+ d1=$(expr $td + $t1)
+ s2=$(expr $ts + $t2)
+
+ cat <<EOF | sed 's/ *#.*//' > exp
+$t2 d/sub/2
+$s2 d/sub
+$t1 d/1
+$tot d
+===
+$s2 d/sub
+$d1 d # d + d/1; don't count the dir. entry for d/sub
+EOF
+
+ compare exp out || fail=1
+fi
+
+Exit $fail
diff --git a/tests/du/bigtime.sh b/tests/du/bigtime.sh
new file mode 100755
index 0000000..4f8cfa2
--- /dev/null
+++ b/tests/du/bigtime.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Exercise du on a file with a big timestamp.
+
+# Copyright (C) 2010-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+export LC_ALL=C
+export TZ=UTC0
+
+# 2**63 - 1
+bignum=9223372036854775807
+
+touch -d @$bignum future 2>/dev/null &&
+future_time=$(ls -l future) &&
+case "$future_time" in
+*" $bignum "*)
+ : ;;
+*' Dec 4 300627798676 '*)
+ skip_ "file system and localtime both handle big timestamps" ;;
+*)
+ skip_ "file system or localtime mishandles big timestamps:" \
+ "$future_time" ;;
+esac || skip_ "file system cannot represent big timestamps"
+
+printf "0\t$bignum\tfuture\n" > exp || framework_failure_
+printf "du: time '$bignum' is out of range\n" > err_ok || framework_failure_
+
+du --time future >out 2>err || fail=1
+
+# On some systems an empty file occupies 4 blocks.
+# Map the number of blocks to 0.
+sed 's/^[0-9][0-9]*/0/' out > k && mv k out
+
+compare exp out || fail=1
+compare err err_ok || fail=1
+
+Exit $fail
diff --git a/tests/du/bind-mount-dir-cycle-v2.sh b/tests/du/bind-mount-dir-cycle-v2.sh
new file mode 100755
index 0000000..60ae8b7
--- /dev/null
+++ b/tests/du/bind-mount-dir-cycle-v2.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Check that du can handle sub-bind-mounts cycles as well.
+
+# Copyright (C) 2014-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_root_
+
+cleanup_() { umount a/b/c; }
+
+mkdir -p a/b/c || framework_failure_
+mount --bind a a/b/c \
+ || skip_ 'This test requires mount with a working --bind option.'
+
+echo a/b/c > exp || framework_failure_
+echo a/b >> exp || framework_failure_
+
+du a/b > out 2> err || fail=1
+sed 's/^[0-9][0-9]* //' out > k && mv k out
+
+compare /dev/null err || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/bind-mount-dir-cycle.sh b/tests/du/bind-mount-dir-cycle.sh
new file mode 100755
index 0000000..0995663
--- /dev/null
+++ b/tests/du/bind-mount-dir-cycle.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Exercise du's new ability to handle bind-mount-induced dir cycles.
+
+# Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_root_
+
+cleanup_() { umount a/b; }
+
+mkdir -p a/b || framework_failure_
+mount --bind a a/b \
+ || skip_ "This test requires mount with a working --bind option."
+
+echo a > exp || framework_failure_
+
+du a > out 2> err || fail=1
+sed 's/^[0-9][0-9]* //' out > k && mv k out
+
+compare /dev/null err || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/deref-args.sh b/tests/du/deref-args.sh
new file mode 100755
index 0000000..debc509
--- /dev/null
+++ b/tests/du/deref-args.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Ensure that --dereference-args (-D) gives reasonable names.
+# This test would fail for coreutils-5.0.91.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/a || framework_failure_
+ln -s dir slink || framework_failure_
+printf %65536s x > 64k || framework_failure_
+ln -s 64k slink-to-64k || framework_failure_
+
+
+du -D slink | sed 's/^[0-9][0-9]* //' > out
+# Ensure that the trailing slash is preserved and handled properly.
+du -D slink/ | sed 's/^[0-9][0-9]* //' >> out
+
+# Ensure that -D makes du dereference even symlinks to non-directories.
+# Be sure to use --apparent-size. Otherwise, we'd get varying block counts
+# depending on file system type (e.g. 68 on ext3 vs. 64 on tmpfs and 72
+# on SELinux-enabled systems).
+du --apparent-size --block-size=1K -D slink-to-64k >> out
+cat <<\EOF > exp
+slink/a
+slink
+slink/a
+slink/
+64 slink-to-64k
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/deref.sh b/tests/du/deref.sh
new file mode 100755
index 0000000..5a1085f
--- /dev/null
+++ b/tests/du/deref.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# prior to coreutils-4.5.3, du -D didn't work in some cases
+# Based on an example from Andreas Schwab and/or Michal Svec.
+# Also, up to coreutils-8.5, du -L sometimes incorrectly
+# counted the space of the followed symlinks.
+
+# Copyright (C) 2002-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/sub || framework_failure_
+ln -s a/sub slink || framework_failure_
+touch b || framework_failure_
+ln -s .. a/sub/dotdot || framework_failure_
+ln -s nowhere dangle || framework_failure_
+
+
+# This used to fail with the following diagnostic:
+# du: 'b': No such file or directory
+du -sD slink b > /dev/null 2>&1 || fail=1
+
+# This used to fail to report the dangling symlink.
+returns_ 1 du -L dangle > /dev/null 2>&1 || fail=1
+
+# du -L used to mess up, either by counting the symlink's file system space
+# itself (-L should follow symlinks, not count their space)
+# or (briefly in July 2010) by omitting the entry for "a".
+du_L_output=$(du -L a) || fail=1
+du_lL_output=$(du -lL a) || fail=1
+du_x_output=$(du --exclude=dotdot a) || fail=1
+test "X$du_L_output" = "X$du_x_output" || fail=1
+test "X$du_lL_output" = "X$du_x_output" || fail=1
+
+Exit $fail
diff --git a/tests/du/exclude.sh b/tests/du/exclude.sh
new file mode 100755
index 0000000..eedf751
--- /dev/null
+++ b/tests/du/exclude.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# make sure du's --exclude option works
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b/c a/x/y a/u/v || framework_failure_
+
+
+du --exclude=x a | sed 's/^[0-9][0-9]* //' | sort > out || fail=1
+printf '===\n' >> out
+printf 'b\n' > excl
+du --exclude-from=excl a | sed 's/^[0-9][0-9]* //' | sort >> out || fail=1
+printf '===\n' >> out
+# Make sure that we can exclude an entire hierarchy.
+du --exclude=a a >> out || fail=1
+# Make sure that we can exclude based on more than one component.
+# Before coreutils-5.3.0, this part would fail.
+printf '===\n' >> out
+du --exclude=a/u --exclude=a/b a \
+ | sed 's/^[0-9][0-9]* //' | sort >> out || fail=1
+cat <<\EOF > exp
+a
+a/b
+a/b/c
+a/u
+a/u/v
+===
+a
+a/u
+a/u/v
+a/x
+a/x/y
+===
+===
+a
+a/x
+a/x/y
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/fd-leak.sh b/tests/du/fd-leak.sh
new file mode 100755
index 0000000..9697d00
--- /dev/null
+++ b/tests/du/fd-leak.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# check for file descriptor leak
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Call this an expensive test. It's not that expensive, but command line
+# limitations might induce failure on some losing systems.
+expensive_
+
+# Create 1296 (36^2) files.
+# Their names and separating spaces take up 3887 bytes.
+x='a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9'
+f=
+for i in $x; do
+ for j in $x; do
+ f="$f $i$j"
+ done
+done
+
+# This may fail due to command line limitations.
+touch $f || framework_failure_
+
+
+# With coreutils-5.0, this would fail due to a file descriptor leak.
+du $f > out || fail=1
+
+Exit $fail
diff --git a/tests/du/files0-from-dir.sh b/tests/du/files0-from-dir.sh
new file mode 100755
index 0000000..44287fe
--- /dev/null
+++ b/tests/du/files0-from-dir.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# ensure that du and wc handle --files0-from=DIR
+
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du wc
+
+mkdir dir
+
+# Skip this test if reading from a directory succeeds.
+# In that case, using --files0-from=dir would yield garbage,
+# interpreting the directory entry as a sequence of
+# NUL-separated file names.
+cat dir > /dev/null && skip_ "cat dir/ succeeds"
+
+for prog in du wc; do
+ $prog --files0-from=dir > /dev/null 2>err && fail=1
+ printf "$prog: dir:\n" > exp || fail=1
+ # The diagnostic string is usually "Is a directory" (ENOTDIR),
+ # but accept a different string or errno value.
+ sed "s/dir:.*/dir:/" err > k; mv k err
+ compare exp err || fail=1
+done
+
+Exit $fail
diff --git a/tests/du/files0-from.pl b/tests/du/files0-from.pl
new file mode 100755
index 0000000..bdc3420
--- /dev/null
+++ b/tests/du/files0-from.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+# Exercise du's --files0-from option.
+# FIXME: keep this file in sync with tests/misc/wc-files0-from.
+
+# Copyright (C) 2004-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+my $prog = 'du';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # invalid extra command line argument
+ ['f-extra-arg', '--files0-from=- no-such', {IN=>"a"}, {EXIT=>1},
+ {ERR => "$prog: extra operand 'no-such'\n"
+ . "file operands cannot be combined with --files0-from\n"
+ . "Try '$prog --help' for more information.\n"}
+ ],
+
+ # missing input file
+ ['missing', '--files0-from=missing', {EXIT=>1},
+ {ERR => "$prog: cannot open 'missing' for reading: "
+ . "No such file or directory\n"}],
+
+ # input file name of '-'
+ ['minus-in-stdin', '--files0-from=-', '<', {IN=>{f=>'-'}}, {EXIT=>1},
+ {ERR => "$prog: when reading file names from stdin, no file name of"
+ . " '-' allowed\n"}],
+
+ # empty input, regular file
+ ['empty', '--files0-from=@AUX@', {AUX=>''}],
+
+ # empty input, from non-regular file
+ ['empty-nonreg', '--files0-from=/dev/null'],
+
+ # one NUL
+ ['nul-1', '--files0-from=-', '<', {IN=>"\0"}, {EXIT=>1},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}],
+
+ # two NULs
+ ['nul-2', '--files0-from=-', '<', {IN=>"\0\0"}, {EXIT=>1},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"
+ . "$prog: -:2: invalid zero-length file name\n"}],
+
+ # one file name, no NUL
+ ['1', '--files0-from=-', '<',
+ {IN=>{f=>"g"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # one file name, with NUL
+ ['1a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # two identical file names, no final NUL
+ ['2', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # two identical file names, with final NUL
+ ['2a', '--files0-from=-', '<',
+ {IN=>{f=>"g\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'} ],
+
+ # Ensure that $prog processes FILEs following a zero-length name.
+ ['zero-len', '--files0-from=-', '<',
+ {IN=>{f=>"\0g\0"}}, {AUX=>{g=>''}},
+ {OUT=>"0\tg\n"}, {OUT_SUBST=>'s/^\d+/0/'},
+ {ERR => "$prog: -:1: invalid zero-length file name\n"}, {EXIT=>1} ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/du/hard-link.sh b/tests/du/hard-link.sh
new file mode 100755
index 0000000..7cd03d3
--- /dev/null
+++ b/tests/du/hard-link.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Ensure that hard-linked files are counted (and listed) only once.
+# Likewise for excluded directories.
+# Ensure that hard links _are_ listed twice when using --count-links.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/sub
+( cd dir &&
+ { echo non-empty > f1
+ ln f1 f2
+ ln -s f1 f3
+ echo non-empty > sub/F; } )
+
+du -a -L --exclude=sub --count-links dir \
+ | sed 's/^[0-9][0-9]* //' | sort -r > out || fail=1
+
+# For these tests, transform f1 or f2 or f3 (whichever name is find
+# first) to f_. That is necessary because, depending on the type of
+# file system, du could encounter any of those linked files first,
+# thus listing that one and not the others.
+for args in '-L' 'dir' '-L dir'
+do
+ echo === >> out
+ du -a --exclude=sub $args dir \
+ | sed 's/^[0-9][0-9]* //' | sed 's/f[123]/f_/' >> out || fail=1
+done
+
+cat <<\EOF > exp
+dir/f3
+dir/f2
+dir/f1
+dir
+===
+dir/f_
+dir
+===
+dir/f_
+dir/f_
+dir
+===
+dir/f_
+dir
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/inacc-dest.sh b/tests/du/inacc-dest.sh
new file mode 100755
index 0000000..b26fd1c
--- /dev/null
+++ b/tests/du/inacc-dest.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Prior to coreutils-6.5, an inaccessible destination dir (chmod a-x)
+# would cause du to exit prematurely on systems with native openat support.
+
+# Copyright (C) 2006-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+skip_if_root_
+
+mkdir f && cd f && mkdir a b c d e && touch c/j && chmod a-x c \
+ || framework_failure_
+
+du > ../t 2>&1 && fail=1
+
+# Accept either of the following outputs.
+# You get the first from a system with openat _emulation_ (via /proc),
+# the second from a system with native openat support.
+# FIXME: there may well be a third output, for systems with neither
+# /proc support, nor native openat support.
+
+sed 's/^[0-9][0-9]* //' ../t | sort -u > out
+cat <<\EOF > exp || framework_failure_
+.
+./a
+./b
+./c
+./d
+./e
+du: cannot read directory './c': Permission denied
+EOF
+
+# Map a diagnostic like this
+# du: cannot access './c/j': Permission denied
+# to this:
+# du: cannot access './c': Permission denied
+# And accept "cannot read directory" in place of "cannot access"
+sed "s,/c/j': ,/c': ," out > t && mv t out
+sed 's,cannot access,cannot read directory,' out > t && mv t out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/inacc-dir.sh b/tests/du/inacc-dir.sh
new file mode 100755
index 0000000..a5c823e
--- /dev/null
+++ b/tests/du/inacc-dir.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Ensure that du counts the size of an inaccessible directory.
+# Copyright (C) 2007-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+skip_if_root_
+
+mkdir -p a/sub || framework_failure_
+
+
+du -s a > exp || fail=1
+chmod 0 a/sub || fail=1
+# Expect failure, ignore diagnostics.
+du -s a > out 2> /dev/null && fail=1
+
+compare exp out || fail=1
+
+# Same as above, but don't use -s, so we print
+# an entry for the unreadable "sub", too.
+chmod 700 a/sub || fail=1
+du -k a > exp || fail=1
+chmod 0 a/sub || fail=1
+# Expect failure, ignore diagnostics.
+du -k a > out 2> /dev/null && fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/inaccessible-cwd.sh b/tests/du/inaccessible-cwd.sh
new file mode 100755
index 0000000..464456d
--- /dev/null
+++ b/tests/du/inaccessible-cwd.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Ensure that even when run from an inaccessible directory, du can still
+# operate on accessible directories elsewhere.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Before the switch to an fts-based implementation in coreutils 5.0.92,
+# this test would fail.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Skip this test if your system has neither the openat-style functions
+# nor /proc/self/fd support with which to emulate them.
+require_openat_support_
+
+skip_if_root_
+
+cwd=$(pwd)
+mkdir -p no-x a/b || framework_failure_
+cd no-x || framework_failure_
+chmod 0 . || framework_failure_
+
+
+du "$cwd/a" > /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/du/inodes.sh b/tests/du/inodes.sh
new file mode 100755
index 0000000..008bfe2
--- /dev/null
+++ b/tests/du/inodes.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+# exercise du's --inodes option
+
+# Copyright (C) 2010-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# An empty directory uses only 1 inode.
+mkdir d || framework_failure_
+printf '1\td\n' > exp || framework_failure_
+
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Add a regular file: 2 inodes used.
+touch d/f || framework_failure_
+printf '2\td\n' > exp || framework_failure_
+
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Add a hardlink to the file: still only 2 inodes used.
+ln -v d/f d/h || framework_failure_
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Now count also hardlinks (-l,--count-links): 3 inodes.
+printf '3\td\n' > exp || framework_failure_
+du --inodes -l d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Create a directory and summarize: 3 inodes.
+mkdir d/d || framework_failure_
+du --inodes -s d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count inodes separated: 1-2.
+printf '1\td/d\n2\td\n' > exp || framework_failure_
+du --inodes -S d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count inodes cumulative (default): 1-3.
+printf '1\td/d\n3\td\n' > exp || framework_failure_
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count all items: 1-1-3.
+# Sort output because the directory entry order is not defined.
+# Also replace the hardlink with the original file name because
+# the system may either return 'd/f' or 'd/h' first, and du(1)
+# will ignore the other one.
+printf '1\td/d\n1\td/f\n3\td\n' | sort > exp || framework_failure_
+du --inodes -a d > out.tmp 2>err || fail=1
+sed 's/h$/f/' out.tmp | sort >out || framework_failure_
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Count all items and hardlinks again: 1-1-1-4
+# Sort output because the directory entry order is not defined.
+printf '1\td/d\n1\td/h\n1\td/f\n4\td\n' | sort > exp || framework_failure_
+du --inodes -al d > out.tmp 2>err || fail=1
+sort <out.tmp >out || framework_failure_
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Run with total (-c) line: 1-3-3
+printf '1\td/d\n3\td\n3\ttotal\n' > exp || framework_failure_
+du --inodes -c d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Create another file in the subdirectory: 2-4
+touch d/d/f || framework_failure_
+printf '2\td/d\n4\td\n' > exp || framework_failure_
+du --inodes d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Ensure human output (-h, --si) works.
+rm -rf d || framework_failure_
+mkdir d || framework_failure_
+seq --format="d/file%g" 1023 | xargs touch || framework_failure_
+printf '1.0K\td\n' > exp || framework_failure_
+du --inodes -h d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+printf '1.1k\td\n' > exp || framework_failure_
+du --inodes --si d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Verify --inodes ignores -B.
+printf '1024\td\n' > exp || framework_failure_
+du --inodes -B10 d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Verify --inodes works with --threshold.
+printf '1024\td\n' > exp || framework_failure_
+du --inodes --threshold=1000 d > out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+du --inodes --threshold=-1000 d > out 2>err || fail=1
+compare /dev/null out || fail=1
+compare /dev/null err || fail=1
+
+# Verify --inodes raises a warning for --apparent-size and -b.
+du --inodes -b d > out 2>err || fail=1
+grep ' ineffective ' err >/dev/null || { fail=1; cat out err; }
+
+du --inodes --apparent-size d > out 2>err || fail=1
+grep ' ineffective ' err >/dev/null || { fail=1; cat out err; }
+
+# Ensure that --inodes is mentioned in the usage.
+du --help > out || fail=1
+grep ' --inodes ' out >/dev/null || { fail=1; cat out; }
+Exit $fail
diff --git a/tests/du/long-from-unreadable.sh b/tests/du/long-from-unreadable.sh
new file mode 100755
index 0000000..3a2e19b
--- /dev/null
+++ b/tests/du/long-from-unreadable.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Show fts fails on old-fashioned systems.
+
+# Copyright (C) 2006-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Show that fts (hence du, chmod, chgrp, chown) fails when all of the
+# following are true:
+# - '.' is not readable
+# - operating on a hierarchy containing a relative name longer than PATH_MAX
+# - run on a system where gnulib's openat emulation must resort to using
+# save_cwd and restore_cwd (which fail if '.' is not readable).
+# Thus, the following du invocation should succeed on newer Linux and
+# Solaris systems, yet it must fail on systems lacking both openat and
+# /proc support. However, before coreutils-6.0 this test would fail even
+# on Linux+PROC_FS systems because its fts implementation would revert
+# unnecessarily to using FTS_NOCHDIR mode in this corner case.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+require_perl_
+
+# ecryptfs for example uses some of the file name space
+# for encrypting filenames, so we must check dynamically.
+name_max=$(stat -f -c %l .)
+test "$name_max" -ge '200' || skip_ "NAME_MAX=$name_max is not sufficient"
+
+proc_file=/proc/self/fd
+if test ! -d $proc_file; then
+ skip_ 'This test would fail, since your system lacks /proc support.'
+fi
+
+dir=$(printf '%200s\n' ' '|tr ' ' x)
+
+# Construct a hierarchy containing a relative file with a name
+# longer than PATH_MAX.
+# for i in $(seq 52); do
+# mkdir $dir || framework_failure_
+# cd $dir || framework_failure_
+# done
+# cd $tmp || framework_failure_
+
+# Sheesh. Bash 3.1.5 can't create this hierarchy. I get
+# cd: error retrieving current directory: getcwd:
+# cannot access parent directories:
+# (all on one line).
+
+cwd=$(pwd)
+# Use perl instead:
+$PERL \
+ -e 'my $d = '$dir'; foreach my $i (1..52)' \
+ -e ' { mkdir ($d, 0700) && chdir $d or die "$!" }' \
+ || framework_failure_
+
+mkdir inaccessible || framework_failure_
+cd inaccessible || framework_failure_
+chmod 0 . || framework_failure_
+
+du -s "$cwd/$dir" > /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/du/long-sloop.sh b/tests/du/long-sloop.sh
new file mode 100755
index 0000000..f93bca8
--- /dev/null
+++ b/tests/du/long-sloop.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# Use du to exercise a corner of fts's FTS_LOGICAL code.
+# Show that du fails with ELOOP (Too many levels of symbolic links)
+# when it encounters that condition.
+
+# Copyright (C) 2006-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Create lots of directories, each containing a single symlink
+# pointing at the next directory in the list.
+
+# This number should be larger than the number of symlinks allowed in
+# file name resolution, but not too large as a number of entries
+# in a single directory.
+n=400
+
+dir_list=$(seq $n)
+mkdir $dir_list || framework_failure_
+file=1
+i_minus_1=0
+for i in $dir_list $(expr $n + 1); do
+ case $i_minus_1 in
+ 0) ;;
+ *)
+ ln -s ../$i $i_minus_1/s || framework_failure_
+ file=$file/s;;
+ esac
+ i_minus_1=$i
+done
+echo foo > $i || framework_failure_
+
+# If a system can handle this many symlinks in a file name,
+# just skip this test.
+
+# The following also serves to record in 'err' the string
+# corresponding to strerror (ELOOP). This is necessary because while
+# Linux/libc gives 'Too many levels of symbolic links', Solaris
+# renders it as "Number of symbolic links encountered during path
+# name traversal exceeds MAXSYMLINKS".
+
+cat $file > /dev/null 2> err &&
+ skip_ 'Your system appears to be able to handle more than $n symlinks
+in file name resolution'
+too_many=$(sed 's/.*: //' err)
+
+
+# With coreutils-5.93 there was no failure.
+# With coreutils-5.94 we get the desired diagnostic:
+# du: cannot access '1/s/s/s/.../s': Too many levels of symbolic links
+du -L 1 > /dev/null 2> out1 && fail=1
+sed "s, .1/s/s/s/[/s]*',," out1 > out || framework_failure_
+
+echo "du: cannot access: $too_many" > exp || framework_failure_
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/max-depth.sh b/tests/du/max-depth.sh
new file mode 100755
index 0000000..4699263
--- /dev/null
+++ b/tests/du/max-depth.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# exercise du's --max-depth=N option
+
+# Copyright (C) 2010-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b/c/d/e || framework_failure_
+printf 'a/b/c\na/b\na\n' > exp || framework_failure_
+
+du --max-depth=2 a > out 2>err || fail=1
+
+# Remove the sizes. They vary between file systems.
+cut -f2- out > k && mv k out
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+# Repeat, but use -d 1.
+printf 'a/b\na\n' > exp || framework_failure_
+du -d 1 a > out 2>err || fail=1
+cut -f2- out > k && mv k out
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/du/move-dir-while-traversing.sh b/tests/du/move-dir-while-traversing.sh
new file mode 100755
index 0000000..a9708de
--- /dev/null
+++ b/tests/du/move-dir-while-traversing.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+# Trigger a failed assertion in coreutils-8.9 and earlier.
+
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_trap_signame_
+
+# We use a python-inotify script, so...
+python -m pyinotify -h > /dev/null \
+ || skip_ 'python inotify package not installed'
+
+# Move a directory "up" while du is processing its sub-directories.
+# While du is processing a hierarchy .../B/C/D/... this script
+# detects when du opens D/, and then moves C/ "up" one level
+# so that it is a sibling of B/.
+# Given the inherent race condition, we have to add enough "weight"
+# under D/ so that in most cases, the monitor performs the single
+# rename syscall before du finishes processing the subtree under D/.
+
+cat <<'EOF' > inotify-watch-for-dir-access.py
+#!/usr/bin/env python
+import pyinotify as pn
+import os,sys
+
+dir = sys.argv[1]
+dest_parent = os.path.dirname(os.path.dirname(dir))
+dest = os.path.join(dest_parent, os.path.basename(dir))
+
+class ProcessDir(pn.ProcessEvent):
+
+ def process_IN_OPEN(self, event):
+ os.rename(dir, dest)
+ sys.exit(0)
+
+ def process_default(self, event):
+ pass
+
+wm = pn.WatchManager()
+notifier = pn.Notifier(wm)
+wm.watch_transient_file(dir, pn.IN_OPEN, ProcessDir)
+sys.stdout.write('started\n')
+sys.stdout.flush()
+notifier.loop()
+EOF
+chmod a+x inotify-watch-for-dir-access.py
+
+t=T/U
+mkdir d2 || framework_failure_
+long=d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z
+# One iteration of this loop creates a tree with which
+# du sometimes completes its traversal before the above rename.
+# Five iterations was not enough in 2 of 7 "make -j20 check" runs on a
+# 6/12-core system. However, using "10", I saw no failure in 20 trials.
+# Using 10 iterations was not enough, either.
+# Using 50, I saw no failure in 200 trials.
+for i in $(seq 50); do
+ mkdir -p $t/3/a/b/c/$i/$long || framework_failure_
+done
+
+# Terminate any background cp process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Prohibit suspension, which could otherwise cause a timeout-induced FP failure.
+trap '' TSTP
+
+timeout 6 ./inotify-watch-for-dir-access.py $t/3/a/b > start-msg & pid=$!
+
+# Wait for the watcher to start...
+nonempty() { sleep $1; test -s start-msg; }
+retry_delay_ nonempty .1 5 || fail=1
+
+# The above watches for an IN_OPEN event on $t/3/a/b,
+# and when it triggers, moves the parent, $t/3/a, up one level
+# so it's directly under $t.
+
+# Before coreutils-8.10, du would abort.
+returns_ 1 du -a $t d2 2> err || fail=1
+
+# check for the new diagnostic
+printf "du: fts_read failed: $t/3/a/b: No such file or directory\n" > exp \
+ || fail=1
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/du/no-deref.sh b/tests/du/no-deref.sh
new file mode 100755
index 0000000..4bae934
--- /dev/null
+++ b/tests/du/no-deref.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Ensure that by default, du doesn't dereference command-line symlinks.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/a/b || framework_failure_
+ln -s dir slink || framework_failure_
+
+
+du slink | sed 's/^[0-9][0-9]* //' > out
+cat <<\EOF > exp
+slink
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/no-x.sh b/tests/du/no-x.sh
new file mode 100755
index 0000000..79920a9
--- /dev/null
+++ b/tests/du/no-x.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Make sure du gives the right diagnostic for a readable,
+# but inaccessible directory.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+skip_if_root_
+
+mkdir -p d/no-x/y || framework_failure_
+chmod u=rw d/no-x || framework_failure_
+
+
+# This must exit nonzero.
+du d >/dev/null 2>out && fail=1
+
+prog=du
+# NOTE: this code is the same for all tests/*/no-x tests.
+# Depending on whether fts is using native fdopendir, we see one
+# of the following diagnostics (note also the /y suffix in one case):
+# prog: 'd/no-x': Permission denied
+# prog: cannot access 'd/no-x/y': Permission denied
+# prog: cannot read directory 'd/no-x': Permission denied
+# Convert either of the latter two to the first one.
+sed "s/^$prog: cannot access /$prog: /" out > t && mv t out
+sed "s/^$prog: cannot read directory /$prog: /" out > t && mv t out
+sed 's,d/no-x/y,d/no-x,' out > t && mv t out
+
+cat <<EOF > exp
+$prog: 'd/no-x': Permission denied
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/one-file-system.sh b/tests/du/one-file-system.sh
new file mode 100755
index 0000000..fff35ea
--- /dev/null
+++ b/tests/du/one-file-system.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Test for bugs in du's --one-file-system (-x) option.
+
+# Copyright (C) 2006-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/tests/other-fs-tmpdir"
+
+mkdir -p b/c y/z d "$other_partition_tmpdir/x" || framework_failure_
+ln -s "$other_partition_tmpdir/x" d || framework_failure_
+
+# Due to a used-uninitialized variable, the "du -x" from coreutils-6.6
+# would not traverse into second and subsequent directories listed
+# on the command line.
+du -ax b y > t || fail=1
+sed 's/^[0-9][0-9]* //' t > out || framework_failure_
+cat <<\EOF > exp || framework_failure_
+b/c
+b
+y/z
+y
+EOF
+
+compare exp out || fail=1
+
+# "du -xL" reported a zero count for a file in a different file system,
+# instead of ignoring it.
+du -xL d > u || fail=1
+sed 's/^[0-9][0-9]* //' u > out1 || framework_failure_
+echo d > exp1 || framework_failure_
+compare exp1 out1 || fail=1
+
+# With coreutils-8.15, "du -xs FILE" would print no output.
+touch f
+for opt in -x -xs; do
+ du $opt f > u || fail=1
+ sed 's/^[0-9][0-9]* //' u > out2 || framework_failure_
+ echo f > exp2 || framework_failure_
+ compare exp2 out2 || fail=1
+done
+
+Exit $fail
diff --git a/tests/du/restore-wd.sh b/tests/du/restore-wd.sh
new file mode 100755
index 0000000..c9c5069
--- /dev/null
+++ b/tests/du/restore-wd.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# due to a bug in glibc's ftw.c, in some cases, nftw w/FTW_CHDIR
+# would not restore the working directory.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir a b || framework_failure_
+
+
+# With du from coreutils-4.5.5 and 4.5.6, this would fail with
+# du: 'b': No such file or directory
+
+du a b > out || fail=1
+
+Exit $fail
diff --git a/tests/du/slash.sh b/tests/du/slash.sh
new file mode 100755
index 0000000..6426d16
--- /dev/null
+++ b/tests/du/slash.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# 'du /' would omit the '/' on the last line.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+require_readable_root_
+
+
+du --exclude='[^/]*' -x / > out-t || fail=1
+sed 's/^[0-9][0-9]* //' out-t > out
+rm -f out-t
+cat <<\EOF > exp
+/
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/threshold.sh b/tests/du/threshold.sh
new file mode 100755
index 0000000..270b885
--- /dev/null
+++ b/tests/du/threshold.sh
@@ -0,0 +1,362 @@
+#!/bin/sh
+# Exercise du's --threshold option.
+
+# Copyright (C) 2013-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p a/b a/c || framework_failure_
+
+touch a/b/0 || framework_failure_
+printf '%1s' x > a/b/1 || framework_failure_
+printf '%2s' x > a/b/2 || framework_failure_
+printf '%3s' x > a/b/3 || framework_failure_
+
+Ba=$(stat --format="%B * %b" a | xargs expr)
+Bb=$(stat --format="%B * %b" a/b | xargs expr)
+Bc=$(stat --format="%B * %b" a/c | xargs expr)
+B0=$(stat --format="%B * %b" a/b/0 | xargs expr)
+B1=$(stat --format="%B * %b" a/b/1 | xargs expr)
+B2=$(stat --format="%B * %b" a/b/2 | xargs expr)
+B3=$(stat --format="%B * %b" a/b/3 | xargs expr)
+
+Sa=$(stat --format=%s a )
+Sb=$(stat --format=%s a/b )
+Sc=$(stat --format=%s a/c )
+S0=$(stat --format=%s a/b/0)
+S1=$(stat --format=%s a/b/1)
+S2=$(stat --format=%s a/b/2)
+S3=$(stat --format=%s a/b/3)
+
+Bb0123=$(expr $Bb + $B0 + $B1 + $B2 + $B3)
+Sb0123=$(expr $Sb + $S0 + $S1 + $S2 + $S3)
+
+Bab0123=$(expr $Ba + $Bc + $Bb0123)
+Sab0123=$(expr $Sa + $Sc + $Sb0123)
+
+# Sanity checks
+test $Ba -gt 4 || skip_ "block size of a directory is smaller than 4 bytes"
+test $Bc -gt 4 || skip_ "block size of an empty directory is smaller than 4 \
+bytes"
+test $Sa -gt 4 || skip_ "apparent size of a directory is smaller than 4 bytes"
+test $B1 -gt 4 || skip_ "block size of small file smaller than 4 bytes"
+test $S3 -eq 3 || framework_failure_
+test $S2 -eq 2 || framework_failure_
+test $S1 -eq 1 || framework_failure_
+test $S0 -eq 0 || framework_failure_
+test $B0 -eq 0 || skip_ "block size of an empty file unequal Zero"
+# block size of a/b/1 == a/b/2
+test $B1 -eq $B2 || framework_failure_
+# a is bigger than a/b.
+test $Sab0123 -gt $Sb0123 || framework_failure_
+test $Bab0123 -gt $Bb0123 || framework_failure_
+# a/b is bigger than empty a/c.
+test $Sb0123 -gt $Sc || framework_failure_
+test $Bb0123 -gt $Bc || framework_failure_
+
+# Exercise a bad argument: unparsable number.
+cat <<EOF > exp
+du: invalid --threshold argument 'SIZE'
+EOF
+du --threshold=SIZE a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+cat <<EOF > exp
+du: invalid -t argument 'SIZE'
+EOF
+du -t SIZE a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+# Exercise a bad argument: -0 is not valid.
+cat <<EOF > exp
+du: invalid --threshold argument '-0'
+EOF
+du --threshold=-0 a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+du -t -0 a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+du -t-0 a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+# Exercise a bad argument: empty argument.
+cat <<EOF > exp
+du: invalid --threshold argument ''
+EOF
+du --threshold= a > out 2>&1 && fail=1
+compare exp out || fail=1
+
+# Exercise a bad argument: no argument.
+du --threshold > out.tmp 2>&1 && fail=1
+sed 's/argument.*/argument/; s/option.*requires/option requires/' \
+ < out.tmp > out || framework_failure_
+cat <<EOF > exp
+du: option requires an argument
+Try 'du --help' for more information.
+EOF
+compare exp out || fail=1
+rm -f out
+
+dutest ()
+{
+ args="$1"
+ exp="$2"
+
+ rm -f exp out
+
+ # Expected output.
+ if [ "$exp" = "" ] ; then
+ touch exp
+ else
+ printf "%s\n" $exp > exp
+ fi
+
+ rc=0
+ du -B1 $args a > out1 2>&1 || { cat out1 ; rc=1 ; }
+
+ # Remove the size column and sort the output.
+ cut -f2- out1 | sort > out || framework_failure_
+
+ compare exp out || { cat out1 ; rc=1 ; }
+ return $rc
+}
+
+# Check numbers around the total size of the main directory 'a'.
+# One byte greater than 'a'.
+s=$(expr $Sab0123 + 1) # apparent size
+dutest "--app -t $s" '' || fail=1
+dutest "--app -a -t $s" '' || fail=1
+dutest "--app -S -t $s" '' || fail=1
+dutest "--app -a -S -t $s" '' || fail=1
+dutest "--app -t -$s" 'a a/b a/c' || fail=1
+dutest "--app -a -t -$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S -t -$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S -t -$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+s=$(expr $Bab0123 + 1) # block size
+dutest " -t $s" '' || fail=1
+dutest " -a -t $s" '' || fail=1
+dutest " -S -t $s" '' || fail=1
+dutest " -a -S -t $s" '' || fail=1
+dutest " -t -$s" 'a a/b a/c' || fail=1
+dutest " -a -t -$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S -t -$s" 'a a/b a/c' || fail=1
+dutest " -a -S -t -$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a'.
+s=$Sab0123 # apparent size
+dutest "--app --th=$s" 'a' || fail=1
+dutest "--app -a --th=$s" 'a' || fail=1
+dutest "--app -S --th=$s" '' || fail=1
+dutest "--app -a -S --th=$s" '' || fail=1
+dutest "--app --th=-$s" 'a a/b a/c' || fail=1
+dutest "--app -a --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=-$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+s=$Bab0123 # block size
+dutest " --th=$s" 'a' || fail=1
+dutest " -a --th=$s" 'a' || fail=1
+dutest " -S --th=$s" '' || fail=1
+dutest " -a -S --th=$s" '' || fail=1
+dutest " --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# One byte smaller than 'a'.
+s=$(expr $Sab0123 - 1) # apparent size
+dutest "--app --th=$s" 'a' || fail=1
+dutest "--app -a --th=$s" 'a' || fail=1
+dutest "--app -S --th=$s" '' || fail=1
+dutest "--app -a -S --th=$s" '' || fail=1
+dutest "--app --th=-$s" 'a/b a/c' || fail=1
+dutest "--app -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=-$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+s=$(expr $Bab0123 - 1) # block size
+dutest " --th=$s" 'a' || fail=1
+dutest " -a --th=$s" 'a' || fail=1
+dutest " -S --th=$s" '' || fail=1
+dutest " -a -S --th=$s" '' || fail=1
+dutest " --th=-$s" 'a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+
+# Check numbers around the total size of the sub directory 'a/b'.
+# One byte greater than 'a/b'.
+s=$(expr $Sb0123 + 1) # apparent size
+dutest "--app --th=$s" 'a' || fail=1
+dutest "--app -a --th=$s" 'a' || fail=1
+dutest "--app -S --th=$s" '' || fail=1
+dutest "--app -a -S --th=$s" '' || fail=1
+dutest "--app --th=-$s" 'a/b a/c' || fail=1
+dutest "--app -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=-$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+s=$(expr $Bb0123 + 1) # block size
+dutest " --th=$s" 'a' || fail=1
+dutest " -a --th=$s" 'a' || fail=1
+dutest " -S --th=$s" '' || fail=1
+dutest " -a -S --th=$s" '' || fail=1
+dutest " --th=-$s" 'a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b'.
+s=$Sb0123 # apparent size
+dutest "--app --th=$s" 'a a/b' || fail=1
+dutest "--app -a --th=$s" 'a a/b' || fail=1
+dutest "--app -S --th=$s" 'a/b' || fail=1
+dutest "--app -a -S --th=$s" 'a/b' || fail=1
+dutest "--app --th=-$s" 'a/b a/c' || fail=1
+dutest "--app -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=-$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+s=$Bb0123 # block size
+dutest " --th=$s" 'a a/b' || fail=1
+dutest " -a --th=$s" 'a a/b' || fail=1
+dutest " -S --th=$s" 'a/b' || fail=1
+dutest " -a -S --th=$s" 'a/b' || fail=1
+dutest " --th=-$s" 'a/b a/c' || fail=1
+dutest " -a --th=-$s" 'a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# One byte smaller than 'a/b'.
+s=$(expr $Sb0123 - 1) # apparent size
+dutest "--app --th=$s" 'a a/b' || fail=1
+dutest "--app -a --th=$s" 'a a/b' || fail=1
+dutest "--app -S --th=$s" 'a/b' || fail=1
+dutest "--app -a -S --th=$s" 'a/b' || fail=1
+dutest "--app --th=-$s" 'a/c' || fail=1
+dutest "--app -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=-$s" 'a a/c' || fail=1
+dutest "--app -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+s=$(expr $Bb0123 - 1) # block size
+dutest " --th=$s" 'a a/b' || fail=1
+dutest " -a --th=$s" 'a a/b' || fail=1
+dutest " -S --th=$s" 'a/b' || fail=1
+dutest " -a -S --th=$s" 'a/b' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+
+# Check numbers around the total size of the files a/b/[0123]'.
+echo One byte greater than 'a/b/3'.
+s=$(expr $S3 + 1) # apparent size
+dutest "--app --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -S --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=$s" 'a a/b a/c' || fail=1
+dutest "--app --th=-$s" '' || fail=1
+dutest "--app -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3' || fail=1
+dutest "--app -S --th=-$s" '' || fail=1
+dutest "--app -a -S --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3' || fail=1
+s=$(expr $B3 + 1) # block size
+dutest " --th=$s" 'a a/b' || fail=1
+dutest " -a --th=$s" 'a a/b' || fail=1
+dutest " -S --th=$s" 'a/b' || fail=1
+dutest " -a -S --th=$s" 'a/b' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/3'.
+echo Exactly the size of 'a/b/3'.
+s=$S3 # apparent size
+dutest "--app --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a --th=$s" 'a a/b a/b/3 a/c' || fail=1
+dutest "--app -S --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=$s" 'a a/b a/b/3 a/c' || fail=1
+dutest "--app --th=-$s" '' || fail=1
+dutest "--app -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3' || fail=1
+dutest "--app -S --th=-$s" '' || fail=1
+dutest "--app -a -S --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3' || fail=1
+s=$B3 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/2'.
+echo Exactly the size of 'a/b/2'.
+s=$S2 # apparent size
+dutest "--app --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a --th=$s" 'a a/b a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=$s" 'a a/b a/b/2 a/b/3 a/c' || fail=1
+dutest "--app --th=-$s" '' || fail=1
+dutest "--app -a --th=-$s" 'a/b/0 a/b/1 a/b/2' || fail=1
+dutest "--app -S --th=-$s" '' || fail=1
+dutest "--app -a -S --th=-$s" 'a/b/0 a/b/1 a/b/2' || fail=1
+s=$B2 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/1'.
+echo Exactly the size of 'a/b/1'.
+s=$S1 # apparent size
+dutest "--app --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app --th=-$s" '' || fail=1
+dutest "--app -a --th=-$s" 'a/b/0 a/b/1' || fail=1
+dutest "--app -S --th=-$s" '' || fail=1
+dutest "--app -a -S --th=-$s" 'a/b/0 a/b/1' || fail=1
+s=$B1 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " --th=-$s" 'a/c' || fail=1
+dutest " -a --th=-$s" 'a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=-$s" 'a a/c' || fail=1
+dutest " -a -S --th=-$s" 'a a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+
+# Exactly the size of 'a/b/0'.
+echo Exactly the size of 'a/b/0'.
+s=$S0 # apparent size
+dutest "--app --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a --th=$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest "--app -S --th=$s" 'a a/b a/c' || fail=1
+dutest "--app -a -S --th=$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+# (maximum tests (-0) not possible).
+s=$B0 # block size
+dutest " --th=$s" 'a a/b a/c' || fail=1
+dutest " -a --th=$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+dutest " -S --th=$s" 'a a/b a/c' || fail=1
+dutest " -a -S --th=$s" 'a a/b a/b/0 a/b/1 a/b/2 a/b/3 a/c' || fail=1
+# (maximum tests (-0) not possible).
+
+Exit $fail
diff --git a/tests/du/trailing-slash.sh b/tests/du/trailing-slash.sh
new file mode 100755
index 0000000..01b5e61
--- /dev/null
+++ b/tests/du/trailing-slash.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Ensure that du works properly for an argument that refers to a
+# symbolic link, and that is specified with a trailing slash.
+
+# Copyright (C) 2002-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# Before coreutils-4.5.3, it would remove a single trailing slash.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+mkdir -p dir/1/2 || framework_failure_
+ln -s dir slink || framework_failure_
+
+
+du slink/ | sed 's/^[0-9][0-9]* //' > out
+echo === >> out
+
+# Ensure that with -L we get the same results (modulo the trailing slash
+# on the third line) even without the trailing slash on the command line.
+du -L slink | sed 's/^[0-9][0-9]* //' >> out
+cat <<\EOF > exp
+slink/1/2
+slink/1
+slink/
+===
+slink/1/2
+slink/1
+slink
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/du/two-args.sh b/tests/du/two-args.sh
new file mode 100755
index 0000000..01b5e33
--- /dev/null
+++ b/tests/du/two-args.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Make sure 'du d/1 d/2' works.
+# That command failed with du from fileutils-4.0q.
+
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ du
+
+# Run this test from a sub-directory one level deeper than normal,
+# so that the "du .." below doesn't traverse sibling directories
+# that may be inaccessible due concurrently-running tests.
+mkdir sub || framework_failure_
+cd sub || framework_failure_
+
+t=t
+mkdir -p $t/1 $t/2 || framework_failure_
+
+test -d $t || fail=1
+du $t/1 $t/2 > /dev/null || fail=1
+
+# Make sure 'du . $t' and 'du .. $t' work.
+# These would fail prior to fileutils-4.0y.
+du . $t > /dev/null || fail=1
+du .. $t > /dev/null || fail=1
+
+Exit $fail