From 5bec8030c77b735147cdf73359bc8f91b19e28fb Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 19 Dec 2018 23:46:24 -0500 Subject: stat: Handle statx() not returning some times /sys/fs/cgroup, for example, doesn't return access times from statx(). That shouldn't matter unless we actually need them, so make it not an error. --- eval.c | 53 +++++++++++++++++++++++++++++++++++++++++------------ stat.c | 5 +++-- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/eval.c b/eval.c index ce72579..5d71318 100644 --- a/eval.c +++ b/eval.c @@ -213,20 +213,33 @@ bool eval_capable(const struct expr *expr, struct eval_state *state) { /** * Get the given timespec field out of a stat buffer. */ -static const struct timespec *eval_stat_time(const struct expr *expr, struct eval_state *state) { - const struct bfs_stat *statbuf = eval_stat(state); - if (!statbuf) { - return NULL; - } +static const struct timespec *eval_stat_time(const struct bfs_stat *statbuf, enum bfs_stat_field field, const struct eval_state *state) { + if (!(statbuf->mask & field)) { + const char *kind = ""; + switch (field) { + case BFS_STAT_ATIME: + kind = "access"; + break; + case BFS_STAT_BTIME: + kind = "birth"; + break; + case BFS_STAT_CTIME: + kind = "change"; + break; + case BFS_STAT_MTIME: + kind = "modification"; + break; + default: + assert(false); + break; + } - if (!(statbuf->mask & expr->stat_field)) { - assert(expr->stat_field == BFS_STAT_BTIME); - cfprintf(state->cmdline->cerr, "%{er}error: '%s': Couldn't get file birth time.%{rs}\n", state->ftwbuf->path); + cfprintf(state->cmdline->cerr, "%{er}error: '%s': Couldn't get file %s time.%{rs}\n", state->ftwbuf->path, kind); *state->ret = EXIT_FAILURE; return NULL; } - switch (expr->stat_field) { + switch (field) { case BFS_STAT_ATIME: return &statbuf->atime; case BFS_STAT_BTIME: @@ -245,7 +258,12 @@ static const struct timespec *eval_stat_time(const struct expr *expr, struct eva * -[aBcm]?newer tests. */ bool eval_newer(const struct expr *expr, struct eval_state *state) { - const struct timespec *time = eval_stat_time(expr, state); + const struct bfs_stat *statbuf = eval_stat(state); + if (!statbuf) { + return false; + } + + const struct timespec *time = eval_stat_time(statbuf, expr->stat_field, state); if (!time) { return false; } @@ -258,7 +276,12 @@ bool eval_newer(const struct expr *expr, struct eval_state *state) { * -[aBcm]{min,time} tests. */ bool eval_time(const struct expr *expr, struct eval_state *state) { - const struct timespec *time = eval_stat_time(expr, state); + const struct bfs_stat *statbuf = eval_stat(state); + if (!statbuf) { + return false; + } + + const struct timespec *time = eval_stat_time(statbuf, expr->stat_field, state); if (!time) { return false; } @@ -285,7 +308,13 @@ bool eval_used(const struct expr *expr, struct eval_state *state) { return false; } - time_t diff = timespec_diff(&statbuf->atime, &statbuf->ctime); + const struct timespec *atime = eval_stat_time(statbuf, BFS_STAT_ATIME, state); + const struct timespec *ctime = eval_stat_time(statbuf, BFS_STAT_CTIME, state); + if (!atime || !ctime) { + return false; + } + + time_t diff = timespec_diff(atime, ctime); diff /= 60*60*24; return expr_cmp(expr, diff); } diff --git a/stat.c b/stat.c index b8f1704..8ce13e9 100644 --- a/stat.c +++ b/stat.c @@ -148,8 +148,9 @@ static int bfs_statx_impl(int at_fd, const char *at_path, int at_flags, enum bfs return ret; } - if ((xbuf.stx_mask & STATX_BASIC_STATS) != STATX_BASIC_STATS) { - // Callers shouldn't have to check anything except BFS_STAT_BTIME + // Callers shouldn't have to check anything except the times + const int guaranteed = STATX_BASIC_STATS ^ (STATX_ATIME | STATX_CTIME | STATX_MTIME); + if ((xbuf.stx_mask & guaranteed) != guaranteed) { errno = EINVAL; return -1; } -- cgit v1.2.3