From 6d2fa2c9a065743b9655427cedaf54bb55cd143f Mon Sep 17 00:00:00 2001 From: Bernhard Voelker Date: Tue, 29 Mar 2022 00:24:47 +0200 Subject: find: omit warning diagnostic for -name '/' Although usually a pattern containing a directory separator does not match anything, a pattern solely consisting of one '/' still does (and has to) for the root directory "/". * find/parser.c (check_name_arg): Omit the warning in the case the given pattern equals "/". find/find.1 (-name): Clarify better that the pattern "/" is valid to match the "/" directory. * init.cfg (find_emits_warnings_): Add utility function. * tests/find/name-slash.sh: Add test. * tests/local.mk (all_tests): Reference it. * MEWS (Bug Fixes): Mention the fix. Fixes https://savannah.gnu.org/bugs/?62227 --- NEWS | 6 +++++ find/find.1 | 25 ++++++++++-------- find/parser.c | 14 +++++----- init.cfg | 9 +++++++ tests/find/name-slash.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/local.mk | 1 + 6 files changed, 105 insertions(+), 18 deletions(-) create mode 100755 tests/find/name-slash.sh diff --git a/NEWS b/NEWS index b9e28fb9..6b8c3493 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout) * Noteworthy changes in release ?.? (????-??-??) [?] +** Bug Fixes + + 'find -name /' no longer outputs a warning, because that is a valid pattern + to match the root directory "/". Previously, a diagnostic falsely claimed + that this pattern would not match anything. [#62227] + * Noteworthy changes in release 4.9.0 (2022-02-22) [stable] diff --git a/find/find.1 b/find/find.1 index 6bad0096..b3ec9753 100644 --- a/find/find.1 +++ b/find/find.1 @@ -848,20 +848,23 @@ modification times. Base of file name (the path with the leading directories removed) matches shell pattern .IR pattern . -Because the leading directories are removed, -the file names considered for a match with -.B \-name -will never include a slash, so `\-name a/b' will never match anything -(you probably need to use +Because the leading directories of the file names are removed, the +.I pattern +should not include a slash, because `\-name a/b' will never match anything +(and you probably want to use .B \-path instead). -A warning is issued if you try to do this, -unless the environment variable +An exception to this is when using only a slash as \fIpattern\fR (`-name /'), +because that is a valid string for matching the root directory "/" (because the +base name of "/" is "/"). +A warning is issued if you try to pass a pattern containing a - but not +consisting solely of one - slash, unless the environment variable .B POSIXLY_CORRECT -is set. -The metacharacters (`*', `?', -and `[]') match a `.\&' at the start of the base name (this is a change -in findutils-4.2.2; see section STANDARDS CONFORMANCE below). To ignore a +is set or the option +.B \-nowarn +is used. + +To ignore a directory and the files under it, use .B \-prune rather than checking every file in the tree; diff --git a/find/parser.c b/find/parser.c index 75c730c3..5774bd94 100644 --- a/find/parser.c +++ b/find/parser.c @@ -1270,16 +1270,16 @@ fnmatch_sanitycheck (void) static void check_name_arg (const char *pred, const char *alt, const char *arg) { - if (should_issue_warnings () && strchr (arg, '/')) + if (should_issue_warnings () && strchr (arg, '/') && (0 != strcmp ("/", arg))) { error (0, 0, _("warning: %s matches against basenames only, " - "but the given pattern contains a directory separator (%s), " - "thus the expression will evaluate to false all the time. " - "Did you mean %s?"), - safely_quote_err_filename (0, pred), - safely_quote_err_filename (1, "/"), - safely_quote_err_filename (2, alt)); + "but the given pattern contains a directory separator (%s), " + "thus the expression will evaluate to false all the time. " + "Did you mean %s?"), + safely_quote_err_filename (0, pred), + safely_quote_err_filename (1, "/"), + safely_quote_err_filename (2, alt)); } } diff --git a/init.cfg b/init.cfg index 5e422291..98423613 100644 --- a/init.cfg +++ b/init.cfg @@ -514,6 +514,15 @@ fiemap_capable_() python "$abs_srcdir"/tests/fiemap-capable "$@" } +# Determine if find(1) emits warnings. This is not the case +# e.g. if stdin is not a tty. +find_emits_warnings_() +{ + # Find usually emits a warning for the deprecated -d option. + find -maxdepth 0 -d -quit 2>&1 \ + | grep -q 'warning:' +} + # Skip the current test if "." lacks d_type support. require_dirent_d_type_() { diff --git a/tests/find/name-slash.sh b/tests/find/name-slash.sh new file mode 100755 index 00000000..abd9522e --- /dev/null +++ b/tests/find/name-slash.sh @@ -0,0 +1,68 @@ +#!/bin/sh +# Exercise 'find -name PATTERN' behavior with a '/' in PATTERN. + +# Copyright (C) 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 . + +. "${srcdir=.}/tests/init.sh"; fu_path_prepend_ +print_ver_ find + +# Ensure that find does not generally skip warnings due to POSIX requirements. +unset POSIXLY_CORRECT + +# Detect if find emits warnings. +find_emits_warnings_ \ + && fwarns=1 \ + || fwarns=0 + +# Exercise '-name PATTERN' with a '/' somewhere in PATTERN. +find -name 'dir/file' > out 2> err || fail=1 +compare /dev/null out || fail=1 +if [ $fwarns = 1 ]; then + grep 'warning: .*matches against basenames only.* evaluate to false' err \ + || { cat err; fail=1; } +else + compare /dev/null out +fi + +# Likewise in POSIX environment. +POSIXLY_CORRECT=1 find -name 'dir/file' > out 2> err || fail=1 +compare /dev/null out || fail=1 +compare /dev/null err || fail=1 + +# Likewise with -nowarn. +find -nowarn -name 'dir/file' > out 2> err || fail=1 +compare /dev/null out || fail=1 +compare /dev/null err || fail=1 + +# Exercise '-name /', i.e., PATTERN just being "/": no warning because this +# is a valid basename in the (trivial) case comparing to root directory "/". +echo '/' > exp || framework_failure_ +find / -maxdepth 0 -name '/' > out 2> err || fail=1 +compare exp out || fail=1 +compare /dev/null err || fail=1 + +# Exercise '-name /' in POSIX environment. +POSIXLY_CORRECT=1 find / -maxdepth 0 -name '/' > out 2> err || fail=1 +compare exp out || fail=1 +compare /dev/null err || fail=1 + +# Exercise '-name /' with the -warn option. +find / -warn -maxdepth 0 -name '/' > out 2> err || fail=1 +compare exp out || fail=1 +compare /dev/null err || fail=1 + + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk index e75a9130..4e8efd41 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -110,6 +110,7 @@ all_tests = \ tests/find/inode-zero.sh \ tests/find/many-dir-entries-vs-OOM.sh \ tests/find/name-lbracket-literal.sh \ + tests/find/name-slash.sh \ tests/find/printf_escapechars.sh \ tests/find/printf_escape_c.sh \ tests/find/printf_inode.sh \ -- cgit v1.2.1