summaryrefslogtreecommitdiffstats
path: root/ctx.c
diff options
context:
space:
mode:
Diffstat (limited to 'ctx.c')
-rw-r--r--ctx.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/ctx.c b/ctx.c
new file mode 100644
index 0000000..95e668c
--- /dev/null
+++ b/ctx.c
@@ -0,0 +1,217 @@
+/****************************************************************************
+ * bfs *
+ * Copyright (C) 2015-2020 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#include "ctx.h"
+#include "darray.h"
+#include "diag.h"
+#include "expr.h"
+#include "mtab.h"
+#include "pwcache.h"
+#include "trie.h"
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct bfs_ctx *bfs_ctx_new(void) {
+ struct bfs_ctx *ctx = malloc(sizeof(*ctx));
+ if (!ctx) {
+ return NULL;
+ }
+
+ ctx->argv = NULL;
+ ctx->paths = NULL;
+ ctx->expr = NULL;
+ ctx->exclude = NULL;
+
+ ctx->mindepth = 0;
+ ctx->maxdepth = INT_MAX;
+ ctx->flags = BFTW_RECOVER;
+ ctx->strategy = BFTW_BFS;
+ ctx->optlevel = 3;
+ ctx->debug = 0;
+ ctx->ignore_races = false;
+ ctx->unique = false;
+ ctx->warn = false;
+ ctx->xargs_safe = false;
+
+ ctx->colors = NULL;
+ ctx->cout = NULL;
+ ctx->cerr = NULL;
+
+ ctx->users = NULL;
+ ctx->users_error = 0;
+ ctx->groups = NULL;
+ ctx->groups_error = 0;
+
+ ctx->mtab = NULL;
+ ctx->mtab_error = 0;
+
+ trie_init(&ctx->files);
+ ctx->nfiles = 0;
+
+ return ctx;
+}
+
+const struct bfs_users *bfs_ctx_users(const struct bfs_ctx *ctx) {
+ struct bfs_ctx *mut = (struct bfs_ctx *)ctx;
+
+ if (mut->users_error) {
+ errno = mut->users_error;
+ } else if (!mut->users) {
+ mut->users = bfs_parse_users();
+ if (!mut->users) {
+ mut->users_error = errno;
+ }
+ }
+
+ return mut->users;
+}
+
+const struct bfs_groups *bfs_ctx_groups(const struct bfs_ctx *ctx) {
+ struct bfs_ctx *mut = (struct bfs_ctx *)ctx;
+
+ if (mut->groups_error) {
+ errno = mut->groups_error;
+ } else if (!mut->groups) {
+ mut->groups = bfs_parse_groups();
+ if (!mut->groups) {
+ mut->groups_error = errno;
+ }
+ }
+
+ return mut->groups;
+}
+
+const struct bfs_mtab *bfs_ctx_mtab(const struct bfs_ctx *ctx) {
+ struct bfs_ctx *mut = (struct bfs_ctx *)ctx;
+
+ if (mut->mtab_error) {
+ errno = mut->mtab_error;
+ } else if (!mut->mtab) {
+ mut->mtab = bfs_parse_mtab();
+ if (!mut->mtab) {
+ mut->mtab_error = errno;
+ }
+ }
+
+ return mut->mtab;
+}
+
+/**
+ * An open file tracked by the bfs context.
+ */
+struct bfs_ctx_file {
+ /** The file itself. */
+ CFILE *cfile;
+ /** The path to the file (for diagnostics). */
+ const char *path;
+};
+
+CFILE *bfs_ctx_open(struct bfs_ctx *ctx, const char *path, bool use_color) {
+ CFILE *cfile = cfopen(path, use_color ? ctx->colors : NULL);
+ if (!cfile) {
+ goto out;
+ }
+
+ struct bfs_stat sb;
+ if (bfs_stat(fileno(cfile->file), NULL, 0, &sb) != 0) {
+ goto out_close;
+ }
+
+ bfs_file_id id;
+ bfs_stat_id(&sb, &id);
+
+ struct trie_leaf *leaf = trie_insert_mem(&ctx->files, id, sizeof(id));
+ if (!leaf) {
+ goto out_close;
+ }
+
+ if (leaf->value) {
+ struct bfs_ctx_file *ctx_file = leaf->value;
+ cfclose(cfile);
+ cfile = ctx_file->cfile;
+ goto out;
+ }
+
+ struct bfs_ctx_file *ctx_file = malloc(sizeof(*ctx_file));
+ if (!ctx_file) {
+ trie_remove(&ctx->files, leaf);
+ goto out_close;
+ }
+
+ ctx_file->cfile = cfile;
+ ctx_file->path = path;
+ leaf->value = ctx_file;
+ ++ctx->nfiles;
+
+ goto out;
+
+out_close:
+ cfclose(cfile);
+ cfile = NULL;
+out:
+ return cfile;
+}
+
+int bfs_ctx_free(struct bfs_ctx *ctx) {
+ int ret = 0;
+
+ if (ctx) {
+ CFILE *cout = ctx->cout;
+ CFILE *cerr = ctx->cerr;
+
+ free_expr(ctx->expr);
+ free_expr(ctx->exclude);
+
+ bfs_free_mtab(ctx->mtab);
+
+ bfs_free_groups(ctx->groups);
+ bfs_free_users(ctx->users);
+
+ struct trie_leaf *leaf;
+ while ((leaf = trie_first_leaf(&ctx->files))) {
+ struct bfs_ctx_file *ctx_file = leaf->value;
+
+ if (cfclose(ctx_file->cfile) != 0) {
+ if (cerr) {
+ bfs_error(ctx, "'%s': %m.\n", ctx_file->path);
+ }
+ ret = -1;
+ }
+
+ free(ctx_file);
+ trie_remove(&ctx->files, leaf);
+ }
+ trie_destroy(&ctx->files);
+
+ if (cout && fflush(cout->file) != 0) {
+ if (cerr) {
+ bfs_error(ctx, "standard output: %m.\n");
+ }
+ ret = -1;
+ }
+
+ cfclose(cout);
+ cfclose(cerr);
+
+ free_colors(ctx->colors);
+ darray_free(ctx->paths);
+ free(ctx->argv);
+ free(ctx);
+ }
+
+ return ret;
+}