summaryrefslogtreecommitdiffhomepage
path: root/findutils
diff options
context:
space:
mode:
authorJames Clarke <jrtc27@jrtc27.com>2017-10-07 18:53:24 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2017-10-31 15:23:55 +0100
commit6bcc2c0f6cb868232ec06231aa37a3fa65c59d22 (patch)
tree3a72a8f7514b8553475dd0e3071bd90d632461aa /findutils
parent59a5604a795ef5ba850e99a3aafc5b015dd237a1 (diff)
grep: skip grepping symlinks to directories
When grep is passed -r, recursive_action will treat any symlinks to directories not in the root as normal files, since it lstat's them and is therefore told they are not directories. However, file_action_grep will still try to fopen and read from them to see whether they match, which varies in behaviour across platforms. Linux will give EISDIR and thus grep will not find any matching lines, but FreeBSD will give the raw contents of the directory itself, which may match the given pattern. Also, if grep is passed -c, it will even print a count for these symlinks, even on Linux. Since this recursive_action behaviour is required for the correct functioning of other applets, such as tar, grep should handle this special case and skip any such symlinks. function old new delta file_action_grep 80 161 +81 Signed-off-by: James Clarke <jrtc27@jrtc27.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'findutils')
-rw-r--r--findutils/grep.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/findutils/grep.c b/findutils/grep.c
index f72175afb..fc6de4b69 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -639,11 +639,28 @@ static void load_regexes_from_file(llist_t *fopt)
}
static int FAST_FUNC file_action_grep(const char *filename,
- struct stat *statbuf UNUSED_PARAM,
+ struct stat *statbuf,
void* matched,
int depth UNUSED_PARAM)
{
- FILE *file = fopen_for_read(filename);
+ FILE *file;
+
+ /* If we are given a link to a directory, we should bail out now, rather
+ * than trying to open the "file" and hoping getline gives us nothing,
+ * since that is not portable across operating systems (FreeBSD for
+ * example will return the raw directory contents). */
+ if (S_ISLNK(statbuf->st_mode)) {
+ struct stat sb;
+ if (stat(filename, &sb) != 0) {
+ if (!SUPPRESS_ERR_MSGS)
+ bb_simple_perror_msg(filename);
+ return 0;
+ }
+ if (S_ISDIR(sb.st_mode))
+ return 1;
+ }
+
+ file = fopen_for_read(filename);
if (file == NULL) {
if (!SUPPRESS_ERR_MSGS)
bb_simple_perror_msg(filename);