/** * -[acm]{min,time} tests. */ bool eval_acmtime(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->timefield) { case ATIME: time = &statbuf->st_atim; break; case CTIME: time = &statbuf->st_ctim; break; case MTIME: time = &statbuf->st_mtim; break; } time_t diff = timespec_diff(&expr->reftime, time); switch (expr->timeunit) { case MINUTES: diff /= 60; break; case DAYS: diff /= 60*60*24; break; } return do_cmp(expr, diff); }
/** * -i?lname test. */ bool eval_lname(const struct expr *expr, struct eval_state *state) { struct BFTW *ftwbuf = state->ftwbuf; if (ftwbuf->typeflag != BFTW_LNK) { return false; } const struct stat *statbuf = fill_statbuf(state); if (!statbuf) { return false; } size_t size = statbuf->st_size + 1; char *name = malloc(size); if (!name) { eval_error(state); return false; } ssize_t ret = readlinkat(ftwbuf->at_fd, ftwbuf->at_path, name, size); if (ret < 0) { eval_error(state); return false; } else if (ret >= size) { return false; } name[ret] = '\0'; bool match = fnmatch(expr->sdata, name, expr->idata) == 0; free(name); return match; }
/** * -samefile test. */ bool eval_samefile(const struct expr *expr, struct eval_state *state) { const struct stat *statbuf = fill_statbuf(state); if (!statbuf) { return false; } return statbuf->st_dev == expr->dev && statbuf->st_ino == expr->ino; }
/** * -links test. */ bool eval_links(const struct expr *expr, struct eval_state *state) { const struct stat *statbuf = fill_statbuf(state); if (!statbuf) { return false; } return do_cmp(expr, statbuf->st_nlink); }
/** * -print action. */ bool eval_print(const struct expr *expr, struct eval_state *state) { const struct colors *colors = state->cmdline->stdout_colors; if (colors) { fill_statbuf(state); } pretty_print(colors, state->ftwbuf); return true; }
/* * -ENOENT, -ENOTDIR, -ENAMETOOLONG */ int sys_stat(const char *path, struct stat *buf) { uint64_t inum; inum = name_i(path); if (inum < 0) return inum; fill_statbuf(inum, buf); return 0; }
int sys_fstat(int fd, struct stat *buf) { struct file *file; file = unrolled_lookup(¤t->fdtable, fd); if (file == NULL) return -EBADF; fill_statbuf(file->inum, buf); return 0; }
/** * -empty test. */ bool eval_empty(const struct expr *expr, struct eval_state *state) { bool ret = false; struct BFTW *ftwbuf = state->ftwbuf; if (ftwbuf->typeflag == BFTW_DIR) { int dfd = openat(ftwbuf->at_fd, ftwbuf->at_path, O_DIRECTORY); if (dfd < 0) { eval_error(state); goto done; } DIR *dir = fdopendir(dfd); if (!dir) { eval_error(state); close(dfd); goto done; } ret = true; struct dirent *de; while ((de = readdir(dir)) != NULL) { if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) { ret = false; break; } } closedir(dir); } else { const struct stat *statbuf = fill_statbuf(state); if (statbuf) { ret = statbuf->st_size == 0; } } done: return ret; }
/** * -[ac]?newer tests. */ bool eval_acnewer(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->timefield) { case ATIME: time = &statbuf->st_atim; break; case CTIME: time = &statbuf->st_ctim; break; case MTIME: time = &statbuf->st_mtim; break; } return time->tv_sec > expr->reftime.tv_sec || (time->tv_sec == expr->reftime.tv_sec && time->tv_nsec > expr->reftime.tv_nsec); }