bug-findutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] find -samedev NAME: true for files on the same device as NAME


From: Kamil Dudka
Subject: [PATCH] find -samedev NAME: true for files on the same device as NAME
Date: Thu, 1 Nov 2018 16:56:58 +0100

There is no easy way to exclude mount points from the output of `find`.
The options -xdev or -mount prevent `find` from traversing over the
mount points but do not exclude the mount points themselves.  It could
be scripted by AWK on Linux as in the following example:

$ find / -xdev -maxdepth 1 $(awk '$2 != "/" { printf("! -path %s ", $2) }' 
/proc/mounts)

Would it make sense to introduce a new predicate similar to -samefile
that takes into account device numbers only?

With the proposed predicate implemented in `find`, the above command
could be encoded in a more user-friendly way:

$ find / -xdev -maxdepth 1 -samedev /

Originally reported at: https://bugzilla.redhat.com/1607772
---
 find/defs.h   |  1 +
 find/find.1   |  8 ++++++++
 find/parser.c | 23 +++++++++++++++++++++++
 find/pred.c   | 18 ++++++++++++++++++
 find/tree.c   |  1 +
 5 files changed, 51 insertions(+)

diff --git a/find/defs.h b/find/defs.h
index 63f3b2a3..2d4965e9 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -461,6 +461,7 @@ PREDICATEFUNCTION pred_print0;
 PREDICATEFUNCTION pred_prune;
 PREDICATEFUNCTION pred_readable;
 PREDICATEFUNCTION pred_regex;
+PREDICATEFUNCTION pred_samedev;
 PREDICATEFUNCTION pred_samefile;
 PREDICATEFUNCTION pred_size;
 PREDICATEFUNCTION pred_true;
diff --git a/find/find.1 b/find/find.1
index 67fdd537..dec78798 100644
--- a/find/find.1
+++ b/find/find.1
@@ -932,6 +932,13 @@ newline), but this can be changed with the
 .B \-regextype
 option.
 
+.IP "\-samedev \fIname\fR"
+File is on the same device as
+.IR name .
+When
+.B \-L
+is in effect, this can include symbolic links.
+
 .IP "\-samefile \fIname\fR"
 File refers to the same inode as
 .IR name .
@@ -2282,6 +2289,7 @@ Feature   Added in        Also occurs in
 \-exec ... +   4.2.12  POSIX
 \-execdir      4.2.12  BSD
 \-okdir        4.2.12
+\-samedev      4.6.1
 \-samefile     4.2.11
 \-H    4.2.5   POSIX
 \-L    4.2.5   POSIX
diff --git a/find/parser.c b/find/parser.c
index d6621506..14279c69 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -128,6 +128,7 @@ static bool parse_printf        (const struct 
parser_table*, char *argv[], int *
 static bool parse_prune         (const struct parser_table*, char *argv[], int 
*arg_ptr);
 static bool parse_regex         (const struct parser_table*, char *argv[], int 
*arg_ptr);
 static bool parse_regextype     (const struct parser_table*, char *argv[], int 
*arg_ptr);
+static bool parse_samedev       (const struct parser_table*, char *argv[], int 
*arg_ptr);
 static bool parse_samefile      (const struct parser_table*, char *argv[], int 
*arg_ptr);
 static bool parse_size          (const struct parser_table*, char *argv[], int 
*arg_ptr);
 static bool parse_time          (const struct parser_table*, char *argv[], int 
*arg_ptr);
@@ -290,6 +291,7 @@ static struct parser_table const parse_table[] =
   {ARG_TEST,       "readable",            parse_accesscheck, pred_readable}, 
/* GNU, 4.3.0+ */
   PARSE_TEST       ("regex",                 regex),        /* GNU */
   PARSE_POSOPT     ("regextype",             regextype),     /* GNU */
+  PARSE_TEST       ("samedev",               samedev),      /* GNU */
   PARSE_TEST       ("samefile",              samefile),             /* GNU */
 #if 0
   PARSE_OPTION     ("show-control-chars",    show_control_chars), /* GNU, 
4.3.0+ */
@@ -2169,6 +2171,27 @@ parse_size (const struct parser_table* entry, char 
**argv, int *arg_ptr)
 }
 
 
+static bool
+parse_samedev (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+  struct predicate *our_pred;
+  struct stat st;
+  const char *filename;
+
+  set_stat_placeholders (&st);
+  if (!collect_arg_stat_info (argv, arg_ptr, &st, &filename))
+    return false;
+
+  our_pred = insert_primary (entry, filename);
+  our_pred->args.samefileid.ino = (ino_t) -1;
+  our_pred->args.samefileid.dev = st.st_dev;
+  our_pred->args.samefileid.fd  = -1;
+  our_pred->need_type = false;
+  our_pred->need_stat = true;
+  our_pred->est_success_rate = 1.0f;
+  return true;
+}
+
 static bool
 parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
diff --git a/find/pred.c b/find/pred.c
index 2014b5ab..f1da8669 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -118,6 +118,7 @@ struct pred_assoc pred_table[] =
   {pred_quit, "quit    "},
   {pred_readable, "readable    "},
   {pred_regex, "regex   "},
+  {pred_samedev, "samedev  "},
   {pred_samefile,"samefile "},
   {pred_size, "size    "},
   {pred_true, "true    "},
@@ -986,6 +987,23 @@ pred_size (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_p
   return (false);
 }
 
+bool
+pred_samedev (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
+{
+  (void) pathname;
+
+  /* Stat the file (if not already statted) to check the device number. */
+  if (0 == get_statinfo (pathname, state.rel_pathname, stat_buf))
+    {
+      return (stat_buf->st_dev == pred_ptr->args.samefileid.dev);
+    }
+  else
+    {
+      /* get_statinfo will already have emitted an error message. */
+      return false;
+    }
+}
+
 bool
 pred_samefile (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
diff --git a/find/tree.c b/find/tree.c
index 5be88f2e..f5ccc943 100644
--- a/find/tree.c
+++ b/find/tree.c
@@ -972,6 +972,7 @@ static struct pred_cost_lookup costlookup[] =
     { pred_quit             ,  NeedsNothing         },
     { pred_readable  ,  NeedsAccessInfo      },
     { pred_regex     ,  NeedsNothing         },
+    { pred_samedev   ,  NeedsStatInfo        },
     { pred_samefile  ,  NeedsStatInfo        },
     { pred_size      ,  NeedsStatInfo        },
     { pred_true             ,  NeedsNothing         },
-- 
2.17.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]