From 7922e45566ab0cdc18ccc75a8dc1881416a3077c Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 23 Jun 2019 11:25:49 -0400 Subject: bftw: Only rebuild the part of the path that changes This is a re-introduction of 998ba6f, which was reverted by the introduction of bftw_reader in 68ae5d0. It's particularly relevant for depth-first searches now that we queue each file before visiting it. --- bftw.c | 66 ++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 24 deletions(-) (limited to 'bftw.c') diff --git a/bftw.c b/bftw.c index 33931f1..762855c 100644 --- a/bftw.c +++ b/bftw.c @@ -336,28 +336,6 @@ static struct bftw_file *bftw_file_new(struct bftw_cache *cache, struct bftw_fil return file; } -/** - * Compute the path to a bftw_file. - */ -static int bftw_file_path(const struct bftw_file *file, char **path) { - size_t pathlen = file->nameoff + file->namelen; - if (dstresize(path, pathlen) != 0) { - return -1; - } - char *dest = *path; - - // Build the path backwards - while (file) { - if (file->nameoff > 0) { - dest[file->nameoff - 1] = '/'; - } - memcpy(dest + file->nameoff, file->name, file->namelen); - file = file->parent; - } - - return 0; -} - /** * Get the appropriate (fd, path) pair for the *at() family of functions. * @@ -684,6 +662,8 @@ struct bftw_state { char *path; /** The current file. */ struct bftw_file *file; + /** The previous file. */ + struct bftw_file *previous; /** The reader for the current directory. */ struct bftw_reader reader; @@ -722,6 +702,7 @@ static int bftw_state_init(struct bftw_state *state, const struct bftw_args *arg } state->file = NULL; + state->previous = NULL; bftw_reader_init(&state->reader); return 0; @@ -1160,6 +1141,41 @@ static int bftw_push(struct bftw_state *state, const char *name, bool fill_id) { return 0; } +/** + * Build the path to the current file. + */ +static int bftw_build_path(struct bftw_state *state) { + const struct bftw_file *file = state->file; + + size_t pathlen = file->nameoff + file->namelen; + if (dstresize(&state->path, pathlen) != 0) { + state->error = errno; + return -1; + } + + // Try to find a common ancestor with the existing path + const struct bftw_file *ancestor = state->previous; + while (ancestor && ancestor->depth > file->depth) { + ancestor = ancestor->parent; + } + + // Build the path backwards + while (file && file != ancestor) { + if (file->nameoff > 0) { + state->path[file->nameoff - 1] = '/'; + } + memcpy(state->path + file->nameoff, file->name, file->namelen); + + if (ancestor && ancestor->depth == file->depth) { + ancestor = ancestor->parent; + } + file = file->parent; + } + + state->previous = state->file; + return 0; +} + /** * Pop the next file from the queue. */ @@ -1174,8 +1190,7 @@ static int bftw_pop(struct bftw_state *state) { state->file = bftw_queue_pop(&state->queue); - if (bftw_file_path(state->file, &state->path) != 0) { - state->error = errno; + if (bftw_build_path(state) != 0) { return -1; } @@ -1242,6 +1257,9 @@ static enum bftw_action bftw_release_file(struct bftw_state *state, bool visit_f do_visit = visit_parents; struct bftw_file *parent = state->file->parent; + if (state->previous == state->file) { + state->previous = parent; + } bftw_file_free(&state->cache, state->file); state->file = parent; } -- cgit v1.2.3