From a54c9309c3291a960fcbcbc9e6407330a9edd044 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 13 Feb 2016 13:13:51 -0500 Subject: Implement -xtype. --- eval.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'eval.c') diff --git a/eval.c b/eval.c index 7c2f104..5c78d0b 100644 --- a/eval.c +++ b/eval.c @@ -370,6 +370,54 @@ bool eval_type(const struct expr *expr, struct eval_state *state) { return state->ftwbuf->typeflag == expr->idata; } +/** + * -xtype test. + */ +bool eval_xtype(const struct expr *expr, struct eval_state *state) { + struct BFTW *ftwbuf = state->ftwbuf; + + bool is_root = ftwbuf->depth == 0; + bool follow = state->cmdline->flags & (is_root ? BFTW_FOLLOW_ROOT : BFTW_FOLLOW_NONROOT); + + bool is_link = ftwbuf->typeflag == BFTW_LNK; + if (follow == is_link) { + return eval_type(expr, state); + } + + // -xtype does the opposite of everything else + int at_flags = follow ? AT_SYMLINK_NOFOLLOW : 0; + + struct stat sb; + if (fstatat(ftwbuf->at_fd, ftwbuf->at_path, &sb, at_flags) != 0) { + if (!follow && errno == ENOENT) { + // Broken symlink + return eval_type(expr, state); + } else { + eval_error(state); + return false; + } + } + + switch (expr->idata) { + case BFTW_BLK: + return S_ISBLK(sb.st_mode); + case BFTW_CHR: + return S_ISCHR(sb.st_mode); + case BFTW_DIR: + return S_ISDIR(sb.st_mode); + case BFTW_FIFO: + return S_ISFIFO(sb.st_mode); + case BFTW_LNK: + return S_ISLNK(sb.st_mode); + case BFTW_REG: + return S_ISREG(sb.st_mode); + case BFTW_SOCK: + return S_ISSOCK(sb.st_mode); + } + + return false; +} + /** * Evaluate a negation. */ -- cgit v1.2.3