summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2016-01-30 14:00:02 -0500
committerTavian Barnes <tavianator@tavianator.com>2016-01-30 14:00:02 -0500
commit132dc9eaf7d6aa9e7892d9b55889f762f1140f4d (patch)
tree3c8dd890176873edcbc4a06852b4a64690c53488
parent3f9f913f5302b71ef57467798f62dd3e83b217bc (diff)
downloadbfs-132dc9eaf7d6aa9e7892d9b55889f762f1140f4d.tar.xz
Implement -empty.
-rw-r--r--bfs.h1
-rw-r--r--eval.c44
-rw-r--r--parse.c2
-rwxr-xr-xtests.sh7
4 files changed, 53 insertions, 1 deletions
diff --git a/bfs.h b/bfs.h
index aedd2c0..441993b 100644
--- a/bfs.h
+++ b/bfs.h
@@ -97,6 +97,7 @@ void free_cmdline(cmdline *cl);
// Predicate evaluation functions
bool eval_access(const expression *expr, eval_state *state);
bool eval_delete(const expression *expr, eval_state *state);
+bool eval_empty(const expression *expr, eval_state *state);
bool eval_false(const expression *expr, eval_state *state);
bool eval_hidden(const expression *expr, eval_state *state);
bool eval_name(const expression *expr, eval_state *state);
diff --git a/eval.c b/eval.c
index 56238ea..417bfc3 100644
--- a/eval.c
+++ b/eval.c
@@ -1,5 +1,6 @@
#include "bfs.h"
#include "bftw.h"
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
@@ -78,6 +79,49 @@ bool eval_delete(const expression *expr, eval_state *state) {
}
/**
+ * -empty test.
+ */
+bool eval_empty(const expression *expr, 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) {
+ perror("openat()");
+ goto done;
+ }
+
+ DIR *dir = fdopendir(dfd);
+ if (!dir) {
+ perror("fdopendir()");
+ 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 {
+ fill_statbuf(state);
+ if (ftwbuf->statbuf) {
+ ret = ftwbuf->statbuf->st_size == 0;
+ }
+ }
+
+done:
+ return ret;
+}
+
+/**
* -prune action.
*/
bool eval_prune(const expression *expr, eval_state *state) {
diff --git a/parse.c b/parse.c
index 348ddd8..5425afa 100644
--- a/parse.c
+++ b/parse.c
@@ -348,6 +348,8 @@ static expression *parse_literal(parser_state *state) {
} else if (strcmp(arg, "-d") == 0 || strcmp(arg, "-depth") == 0) {
state->cl->flags |= BFTW_DEPTH;
return new_option(state, arg);
+ } else if (strcmp(arg, "-empty") == 0) {
+ return new_test(state, eval_empty);
} else if (strcmp(arg, "-executable") == 0) {
return new_test_idata(state, eval_access, X_OK);
} else if (strcmp(arg, "-false") == 0) {
diff --git a/tests.sh b/tests.sh
index 90ef066..bb24fe0 100755
--- a/tests.sh
+++ b/tests.sh
@@ -105,7 +105,12 @@ function test_0014() {
find_diff "$1" -writable
}
-for i in {1..14}; do
+function test_0015() {
+ basic_structure "$1"
+ find_diff "$1" -empty
+}
+
+for i in {1..15}; do
dir="$(mktemp -d "${TMPDIR:-/tmp}"/bfs.XXXXXXXXXX)"
test="test_$(printf '%04d' $i)"
"$test" "$dir"