From d3e64d6e1f905cd67264845c38b38fc6d1bdb088 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 4 Jul 2019 17:07:50 -0400 Subject: Make -mount and -xdev do different things POSIX now says -mount should skip the whole mount point, while -xdev should only skip its descendents. C.f. http://austingroupbugs.net/view.php?id=1133 C.f. https://savannah.gnu.org/bugs/?42318 C.f. https://savannah.gnu.org/bugs/?54745 --- bftw.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'bftw.c') diff --git a/bftw.c b/bftw.c index 444310c..370ab12 100644 --- a/bftw.c +++ b/bftw.c @@ -901,7 +901,7 @@ static bool bftw_need_stat(const struct bftw_state *state) { } if (ftwbuf->typeflag == BFTW_DIR) { - if (state->flags & (BFTW_DETECT_CYCLES | BFTW_XDEV)) { + if (state->flags & (BFTW_DETECT_CYCLES | BFTW_MOUNT | BFTW_XDEV)) { return true; } #if __linux__ @@ -1041,6 +1041,23 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) { } } +/** Check if the current file is a mount point. */ +static bool bftw_is_mount(struct bftw_state *state, const char *name) { + const struct bftw_file *file = state->file; + if (!file) { + return false; + } + + const struct bftw_file *parent = name ? file : file->parent; + if (!parent) { + return false; + } + + const struct BFTW *ftwbuf = &state->ftwbuf; + const struct bfs_stat *statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags); + return statbuf && statbuf->dev != parent->dev; +} + /** Fill file identity information from an ftwbuf. */ static void bftw_fill_id(struct bftw_file *file, const struct BFTW *ftwbuf) { const struct bfs_stat *statbuf = ftwbuf->stat_cache.buf; @@ -1071,6 +1088,10 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e return BFTW_STOP; } + if ((state->flags & BFTW_MOUNT) && bftw_is_mount(state, name)) { + return BFTW_PRUNE; + } + enum bftw_action ret = state->callback(ftwbuf, state->ptr); switch (ret) { case BFTW_CONTINUE: @@ -1088,19 +1109,9 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e goto done; } - if (state->flags & BFTW_XDEV) { - const struct bftw_file *parent = state->file; - if (parent && !name) { - parent = parent->parent; - } - - if (parent) { - const struct bfs_stat *statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags); - if (statbuf && statbuf->dev != parent->dev) { - ret = BFTW_PRUNE; - goto done; - } - } + if ((state->flags & BFTW_XDEV) && bftw_is_mount(state, name)) { + ret = BFTW_PRUNE; + goto done; } done: -- cgit v1.2.3