From ccf75c74bdac06eec97a2a6a5228c2e706c121bd Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 18 Sep 2020 17:34:03 -0400 Subject: Don't call stat() just to determine symbolic lengths The new bftw_cached_stat() helper gets us stat info if we already have it, but doesn't call stat() if we don't. In that case we just take a guess for the initial length to readlinkat(). This lets us avoid stat() entirely in many cases for -lname and -printf %l. --- bftw.c | 8 ++++++++ bftw.h | 13 +++++++++++++ color.c | 7 ++----- eval.c | 8 +++----- printf.c | 5 ++++- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/bftw.c b/bftw.c index ff4797d..1296360 100644 --- a/bftw.c +++ b/bftw.c @@ -886,6 +886,14 @@ const struct bfs_stat *bftw_stat(const struct BFTW *ftwbuf, enum bfs_stat_flag f return ret; } +const struct bfs_stat *bftw_cached_stat(const struct BFTW *ftwbuf, enum bfs_stat_flag flags) { + if (flags & BFS_STAT_NOFOLLOW) { + return ftwbuf->lstat_cache.buf; + } else { + return ftwbuf->stat_cache.buf; + } +} + enum bftw_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flag flags) { if (ftwbuf->stat_flags & BFS_STAT_NOFOLLOW) { if ((flags & BFS_STAT_NOFOLLOW) || ftwbuf->type != BFTW_LNK) { diff --git a/bftw.h b/bftw.h index 0a4f2aa..2198b52 100644 --- a/bftw.h +++ b/bftw.h @@ -130,6 +130,19 @@ struct BFTW { */ const struct bfs_stat *bftw_stat(const struct BFTW *ftwbuf, enum bfs_stat_flag flags); +/** + * Get bfs_stat() info for a file encountered during bftw(), if it has already + * been cached. + * + * @param ftwbuf + * bftw() data for the file to stat. + * @param flags + * flags for bfs_stat(). Pass ftwbuf->stat_flags for the default flags. + * @return + * A pointer to a bfs_stat() buffer, or NULL if no stat info is cached. + */ +const struct bfs_stat *bftw_cached_stat(const struct BFTW *ftwbuf, enum bfs_stat_flag flags); + /** * Get the type of a file encountered during bftw(), with flags controlling * whether to follow links. This function will avoid calling bfs_stat() if diff --git a/color.c b/color.c index 11684ef..4b70e19 100644 --- a/color.c +++ b/color.c @@ -841,11 +841,8 @@ static int print_path(CFILE *cfile, const struct BFTW *ftwbuf) { static int print_link_target(CFILE *cfile, const struct BFTW *ftwbuf) { int ret = -1; - size_t len = 0; - const struct bfs_stat *statbuf = bftw_stat(ftwbuf, BFS_STAT_NOFOLLOW); - if (statbuf) { - len = statbuf->size; - } + const struct bfs_stat *statbuf = bftw_cached_stat(ftwbuf, BFS_STAT_NOFOLLOW); + size_t len = statbuf ? statbuf->size : 0; char *target = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, len); if (!target) { diff --git a/eval.c b/eval.c index f8b9a6d..b50efd7 100644 --- a/eval.c +++ b/eval.c @@ -484,12 +484,10 @@ bool eval_lname(const struct expr *expr, struct eval_state *state) { goto done; } - const struct bfs_stat *statbuf = eval_stat(state); - if (!statbuf) { - goto done; - } + const struct bfs_stat *statbuf = bftw_cached_stat(ftwbuf, BFS_STAT_NOFOLLOW); + size_t len = statbuf ? statbuf->size : 0; - name = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, statbuf->size); + name = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, len); if (!name) { eval_report_error(state); goto done; diff --git a/printf.c b/printf.c index b9149f3..6eb59dd 100644 --- a/printf.c +++ b/printf.c @@ -310,7 +310,10 @@ static int bfs_printf_l(FILE *file, const struct bfs_printf *directive, const st return 0; } - char *target = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, 0); + const struct bfs_stat *statbuf = bftw_cached_stat(ftwbuf, BFS_STAT_NOFOLLOW); + size_t len = statbuf ? statbuf->size : 0; + + char *target = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, len); if (!target) { return -1; } -- cgit v1.2.3