diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2018-12-19 23:46:24 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2018-12-19 23:46:24 -0500 |
commit | 5bec8030c77b735147cdf73359bc8f91b19e28fb (patch) | |
tree | cfdea987c53787a0543718cfbc5fb63f6cfb1061 | |
parent | 201b3345f6880d2c8400259b1b0cedec4f885460 (diff) | |
download | bfs-5bec8030c77b735147cdf73359bc8f91b19e28fb.tar.xz |
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.
-rw-r--r-- | eval.c | 53 | ||||
-rw-r--r-- | stat.c | 5 |
2 files changed, 44 insertions, 14 deletions
@@ -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); } @@ -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; } |