From 4cd28ed2aa3f098a1d35dd44ecec27002fadb89b Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 13 Feb 2016 15:57:41 -0500 Subject: Fix -name handling when the root has trailing slashes. --- bftw.c | 20 ++++++++++++++++++-- eval.c | 26 +++++++++++++++++++++++++- tests.sh | 18 +++++++++++++++++- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/bftw.c b/bftw.c index 8a55f13..e64a93c 100644 --- a/bftw.c +++ b/bftw.c @@ -599,15 +599,28 @@ static void bftw_set_error(struct bftw_state *state, int error) { state->ftwbuf.typeflag = BFTW_ERROR; } +/** + * Figure out the name offset in a path. + */ +static size_t basename_offset(const char *path) { + size_t i; + + // Strip trailing slashes + for (i = strlen(path); i > 0 && path[i - 1] == '/'; --i); + + // Find the beginning of the name + for (; i > 0 && path[i - 1] != '/'; --i); + + return i; +} + /** * Initialize the buffers with data about the current path. */ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de) { struct BFTW *ftwbuf = &state->ftwbuf; ftwbuf->path = state->path.str; - ftwbuf->nameoff = 0; ftwbuf->error = 0; - ftwbuf->depth = 0; ftwbuf->visit = (state->status == BFTW_GC ? BFTW_POST : BFTW_PRE); ftwbuf->statbuf = NULL; ftwbuf->at_fd = AT_FDCWD; @@ -624,6 +637,9 @@ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de) } dircache_entry_base(&state->cache, current, &ftwbuf->at_fd, &ftwbuf->at_path); + } else { + ftwbuf->nameoff = basename_offset(ftwbuf->path); + ftwbuf->depth = 0; } if (de) { diff --git a/eval.c b/eval.c index 5c78d0b..cd9b2e5 100644 --- a/eval.c +++ b/eval.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -311,7 +312,30 @@ bool eval_links(const struct expr *expr, struct eval_state *state) { */ bool eval_name(const struct expr *expr, struct eval_state *state) { struct BFTW *ftwbuf = state->ftwbuf; - return fnmatch(expr->sdata, ftwbuf->path + ftwbuf->nameoff, 0) == 0; + + const char *name = ftwbuf->path + ftwbuf->nameoff; + char *copy = NULL; + if (ftwbuf->depth == 0) { + // Any trailing slashes are not part of the name. This can only + // happen for the root path. + const char *slash = strchr(name, '/'); + if (slash == name) { + // The name of "/" (or "//", etc.) is "/" + name = "/"; + } else if (slash) { + copy = strdup(name); + if (!copy) { + eval_error(state); + return false; + } + copy[slash - name] = '\0'; + name = copy; + } + } + + bool ret = fnmatch(expr->sdata, name, 0) == 0; + free(copy); + return ret; } /** diff --git a/tests.sh b/tests.sh index 046fddd..97d274b 100755 --- a/tests.sh +++ b/tests.sh @@ -199,7 +199,23 @@ function test_0032() { find_diff -L "$links" -xtype f 2>/dev/null } -for i in {1..32}; do +function test_0033() { + find_diff "$basic/a" -name 'a' +} + +function test_0034() { + find_diff "$basic/g/" -name 'g' +} + +function test_0035() { + find_diff "/" -maxdepth 0 -name '/' 2>/dev/null +} + +function test_0036() { + find_diff "//" -maxdepth 0 -name '/' 2>/dev/null +} + +for i in {1..36}; do test="test_$(printf '%04d' $i)" "$test" "$dir" status=$? -- cgit v1.2.3