From aeff24ee344e5b9c4f2f9040a02320952e70ccd7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 10 Feb 2016 22:15:41 -0500 Subject: Implement -samefile. --- bfs.h | 7 +++++++ eval.c | 12 ++++++++++++ parse.c | 48 +++++++++++++++++++++++++++++++++++++++++------- tests.sh | 7 ++++++- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/bfs.h b/bfs.h index 24aeed8..c20fa17 100644 --- a/bfs.h +++ b/bfs.h @@ -15,6 +15,7 @@ #include "color.h" #include #include +#include #include /** @@ -117,6 +118,11 @@ struct expr { /** The optional time unit. */ enum timeunit timeunit; + /** Optional device number for a target file. */ + dev_t dev; + /** Optional inode number for a target file. */ + ino_t ino; + /** Optional integer data for this expression. */ int idata; @@ -155,6 +161,7 @@ bool eval_empty(const struct expr *expr, struct eval_state *state); bool eval_hidden(const struct expr *expr, struct eval_state *state); bool eval_inum(const struct expr *expr, struct eval_state *state); bool eval_links(const struct expr *expr, struct eval_state *state); +bool eval_samefile(const struct expr *expr, struct eval_state *state); bool eval_type(const struct expr *expr, struct eval_state *state); bool eval_name(const struct expr *expr, struct eval_state *state); diff --git a/eval.c b/eval.c index 543a98a..01da7a4 100644 --- a/eval.c +++ b/eval.c @@ -341,6 +341,18 @@ bool eval_quit(const struct expr *expr, struct eval_state *state) { return true; } +/** + * -samefile test. + */ +bool eval_samefile(const struct expr *expr, struct eval_state *state) { + const struct stat *statbuf = fill_statbuf(state); + if (!statbuf) { + return false; + } + + return statbuf->st_dev == expr->dev && statbuf->st_ino == expr->ino; +} + /** * -type test. */ diff --git a/parse.c b/parse.c index 4613aed..3498901 100644 --- a/parse.c +++ b/parse.c @@ -148,6 +148,21 @@ struct parser_state { struct timespec now; }; +/** + * Invoke stat() on an argument. + */ +static int stat_arg(const struct parser_state *state, struct expr *expr, struct stat *sb) { + bool follow = state->cl->flags & BFTW_FOLLOW; + int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW; + + int ret = fstatat(AT_FDCWD, expr->sdata, sb, flags); + if (ret != 0) { + print_error(NULL, expr->sdata, errno); + free_expr(expr); + } + return ret; +} + /** * Parse the expression specified on the command line. */ @@ -344,13 +359,7 @@ static struct expr *parse_acnewer(struct parser_state *state, const char *option } struct stat sb; - - bool follow = state->cl->flags & BFTW_FOLLOW; - int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW; - - if (fstatat(AT_FDCWD, expr->sdata, &sb, flags) != 0) { - print_error(NULL, expr->sdata, errno); - free_expr(expr); + if (stat_arg(state, expr, &sb) != 0) { return NULL; } @@ -408,6 +417,26 @@ static struct expr *parse_depth(struct parser_state *state, const char *option, return new_option(state, option); } +/** + * Parse -samefile FILE. + */ +static struct expr *parse_samefile(struct parser_state *state, const char *option) { + struct expr *expr = parse_test_sdata(state, option, eval_samefile); + if (!expr) { + return NULL; + } + + struct stat sb; + if (stat_arg(state, expr, &sb) != 0) { + return NULL; + } + + expr->dev = sb.st_dev; + expr->ino = sb.st_ino; + + return expr; +} + /** * Parse -type [bcdpfls]. */ @@ -619,6 +648,11 @@ static struct expr *parse_literal(struct parser_state *state) { } break; + case 's': + if (strcmp(arg, "-samefile") == 0) { + return parse_samefile(state, arg); + } + case 't': if (strcmp(arg, "-true") == 0) { return &expr_true; diff --git a/tests.sh b/tests.sh index 8c8c347..f869acc 100755 --- a/tests.sh +++ b/tests.sh @@ -189,7 +189,12 @@ function test_0027() { find_diff -L "$1" -depth 2>/dev/null } -for i in {1..27}; do +function test_0028() { + links_structure "$1" + find_diff "$1" -samefile "$1/a" +} + +for i in {1..28}; do dir="$(mktemp -d "${TMPDIR:-/tmp}"/bfs.XXXXXXXXXX)" test="test_$(printf '%04d' $i)" "$test" "$dir" -- cgit v1.2.3