On 04/08/2016 03:15 PM, Young Mo Kang wrote: > On 04/06/2016 07:33 PM, Bernhard Voelker wrote: >> Sorry for the late reply. >> I thought a bit about the implementation and thought it'd be better >> to avoid artificially creating the OR-ed predicates, and rather store >> the wanted file types in an array and check for that in pred.c. >> I think this should be faster, too. >> > OK, I agree with that. > >> @James: did you get green lights regarding FSF Copyright assignment? >> Otherwise, or if you, Young, feel that my re-implementation is too far >> away from your original, I can also set myself as author (and change >> the "Co-authored-by: ..." to "Inspired by a proposal of ..." in the >> commit msg). >> > I completed the FSF Copyright assignment with [email protected]. > Yeah, I think that you should be the author of the patch; it is a > completely different patch from what I originally submitted.
Good. I've moved your spelling fixes in README-hacking into a separate patch. I'll push both attached patches soon. Thanks & have a nice day, Berny
>From 6c37ce48a1eb3d1f21a1848cc9c40f2cdb191e88 Mon Sep 17 00:00:00 2001 From: Bernhard Voelker <[email protected]> Date: Sun, 10 Apr 2016 14:58:55 +0200 Subject: [PATCH 1/2] find: support list of file types for -type and -xtype * find/defs.h (enum file_type): Add enumeration for all (supported) file types. (struct predicate): Replace 'type' by 'types' as an array of bool for the above enum file_type. * find/parser.c (insert_type): Treat the argument to -type and -xtype as a comma-separated list of type letters: instead of storing the single type of the predicate, save the searched type letters in the above 'types' array. * find/pred.c (pred_type): Change the comparison against the saved file type predicate: now check if the type of the actual file is in the array of searched 'types'. * find/testsuite/test_type-list.sh: Add test. * find/testsuite/Makefile.am: Reference the test. * find/find.1: Document the new feature. * doc/find.texi: Likewise. * NEWS: Likewise. RFE originally initiated by Young Mo Kang in http://lists.gnu.org/archive/html/bug-findutils/2016-02/msg00025.html --- NEWS | 5 + doc/find.texi | 4 + find/defs.h | 23 ++- find/find.1 | 19 +++ find/parser.c | 252 +++++++++++++++++------------ find/pred.c | 77 +++++++-- find/testsuite/Makefile.am | 1 + find/testsuite/test_type-list.sh | 340 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 598 insertions(+), 123 deletions(-) create mode 100755 find/testsuite/test_type-list.sh diff --git a/NEWS b/NEWS index 556eab8..59f6cb9 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,11 @@ the --help option. Previously, when the user passed invalid options or arguments, the user's attention to the corresponding error diagnostic was distracted by that lengthy text. +find now accepts multiple file type arguments to the -type and -xtype +options separated by comma ','. For example, to search for symbolic +links and directories simply provide the shorter '-type l,d' instead +of the - yet more portable - '( -type l -o -type d )'. + ** Bug Fixes #46784: frcode drops last char if no final newline diff --git a/doc/find.texi b/doc/find.texi index 634e229..93c67c3 100644 --- a/doc/find.texi +++ b/doc/find.texi @@ -1081,6 +1081,10 @@ socket @item D door (Solaris) @end table + +As a GNU extension, multiple file types can be provided as a combined list +separated by comma @samp{,}. For example, @samp{-type f,d,l} is logically +interpreted as @samp{( -type f -o -type d -o -type l )}. @end deffn @deffn Test -xtype c diff --git a/find/defs.h b/find/defs.h index 9311565..52e522f 100644 --- a/find/defs.h +++ b/find/defs.h @@ -163,6 +163,27 @@ struct size_val uintmax_t size; }; +/* Supported file types for the -type/-xtype options. */ +enum file_type + { + FTYPE_BLK, + FTYPE_CHR, + FTYPE_DIR, + FTYPE_REG, +#ifdef S_IFLNK + FTYPE_LNK, +#endif +#ifdef S_IFIFO + FTYPE_FIFO, +#endif +#ifdef S_IFSOCK + FTYPE_SOCK, +#endif +#ifdef S_IFDOOR + FTYPE_DOOR, +#endif + FTYPE_COUNT + }; enum xval { @@ -305,7 +326,7 @@ struct predicate struct time_val reftime; /* newer newerXY anewer cnewer mtime atime ctime mmin amin cmin */ struct perm_val perm; /* perm */ struct samefile_file_id samefileid; /* samefile */ - mode_t type; /* type */ + bool types[FTYPE_COUNT]; /* file type(s) */ struct format_val printf_vec; /* printf fprintf fprint ls fls print0 fprint0 print */ security_context_t scontext; /* security context */ } args; diff --git a/find/find.1 b/find/find.1 index c948b4b..7b626b5 100644 --- a/find/find.1 +++ b/find/find.1 @@ -954,6 +954,9 @@ socket .IP D door (Solaris) .RE +.IP +To search for more than one type at once, you can supply the combined list of +type letters separated by a comma `,' (GNU extension). .IP "\-uid \fIn\fR" File's numeric user ID is \fIn\fR. @@ -1653,6 +1656,8 @@ previous versions of findutils. .IP \fB\-type\fR Supported. POSIX specifies `b', `c', `d', `l', `p', `f' and `s'. GNU find also supports `D', representing a Door, where the OS provides these. +Furthermore, GNU find allows multiple types to be specified at once in a +comma-separated list. .IP \fB\-ok\fR Supported. @@ -2087,6 +2092,20 @@ discovered (for example we do not search project3/src because we already found project3/.svn), but ensures sibling directories (project2 and project3) are found. +.P +.nf +.B find /tmp -type f,d,l +.fi + +Search for files, directories, and symbolic links in the directory +.B /tmp +passing these types as a comma-separated list (GNU extension), +which is otherwise equivalent to the longer, yet more portable: + +.nf +.B find /tmp \e( -type f -o -type d -o -type l \e) +.fi + .SH EXIT STATUS .PP .B find diff --git a/find/parser.c b/find/parser.c index 57fb296..dfe0523 100644 --- a/find/parser.c +++ b/find/parser.c @@ -2679,131 +2679,171 @@ insert_type (char **argv, int *arg_ptr, PRED_FUNC which_pred) { struct predicate *our_pred; - float rate = 0.01; const char *typeletter; + const char *pred_string = which_pred == pred_xtype ? "-xtype" : "-type"; - if (collect_arg (argv, arg_ptr, &typeletter)) + if (! collect_arg (argv, arg_ptr, &typeletter)) + return false; + + if (!*typeletter) { - if (strlen (typeletter) != 1u) - { - error (EXIT_FAILURE, 0, - _("Arguments to -type should contain only one letter")); - /*NOTREACHED*/ - return false; - } + error (EXIT_FAILURE, 0, + _("Arguments to %s should contain at least one letter"), + pred_string); + /*NOTREACHED*/ + return false; + } - /* From a real system here are the counts of files by type: - Type Count Fraction - f 4410884 0.875 - d 464722 0.0922 - l 156662 0.0311 - b 4476 0.000888 - c 2233 0.000443 - s 80 1.59e-05 - p 38 7.54e-06 - */ - { - mode_t type_cell; + our_pred = insert_primary_withpred (entry, which_pred, typeletter); + our_pred->est_success_rate = 0.0; - switch (typeletter[0]) - { - case 'b': /* block special */ - type_cell = S_IFBLK; - rate = 0.000888f; - break; - case 'c': /* character special */ - type_cell = S_IFCHR; - rate = 0.000443f; - break; - case 'd': /* directory */ - type_cell = S_IFDIR; - rate = 0.0922f; - break; - case 'f': /* regular file */ - type_cell = S_IFREG; - rate = 0.875f; - break; - case 'l': /* symbolic link */ + /* Figure out if we will need to stat the file, because if we don't + * need to follow symlinks, we can avoid a stat call by using + * struct dirent.d_type. + */ + if (which_pred == pred_xtype) + { + our_pred->need_stat = true; + our_pred->need_type = false; + } + else + { + our_pred->need_stat = false; /* struct dirent is enough */ + our_pred->need_type = true; + } + + /* From a real system here are the counts of files by type: + Type Count Fraction + f 4410884 0.875 + d 464722 0.0922 + l 156662 0.0311 + b 4476 0.000888 + c 2233 0.000443 + s 80 1.59e-05 + p 38 7.54e-06 + */ + + for (; *typeletter; ) + { + unsigned int type_cell; + float rate = 0.01; + + switch (*typeletter) + { + case 'b': /* block special */ + type_cell = FTYPE_BLK; + rate = 0.000888f; + break; + case 'c': /* character special */ + type_cell = FTYPE_CHR; + rate = 0.000443f; + break; + case 'd': /* directory */ + type_cell = FTYPE_DIR; + rate = 0.0922f; + break; + case 'f': /* regular file */ + type_cell = FTYPE_REG; + rate = 0.875f; + break; + case 'l': /* symbolic link */ #ifdef S_IFLNK - type_cell = S_IFLNK; - rate = 0.0311f; + type_cell = FTYPE_LNK; + rate = 0.0311f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because symbolic links " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because symbolic links " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - case 'p': /* pipe */ + break; + case 'p': /* pipe */ #ifdef S_IFIFO - type_cell = S_IFIFO; - rate = 7.554e-6f; + type_cell = FTYPE_FIFO; + rate = 7.554e-6f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because FIFOs " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because FIFOs " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - case 's': /* socket */ + break; + case 's': /* socket */ #ifdef S_IFSOCK - type_cell = S_IFSOCK; - rate = 1.59e-5f; + type_cell = FTYPE_SOCK; + rate = 1.59e-5f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because named sockets " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because named sockets " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - case 'D': /* Solaris door */ + break; + case 'D': /* Solaris door */ #ifdef S_IFDOOR - type_cell = S_IFDOOR; - /* There are no Solaris doors on the example system surveyed - * above, but if someone uses -type D, they are presumably - * expecting to find a non-zero number. We guess at a - * rate. */ - rate = 1.0e-5f; + type_cell = FTYPE_DOOR; + /* There are no Solaris doors on the example system surveyed + * above, but if someone uses -type D, they are presumably + * expecting to find a non-zero number. We guess at a + * rate. */ + rate = 1.0e-5f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because Solaris doors " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because Solaris doors " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - default: /* None of the above ... nuke 'em. */ - type_cell = 0; - error (EXIT_FAILURE, 0, - _("Unknown argument to -type: %c"), (*typeletter)); - /*NOTREACHED*/ - return false; - } - our_pred = insert_primary_withpred (entry, which_pred, typeletter); - our_pred->est_success_rate = rate; - - /* Figure out if we will need to stat the file, because if we don't - * need to follow symlinks, we can avoid a stat call by using - * struct dirent.d_type. - */ - if (which_pred == pred_xtype) - { - our_pred->need_stat = true; - our_pred->need_type = false; - } - else - { - our_pred->need_stat = false; /* struct dirent is enough */ - our_pred->need_type = true; - } - our_pred->args.type = type_cell; + break; + default: /* None of the above ... nuke 'em. */ + type_cell = 0; + error (EXIT_FAILURE, 0, + _("Unknown argument to %s: %c"), pred_string, (*typeletter)); + /*NOTREACHED*/ + return false; } - return true; + + if (our_pred->args.types[type_cell]) + { + error (EXIT_FAILURE, 0, + _("Duplicate file type '%c' in the argument list to %s."), + (*typeletter), pred_string); + } + + our_pred->est_success_rate += rate; + our_pred->args.types[type_cell] = true; + + /* Advance. + * Currently, only 1-character file types separated by ',' are supported. + */ + typeletter++; + if (*typeletter) + { + if (*typeletter != ',') + { + error (EXIT_FAILURE, 0, + _("Must separate multiple arguments to %s using: ','"), + pred_string); + /*NOTREACHED*/ + return false; + } + typeletter++; + if (!*typeletter) + { + error (EXIT_FAILURE, 0, + _("Last file type in list argument to %s " + "is missing, i.e., list is ending on: ','"), + pred_string); + /*NOTREACHED*/ + return false; + } + } } - return false; + + return true; } diff --git a/find/pred.c b/find/pred.c index d633ab9..f7e9b59 100644 --- a/find/pred.c +++ b/find/pred.c @@ -1032,7 +1032,7 @@ bool pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { mode_t mode; - mode_t type = pred_ptr->args.type; + enum file_type type = FTYPE_COUNT; assert (state.have_type); @@ -1052,31 +1052,76 @@ pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_p mode = state.type; #ifndef S_IFMT - /* POSIX system; check `mode' the slow way. */ - if ((S_ISBLK (mode) && type == S_IFBLK) - || (S_ISCHR (mode) && type == S_IFCHR) - || (S_ISDIR (mode) && type == S_IFDIR) - || (S_ISREG (mode) && type == S_IFREG) + /* POSIX system; check `mode' the slow way. + * Search in the order of probability (f,d,l,b,c,s,p,D). + */ + if (S_ISREG (mode)) + type = FTYPE_REG; + else if (S_ISDIR (mode)) + type = FTYPE_DIR; #ifdef S_IFLNK - || (S_ISLNK (mode) && type == S_IFLNK) -#endif -#ifdef S_IFIFO - || (S_ISFIFO (mode) && type == S_IFIFO) + else if (S_ISLNK (mode)) + type = FTYPE_LNK; #endif + else if (S_ISBLK (mode)) + type = FTYPE_BLK; + else if (S_ISCHR (mode)) + type = FTYPE_CHR; #ifdef S_IFSOCK - || (S_ISSOCK (mode) && type == S_IFSOCK) + else if (S_ISSOCK (mode)) + type = FTYPE_SOCK; +#endif +#ifdef S_IFIFO + else if (S_ISFIFO (mode)) + type = FTYPE_FIFO; #endif #ifdef S_IFDOOR - || (S_ISDOOR (mode) && type == S_IFDOOR) + else if (S_ISDOOR (mode)) + type = FTYPE_DOOR; #endif - ) #else /* S_IFMT */ /* Unix system; check `mode' the fast way. */ - if ((mode & S_IFMT) == type) + switch (mode & S_IFMT) + { + case S_IFREG: + type = FTYPE_REG; + break; + case S_IFDIR: + type = FTYPE_DIR; + break; +#ifdef S_IFLNK + case S_IFLNK: + type = FTYPE_LNK; + break; +#endif + case S_IFBLK: + type = FTYPE_BLK; + break; + case S_IFCHR: + type = FTYPE_CHR; + break; +#ifdef S_IFSOCK + case S_IFSOCK: + type = FTYPE_SOCK; + break; +#endif +#ifdef S_IFIFO + case S_IFIFO: + type = FTYPE_FIFO; + break; +#endif +#ifdef S_IFDOOR + case S_IFDOOR: + type = FTYPE_DOOR; + break; +#endif + } #endif /* S_IFMT */ - return (true); + + if ((type != FTYPE_COUNT) && pred_ptr->args.types[type]) + return true; else - return (false); + return false; } bool diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am index 228957f..65d5d32 100644 --- a/find/testsuite/Makefile.am +++ b/find/testsuite/Makefile.am @@ -257,6 +257,7 @@ sv-bug-32043.sh \ test_escapechars.sh \ test_escape_c.sh \ test_inode.sh \ +test_type-list.sh \ sv-34079.sh \ sv-34976-execdir-fd-leak.sh diff --git a/find/testsuite/test_type-list.sh b/find/testsuite/test_type-list.sh new file mode 100755 index 0000000..c500b02 --- /dev/null +++ b/find/testsuite/test_type-list.sh @@ -0,0 +1,340 @@ +#! /bin/sh +# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>. +# + +# This test verifies find's behavior regarding comma-separated file +# type arguments to the -type/-xtype options. + +testname="$(basename $0)" + +. "${srcdir}"/binary_locations.sh + +die() { + echo "$@" >&2 + exit 1 +} + +# This is used to simplify checking of the return value +# which is useful when ensuring a command fails as desired. +# I.e., just doing `command ... &&fail=1` will not catch +# a segfault in command for example. With this helper you +# instead check an explicit exit code like +# returns_ 1 command ... || fail +returns_ () { + # Disable tracing so it doesn't interfere with stderr of the wrapped command + { set +x; } 2>/dev/null + + local exp_exit="$1" + shift + "$@" + test $? -eq $exp_exit && ret_=0 || ret_=1 + + set -x + { return $ret_; } 2>/dev/null +} + +# Define the nicest compare available (borrowed from gnulib). +if diff_out_=`exec 2>/dev/null; diff -u "$0" "$0" < /dev/null` \ + && diff -u Makefile "$0" 2>/dev/null | grep '^[+]#!' >/dev/null; then + # diff accepts the -u option and does not (like AIX 7 'diff') produce an + # extra space on column 1 of every content line. + if test -z "$diff_out_"; then + compare () { diff -u "$@"; } + else + compare () + { + if diff -u "$@" > diff.out; then + # No differences were found, but Solaris 'diff' produces output + # "No differences encountered". Hide this output. + rm -f diff.out + true + else + cat diff.out + rm -f diff.out + false + fi + } + fi +elif diff_out_=`exec 2>/dev/null; diff -c "$0" "$0" < /dev/null`; then + if test -z "$diff_out_"; then + compare () { diff -c "$@"; } + else + compare () + { + if diff -c "$@" > diff.out; then + # No differences were found, but AIX and HP-UX 'diff' produce output + # "No differences encountered" or "There are no differences between the + # files.". Hide this output. + rm -f diff.out + true + else + cat diff.out + rm -f diff.out + false + fi + } + fi +elif cmp -s /dev/null /dev/null 2>/dev/null; then + compare () { cmp -s "$@"; } +else + compare () { cmp "$@"; } +fi + +# Check if the given file type is supported by find. +# Used for the file type compiled in conditionally: l,p,s,D) +find_supports_type() { + find '.' -maxdepth 0 -type "$1" +} + +# Create test files of all possible types (if possible): +# f,d,p,l,b,c,s,D, and a dangling symlink. +make_test_data() { + d="$1" + ( + cd "$1" || exit 1 + # regular file + : > reg || exit 1 + # directory + mkdir dir || exit 1 + # BLK device + mknod blk b 0 0 || : # ignore failure + # CHR device + mknod chr c 0 0 || : # ignore failure + + # FIFO + if [ $HAVE_FIFO = 1 ]; then + mkfifo fifo || : # ignore failure + fi + + # Socket: try various ways to create one. + if [ $HAVE_SOCK = 1 ]; then + perl -e ' + use IO::Socket::UNIX; + my $s = IO::Socket::UNIX->new (Type => SOCK_STREAM(), Local => "sock");' + + test -S sock \ + || python -c \ + "import socket as s; + sock = s.socket(s.AF_UNIX); + sock.bind('sock'); + " + # Also the netcat family leaves the socket behind ... + test -S sock \ + || { nc -lU sock & pid=$!; \ + sleep 1; kill $pid; wait $pid; } + test -S sock \ + || { netcat -lU sock & pid=$!; \ + sleep 1; kill $pid; wait $pid; } + # ... while socat has to be forcefully killed. + test -S sock \ + || { socat unix-listen:sock fd:2 & pid=$!; \ + sleep 1; kill -9 $!; wait $pid; } + fi + + # Door: not that easy. + if [ $HAVE_DOOR = 1 ]; then + : # TODO + fi + + # Symbolic links to all types, and a dangling one. + if [ $HAVE_LINK = 1 ]; then + test -f reg && ln -s reg reg-link + test -d dir && ln -s dir dir-link + test -b blk && ln -s blk blk-link + test -c chr && ln -s chr chr-link + test -S sock && ln -s sock sock-link + test -p fifo && ln -s fifo fifo-link + ln -s enoent dangling-link + fi + ) \ + || die "failed to set up the test in ${outdir}" +} + +set -x +outdir="$(mktemp -d)" || die "FAIL: could not create a test directory." +all="${outdir}.all" +exp="${outdir}.exp" +out="${outdir}.out" +err="${outdir}.err" + +# Check what file types are compiled into find(1). +find_supports_type l && HAVE_LINK=1 || HAVE_LINK=0 +find_supports_type p && HAVE_FIFO=1 || HAVE_FIFO=0 +find_supports_type s && HAVE_SOCK=1 || HAVE_SOCK=0 +find_supports_type D && HAVE_DOOR=1 || HAVE_DOOR=0 + +# Create some test files. +make_test_data "${outdir}" \ + && "${ftsfind}" "${outdir}" -mindepth 1 > $all \ + && sort -o $all $all \ + || die "FAIL: failed to set up the test in ${outdir}" +# Just to see what's there. +"${ftsfind}" "${outdir}" -mindepth 1 -ls + +fail=0 +for exe in "${ftsfind}" "${oldfind}"; do + + # Negative tests first. Expect the output to be empty. + : > $exp + + # Ensure empty type arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type '' > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Arguments to -type should contain at least one letter' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype '' > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Arguments to -xtype should contain at least one letter' $err \ + || { cat $err; fail=1; } + + # Ensure non-separated type arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type fd > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Must separate multiple arguments to -type' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype fd > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Must separate multiple arguments to -xtype' $err \ + || { cat $err; fail=1; } + + # Ensure unterminated type list arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type f, > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Last file type in list argument to -type is missing' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype f, > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Last file type in list argument to -xtype is missing' $err \ + || { cat $err; fail=1; } + + # Ensure duplicate entries in the type list arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type f,f > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Duplicate file type .* in the argument list to -type' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype f,f > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Duplicate file type .* in the argument list to -xtype' $err \ + || { cat $err; fail=1; } + + # Continue with positive tests. + # Files and directories. + grep -e '/reg$' -e '/dir$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # Block devices. + grep -e '/reg$' -e '/dir$' -e '/blk$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type b,f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/blk' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype b,f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # Character devices. + grep -e '/reg$' -e '/dir$' -e '/chr$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,c,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/chr' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,c,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # FIFOs. + if [ $HAVE_FIFO = 1 ]; then + grep -e '/reg$' -e '/dir$' -e '/fifo$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,d,p > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/fifo' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,d,p > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # Sockets. + if [ $HAVE_SOCK = 1 ]; then + grep -e '/reg$' -e '/dir$' -e '/sock$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,d,s > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/sock' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,d,s > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # Symbolic links. + if [ $HAVE_LINK = 1 ]; then + + grep -e '/reg$' -e 'link$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,l > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e 'dangling-link$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,l > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # -xtype: all but the dangling symlink. + t='f,d,b,c' + [ $HAVE_FIFO = 1 ] && t="$t,p" + [ $HAVE_SOCK = 1 ] && t="$t,s" + [ $HAVE_DOOR = 1 ] && t="$t,D" + grep -v 'dangling-link$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype "$t" > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # negation + if [ $HAVE_LINK = 1 ]; then + "${exe}" "${outdir}" -mindepth 1 -not -xtype l > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # Finally: full list + [ $HAVE_LINK = 1 ] && t="$t,l" + "${exe}" "${outdir}" -mindepth 1 -type "$t" > $out || fail=1 + sort -o $out $out + compare $all $out || fail=1; + + "${exe}" "${outdir}" -mindepth 1 -xtype "$t" > $out || fail=1 + sort -o $out $out + compare $all $out || fail=1; +done + +rm -rf "${outdir}" $all $exp $out $err || exit 1 +exit $fail -- 2.1.4
>From 9333e22e91b68107a9608b80d611ef9b8b2286e1 Mon Sep 17 00:00:00 2001 From: Young Mo Kang <[email protected]> Date: Sun, 10 Apr 2016 15:26:09 +0200 Subject: [PATCH 2/2] maint: correct some misspelled words in README-hacking * README-hacking: Do the above. --- README-hacking | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README-hacking b/README-hacking index 12de1bb..26306e6 100644 --- a/README-hacking +++ b/README-hacking @@ -10,7 +10,7 @@ Prerequisites * git (to check out both findutils and gnulib). * A C compiler, linker and software development libraries (the standard - C library). Any compiler compliant with the 1990 ICO C standard running + C library). Any compiler compliant with the 1990 ISO C standard running on a POSIX system should work. * GNU Autoconf * GNU Automake @@ -18,7 +18,7 @@ Prerequisites * GNU gettext * GNU Dejagnu -Dejagnu is in fact optional, but it's strongly recommened, since it is +Dejagnu is in fact optional, but it's strongly recommended, since it is needed to run findutils' test suite (which is how you know that find works once it is built on your system). @@ -106,10 +106,10 @@ MAX_PROC_MAX. --- example ends --- There are several things to notice about this checkin message. Most -importatly, it begins with a single line summary of the whole change. +importantly, it begins with a single line summary of the whole change. This needs to be short. It would be used as the subject line of patches mailed by "git send-email". Some people begin that line with -a one-word tag indicating what is addected (for example find: for +a one-word tag indicating what is affected (for example find: for changes to find, doc: to changes to the documentation, maint: for changes to the maintainer automation and so forth). -- 2.1.4
