Paul Eggert 6bf2c33ea4 diff: use openat, fstatat when recursive
This should improve performance when doing recursive comparisons.
Currently there is no attempt to avoid file descriptor exhaustion,
just as previously there is no attempt to avoid file names
that provoke ENAMETOOLONG.  Because of this change, ‘diff - A/B’
now works correctly when standard input is a directory.
* .gitignore: Add lib/dirent.h.
* bootstrap.conf (gnulib_modules): Add fdopendir.
* src/diff.c (main): Initialize noparent’s desc to AT_FDCWD.
(compare_files): Use fstatat with parent directory’s file
descriptor and relative name, instead of lstat or stat.
Likewise for openat and open.
* src/diff.h (struct file_data): New member ‘dirstream’.
(struct comparison): The ‘parent’ member is now &noparent (instead
of null) if there is no parent.  All uses changed.
(curr): New toplevel variable, replacing ‘files’.  All uses changed.
* src/dir.c: Include dirname.h, for last_component.
(dir_read): New arg PARENTDIRFD.  Arg DIR is no longer
pointer-to-const since DIR->desc and DIR->dirstream are now
updated.  Use PARENTDIRFD to open the directory via
opendat+fdopendir instead of via opendir.  Update new dirstream
component instead of closing the directory, since it’s now the
caller’s responsibility to close the directory because callers now
want the file descriptor.  All callers changed.
(diff_dirs): First arg CMP is no longer pointer-to-const since
CMP->file is updated by dir_read.  All callers changed.
(find_dir_file_pathname): First arg is now struct file_data *,
not merely a file name.  All callers changed.
* tests/stdin: Test new behavior when stdin is a directory.
2023-07-18 20:07:13 -07:00

32 lines
637 B
Bash
Executable File

#!/bin/sh
# Ensure that "-" means "standard input".
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
echo a > a || framework_failure_
echo b > b || framework_failure_
cat <<'EOF' > exp || framework_failure_
--- -
+++ b
@@ -1 +1 @@
-a
+b
EOF
returns_ 1 diff -u - b < a > out 2> err || fail=1
# Remove date and time.
sed -e 's/^\([-+*][-+*][-+*] [^ ]*\) .*/\1/' out >outk || framework_failure_
compare exp outk || fail=1
compare /dev/null err || fail=1
mkdir d || framework_failure_
echo a >d/a || framework_failure_
diff -u - a <d >out 2>err || fail=1
compare /dev/null out || fail=1
compare /dev/null err || fail=1
Exit $fail