diff options
author | James Youngman <jay@gnu.org> | 2011-06-13 23:29:50 +0100 |
---|---|---|
committer | James Youngman <jay@gnu.org> | 2011-06-13 23:54:48 +0100 |
commit | fce18654244a4ad55ed51f5e8adae1db5ff7555b (patch) | |
tree | d51f86a09f7aa71b3a894895c389e3c644121e8a | |
parent | b43a69932d4234e3d49cf22d7a756abfc2418132 (diff) | |
download | findutils-fce18654244a4ad55ed51f5e8adae1db5ff7555b.tar.gz |
Split strings into fields nondestructively.
* lib/splitstring.c: New file; defines splitstring(), which will
non-destructively locate character-separated fields in a string.
* lib/splitstring.h: New file; declares splitstring.
* lib/test_splitstring.c: New file; unit test for splitstring.c.
* lib/nextelem.c: Delete (obsoleted by splitstring.c).
* lib/nextelem.h: Delete (obsoleted by splitstring.h).
* lib/Makefile.am (libfind_a_SOURCES): Add splitstring.c,
splitstring.c. Remove nextelem.c, nextelem.h.
(check_PROGRAMS): Add test_splitstring.
(TESTS): Add test_splitstring.
(test_splitstring_SOURCES): Sources for the
test_splitstring unit test.
* locate/locate.c: Include splitstring.h rather than nextelem.h.
(dolocate): Use splitstring rather than next_element. In places
where we need a nul-terminated string, use strndup() to create it.
Convert some space-tab sequences to regular spacing.
* find/parser.c: Include splitstring.h rather than nextelem.h.
(check_path_safety): Use splitstring rather than next_element.
* import-gnulib.config (modules): Depend on the module strndup.
* cfg.mk: Exempt lib/test_splitstring.c from calling
bindtextdomain or set_program_name.
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | cfg.mk | 4 | ||||
-rw-r--r-- | find/parser.c | 32 | ||||
-rw-r--r-- | import-gnulib.config | 1 | ||||
-rw-r--r-- | lib/Makefile.am | 14 | ||||
-rw-r--r-- | lib/nextelem.c | 85 | ||||
-rw-r--r-- | lib/nextelem.h | 26 | ||||
-rw-r--r-- | lib/splitstring.c | 60 | ||||
-rw-r--r-- | lib/splitstring.h | 40 | ||||
-rw-r--r-- | lib/test_splitstring.c | 201 | ||||
-rw-r--r-- | locate/locate.c | 1307 |
11 files changed, 1019 insertions, 776 deletions
@@ -1,5 +1,30 @@ 2011-06-13 James Youngman <jay@gnu.org> + Split strings into fields nondestructively. + * lib/splitstring.c: New file; defines splitstring(), which will + non-destructively locate character-separated fields in a string. + * lib/splitstring.h: New file; declares splitstring. + * lib/test_splitstring.c: New file; unit test for splitstring.c. + * lib/nextelem.c: Delete (obsoleted by splitstring.c). + * lib/nextelem.h: Delete (obsoleted by splitstring.h). + * lib/Makefile.am (libfind_a_SOURCES): Add splitstring.c, + splitstring.c. Remove nextelem.c, nextelem.h. + (check_PROGRAMS): Add test_splitstring. + (TESTS): Add test_splitstring. + (test_splitstring_SOURCES): Sources for the + test_splitstring unit test. + * locate/locate.c: Include splitstring.h rather than nextelem.h. + (dolocate): Use splitstring rather than next_element. In places + where we need a nul-terminated string, use strndup() to create it. + Convert some space-tab sequences to regular spacing. + * find/parser.c: Include splitstring.h rather than nextelem.h. + (check_path_safety): Use splitstring rather than next_element. + * import-gnulib.config (modules): Depend on the module strndup. + * cfg.mk: Exempt lib/test_splitstring.c from calling + bindtextdomain or set_program_name. + +2011-06-13 James Youngman <jay@gnu.org> + Fix compilation failure in bigram.c by including <locale.h>. * locate/bigram.c: Include <locale.h>. @@ -36,13 +36,15 @@ exclude_file_name_regexp--sc_trailing_blank = \ exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ ^(.*/testsuite/.*\.(xo|xi|xe))|COPYING|doc/regexprops\.texi|m4/order-(bad|good)\.bin$$ exclude_file_name_regexp--sc_bindtextdomain = \ - ^lib/regexprops\.c$$ + ^lib/(regexprops|test_splitstring)\.c$$ exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \ ^(build-aux/src-sniff\.py)|ChangeLog$$ exclude_file_name_regexp--sc_prohibit_test_minus_ao = \ ^(ChangeLog)|((find|locate|xargs)/testsuite/.*\.exp)$$ exclude_file_name_regexp--sc_prohibit_doubled_word = \ ^(xargs/testsuite/xargs\.sysv/iquotes\.xo)|ChangeLog|po/.*\.po$$ +exclude_file_name_regexp--sc_program_name = \ + ^lib/test_splitstring\.c$$ # sc_texinfo_acronym: perms.texi from coreutils uses @acronym{GNU}. exclude_file_name_regexp--sc_texinfo_acronym = doc/perm\.texi diff --git a/find/parser.c b/find/parser.c index 7b82ae7a..ea676bd6 100644 --- a/find/parser.c +++ b/find/parser.c @@ -34,7 +34,6 @@ #include "xalloc.h" #include "quotearg.h" #include "buildcmd.h" -#include "nextelem.h" #include "regextype.h" #include "stat-time.h" #include "xstrtod.h" @@ -44,6 +43,7 @@ #include "findutils-version.h" #include "safe-atoi.h" #include "fdleak.h" +#include "splitstring.h" #include <fcntl.h> @@ -3227,11 +3227,16 @@ make_segment (struct segment **segment, return &(*segment)->next; } + + + static void check_path_safety (const char *action, char **argv) { - char *s; const char *path = getenv ("PATH"); + const char *path_separators = ":"; + size_t pos, len; + if (NULL == path) { /* $PATH is not set. Assume the OS default is safe. @@ -3242,34 +3247,35 @@ check_path_safety (const char *action, char **argv) return; } - (void)argv; - - s = next_element (path, 1); - while ((s = next_element ((char *) NULL, 1)) != NULL) + splitstring (path, path_separators, true, &pos, &len); + do { - if (0 == strcmp (s, ".")) + if (0 == len || (1 == len && path[pos] == '.')) { + /* empty field signifies . */ error (EXIT_FAILURE, 0, _("The current directory is included in the PATH " "environment variable, which is insecure in " "combination with the %s action of find. " "Please remove the current directory from your " - "$PATH (that is, remove \".\" or leading or trailing " - "colons)"), + "$PATH (that is, remove \".\", doubled colons, " + "or leading or trailing colons)"), action); } - else if ('/' != s[0]) + else if (path[pos] != '/') { - /* Relative paths are also dangerous in $PATH. */ + char *relpath = strndup (&path[pos], len); error (EXIT_FAILURE, 0, _("The relative path %s is included in the PATH " "environment variable, which is insecure in " "combination with the %s action of find. " "Please remove that entry from $PATH"), - safely_quote_err_filename (0, s), + safely_quote_err_filename (0, relpath ? relpath : &path[pos]), action); + /*NOTREACHED*/ + free (relpath); } - } + } while (splitstring (path, path_separators, false, &pos, &len)); } diff --git a/import-gnulib.config b/import-gnulib.config index 5fb46c21..567d66c5 100644 --- a/import-gnulib.config +++ b/import-gnulib.config @@ -132,6 +132,7 @@ strcasestr strdup-posix strftime string +strndup strtol strtoul strtoull diff --git a/lib/Makefile.am b/lib/Makefile.am index f8ff625e..5450e9aa 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -6,7 +6,7 @@ AM_CFLAGS = $(WARN_CFLAGS) noinst_LIBRARIES = libfind.a -check_PROGRAMS = regexprops +check_PROGRAMS = regexprops test_splitstring check_SCRIPTS = check-regexprops regexprops_SOURCES = regexprops.c regextype.c @@ -15,7 +15,7 @@ if CROSS_COMPILING # The regexprops program needs to be a native executable, so we # can't build it with a cross-compiler. else -TESTS += check-regexprops +TESTS += check-regexprops test_splitstring endif libfind_a_SOURCES = findutils-version.c @@ -32,11 +32,11 @@ MAINTAINERCLEANFILES = INCLUDES = -I../gl/lib -I$(top_srcdir)/gl/lib LDADD = ../gl/lib/libgnulib.a $(LIBINTL) -libfind_a_SOURCES += nextelem.h printquoted.h listfile.h \ - regextype.h dircallback.h safe-atoi.h -libfind_a_SOURCES += listfile.c nextelem.c extendbuf.c buildcmd.c savedirinfo.c \ +libfind_a_SOURCES += printquoted.h listfile.h \ + regextype.h dircallback.h safe-atoi.h splitstring.h +libfind_a_SOURCES += listfile.c extendbuf.c buildcmd.c savedirinfo.c \ forcefindlib.c qmark.c printquoted.c regextype.c dircallback.c fdleak.c \ - safe-atoi.c + safe-atoi.c splitstring.c EXTRA_DIST += waitpid.c forcefindlib.c TESTS_ENVIRONMENT = REGEXPROPS=regexprops$(EXEEXT) @@ -46,3 +46,5 @@ libfind_a_DEPENDENCIES = $(FINDLIBOBJS) check-regexprops: check-regexprops.sh cp $(srcdir)/check-regexprops.sh check-regexprops chmod +x check-regexprops + +test_splitstring_SOURCES = test_splitstring.c splitstring.c diff --git a/lib/nextelem.c b/lib/nextelem.c deleted file mode 100644 index 3e9246cf..00000000 --- a/lib/nextelem.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Return the next element of a path. - Copyright (C) 1992, 2005, 2010, 2011 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/>. -*/ - -/* Written by David MacKenzie <djm@gnu.org>, - inspired by John P. Rouillard <rouilj@cs.umb.edu>. */ - -#include <config.h> - - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - - -#include "nextelem.h" - - -/* Return the next element of a colon-separated path. - A null entry in the path is equivalent to "." (the current directory). - - If NEW_PATH is non-NULL, set the path and return NULL. - If NEW_PATH is NULL, return the next item in the string, or - return NULL if there are no more elements. */ - -char * -next_element (const char *new_path, int curdir_ok) -{ - static char *path = NULL; /* Freshly allocated copy of NEW_PATH. */ - static char *end; /* Start of next element to return. */ - static int final_colon; /* If zero, path didn't end with a colon. */ - char *start; /* Start of path element to return. */ - - if (new_path) - { - free (path); - end = path = strdup (new_path); - final_colon = 0; - return NULL; - } - - if (*end == '\0') - { - if (final_colon) - { - final_colon = 0; - return curdir_ok ? "." : ""; - } - return NULL; - } - - start = end; - final_colon = 1; /* Maybe there will be one. */ - - end = strchr (start, ':'); - if (end == start) - { - /* An empty path element. */ - *end++ = '\0'; - return curdir_ok ? "." : ""; - } - else if (end == NULL) - { - /* The last path element. */ - end = strchr (start, '\0'); - final_colon = 0; - } - else - *end++ = '\0'; - - return start; -} diff --git a/lib/nextelem.h b/lib/nextelem.h deleted file mode 100644 index 00ffcfef..00000000 --- a/lib/nextelem.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Return the next element of a path. - Copyright (C) 1992, 2010, 2011 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/>. -*/ - -/* Written by David MacKenzie <djm@gnu.org>, - inspired by John P. Rouillard <rouilj@cs.umb.edu>. */ - -#ifndef INC_NEXTELEM_H -#define INC_NEXTELEM_H 1 - -char *next_element (const char *path, int curdir_ok); - -#endif diff --git a/lib/splitstring.c b/lib/splitstring.c new file mode 100644 index 00000000..e706d9c8 --- /dev/null +++ b/lib/splitstring.c @@ -0,0 +1,60 @@ +/* splitstring.c -- split a const string into fields. + Copyright (C) 2011 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/>. +*/ +/* + * Written by James Youngman. + */ + +#include <config.h> +#include <stdbool.h> +#include <string.h> + +#include "splitstring.h" + +static size_t +field_length (const char *str, const char *separators) +{ + /* if there are no separators, the whole input is one field. */ + if (*separators) + { + const char *end = strpbrk (str, separators); + if (end) + return end - str; + } + return strlen (str); +} + + +bool +splitstring(const char *s, const char *separators, bool first, + size_t *pos, size_t *len) +{ + if (first) + { + *pos = 0u; + *len = 0u; + } + else + { + *pos += *len; /* advance to the next field. */ + if (s[*pos]) + ++*pos; /* skip the separator */ + else + return false; /* we reached the end. */ + } + *len = field_length (&s[*pos], separators); + return true; +} diff --git a/lib/splitstring.h b/lib/splitstring.h new file mode 100644 index 00000000..c91f7e75 --- /dev/null +++ b/lib/splitstring.h @@ -0,0 +1,40 @@ +/* splitstring.h -- split a const string into fields. + Copyright (C) 2011 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/>. +*/ +/* + * Written by James Youngman. + */ + +/* Split a string into fields. The string is never modified. + * + * A false return value indicates that there are no more fields. + * Otherwise the next field is at the poisition indicated by *POS and + * has length *LEN. + * + * Set FIRST to true only on the first call for any given value of s. + * *POS and *LEN do not need to be initialised in this case. + * On subsequent calls, these values should be left at the values + * set by the last call. + * + * Any character in SEPARATORS is taken to be a field separator. + * Consecutive field separators are taken to indicate the presence of + * an empty field. + */ +#include <stdbool.h> +#include <stddef.h> + +bool splitstring(const char *s, const char *separators, + bool first, size_t *pos, size_t *len); diff --git a/lib/test_splitstring.c b/lib/test_splitstring.c new file mode 100644 index 00000000..9dedb7cb --- /dev/null +++ b/lib/test_splitstring.c @@ -0,0 +1,201 @@ +/* test_splitstring.c -- unit test for splitstring() + Copyright (C) 2011 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/>. +*/ +#include <config.h> +#include <stdio.h> +#include <assert.h> + +#include "splitstring.h" + +static void +assertEqualFunc(const char *file, int line, const char *label, + size_t expected, size_t got) +{ + if (expected != got) + fprintf(stderr, "%s line %d: %s: expected %lu, got %lu\n", + file, line, label, (unsigned long)expected, (unsigned long)got); +} +#define ASSERT_EQUAL(expected,got) \ + do{ \ + assertEqualFunc(__FILE__,__LINE__,"ASSERT_EQUAL",expected,got); \ + assert (expected == got); \ + } while (0); + + +static void +test_empty (void) +{ + size_t len, pos; + bool result; + const char *empty = ""; + + result = splitstring (empty, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (0, len); + result = splitstring (empty, ":", false, &pos, &len); + assert (!result); +} + +static void test_onefield (void) +{ + size_t len, pos; + bool result; + const char *input = "aaa"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (3, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_not_colon (void) +{ + size_t len, pos; + bool result; + const char *separators = "!"; + const char *input = "aa!b"; + + result = splitstring (input, separators, true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (2, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (result); + ASSERT_EQUAL (3, pos); + ASSERT_EQUAL (1, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (!result); +} + +static void test_empty_back (void) +{ + size_t len, pos; + bool result; + const char *input = "aa:"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (2, len); + result = splitstring (input, ":", false, &pos, &len); + assert (result); + ASSERT_EQUAL (3, pos); + ASSERT_EQUAL (0, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_empty_front (void) +{ + size_t len, pos; + bool result; + const char *input = ":aaa"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (0, len); + result = splitstring (input, ":", false, &pos, &len); + assert (result); + ASSERT_EQUAL (1, pos); + ASSERT_EQUAL (3, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_twofields (void) +{ + size_t len, pos; + bool result; + const char *input = "aaa:bb"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (3, len); + result = splitstring (input, ":", false, &pos, &len); + assert (result); + ASSERT_EQUAL (4, pos); + ASSERT_EQUAL (2, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_twoseparators (void) +{ + size_t len, pos; + bool result; + const char *input = "a:bb!c"; + + result = splitstring (input, ":!", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (1, len); + result = splitstring (input, ":!", false, &pos, &len); + assert (result); + ASSERT_EQUAL (2, pos); + ASSERT_EQUAL (2, len); + result = splitstring (input, ":!", false, &pos, &len); + assert (result); + ASSERT_EQUAL (5, pos); + ASSERT_EQUAL (1, len); + result = splitstring (input, ":!", false, &pos, &len); + assert (!result); +} + +static void test_consecutive_empty (void) +{ + size_t len, pos; + bool result; + const char *input = "a::b"; + const char *separators = ":"; + + result = splitstring (input, separators, true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (1, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (result); + ASSERT_EQUAL (2, pos); + ASSERT_EQUAL (0, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (result); + ASSERT_EQUAL (3, pos); + ASSERT_EQUAL (1, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (!result); +} + +int main (int argc, char *argv[]) +{ + test_empty (); + test_onefield (); + test_not_colon (); + test_empty_back (); + test_empty_front (); + test_twofields (); + test_twoseparators (); + test_consecutive_empty (); + return 0; +} diff --git a/locate/locate.c b/locate/locate.c index ad7b56ae..42089eeb 100644 --- a/locate/locate.c +++ b/locate/locate.c @@ -26,8 +26,8 @@ bigram coded, which reduces space by a further 20-25% and uses the following encoding of the database bytes: - 0-28 likeliest differential counts + offset (14) to make nonnegative - 30 escape code for out-of-range count to follow in next halfword + 0-28 likeliest differential counts + offset (14) to make nonnegative + 30 escape code for out-of-range count to follow in next halfword 128-255 bigram codes (the 128 most common, as determined by `updatedb') 32-127 single character (printable) ASCII remainder @@ -64,7 +64,7 @@ #include <signal.h> #include <ctype.h> #include <sys/types.h> -#include <grp.h> /* for setgroups() */ +#include <grp.h> /* for setgroups() */ #include <sys/stat.h> #include <time.h> #include <fnmatch.h> @@ -123,11 +123,11 @@ #include "human.h" #include "dirname.h" #include "closeout.h" -#include "nextelem.h" #include "regex.h" #include "quotearg.h" #include "printquoted.h" #include "regextype.h" +#include "splitstring.h" #include "findutils-version.h" /* Note that this evaluates Ch many times. */ @@ -157,9 +157,9 @@ enum visit_result enum ExistenceCheckType { - ACCEPT_EITHER, /* Corresponds to lack of -E/-e option */ - ACCEPT_EXISTING, /* Corresponds to option -e */ - ACCEPT_NON_EXISTING /* Corresponds to option -E */ + ACCEPT_EITHER, /* Corresponds to lack of -E/-e option */ + ACCEPT_EXISTING, /* Corresponds to option -e */ + ACCEPT_NON_EXISTING /* Corresponds to option -E */ }; /* Check for existence of files before printing them out? */ @@ -191,7 +191,7 @@ set_max_db_age (const char *s) if (0 == *s) { error (EXIT_FAILURE, 0, - _("The argument for option --max-database-age must not be empty")); + _("The argument for option --max-database-age must not be empty")); } @@ -207,15 +207,15 @@ set_max_db_age (const char *s) (0 == val && EINVAL == errno)) { error (EXIT_FAILURE, errno, - _("Invalid argument %s for option --max-database-age"), - quotearg_n_style (0, locale_quoting_style, s)); + _("Invalid argument %s for option --max-database-age"), + quotearg_n_style (0, locale_quoting_style, s)); } else if (*end) { /* errno wasn't set, don't print its message */ error (EXIT_FAILURE, 0, - _("Invalid argument %s for option --max-database-age"), - quotearg_n_style (0, locale_quoting_style, s)); + _("Invalid argument %s for option --max-database-age"), + quotearg_n_style (0, locale_quoting_style, s)); } else { @@ -280,18 +280,18 @@ locate_read_str (char **buf, size_t *siz, FILE *fp, int delimiter, int offs) needed = offs + nread + 1u; if (needed > (*siz)) - { - char *pnew = realloc (*buf, needed); - if (NULL == pnew) - { - return -1; /* FAIL */ - } - else - { - *siz = needed; - *buf = pnew; - } - } + { + char *pnew = realloc (*buf, needed); + if (NULL == pnew) + { + return -1; /* FAIL */ + } + else + { + *siz = needed; + *buf = pnew; + } + } memcpy ((*buf)+offs, p, nread); free (p); } @@ -327,16 +327,16 @@ struct regular_expression struct process_data { - int c; /* An input byte. */ - char itemcount; /* Indicates we're at the beginning of an slocate db. */ + int c; /* An input byte. */ + char itemcount; /* Indicates we're at the beginning of an slocate db. */ int count; /* The length of the prefix shared with the previous database entry. */ int len; - char *original_filename; /* The current input database entry. */ - size_t pathsize; /* Amount allocated for it. */ - char *munged_filename; /* path or basename(path) */ - FILE *fp; /* The pathname database. */ - const char *dbfile; /* Its name, or "<stdin>" */ - int slocatedb_format; /* Allows us to cope with slocate's format variant */ + char *original_filename; /* The current input database entry. */ + size_t pathsize; /* Amount allocated for it. */ + char *munged_filename; /* path or basename(path) */ + FILE *fp; /* The pathname database. */ + const char *dbfile; /* Its name, or "<stdin>" */ + int slocatedb_format; /* Allows us to cope with slocate's format variant */ GetwordEndianState endian_state; /* for the old database format, the first and second characters of the most common bigrams. */ @@ -346,7 +346,7 @@ struct process_data typedef int (*visitfunc)(struct process_data *procdata, - void *context); + void *context); struct visitor { @@ -361,9 +361,9 @@ static struct visitor *lastinspector = NULL; static struct visitor *past_pat_inspector = NULL; static inline int visit (const struct visitor *p, - int accept_flags, - struct process_data *procdata, - const struct visitor * const stop) + int accept_flags, + struct process_data *procdata, + const struct visitor * const stop) { register int result = accept_flags; while ( (accept_flags & result) && (stop != p) ) @@ -447,8 +447,8 @@ visit_justprint_quoted (struct process_data *procdata, void *context) { (void) context; print_quoted (stdout, quote_opts, stdout_is_a_tty, - "%s", - procdata->original_filename); + "%s", + procdata->original_filename); putchar (separator); return VISIT_CONTINUE; } @@ -466,9 +466,9 @@ static void toolong (struct process_data *procdata) { error (EXIT_FAILURE, 0, - _("locate database %s contains a " - "filename longer than locate can handle"), - procdata->dbfile); + _("locate database %s contains a " + "filename longer than locate can handle"), + procdata->dbfile); } static void @@ -483,8 +483,8 @@ extend (struct process_data *procdata, size_t siz1, size_t siz2) { procdata->pathsize = siz1+siz2; procdata->original_filename = x2nrealloc (procdata->original_filename, - &procdata->pathsize, - 1); + &procdata->pathsize, + 1); } } @@ -506,11 +506,11 @@ visit_old_format (struct process_data *procdata, void *context) procdata->count -= LOCATEDB_OLD_OFFSET; minval = (0 - procdata->count); if (procdata->count >= 0) - maxval = (procdata->len - procdata->count); + maxval = (procdata->len - procdata->count); else - maxval = (procdata->len - 0); + maxval = (procdata->len - 0); word = getword (procdata->fp, procdata->dbfile, - minval, maxval, &procdata->endian_state); + minval, maxval, &procdata->endian_state); procdata->count += word; assert (procdata->count >= 0); } @@ -527,22 +527,22 @@ visit_old_format (struct process_data *procdata, void *context) (procdata->c = getc (procdata->fp)) > LOCATEDB_OLD_ESCAPE;) { if (EOF == procdata->c) - break; + break; if (procdata->c < 0200) - { - /* An ordinary character. */ - extend (procdata, i, 1u); - procdata->original_filename[i++] = procdata->c; - } + { + /* An ordinary character. */ + extend (procdata, i, 1u); + procdata->original_filename[i++] = procdata->c; + } else - { - /* Bigram markers have the high bit set. */ - extend (procdata, i, 2u); - procdata->c &= 0177; - procdata->original_filename[i++] = procdata->bigram1[procdata->c]; - procdata->original_filename[i++] = procdata->bigram2[procdata->c]; - } + { + /* Bigram markers have the high bit set. */ + extend (procdata, i, 2u); + procdata->c &= 0177; + procdata->original_filename[i++] = procdata->bigram1[procdata->c]; + procdata->original_filename[i++] = procdata->bigram2[procdata->c]; + } } /* Consider the case where we executed the loop body zero times; we @@ -566,33 +566,33 @@ visit_locate02_format (struct process_data *procdata, void *context) if (procdata->slocatedb_format) { if (procdata->itemcount == 0) - { - ungetc (procdata->c, procdata->fp); - procdata->count = 0; - procdata->len = 0; - } + { + ungetc (procdata->c, procdata->fp); + procdata->count = 0; + procdata->len = 0; + } else if (procdata->itemcount == 1) - { - procdata->count = procdata->len-1; - } + { + procdata->count = procdata->len-1; + } else - { - if (procdata->c == LOCATEDB_ESCAPE) - procdata->count += (short)get_short (procdata->fp); - else if (procdata->c > 127) - procdata->count += procdata->c - 256; - else - procdata->count += procdata->c; - } + { + if (procdata->c == LOCATEDB_ESCAPE) + procdata->count += (short)get_short (procdata->fp); + else if (procdata->c > 127) + procdata->count += procdata->c - 256; + else + procdata->count += procdata->c; + } } else { if (procdata->c == LOCATEDB_ESCAPE) - procdata->count += (short)get_short (procdata->fp); + procdata->count += (short)get_short (procdata->fp); else if (procdata->c > 127) - procdata->count += procdata->c - 256; + procdata->count += procdata->c - 256; else - procdata->count += procdata->c; + procdata->count += procdata->c; } if (procdata->count > procdata->len || procdata->count < 0) @@ -602,13 +602,13 @@ visit_locate02_format (struct process_data *procdata, void *context) * cannot prevent it. */ error (EXIT_FAILURE, 0, _("locate database %s is corrupt or invalid"), - quotearg_n_style (0, locale_quoting_style, procdata->dbfile)); + quotearg_n_style (0, locale_quoting_style, procdata->dbfile)); } /* Overlay the old path with the remainder of the new. */ nread = locate_read_str (&procdata->original_filename, - &procdata->pathsize, - procdata->fp, 0, procdata->count); + &procdata->pathsize, + procdata->fp, 0, procdata->count); if (nread < 0) return VISIT_ABORT; procdata->c = getc (procdata->fp); @@ -624,9 +624,9 @@ visit_locate02_format (struct process_data *procdata, void *context) { /* Don't increment indefinitely, it might overflow. */ if (procdata->itemcount < 6) - { - ++(procdata->itemcount); - } + { + ++(procdata->itemcount); + } } @@ -807,15 +807,15 @@ visit_regex (struct process_data *procdata, void *context) const size_t len = strlen (procdata->munged_filename); int rv = re_search (&p->regex, procdata->munged_filename, - len, 0, len, - (struct re_registers *) NULL); + len, 0, len, + (struct re_registers *) NULL); if (rv < 0) { - return VISIT_REJECTED; /* no match (-1), or internal error (-2) */ + return VISIT_REJECTED; /* no match (-1), or internal error (-2) */ } else { - return VISIT_ACCEPTED; /* match */ + return VISIT_ACCEPTED; /* match */ } } @@ -835,15 +835,15 @@ visit_stats (struct process_data *procdata, void *context) for (s=procdata->original_filename; *s; ++s) { if ( (int)(*s) & 128 ) - highbit = 1; + highbit = 1; if ('\n' == *s) - { - newline = whitespace = 1; - } + { + newline = whitespace = 1; + } else if (isspace ((unsigned char)*s)) - { - whitespace = 1; - } + { + whitespace = 1; + } } if (highbit) @@ -892,56 +892,56 @@ print_stats (int argc, size_t database_file_size) char hbuf4[LONGEST_HUMAN_READABLE + 1]; printf (ngettext ("Locate database size: %s byte\n", - "Locate database size: %s bytes\n", - database_file_size), - human_readable ((uintmax_t) database_file_size, - hbuf1, human_ceiling, 1, 1)); + "Locate database size: %s bytes\n", + database_file_size), + human_readable ((uintmax_t) database_file_size, + hbuf1, human_ceiling, 1, 1)); printf ( (results_were_filtered ? - _("Matching Filenames: %s\n") : - _("All Filenames: %s\n")), - human_readable (statistics.total_filename_count, - hbuf1, human_ceiling, 1, 1)); + _("Matching Filenames: %s\n") : + _("All Filenames: %s\n")), + human_readable (statistics.total_filename_count, + hbuf1, human_ceiling, 1, 1)); /* XXX: We would ideally use ngettext () here, but I don't know * how to use it to handle more than one possibly-plural thing/ */ printf (_("File names have a cumulative length of %s bytes.\n" - "Of those file names,\n" - "\n\t%s contain whitespace, " - "\n\t%s contain newline characters, " - "\n\tand %s contain characters with the high bit set.\n"), - human_readable (statistics.total_filename_length, hbuf1, human_ceiling, 1, 1), - human_readable (statistics.whitespace_count, hbuf2, human_ceiling, 1, 1), - human_readable (statistics.newline_count, hbuf3, human_ceiling, 1, 1), - human_readable (statistics.highbit_filename_count, hbuf4, human_ceiling, 1, 1)); + "Of those file names,\n" + "\n\t%s contain whitespace, " + "\n\t%s contain newline characters, " + "\n\tand %s contain characters with the high bit set.\n"), + human_readable (statistics.total_filename_length, hbuf1, human_ceiling, 1, 1), + human_readable (statistics.whitespace_count, hbuf2, human_ceiling, 1, 1), + human_readable (statistics.newline_count, hbuf3, human_ceiling, 1, 1), + human_readable (statistics.highbit_filename_count, hbuf4, human_ceiling, 1, 1)); if (!argc) { if (results_were_filtered) - { - printf (_("Some filenames may have been filtered out, " - "so we cannot compute the compression ratio.\n")); - } + { + printf (_("Some filenames may have been filtered out, " + "so we cannot compute the compression ratio.\n")); + } else - { - if (statistics.total_filename_length) - { - /* A negative compression ratio just means that the - * compressed database is larger than the list of - * filenames. This can happen for example for - * old-format databases containing a small list of short - * filenames, because the bigram list is 256 bytes. - */ - printf (_("Compression ratio %4.2f%% (higher is better)\n"), - 100.0 * ((double)statistics.total_filename_length - - (double) database_file_size) - / (double) statistics.total_filename_length); - } - else - { - printf (_("Compression ratio is undefined\n")); - } - } + { + if (statistics.total_filename_length) + { + /* A negative compression ratio just means that the + * compressed database is larger than the list of + * filenames. This can happen for example for + * old-format databases containing a small list of short + * filenames, because the bigram list is 256 bytes. + */ + printf (_("Compression ratio %4.2f%% (higher is better)\n"), + 100.0 * ((double)statistics.total_filename_length + - (double) database_file_size) + / (double) statistics.total_filename_length); + } + else + { + printf (_("Compression ratio is undefined\n")); + } + } } printf ("\n"); } @@ -956,7 +956,7 @@ looking_at_gnu_locatedb (const char *data, size_t len) if (len < sizeof (LOCATEDB_MAGIC)) return 0; else if (0 == memcmp (data, LOCATEDB_MAGIC, sizeof (LOCATEDB_MAGIC))) - return 1; /* We saw the magic byte sequence */ + return 1; /* We saw the magic byte sequence */ else return 0; } @@ -967,9 +967,9 @@ looking_at_gnu_locatedb (const char *data, size_t len) */ static int looking_at_slocate_locatedb (const char *filename, - const char *data, - size_t len, - int *seclevel) + const char *data, + size_t len, + int *seclevel) { assert (len <= 2); @@ -981,42 +981,42 @@ looking_at_slocate_locatedb (const char *filename, { /* Check that the magic number is a one-byte string */ if (0 == data[1]) - { - if (isdigit ((unsigned char)data[0])) - { - /* looks promising. */ - *seclevel = (data[0] - '0'); - - if (*seclevel > 1) - { - /* Hmm, well it's probably an slocate database - * of some awsomely huge security level, like 2. - * We don't know how to handle those. - */ - error (0, 0, - _("locate database %s looks like an slocate " - "database but it seems to have security level %c, " - "which GNU findutils does not currently support"), - quotearg_n_style (0, locale_quoting_style, filename), - data[1]); - return 1; - } - else - { - return 1; - } - } - else - { - /* Not a digit. */ - return 0; - } - } + { + if (isdigit ((unsigned char)data[0])) + { + /* looks promising. */ + *seclevel = (data[0] - '0'); + + if (*seclevel > 1) + { + /* Hmm, well it's probably an slocate database + * of some awsomely huge security level, like 2. + * We don't know how to handle those. + */ + error (0, 0, + _("locate database %s looks like an slocate " + "database but it seems to have security level %c, " + "which GNU findutils does not currently support"), + quotearg_n_style (0, locale_quoting_style, filename), + data[1]); + return 1; + } + else + { + return 1; + } + } + else + { + /* Not a digit. */ + return 0; + } + } else - { - /* Definitely not slocate. */ - return 0; - } + { + /* Definitely not slocate. */ + return 0; + } } } @@ -1043,24 +1043,24 @@ i_am_little_endian (void) static unsigned long search_one_database (int argc, - char **argv, - const char *dbfile, - FILE *fp, - off_t filesize, - int ignore_case, - int enable_print, - int basename_only, - int use_limit, - struct locate_limits *plimit, - int stats, - int op_and, - int regex, - int regex_options) + char **argv, + const char *dbfile, + FILE *fp, + off_t filesize, + int ignore_case, + int enable_print, + int basename_only, + int use_limit, + struct locate_limits *plimit, + int stats, + int op_and, + int regex, + int regex_options) { - char *pathpart; /* A pattern to consider. */ - int argn; /* Index to current pattern in argv. */ - int nread; /* number of bytes read from an entry. */ - struct process_data procdata; /* Storage for data shared with visitors. */ + char *pathpart; /* A pattern to consider. */ + int argn; /* Index to current pattern in argv. */ + int nread; /* number of bytes read from an entry. */ + struct process_data procdata; /* Storage for data shared with visitors. */ int slocate_seclevel; int oldformat; struct visitor* pvis; /* temp for determining past_pat_inspector. */ @@ -1094,68 +1094,68 @@ search_one_database (int argc, lastinspector = NULL; past_pat_inspector = NULL; results_were_filtered = false; - procdata.pathsize = 128; /* Increased as necessary by locate_read_str. */ + procdata.pathsize = 128; /* Increased as necessary by locate_read_str. */ procdata.original_filename = xmalloc (procdata.pathsize); nread = fread (procdata.original_filename, 1, SLOCATE_DB_MAGIC_LEN, - procdata.fp); + procdata.fp); slocate_seclevel = 0; if (looking_at_slocate_locatedb (procdata.dbfile, - procdata.original_filename, - nread, - &slocate_seclevel)) + procdata.original_filename, + nread, + &slocate_seclevel)) { error (0, 0, - _("%s is an slocate database. " - "Support for these is new, expect problems for now."), - quotearg_n_style (0, locale_quoting_style, procdata.dbfile)); + _("%s is an slocate database. " + "Support for these is new, expect problems for now."), + quotearg_n_style (0, locale_quoting_style, procdata.dbfile)); /* slocate also uses frcode, but with a different header. * We handle the header here and then work with the data * in the normal way. */ if (slocate_seclevel > 1) - { - /* We don't know what those security levels mean, - * so do nothing further - */ - error (0, 0, - _("%s is an slocate database of unsupported security level %d; skipping it."), - quotearg_n_style (0, locale_quoting_style, procdata.dbfile), - slocate_seclevel); - return 0; - } + { + /* We don't know what those security levels mean, + * so do nothing further + */ + error (0, 0, + _("%s is an slocate database of unsupported security level %d; skipping it."), + quotearg_n_style (0, locale_quoting_style, procdata.dbfile), + slocate_seclevel); + return 0; + } else if (slocate_seclevel > 0) - { - /* Don't show the filenames to the user if they don't exist. - * Showing stats is safe since filenames are only counted - * after the existence check - */ - if (ACCEPT_NON_EXISTING == check_existence) - { - /* Do not allow the user to see a list of filenames that they - * cannot stat(). - */ - error (0, 0, - _("You specified the -E option, but that option " - "cannot be used with slocate-format databases " - "with a non-zero security level. No results will be " - "generated for this database.\n")); - return 0; - } - if (ACCEPT_EXISTING != do_check_existence) - { - if (enable_print || stats) - { - error (0, 0, - _("%s is an slocate database. " - "Turning on the '-e' option."), - quotearg_n_style (0, locale_quoting_style, procdata.dbfile)); - } - do_check_existence = ACCEPT_EXISTING; - } - } + { + /* Don't show the filenames to the user if they don't exist. + * Showing stats is safe since filenames are only counted + * after the existence check + */ + if (ACCEPT_NON_EXISTING == check_existence) + { + /* Do not allow the user to see a list of filenames that they + * cannot stat(). + */ + error (0, 0, + _("You specified the -E option, but that option " + "cannot be used with slocate-format databases " + "with a non-zero security level. No results will be " + "generated for this database.\n")); + return 0; + } + if (ACCEPT_EXISTING != do_check_existence) + { + if (enable_print || stats) + { + error (0, 0, + _("%s is an slocate database. " + "Turning on the '-e' option."), + quotearg_n_style (0, locale_quoting_style, procdata.dbfile)); + } + do_check_existence = ACCEPT_EXISTING; + } + } add_visitor (visit_locate02_format, NULL); format_name = "slocate"; procdata.slocatedb_format = 1; @@ -1167,42 +1167,42 @@ search_one_database (int argc, procdata.slocatedb_format = 0; extend (&procdata, sizeof (LOCATEDB_MAGIC), 0u); nread2 = fread (procdata.original_filename+nread, 1, sizeof (LOCATEDB_MAGIC)-nread, - procdata.fp); + procdata.fp); if (looking_at_gnu_locatedb (procdata.original_filename, nread+nread2)) - { - add_visitor (visit_locate02_format, NULL); - format_name = "GNU LOCATE02"; - } - else /* Use the old format */ - { - int i; - - nread += nread2; - extend (&procdata, 256u, 0u); - /* Read the list of the most common bigrams in the database. */ - if (nread < 256) - { - int more_read = fread (procdata.original_filename + nread, 1, - 256 - nread, procdata.fp); - if ( (more_read + nread) != 256 ) - { - error (EXIT_FAILURE, 0, - _("Old-format locate database %s is " - "too short to be valid"), - quotearg_n_style (0, locale_quoting_style, dbfile)); - - } - } - - for (i = 0; i < 128; i++) - { - procdata.bigram1[i] = procdata.original_filename[i << 1]; - procdata.bigram2[i] = procdata.original_filename[(i << 1) + 1]; - } - format_name = "old"; - oldformat = 1; - add_visitor (visit_old_format, NULL); - } + { + add_visitor (visit_locate02_format, NULL); + format_name = "GNU LOCATE02"; + } + else /* Use the old format */ + { + int i; + + nread += nread2; + extend (&procdata, 256u, 0u); + /* Read the list of the most common bigrams in the database. */ + if (nread < 256) + { + int more_read = fread (procdata.original_filename + nread, 1, + 256 - nread, procdata.fp); + if ( (more_read + nread) != 256 ) + { + error (EXIT_FAILURE, 0, + _("Old-format locate database %s is " + "too short to be valid"), + quotearg_n_style (0, locale_quoting_style, dbfile)); + + } + } + + for (i = 0; i < 128; i++) + { + procdata.bigram1[i] = procdata.original_filename[i << 1]; + procdata.bigram2[i] = procdata.original_filename[(i << 1) + 1]; + } + format_name = "old"; + oldformat = 1; + add_visitor (visit_old_format, NULL); + } } if (basename_only) @@ -1214,66 +1214,66 @@ search_one_database (int argc, results_were_filtered = true; pathpart = argv[argn]; if (regex) - { - struct regular_expression *p = xmalloc (sizeof (*p)); - const char *error_message = NULL; - - memset (&p->regex, 0, sizeof (p->regex)); - - re_set_syntax (regex_options); - p->regex.allocated = 100; - p->regex.buffer = xmalloc (p->regex.allocated); - p->regex.fastmap = NULL; - p->regex.syntax = regex_options; - p->regex.translate = NULL; - - error_message = re_compile_pattern (pathpart, strlen (pathpart), - &p->regex); - if (error_message) - { - error (EXIT_FAILURE, 0, "%s", error_message); - } - else - { - add_visitor (visit_regex, p); - } - } + { + struct regular_expression *p = xmalloc (sizeof (*p)); + const char *error_message = NULL; + + memset (&p->regex, 0, sizeof (p->regex)); + + re_set_syntax (regex_options); + p->regex.allocated = 100; + p->regex.buffer = xmalloc (p->regex.allocated); + p->regex.fastmap = NULL; + p->regex.syntax = regex_options; + p->regex.translate = NULL; + + error_message = re_compile_pattern (pathpart, strlen (pathpart), + &p->regex); + if (error_message) + { + error (EXIT_FAILURE, 0, "%s", error_message); + } + else + { + add_visitor (visit_regex, p); + } + } else if (contains_metacharacter (pathpart)) - { - if (ignore_case) - add_visitor (visit_globmatch_casefold, pathpart); - else - add_visitor (visit_globmatch_nofold, pathpart); - } + { + if (ignore_case) + add_visitor (visit_globmatch_casefold, pathpart); + else + add_visitor (visit_globmatch_nofold, pathpart); + } else - { - /* No glob characters used. Hence we match on - * _any part_ of the filename, not just the - * basename. This seems odd to me, but it is the - * traditional behaviour. - * James Youngman <jay@gnu.org> - */ - visitfunc matcher; - if (1 == MB_CUR_MAX) - { - /* As an optimisation, use a strstr () matcher if we are - * in a unibyte locale. This can give a x2 speedup in - * the C locale. Some light testing reveals that - * glibc's strstr () is somewhere around 40% faster than - * gnulib's, so we just use strstr (). - */ - matcher = ignore_case ? - visit_substring_match_casefold_narrow : - visit_substring_match_nocasefold_narrow; - } - else - { - matcher = ignore_case ? - visit_substring_match_casefold_wide : - visit_substring_match_nocasefold_wide; - } - add_visitor (matcher, pathpart); - } + { + /* No glob characters used. Hence we match on + * _any part_ of the filename, not just the + * basename. This seems odd to me, but it is the + * traditional behaviour. + * James Youngman <jay@gnu.org> + */ + visitfunc matcher; + if (1 == MB_CUR_MAX) + { + /* As an optimisation, use a strstr () matcher if we are + * in a unibyte locale. This can give a x2 speedup in + * the C locale. Some light testing reveals that + * glibc's strstr () is somewhere around 40% faster than + * gnulib's, so we just use strstr (). + */ + matcher = ignore_case ? + visit_substring_match_casefold_narrow : + visit_substring_match_nocasefold_narrow; + } + else + { + matcher = ignore_case ? + visit_substring_match_casefold_wide : + visit_substring_match_nocasefold_wide; + } + add_visitor (matcher, pathpart); + } } pvis = lastinspector; @@ -1284,24 +1284,24 @@ search_one_database (int argc, switch (do_check_existence) { case ACCEPT_EXISTING: - results_were_filtered = true; - if (follow_symlinks) /* -L, default */ - add_visitor (visit_existing_follow, NULL); - else /* -P */ - add_visitor (visit_existing_nofollow, NULL); - break; + results_were_filtered = true; + if (follow_symlinks) /* -L, default */ + add_visitor (visit_existing_follow, NULL); + else /* -P */ + add_visitor (visit_existing_nofollow, NULL); + break; case ACCEPT_NON_EXISTING: - results_were_filtered = true; - if (follow_symlinks) /* -L, default */ - add_visitor (visit_non_existing_follow, NULL); - else /* -P */ - add_visitor (visit_non_existing_nofollow, NULL); - break; - - case ACCEPT_EITHER: /* Default, neither -E nor -e */ - /* do nothing; no extra processing. */ - break; + results_were_filtered = true; + if (follow_symlinks) /* -L, default */ + add_visitor (visit_non_existing_follow, NULL); + else /* -P */ + add_visitor (visit_non_existing_nofollow, NULL); + break; + + case ACCEPT_EITHER: /* Default, neither -E nor -e */ + /* do nothing; no extra processing. */ + break; } /* Security issue: The stats visitor must be added immediately @@ -1314,9 +1314,9 @@ search_one_database (int argc, if (enable_print) { if (print_quoted_filename) - add_visitor (visit_justprint_quoted, NULL); + add_visitor (visit_justprint_quoted, NULL); else - add_visitor (visit_justprint_unquoted, NULL); + add_visitor (visit_justprint_unquoted, NULL); } @@ -1340,8 +1340,8 @@ search_one_database (int argc, if (stats) { printf (_("Database %s is in the %s format.\n"), - procdata.dbfile, - format_name); + procdata.dbfile, + format_name); } @@ -1358,35 +1358,35 @@ search_one_database (int argc, if (stats) { if (oldformat) - { - int host_little_endian = i_am_little_endian (); - const char *little = _("The database has little-endian " - "machine-word encoding.\n"); - const char *big = _("The database has big-endian " - "machine-word encoding.\n"); - - if (GetwordEndianStateNative == procdata.endian_state) - { - printf ("%s", (host_little_endian ? little : big)); - } - else if (GetwordEndianStateSwab == procdata.endian_state) - { - printf ("%s", (host_little_endian ? big : little)); - } - else - { - printf (_("The database machine-word encoding order " - "is not obvious.\n")); - } - } + { + int host_little_endian = i_am_little_endian (); + const char *little = _("The database has little-endian " + "machine-word encoding.\n"); + const char *big = _("The database has big-endian " + "machine-word encoding.\n"); + + if (GetwordEndianStateNative == procdata.endian_state) + { + printf ("%s", (host_little_endian ? little : big)); + } + else if (GetwordEndianStateSwab == procdata.endian_state) + { + printf ("%s", (host_little_endian ? big : little)); + } + else + { + printf (_("The database machine-word encoding order " + "is not obvious.\n")); + } + } if (filesize) - print_stats (argc, filesize); + print_stats (argc, filesize); } if (ferror (procdata.fp)) { error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, procdata.dbfile)); + quotearg_n_style (0, locale_quoting_style, procdata.dbfile)); return 0; } return plimit->items_accepted; @@ -1406,7 +1406,7 @@ Usage: %s [-d path | --database=path] [-e | -E | --[non-]existing]\n\ [-A | --all] [-p | --print] [-r | --regex] [--regextype=TYPE]\n\ [--max-database-age D] [--version] [--help]\n\ pattern...\n"), - program_name); + program_name); fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream); } enum @@ -1460,10 +1460,10 @@ drop_privs (void) gid_t groups[1]; groups[0] = gid; if (0 != setgroups (1u, groups)) - { - what = _("failed to drop group privileges"); - goto fail; - } + { + what = _("failed to drop group privileges"); + goto fail; + } } #endif @@ -1471,40 +1471,40 @@ drop_privs (void) if (uid != orig_euid) { if (0 == uid) - { - /* We're really root anyway, but are setuid to something else. Leave it. */ - } + { + /* We're really root anyway, but are setuid to something else. Leave it. */ + } else - { - errno = 0; - if (0 != setuid (getuid ())) - { - what = _("failed to drop setuid privileges"); - goto fail; - } - - /* Defend against the case where the attacker runs us with the - * capability to call setuid () turned off, which on some systems - * will cause the above attempt to drop privileges fail (leaving us - * privileged). - */ - else - { - /* Check that we can no longer switch bask to root */ - if (0 == setuid (0)) - { - what = _("Failed to fully drop privileges"); - /* The errno value here is not interesting (since - * the system call we are complaining about - * succeeded when we wanted it to fail). Arrange - * for the call to error () not to print the errno - * value by setting errno=0. - */ - errno = 0; - goto fail; - } - } - } + { + errno = 0; + if (0 != setuid (getuid ())) + { + what = _("failed to drop setuid privileges"); + goto fail; + } + + /* Defend against the case where the attacker runs us with the + * capability to call setuid () turned off, which on some systems + * will cause the above attempt to drop privileges fail (leaving us + * privileged). + */ + else + { + /* Check that we can no longer switch bask to root */ + if (0 == setuid (0)) + { + what = _("Failed to fully drop privileges"); + /* The errno value here is not interesting (since + * the system call we are complaining about + * succeeded when we wanted it to fail). Arrange + * for the call to error () not to print the errno + * value by setting errno=0. + */ + errno = 0; + goto fail; + } + } + } } /* Drop any setgid privileges */ @@ -1520,7 +1520,7 @@ drop_privs (void) fail: error (EXIT_FAILURE, errno, "%s", - quotearg_n_style (0, locale_quoting_style, what)); + quotearg_n_style (0, locale_quoting_style, what)); abort (); kill (0, SIGKILL); _exit (1); @@ -1537,17 +1537,17 @@ opendb (const char *name) { int fd = open (name, O_RDONLY #if defined O_LARGEFILE - |O_LARGEFILE + |O_LARGEFILE #endif - ); + ); if (fd >= 0) { /* Make sure it won't survive an exec */ if (0 != fcntl (fd, F_SETFD, FD_CLOEXEC)) - { - close (fd); - fd = -1; - } + { + close (fd); + fd = -1; + } } return fd; } @@ -1555,7 +1555,11 @@ opendb (const char *name) int dolocate (int argc, char **argv, int secure_db_fd) { - char *dbpath; + char *path_element; + size_t path_element_pos, path_element_len; + const char *locate_path; + const char *db_name; + const char *path_separators = ":"; unsigned long int found = 0uL; int ignore_case = 0; int print = 0; @@ -1569,7 +1573,7 @@ dolocate (int argc, char **argv, int secure_db_fd) const char *e; FILE *fp; int they_chose_db = 0; - bool did_stdin = false; /* Set to prevent rereading stdin. */ + bool did_stdin = false; /* Set to prevent rereading stdin. */ if (argv[0]) set_program_name (argv[0]); @@ -1593,11 +1597,9 @@ dolocate (int argc, char **argv, int secure_db_fd) * setuid-access-controlled database,, since that could cause a leak * of private data. */ - dbpath = getenv ("LOCATE_PATH"); - if (dbpath) - { - they_chose_db = 1; - } + locate_path = getenv ("LOCATE_PATH"); + if (locate_path) + they_chose_db = 1; check_existence = ACCEPT_EITHER; @@ -1605,115 +1607,115 @@ dolocate (int argc, char **argv, int secure_db_fd) { int opti = -1; int optc = getopt_long (argc, argv, "Abcd:eEil:prsm0SwHPL", longopts, - &opti); + &opti); if (optc == -1) - break; + break; switch (optc) - { - case '0': - separator = 0; - print_quoted_filename = false; /* print filename 'raw'. */ - break; - - case 'A': - op_and = 1; - break; - - case 'b': - basename_only = 1; - break; - - case 'c': - just_count = 1; - break; - - case 'd': - dbpath = optarg; - they_chose_db = 1; - break; - - case 'e': - check_existence = ACCEPT_EXISTING; - break; - - case 'E': - check_existence = ACCEPT_NON_EXISTING; - break; - - case 'i': - ignore_case = 1; - break; - - case 'h': - usage (stdout); - return 0; - - case MAX_DB_AGE: - /* XXX: nothing in the test suite for this option. */ - set_max_db_age (optarg); - break; - - case 'p': - print = 1; - break; - - case 'v': - display_findutils_version ("locate"); - return 0; - - case 'w': - basename_only = 0; - break; - - case 'r': - regex = 1; - break; - - case REGEXTYPE_OPTION: - regex_options = get_regex_type (optarg); - break; - - case 'S': - stats = 1; - break; - - case 'L': - follow_symlinks = 1; - break; - - /* In find, -P and -H differ in the way they handle paths - * given on the command line. This is not relevant for - * locate, but the -H option is supported because it is - * probably more intuitive to do so. - */ - case 'P': - case 'H': - follow_symlinks = 0; - break; - - case 'l': - { - char *end = optarg; - strtol_error err = xstrtoumax (optarg, &end, 10, &limits.limit, - NULL); - if (LONGINT_OK != err) - xstrtol_fatal (err, opti, optc, longopts, optarg); - use_limit = 1; - } - break; - - case 's': /* use stdio */ - case 'm': /* use mmap */ - /* These options are implemented simply for - * compatibility with FreeBSD - */ - break; - - default: - usage (stderr); - return 1; - } + { + case '0': + separator = 0; + print_quoted_filename = false; /* print filename 'raw'. */ + break; + + case 'A': + op_and = 1; + break; + + case 'b': + basename_only = 1; + break; + + case 'c': + just_count = 1; + break; + + case 'd': + locate_path = optarg; + they_chose_db = 1; + break; + + case 'e': + check_existence = ACCEPT_EXISTING; + break; + + case 'E': + check_existence = ACCEPT_NON_EXISTING; + break; + + case 'i': + ignore_case = 1; + break; + + case 'h': + usage (stdout); + return 0; + + case MAX_DB_AGE: + /* XXX: nothing in the test suite for this option. */ + set_max_db_age (optarg); + break; + + case 'p': + print = 1; + break; + + case 'v': + display_findutils_version ("locate"); + return 0; + + case 'w': + basename_only = 0; + break; + + case 'r': + regex = 1; + break; + + case REGEXTYPE_OPTION: + regex_options = get_regex_type (optarg); + break; + + case 'S': + stats = 1; + break; + + case 'L': + follow_symlinks = 1; + break; + + /* In find, -P and -H differ in the way they handle paths + * given on the command line. This is not relevant for + * locate, but the -H option is supported because it is + * probably more intuitive to do so. + */ + case 'P': + case 'H': + follow_symlinks = 0; + break; + + case 'l': + { + char *end = optarg; + strtol_error err = xstrtoumax (optarg, &end, 10, &limits.limit, + NULL); + if (LONGINT_OK != err) + xstrtol_fatal (err, opti, optc, longopts, optarg); + use_limit = 1; + } + break; + + case 's': /* use stdio */ + case 'm': /* use mmap */ + /* These options are implemented simply for + * compatibility with FreeBSD + */ + break; + + default: + usage (stderr); + return 1; + } } @@ -1723,10 +1725,10 @@ dolocate (int argc, char **argv, int secure_db_fd) if (they_chose_db) { if (secure_db_fd >= 0) - { - close (secure_db_fd); - secure_db_fd = -1; - } + { + close (secure_db_fd); + secure_db_fd = -1; + } } if (!just_count && !stats) @@ -1735,15 +1737,15 @@ dolocate (int argc, char **argv, int secure_db_fd) if (stats) { if (optind == argc) - use_limit = 0; + use_limit = 0; } else { if (!just_count && optind == argc) - { - usage (stderr); - return 1; - } + { + usage (stderr); + return 1; + } } @@ -1753,7 +1755,8 @@ dolocate (int argc, char **argv, int secure_db_fd) stdout_is_a_tty = false; if (they_chose_db) - next_element (dbpath, 0); /* Initialize. */ + splitstring (locate_path, path_separators, true, + &path_element_pos, &path_element_len); /* Bail out early if limit already reached. */ while (!use_limit || limits.limit > limits.items_accepted) @@ -1770,120 +1773,134 @@ dolocate (int argc, char **argv, int secure_db_fd) statistics.highbit_filename_count = 0u; if (they_chose_db) - { - /* Take the next element from the list of databases */ - e = next_element ((char *) NULL, 0); - if (NULL == e) - break; - - if (0 == strcmp (e, "-")) - { - if (did_stdin) - { - error (0, 0, - _("warning: the locate database can only be read from stdin once.")); - return 0; - } - else - { - e = "<stdin>"; - fd = 0; - did_stdin = true; - } - } - else - { - if (0 == strlen (e) || 0 == strcmp (e, ".")) - { - e = LOCATE_DB; - } - - /* open the database */ - fd = opendb (e); - if (fd < 0) - { - error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); - return 0; - } - } - } + { + /* Take the next element from the list of databases */ + if (1 == path_element_len && '-' == locate_path[path_element_pos]) + { + if (did_stdin) + { + error (0, 0, + _("warning: the locate database can only be read from stdin once.")); + return 0; + } + else + { + e = "<stdin>"; + fd = 0; + did_stdin = true; + } + } + else + { + if (0 == path_element_len + || (1 == path_element_len + && '.' == locate_path[path_element_pos])) + { + db_name = LOCATE_DB; + } + else + { + path_element = strndup (&locate_path[path_element_pos], + path_element_len); + db_name = path_element; + } + + /* open the database */ + fd = opendb (db_name); + if (fd < 0) + { + error (0, errno, "%s", + quotearg_n_style (0, locale_quoting_style, db_name)); + return 0; + } + } + } else - { - if (-1 == secure_db_fd) - { - /* Already searched the database, it's time to exit the loop */ - break; - } - else - { - e = selected_secure_db; - fd = secure_db_fd; - secure_db_fd = -1; - } - } + { + if (-1 == secure_db_fd) + { + /* Already searched the database, it's time to exit the loop */ + break; + } + else + { + db_name = selected_secure_db; + fd = secure_db_fd; + secure_db_fd = -1; + } + } /* Check the database to see if it is old. */ if (fstat (fd, &st)) - { - error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); - /* continue anyway */ - filesize = (off_t)0; - } + { + error (0, errno, "%s", + quotearg_n_style (0, locale_quoting_style, db_name)); + /* continue anyway */ + filesize = (off_t)0; + } else - { - time_t now; - - filesize = st.st_size; - - if ((time_t)-1 == time (&now)) - { - /* If we can't tell the time, we don't know how old the - * database is. But since the message is just advisory, - * we continue anyway. - */ - error (0, errno, _("time system call failed")); - } - else - { - double age = difftime (now, st.st_mtime); - double warn_seconds = SECONDS_PER_UNIT * warn_number_units; - if (age > warn_seconds) - { - /* For example: - warning: database `fred' is more than 8 days old (actual age is 10 days)*/ - error (0, 0, - _("warning: database %s is more than %d %s old (actual age is %.1f %s)"), - quotearg_n_style (0, locale_quoting_style, e), - warn_number_units, _(warn_name_units), - (age/(double)SECONDS_PER_UNIT), _(warn_name_units)); - } - } - } + { + time_t now; + + filesize = st.st_size; + + if ((time_t)-1 == time (&now)) + { + /* If we can't tell the time, we don't know how old the + * database is. But since the message is just advisory, + * we continue anyway. + */ + error (0, errno, _("time system call failed")); + } + else + { + double age = difftime (now, st.st_mtime); + double warn_seconds = SECONDS_PER_UNIT * warn_number_units; + if (age > warn_seconds) + { + /* For example: + warning: database `fred' is more than 8 days old (actual age is 10 days)*/ + error (0, 0, + _("warning: database %s is more than %d %s old (actual age is %.1f %s)"), + quotearg_n_style (0, locale_quoting_style, db_name), + warn_number_units, _(warn_name_units), + (age/(double)SECONDS_PER_UNIT), _(warn_name_units)); + } + } + } fp = fdopen (fd, "r"); if (NULL == fp) - { - error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); - return 0; - } + { + error (0, errno, "%s", + quotearg_n_style (0, locale_quoting_style, db_name)); + return 0; + } /* Search this database for all patterns simultaneously */ found = search_one_database (argc - optind, &argv[optind], - e, fp, filesize, - ignore_case, print, basename_only, - use_limit, &limits, stats, - op_and, regex, regex_options); + e, fp, filesize, + ignore_case, print, basename_only, + use_limit, &limits, stats, + op_and, regex, regex_options); /* Close the databsase (even if it is stdin) */ if (fclose (fp) == EOF) - { - error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); - return 0; - } + { + error (0, errno, "%s", + quotearg_n_style (0, locale_quoting_style, db_name)); + return 0; + } + if (path_element) + { + free (path_element); + path_element = NULL; + } + if (!splitstring (locate_path, path_separators, false, + &path_element_pos, &path_element_len)) + { + break; + } } if (just_count) @@ -1913,10 +1930,10 @@ open_secure_db (void) { fd = opendb (secure_db_list[i]); if (fd >= 0) - { - selected_secure_db = secure_db_list[i]; - return fd; - } + { + selected_secure_db = secure_db_list[i]; + return fd; + } } return -1; } |