diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | bftw.c | 27 | ||||
-rw-r--r-- | bftw.h | 6 | ||||
-rw-r--r-- | color.c | 23 | ||||
-rw-r--r-- | eval.c | 176 | ||||
-rw-r--r-- | expr.h | 19 | ||||
-rw-r--r-- | mtab.c | 24 | ||||
-rw-r--r-- | mtab.h | 6 | ||||
-rw-r--r-- | parse.c | 109 | ||||
-rw-r--r-- | printf.c | 92 | ||||
-rw-r--r-- | printf.h | 2 | ||||
-rw-r--r-- | stat.c | 243 | ||||
-rw-r--r-- | stat.h | 94 | ||||
-rw-r--r-- | util.c | 11 | ||||
-rw-r--r-- | util.h | 30 |
15 files changed, 565 insertions, 299 deletions
@@ -51,7 +51,7 @@ ALL_LDFLAGS = $(ALL_CFLAGS) $(LDFLAGS) all: bfs -bfs: bftw.o color.o dstring.o eval.o exec.o main.o mtab.o opt.o parse.o printf.o typo.o util.o +bfs: bftw.o color.o dstring.o eval.o exec.o main.o mtab.o opt.o parse.o printf.o stat.o typo.o util.o $(CC) $(ALL_LDFLAGS) $^ -o $@ release: CFLAGS := -O3 -flto $(WFLAGS) -DNDEBUG -g @@ -35,6 +35,7 @@ #include "bftw.h" #include "dstring.h" +#include "stat.h" #include "util.h" #include <assert.h> #include <dirent.h> @@ -45,8 +46,6 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> -#include <sys/stat.h> -#include <sys/types.h> #include <unistd.h> /** @@ -550,11 +549,11 @@ static void bftw_queue_destroy(struct bftw_queue *queue) { } /** Call stat() and use the results. */ -static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb) { - int ret = xfstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, ftwbuf->at_flags); +static int ftwbuf_stat(struct BFTW *ftwbuf, struct bfs_stat *sb) { + int ret = bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, ftwbuf->at_flags, BFS_STAT_BROKEN_OK, sb); if (ret == 0) { ftwbuf->statbuf = sb; - ftwbuf->typeflag = mode_to_typeflag(sb->st_mode); + ftwbuf->typeflag = mode_to_typeflag(sb->mode); } return ret; } @@ -606,8 +605,8 @@ struct bftw_state { /** Extra data about the current file. */ struct BFTW ftwbuf; - /** stat() buffer for the current file. */ - struct stat statbuf; + /** bfs_stat() buffer for the current file. */ + struct bfs_stat statbuf; }; /** @@ -840,8 +839,8 @@ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de) } if (ftwbuf->typeflag == BFTW_DIR && detect_cycles) { - dev_t dev = ftwbuf->statbuf->st_dev; - ino_t ino = ftwbuf->statbuf->st_ino; + dev_t dev = ftwbuf->statbuf->dev; + ino_t ino = ftwbuf->statbuf->ino; for (const struct bftw_dir *dir = current; dir; dir = dir->parent) { if (dev == dir->dev && ino == dir->ino) { bftw_set_error(state, ELOOP); @@ -890,10 +889,10 @@ static struct bftw_dir *bftw_add(struct bftw_state *state, const char *name) { return NULL; } - const struct stat *statbuf = state->ftwbuf.statbuf; + const struct bfs_stat *statbuf = state->ftwbuf.statbuf; if (statbuf) { - dir->dev = statbuf->st_dev; - dir->ino = statbuf->st_ino; + dir->dev = statbuf->dev; + dir->ino = statbuf->ino; } return dir; @@ -1083,10 +1082,10 @@ int bftw(const char *path, bftw_fn *fn, int nopenfd, enum bftw_flags flags, void } if (state.ftwbuf.typeflag == BFTW_DIR) { - const struct stat *statbuf = state.ftwbuf.statbuf; + const struct bfs_stat *statbuf = state.ftwbuf.statbuf; if ((flags & BFTW_XDEV) && statbuf - && statbuf->st_dev != state.current->dev) { + && statbuf->dev != state.current->dev) { continue; } @@ -17,8 +17,8 @@ #ifndef BFS_BFTW_H #define BFS_BFTW_H +#include "stat.h" #include <stddef.h> -#include <sys/stat.h> /** * Possible file types. @@ -81,8 +81,8 @@ struct BFTW { /** The errno that occurred, if typeflag == BFTW_ERROR. */ int error; - /** A stat() buffer; may be NULL if no stat() call was needed. */ - const struct stat *statbuf; + /** A bfs_stat() buffer; may be NULL if no stat() call was needed. */ + const struct bfs_stat *statbuf; /** A parent file descriptor for the *at() family of calls. */ int at_fd; @@ -16,6 +16,7 @@ #include "color.h" #include "bftw.h" +#include "stat.h" #include "util.h" #include <assert.h> #include <errno.h> @@ -296,24 +297,24 @@ int cfclose(CFILE *cfile) { } static const char *file_color(const struct colors *colors, const char *filename, const struct BFTW *ftwbuf) { - const struct stat *sb = ftwbuf->statbuf; + const struct bfs_stat *sb = ftwbuf->statbuf; if (!sb) { return colors->orphan; } const char *color = NULL; - switch (sb->st_mode & S_IFMT) { + switch (sb->mode & S_IFMT) { case S_IFREG: - if (sb->st_mode & S_ISUID) { + if (sb->mode & S_ISUID) { color = colors->setuid; - } else if (sb->st_mode & S_ISGID) { + } else if (sb->mode & S_ISGID) { color = colors->setgid; - } else if (sb->st_mode & 0111) { + } else if (sb->mode & 0111) { color = colors->exec; } - if (!color && sb->st_nlink > 1) { + if (!color && sb->nlink > 1) { color = colors->multi_hard; } @@ -335,13 +336,13 @@ static const char *file_color(const struct colors *colors, const char *filename, break; case S_IFDIR: - if (sb->st_mode & S_ISVTX) { - if (sb->st_mode & S_IWOTH) { + if (sb->mode & S_ISVTX) { + if (sb->mode & S_IWOTH) { color = colors->sticky_ow; } else { color = colors->sticky; } - } else if (sb->st_mode & S_IWOTH) { + } else if (sb->mode & S_IWOTH) { color = colors->ow; } @@ -455,8 +456,8 @@ static int print_link(CFILE *cfile, const struct BFTW *ftwbuf) { altbuf.path = target; altbuf.nameoff = xbasename(target) - target; - struct stat statbuf; - if (fstatat(ftwbuf->at_fd, ftwbuf->at_path, &statbuf, 0) == 0) { + struct bfs_stat statbuf; + if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, 0, 0, &statbuf) == 0) { altbuf.statbuf = &statbuf; } else { altbuf.statbuf = NULL; @@ -22,6 +22,7 @@ #include "exec.h" #include "mtab.h" #include "printf.h" +#include "stat.h" #include "util.h" #include <assert.h> #include <dirent.h> @@ -51,7 +52,9 @@ struct eval_state { /** Whether to quit immediately. */ bool *quit; /** A stat() buffer, if necessary. */ - struct stat statbuf; + struct bfs_stat statbuf; + /** A bfs_stat() buffer, if necessary. */ + struct bfs_stat bfs_statbuf; }; /** @@ -74,13 +77,13 @@ static void eval_error(struct eval_state *state) { } /** - * Perform a stat() call if necessary. + * Perform a bfs_stat() call if necessary. */ -static const struct stat *fill_statbuf(struct eval_state *state) { +static const struct bfs_stat *eval_bfs_stat(struct eval_state *state) { struct BFTW *ftwbuf = state->ftwbuf; if (!ftwbuf->statbuf) { - if (xfstatat(ftwbuf->at_fd, ftwbuf->at_path, &state->statbuf, ftwbuf->at_flags) == 0) { - ftwbuf->statbuf = &state->statbuf; + if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, ftwbuf->at_flags, BFS_STAT_BROKEN_OK, &state->bfs_statbuf) == 0) { + ftwbuf->statbuf = &state->bfs_statbuf; } else { eval_error(state); } @@ -135,34 +138,42 @@ bool eval_access(const struct expr *expr, struct eval_state *state) { } /** - * -[aBcm]?newer tests. + * Get the given timespec field out of a stat buffer. */ -bool eval_newer(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); +static const struct timespec *eval_stat_time(const struct expr *expr, struct eval_state *state) { + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { - return false; + return NULL; } - const struct timespec *time; - switch (expr->time_field) { - case ATIME: - time = &statbuf->st_atim; - break; - case CTIME: - time = &statbuf->st_ctim; - break; - case MTIME: - time = &statbuf->st_mtim; - break; - -#if BFS_HAVE_ST_BIRTHTIM - case BTIME: - time = &statbuf->st_birthtim; - break; -#endif - + 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); + *state->ret = EXIT_FAILURE; + return NULL; + } + + switch (expr->stat_field) { + case BFS_STAT_ATIME: + return &statbuf->atime; + case BFS_STAT_BTIME: + return &statbuf->btime; + case BFS_STAT_CTIME: + return &statbuf->ctime; + case BFS_STAT_MTIME: + return &statbuf->mtime; default: assert(false); + return NULL; + } +} + +/** + * -[aBcm]?newer tests. + */ +bool eval_newer(const struct expr *expr, struct eval_state *state) { + const struct timespec *time = eval_stat_time(expr, state); + if (!time) { return false; } @@ -174,31 +185,8 @@ 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 stat *statbuf = fill_statbuf(state); - if (!statbuf) { - return false; - } - - const struct timespec *time; - switch (expr->time_field) { - case ATIME: - time = &statbuf->st_atim; - break; - case CTIME: - time = &statbuf->st_ctim; - break; - case MTIME: - time = &statbuf->st_mtim; - break; - -#if BFS_HAVE_ST_BIRTHTIM - case BTIME: - time = &statbuf->st_birthtim; - break; -#endif - - default: - assert(false); + const struct timespec *time = eval_stat_time(expr, state); + if (!time) { return false; } @@ -219,12 +207,12 @@ bool eval_time(const struct expr *expr, struct eval_state *state) { * -used test. */ bool eval_used(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - time_t diff = timespec_diff(&statbuf->st_atim, &statbuf->st_ctim); + time_t diff = timespec_diff(&statbuf->atime, &statbuf->ctime); diff /= 60*60*24; return expr_cmp(expr, diff); } @@ -233,48 +221,48 @@ bool eval_used(const struct expr *expr, struct eval_state *state) { * -gid test. */ bool eval_gid(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - return expr_cmp(expr, statbuf->st_gid); + return expr_cmp(expr, statbuf->gid); } /** * -uid test. */ bool eval_uid(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - return expr_cmp(expr, statbuf->st_uid); + return expr_cmp(expr, statbuf->uid); } /** * -nogroup test. */ bool eval_nogroup(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - return getgrgid(statbuf->st_gid) == NULL; + return getgrgid(statbuf->gid) == NULL; } /** * -nouser test. */ bool eval_nouser(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - return getpwuid(statbuf->st_uid) == NULL; + return getpwuid(statbuf->uid) == NULL; } /** @@ -390,9 +378,9 @@ bool eval_empty(const struct expr *expr, struct eval_state *state) { done_dir: closedir(dir); } else { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (statbuf) { - ret = statbuf->st_size == 0; + ret = statbuf->size == 0; } } @@ -404,7 +392,7 @@ done: * -fstype test. */ bool eval_fstype(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } @@ -437,24 +425,24 @@ bool eval_nohidden(const struct expr *expr, struct eval_state *state) { * -inum test. */ bool eval_inum(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - return expr_cmp(expr, statbuf->st_ino); + return expr_cmp(expr, statbuf->ino); } /** * -links test. */ bool eval_links(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - return expr_cmp(expr, statbuf->st_nlink); + return expr_cmp(expr, statbuf->nlink); } /** @@ -469,12 +457,12 @@ bool eval_lname(const struct expr *expr, struct eval_state *state) { goto done; } - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { goto done; } - name = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, statbuf->st_size); + name = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, statbuf->size); if (!name) { eval_error(state); goto done; @@ -526,12 +514,12 @@ bool eval_path(const struct expr *expr, struct eval_state *state) { * -perm test. */ bool eval_perm(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - mode_t mode = statbuf->st_mode; + mode_t mode = statbuf->mode; mode_t target; if (state->ftwbuf->typeflag == BFTW_DIR) { target = expr->dir_mode; @@ -560,21 +548,21 @@ bool eval_fls(const struct expr *expr, struct eval_state *state) { CFILE *cfile = expr->cfile; FILE *file = cfile->file; const struct BFTW *ftwbuf = state->ftwbuf; - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { goto done; } - uintmax_t ino = statbuf->st_ino; - uintmax_t blocks = (statbuf->st_blocks + 1)/2; + uintmax_t ino = statbuf->ino; + uintmax_t blocks = (statbuf->blocks + 1)/2; char mode[11]; - format_mode(statbuf->st_mode, mode); - uintmax_t nlink = statbuf->st_nlink; + format_mode(statbuf->mode, mode); + uintmax_t nlink = statbuf->nlink; if (fprintf(file, "%9ju %6ju %s %3ju ", ino, blocks, mode, nlink) < 0) { goto error; } - uintmax_t uid = statbuf->st_uid; + uintmax_t uid = statbuf->uid; struct passwd *pwd = getpwuid(uid); if (pwd) { if (fprintf(file, " %-8s", pwd->pw_name) < 0) { @@ -586,7 +574,7 @@ bool eval_fls(const struct expr *expr, struct eval_state *state) { } } - uintmax_t gid = statbuf->st_gid; + uintmax_t gid = statbuf->gid; struct group *grp = getgrgid(gid); if (grp) { if (fprintf(file, " %-8s", grp->gr_name) < 0) { @@ -598,12 +586,12 @@ bool eval_fls(const struct expr *expr, struct eval_state *state) { } } - uintmax_t size = statbuf->st_size; + uintmax_t size = statbuf->size; if (fprintf(file, " %8ju", size) < 0) { goto error; } - time_t time = statbuf->st_mtim.tv_sec; + time_t time = statbuf->mtime.tv_sec; time_t now = expr->reftime.tv_sec; time_t six_months_ago = now - 6*30*24*60*60; time_t tomorrow = now + 24*60*60; @@ -652,7 +640,7 @@ error: bool eval_fprint(const struct expr *expr, struct eval_state *state) { CFILE *cfile = expr->cfile; if (cfile->colors) { - fill_statbuf(state); + eval_bfs_stat(state); } if (cfprintf(cfile, "%P\n", state->ftwbuf) < 0) { @@ -679,7 +667,7 @@ bool eval_fprint0(const struct expr *expr, struct eval_state *state) { */ bool eval_fprintf(const struct expr *expr, struct eval_state *state) { if (expr->printf->needs_stat) { - if (!fill_statbuf(state)) { + if (!eval_bfs_stat(state)) { goto done; } } @@ -784,19 +772,19 @@ bool eval_regex(const struct expr *expr, struct eval_state *state) { * -samefile test. */ bool eval_samefile(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - return statbuf->st_dev == expr->dev && statbuf->st_ino == expr->ino; + return statbuf->dev == expr->dev && statbuf->ino == expr->ino; } /** * -size test. */ bool eval_size(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } @@ -813,7 +801,7 @@ bool eval_size(const struct expr *expr, struct eval_state *state) { }; off_t scale = scales[expr->size_unit]; - off_t size = (statbuf->st_size + scale - 1)/scale; // Round up + off_t size = (statbuf->size + scale - 1)/scale; // Round up return expr_cmp(expr, size); } @@ -821,13 +809,13 @@ bool eval_size(const struct expr *expr, struct eval_state *state) { * -sparse test. */ bool eval_sparse(const struct expr *expr, struct eval_state *state) { - const struct stat *statbuf = fill_statbuf(state); + const struct bfs_stat *statbuf = eval_bfs_stat(state); if (!statbuf) { return false; } - blkcnt_t expected = (statbuf->st_size + 511)/512; - return statbuf->st_blocks < expected; + blkcnt_t expected = (statbuf->size + 511)/512; + return statbuf->blocks < expected; } /** @@ -852,8 +840,8 @@ bool eval_xtype(const struct expr *expr, struct eval_state *state) { // -xtype does the opposite of everything else int at_flags = ftwbuf->at_flags ^ AT_SYMLINK_NOFOLLOW; - struct stat sb; - if (fstatat(ftwbuf->at_fd, ftwbuf->at_path, &sb, at_flags) != 0) { + struct bfs_stat sb; + if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, at_flags, 0, &sb) != 0) { if (!follow && is_nonexistence_error(errno)) { // Broken symlink return eval_type(expr, state); @@ -863,7 +851,7 @@ bool eval_xtype(const struct expr *expr, struct eval_state *state) { } } - return mode_to_typeflag(sb.st_mode) & expr->idata; + return mode_to_typeflag(sb.mode) & expr->idata; } #if _POSIX_MONOTONIC_CLOCK > 0 @@ -20,6 +20,7 @@ #include "color.h" #include "exec.h" #include "printf.h" +#include "stat.h" #include <regex.h> #include <stdbool.h> #include <stddef.h> @@ -73,20 +74,6 @@ enum mode_cmp { }; /** - * Available struct stat time fields. - */ -enum time_field { - /** Access time. */ - ATIME, - /** Status change time. */ - CTIME, - /** Modification time. */ - MTIME, - /** Birth time. */ - BTIME, -}; - -/** * Possible time units. */ enum time_unit { @@ -160,10 +147,10 @@ struct expr { /** Mode to use for directories (different due to X). */ mode_t dir_mode; + /** The optional stat field to look at. */ + enum bfs_stat_field stat_field; /** The optional reference time. */ struct timespec reftime; - /** The optional time field. */ - enum time_field time_field; /** The optional time unit. */ enum time_unit time_unit; @@ -15,7 +15,9 @@ ****************************************************************************/ #include "mtab.h" +#include "util.h" #include <errno.h> +#include <fcntl.h> #include <stdlib.h> #include <string.h> #include <sys/param.h> @@ -110,12 +112,12 @@ struct bfs_mtab *parse_bfs_mtab() { struct mntent *mnt; while ((mnt = getmntent(file))) { - struct stat sb; - if (stat(mnt->mnt_dir, &sb) != 0) { + struct bfs_stat sb; + if (bfs_stat(AT_FDCWD, mnt->mnt_dir, 0, 0, &sb) != 0) { continue; } - if (bfs_mtab_push(mtab, sb.st_dev, mnt->mnt_type) != 0) { + if (bfs_mtab_push(mtab, sb.dev, mnt->mnt_type) != 0) { goto fail_mtab; } } @@ -151,12 +153,12 @@ fail: mtab->capacity = size; for (struct statfs *mnt = mntbuf; mnt < mntbuf + size; ++mnt) { - struct stat sb; - if (stat(mnt->f_mntonname, &sb) != 0) { + struct bfs_stat sb; + if (bfs_stat(AT_FDCWD, mnt->f_mntonname, 0, 0, &sb) != 0) { continue; } - if (bfs_mtab_push(mtab, sb.st_dev, mnt->f_fstypename) != 0) { + if (bfs_mtab_push(mtab, sb.dev, mnt->f_fstypename) != 0) { goto fail_mtab; } } @@ -185,12 +187,12 @@ fail: struct mnttab mnt; while (getmntent(file, &mnt) == 0) { - struct stat sb; - if (stat(mnt.mnt_mountp, &sb) != 0) { + struct bfs_stat sb; + if (bfs_stat(AT_FDCWD, mnt.mnt_mountp, 0, 0, &sb) != 0) { continue; } - if (bfs_mtab_push(mtab, sb.st_dev, mnt.mnt_fstype) != 0) { + if (bfs_mtab_push(mtab, sb.dev, mnt.mnt_fstype) != 0) { goto fail_mtab; } } @@ -212,9 +214,9 @@ fail: #endif } -const char *bfs_fstype(const struct bfs_mtab *mtab, const struct stat *statbuf) { +const char *bfs_fstype(const struct bfs_mtab *mtab, const struct bfs_stat *statbuf) { for (struct bfs_mtab_entry *mnt = mtab->table; mnt < mtab->table + mtab->size; ++mnt) { - if (statbuf->st_dev == mnt->dev) { + if (statbuf->dev == mnt->dev) { return mnt->type; } } @@ -17,7 +17,7 @@ #ifndef BFS_MTAB_H #define BFS_MTAB_H -#include <sys/stat.h> +#include "stat.h" /** * A file system mount table. @@ -37,11 +37,11 @@ struct bfs_mtab *parse_bfs_mtab(void); * @param mtab * The current mount table. * @param statbuf - * The stat() buffer for the file in question. + * The bfs_stat() buffer for the file in question. * @return The type of file system containing this file, "unknown" if not known, * or NULL on error. */ -const char *bfs_fstype(const struct bfs_mtab *mtab, const struct stat *statbuf); +const char *bfs_fstype(const struct bfs_mtab *mtab, const struct bfs_stat *statbuf); /** * Free a mount table. @@ -22,6 +22,7 @@ #include "expr.h" #include "mtab.h" #include "printf.h" +#include "stat.h" #include "typo.h" #include "util.h" #include <ctype.h> @@ -389,14 +390,14 @@ static int expr_open(struct parser_state *state, struct expr *expr, const char * goto out; } - struct stat sb; - if (fstat(fileno(cfile->file), &sb) != 0) { + struct bfs_stat sb; + if (bfs_fstat(fileno(cfile->file), &sb) != 0) { cfprintf(cmdline->cerr, "%{er}error: '%s': %m%{rs}\n", path); goto out_close; } for (struct open_file *ofile = cmdline->open_files; ofile; ofile = ofile->next) { - if (ofile->dev == sb.st_dev && ofile->ino == sb.st_ino) { + if (ofile->dev == sb.dev && ofile->ino == sb.ino) { expr->cfile = ofile->cfile; ret = 0; goto out_close; @@ -410,8 +411,8 @@ static int expr_open(struct parser_state *state, struct expr *expr, const char * ofile->cfile = cfile; ofile->path = path; - ofile->dev = sb.st_dev; - ofile->ino = sb.st_ino; + ofile->dev = sb.dev; + ofile->ino = sb.ino; ofile->next = cmdline->open_files; cmdline->open_files = ofile; ++cmdline->nopen_files; @@ -428,15 +429,15 @@ out: } /** - * Invoke stat() on an argument. + * Invoke bfs_stat() on an argument. */ -static int stat_arg(const struct parser_state *state, struct expr *expr, struct stat *sb) { +static int stat_arg(const struct parser_state *state, struct expr *expr, struct bfs_stat *sb) { const struct cmdline *cmdline = state->cmdline; bool follow = cmdline->flags & (BFTW_COMFOLLOW | BFTW_LOGICAL); - int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW; + int at_flags = follow ? 0 : AT_SYMLINK_NOFOLLOW; - int ret = xfstatat(AT_FDCWD, expr->sdata, sb, flags); + int ret = bfs_stat(AT_FDCWD, expr->sdata, at_flags, BFS_STAT_BROKEN_OK, sb); if (ret != 0) { cfprintf(cmdline->cerr, "%{er}error: '%s': %m%{rs}\n", expr->sdata); } @@ -911,21 +912,14 @@ static struct expr *parse_newer(struct parser_state *state, int field, int arg2) return NULL; } -#if !BFS_HAVE_ST_BIRTHTIM - if (field == BTIME) { - cfprintf(state->cmdline->cerr, "%{er}error: %s: File birth times are not supported on this platform.%{rs}\n", expr->argv[0]); - goto fail; - } -#endif - - struct stat sb; + struct bfs_stat sb; if (stat_arg(state, expr, &sb) != 0) { goto fail; } expr->cost = STAT_COST; - expr->reftime = sb.st_mtim; - expr->time_field = field; + expr->reftime = sb.mtime; + expr->stat_field = field; return expr; fail: @@ -942,17 +936,9 @@ static struct expr *parse_time(struct parser_state *state, int field, int unit) return NULL; } -#if !BFS_HAVE_ST_BIRTHTIM - if (field == BTIME) { - cfprintf(state->cmdline->cerr, "%{er}error: %s: File birth times are not supported on this platform.%{rs}\n", expr->argv[0]); - free_expr(expr); - return NULL; - } -#endif - expr->cost = STAT_COST; expr->reftime = state->now; - expr->time_field = field; + expr->stat_field = field; expr->time_unit = unit; return expr; } @@ -1496,23 +1482,17 @@ static struct expr *parse_newerxy(struct parser_state *state, int arg1, int arg2 switch (arg[6]) { case 'a': - expr->time_field = ATIME; + expr->stat_field = BFS_STAT_ATIME; break; case 'c': - expr->time_field = CTIME; + expr->stat_field = BFS_STAT_CTIME; break; case 'm': - expr->time_field = MTIME; + expr->stat_field = BFS_STAT_MTIME; break; - case 'B': -#if BFS_HAVE_ST_BIRTHTIM - expr->time_field = BTIME; + expr->stat_field = BFS_STAT_BTIME; break; -#else - cfprintf(cerr, "%{er}error: %s: File birth times ('B') are not supported on this platform.%{rs}\n", arg); - goto fail; -#endif default: cfprintf(cerr, "%{er}error: %s: For -newerXY, X should be 'a', 'c', 'm', or 'B'.%{rs}\n", arg); @@ -1523,29 +1503,30 @@ static struct expr *parse_newerxy(struct parser_state *state, int arg1, int arg2 cfprintf(cerr, "%{er}error: %s: Explicit reference times ('t') are not supported.%{rs}\n", arg); goto fail; } else { - struct stat sb; + struct bfs_stat sb; if (stat_arg(state, expr, &sb) != 0) { goto fail; } switch (arg[7]) { case 'a': - expr->reftime = sb.st_atim; + expr->reftime = sb.atime; break; case 'c': - expr->reftime = sb.st_ctim; + expr->reftime = sb.ctime; break; case 'm': - expr->reftime = sb.st_mtim; + expr->reftime = sb.mtime; break; case 'B': -#if BFS_HAVE_ST_BIRTHTIM - expr->reftime = sb.st_birthtim; -#else - cfprintf(cerr, "%{er}error: %s: File birth times ('B') are not supported on this platform.%{rs}\n", arg); - goto fail; -#endif + if (sb.mask & BFS_STAT_BTIME) { + expr->reftime = sb.btime; + } else { + cfprintf(cerr, "%{er}error: '%s': Couldn't get file birth time.%{rs}\n", expr->sdata); + goto fail; + } + break; default: cfprintf(cerr, "%{er}error: %s: For -newerXY, Y should be 'a', 'c', 'm', 'B', or 't'.%{rs}\n", arg); @@ -2033,14 +2014,14 @@ static struct expr *parse_samefile(struct parser_state *state, int arg1, int arg return NULL; } - struct stat sb; + struct bfs_stat sb; if (stat_arg(state, expr, &sb) != 0) { free_expr(expr); return NULL; } - expr->dev = sb.st_dev; - expr->ino = sb.st_ino; + expr->dev = sb.dev; + expr->ino = sb.ino; expr->cost = STAT_COST; expr->probability = 0.01; @@ -2502,9 +2483,9 @@ struct table_entry { * The parse table for literals. */ static const struct table_entry parse_table[] = { - {"-Bmin", false, parse_time, BTIME, MINUTES}, - {"-Bnewer", false, parse_newer, BTIME}, - {"-Btime", false, parse_time, BTIME, DAYS}, + {"-Bmin", false, parse_time, BFS_STAT_BTIME, MINUTES}, + {"-Bnewer", false, parse_newer, BFS_STAT_BTIME}, + {"-Btime", false, parse_time, BFS_STAT_BTIME, DAYS}, {"-D", false, parse_debug}, {"-E", false, parse_regex_extended}, {"-O", true, parse_optlevel}, @@ -2513,13 +2494,13 @@ static const struct table_entry parse_table[] = { {"-L", false, parse_follow, BFTW_LOGICAL | BFTW_DETECT_CYCLES, false}, {"-X", false, parse_xargs_safe}, {"-a"}, - {"-amin", false, parse_time, ATIME, MINUTES}, + {"-amin", false, parse_time, BFS_STAT_ATIME, MINUTES}, {"-and"}, - {"-anewer", false, parse_newer, ATIME}, - {"-atime", false, parse_time, ATIME, DAYS}, - {"-cmin", false, parse_time, CTIME, MINUTES}, - {"-cnewer", false, parse_newer, CTIME}, - {"-ctime", false, parse_time, CTIME, DAYS}, + {"-anewer", false, parse_newer, BFS_STAT_ATIME}, + {"-atime", false, parse_time, BFS_STAT_ATIME, DAYS}, + {"-cmin", false, parse_time, BFS_STAT_CTIME, MINUTES}, + {"-cnewer", false, parse_newer, BFS_STAT_CTIME}, + {"-ctime", false, parse_time, BFS_STAT_CTIME, DAYS}, {"-color", false, parse_color, true}, {"-d", false, parse_depth}, {"-daystart", false, parse_daystart}, @@ -2554,12 +2535,12 @@ static const struct table_entry parse_table[] = { {"-ls", false, parse_ls}, {"-maxdepth", false, parse_depth_limit, false}, {"-mindepth", false, parse_depth_limit, true}, - {"-mmin", false, parse_time, MTIME, MINUTES}, - {"-mnewer", false, parse_newer, MTIME}, + {"-mmin", false, parse_time, BFS_STAT_MTIME, MINUTES}, + {"-mnewer", false, parse_newer, BFS_STAT_MTIME}, {"-mount", false, parse_mount}, - {"-mtime", false, parse_time, MTIME, DAYS}, + {"-mtime", false, parse_time, BFS_STAT_MTIME, DAYS}, {"-name", false, parse_name, false}, - {"-newer", false, parse_newer, MTIME}, + {"-newer", false, parse_newer, BFS_STAT_MTIME}, {"-newer", true, parse_newerxy}, {"-nocolor", false, parse_color, false}, {"-nogroup", false, parse_nogroup}, @@ -20,6 +20,7 @@ #include "dstring.h" #include "expr.h" #include "mtab.h" +#include "stat.h" #include "util.h" #include <assert.h> #include <errno.h> @@ -29,7 +30,6 @@ #include <stdint.h> #include <stdio.h> #include <string.h> -#include <sys/stat.h> #include <time.h> typedef int bfs_printf_fn(FILE *file, const struct bfs_printf_directive *directive, const struct BFTW *ftwbuf); @@ -42,8 +42,8 @@ struct bfs_printf_directive { bfs_printf_fn *fn; /** String data associated with this directive. */ char *str; - /** The time field to print. */ - enum time_field time_field |