diff --git a/NEWS b/NEWS index f1108854..f6573b67 100644 --- a/NEWS +++ b/NEWS @@ -14,7 +14,7 @@ the configure option '--without-fts'. New tests, -readable, -writable, -executable. These check that a file can be read, written or executed respectively. -* Major changes in release 4.2.27-CVS +* Major changes in release 4.2.27 ** Warnings of Future Changes @@ -39,6 +39,10 @@ remounted elsewhere using "mount --bind". (Savannah bug #14921). ** Documentation Changes +Following some extensive and detailed review comments from Aaron +Hawley, the material in the manual pages and the Texinfo manual are +now synchronised. + The %M format specifier of "find -printf" is now documented, although it has existed since release 4.2.5. @@ -87,6 +91,12 @@ affected (albeit for longer command lines). In theory the same problem could affect 'find -exec {} +', but that's much less likely (even so, the bug is fixed there too). +Bugfix for an unusual failure mode (Savannah bug #14842) where an +attempt to allocate more space for directory contents succeeds but is +incorrectly diagnosed as a failure. The likelihood of you +experiencing this depends on your architecture, operating system and +resource limits. This failure has been observed in a directory +containing 35396 entries. ** Documentation Changes diff --git a/doc/find.texi b/doc/find.texi index aaa7b41f..aecab959 100644 --- a/doc/find.texi +++ b/doc/find.texi @@ -1421,6 +1421,47 @@ you are searching might contain a newline, you should use @samp{-fprint0} instead. @end deffn + +@c @deffn Option -show-control-chars how +@c This option affects how some of @code{find}'s actions treat +@c unprintable characters in file names. If @samp{how} is +@c @samp{literal}, any subsequent actions (i.e. actions further on in the +@c command line) print file names as-is. +@c +@c If this option is not specified, it currently defaults to @samp{safe}. +@c If @samp{how} is @samp{safe}, C-like backslash escapes are used to +@c indicate the non-printable characters for @samp{-ls} and @samp{-fls}. +@c On the other hand, @samp{-print}, @samp{-fprint}, @samp{-fprintf} and +@c @code{-printf} all quote unprintable characters if the data is going +@c to a tty, and otherwise the data is emitted literally. +@c +@c @table @code +@c @item -ls +@c Escaped if @samp{how} is @samp{safe} +@c @item -fls +@c Escaped if @samp{how} is @samp{safe} +@c @item -print +@c Always quoted if stdout is a tty, +@c @samp{-show-control-chars} is ignored +@c @item -print0 +@c Always literal, never escaped +@c @item -fprint +@c Always quoted if the destination is a tty; +@c @samp{-show-control-chars} is ignored +@c @item -fprint0 +@c Always literal, never escaped +@c @item -fprintf +@c If the destination is a tty, the @samp{%f}, +@c @samp{%F}, @samp{%h}, @samp{%l}, @samp{%p}, +@c and @samp{%P} directives produce quoted +@c strings if stdout is a tty and are treated +@c literally otherwise. +@c @item -printf +@c As for @code{-fprintf}. +@c @end table +@c @end deffn + + @node Print File Information @section Print File Information diff --git a/find/defs.h b/find/defs.h index a00eb8cf..4fe5a71c 100644 --- a/find/defs.h +++ b/find/defs.h @@ -308,6 +308,9 @@ struct predicate /* True if this predicate node requires knowledge of the file type. */ boolean need_type; + /* True if this predicate should display control characters literally */ + boolean literal_control_chars; + /* Information needed by the predicate processor. Next to each member are listed the predicates that use it. */ union @@ -356,7 +359,6 @@ char *dirname PARAMS((char *path)); void error PARAMS((int status, int errnum, char *message, ...)); /* listfile.c */ -void list_file PARAMS((char *name, char *relname, struct stat *statp, time_t current_time, int output_block_size, FILE *stream)); char *get_link_name PARAMS((char *name, char *relname)); /* stpcpy.c */ @@ -549,9 +551,14 @@ struct options * no longer exists by the time we get around to processing it. */ boolean ignore_readdir_race; + + /* If true, pass control characters through. If false, escape them + * or turn them into harmless things. + */ + boolean literal_control_chars; -/* If true, we issue warning messages - */ + /* If true, we issue warning messages + */ boolean warnings; time_t start_time; /* Time at start of execution. */ diff --git a/find/find.c b/find/find.c index 36b789e2..c452fd4d 100644 --- a/find/find.c +++ b/find/find.c @@ -162,10 +162,12 @@ main (int argc, char **argv) if (isatty(0)) { options.warnings = true; + options.literal_control_chars = false; } else { options.warnings = false; + options.literal_control_chars = false; /* may change */ } diff --git a/find/ftsfind.c b/find/ftsfind.c index 4b597ec9..9f926c5f 100644 --- a/find/ftsfind.c +++ b/find/ftsfind.c @@ -445,10 +445,12 @@ main (int argc, char **argv) if (isatty(0)) { options.warnings = true; + options.literal_control_chars = false; } else { options.warnings = false; + options.literal_control_chars = false; /* may change */ } diff --git a/find/parser.c b/find/parser.c index 938ceb88..9f359a5f 100644 --- a/find/parser.c +++ b/find/parser.c @@ -135,6 +135,7 @@ static boolean parse_readable PARAMS((const struct parser_table*, char *arg static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); +static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); @@ -276,6 +277,9 @@ static struct parser_table const parse_table[] = PARSE_TEST ("regex", regex), /* GNU */ PARSE_OPTION ("regextype", regextype), /* GNU */ PARSE_TEST ("samefile", samefile), /* GNU */ +#if 0 + PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */ +#endif PARSE_TEST ("size", size), PARSE_TEST ("type", type), PARSE_TEST ("uid", uid), /* GNU */ @@ -1644,6 +1648,42 @@ parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr) return true; } +#if 0 +static boolean +parse_show_control_chars (const struct parser_table* entry, char **argv, int *arg_ptr) +{ + const char *arg; + const char *errmsg = _("The -show-control-chars option takes a single argument which " + "must be 'literal' or 'safe'"); + + if ((argv == NULL) || (argv[*arg_ptr] == NULL)) + { + error (1, errno, "%s", errmsg); + return false; + } + else + { + arg = argv[*arg_ptr]; + + if (0 == strcmp("literal", arg)) + { + options.literal_control_chars = true; + } + else if (0 == strcmp("safe", arg)) + { + options.literal_control_chars = false; + } + else + { + error (1, errno, "%s", errmsg); + return false; + } + (*arg_ptr)++; /* consume the argument. */ + return true; + } +} +#endif + static boolean parse_true (const struct parser_table* entry, char **argv, int *arg_ptr) diff --git a/find/pred.c b/find/pred.c index 1f021ee3..085475ae 100644 --- a/find/pred.c +++ b/find/pred.c @@ -37,6 +37,7 @@ #include "printquoted.h" #include "buildcmd.h" #include "yesno.h" +#include "listfile.h" #if ENABLE_NLS # include @@ -527,8 +528,9 @@ boolean pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { list_file (pathname, state.rel_pathname, stat_buf, options.start_time, - options.output_block_size, pred_ptr->args.stream); - return (true); + options.output_block_size, + pred_ptr->literal_control_chars, pred_ptr->args.stream); + return true; } boolean @@ -1060,11 +1062,11 @@ insert_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { - (void) pred_ptr; - list_file (pathname, state.rel_pathname, stat_buf, options.start_time, - options.output_block_size, stdout); - return (true); + options.output_block_size, + pred_ptr->literal_control_chars, + stdout); + return true; } boolean diff --git a/find/util.c b/find/util.c index 4d81f3e0..63c1d419 100644 --- a/find/util.c +++ b/find/util.c @@ -92,7 +92,8 @@ get_new_pred (const struct parser_table *entry) last_pred->pred_next = NULL; last_pred->pred_left = NULL; last_pred->pred_right = NULL; - return (last_pred); + last_pred->literal_control_chars = options.literal_control_chars; + return last_pred; } /* Return a pointer to a new predicate, with operator check. diff --git a/lib/listfile.c b/lib/listfile.c index 642f20a8..cb200bf8 100644 --- a/lib/listfile.c +++ b/lib/listfile.c @@ -178,7 +178,7 @@ struct group *getgrgid (); char * get_link_name (char *name, char *relname); -static void print_name_with_quoting (register char *p, FILE *stream); +static void print_name (register char *p, FILE *stream, int literal_control_chars); extern char * getgroup (gid_t gid); extern char * getuser (uid_t uid); @@ -198,6 +198,7 @@ list_file (char *name, struct stat *statp, time_t current_time, int output_block_size, + int literal_control_chars, FILE *stream) { char modebuf[11]; @@ -302,7 +303,7 @@ list_file (char *name, 1, 1)); } - print_name_with_quoting (name, stream); + print_name (name, stream, literal_control_chars); #ifdef S_ISLNK if (S_ISLNK (statp->st_mode)) @@ -312,7 +313,7 @@ list_file (char *name, if (linkname) { fputs (" -> ", stream); - print_name_with_quoting (linkname, stream); + print_name (linkname, stream, literal_control_chars); free (linkname); } } @@ -320,6 +321,14 @@ list_file (char *name, putc ('\n', stream); } + +static void +print_name_without_quoting (char *p, FILE *stream) +{ + fprintf(stream, "%s", p); +} + + static void print_name_with_quoting (register char *p, FILE *stream) { @@ -370,6 +379,14 @@ print_name_with_quoting (register char *p, FILE *stream) } } +static void print_name (register char *p, FILE *stream, int literal_control_chars) +{ + if (literal_control_chars) + print_name_without_quoting(p, stream); + else + print_name_with_quoting(p, stream); +} + #ifdef S_ISLNK char * get_link_name (char *name, char *relname) diff --git a/lib/listfile.h b/lib/listfile.h index 64d86c51..d60a0ad3 100644 --- a/lib/listfile.h +++ b/lib/listfile.h @@ -21,7 +21,7 @@ #if !defined LISTFILE_H # define LISTFILE_H -void list_file (char *name, char *relname, struct stat *statp, time_t current_time, int output_block_size, FILE *stream); +void list_file (char *name, char *relname, struct stat *statp, time_t current_time, int output_block_size, int literal_control_chars, FILE *stream);