summaryrefslogtreecommitdiffstats
path: root/ctx.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2021-09-21 11:56:02 -0400
committerTavian Barnes <tavianator@tavianator.com>2021-09-21 11:56:02 -0400
commit5353347f23f4a0cb044d1d87d7747dedc71f525c (patch)
treeaed48680549c5f062f2f9bea8eae9ad5cb46fded /ctx.c
parent4bcb10a88e3d282494642c1fa10140b42f501e97 (diff)
downloadbfs-5353347f23f4a0cb044d1d87d7747dedc71f525c.tar.xz
ctx: Also deduplicate the standard streams
This fixes some potential missing output when the same file is used in a redirection and something like -fprint. The main benefit is smarter handling of /dev/stdout, which will now share the CFILE* with cout.
Diffstat (limited to 'ctx.c')
-rw-r--r--ctx.c72
1 files changed, 43 insertions, 29 deletions
diff --git a/ctx.c b/ctx.c
index 0b7296c..450d87e 100644
--- a/ctx.c
+++ b/ctx.c
@@ -161,19 +161,10 @@ struct bfs_ctx_file {
const char *path;
};
-CFILE *bfs_ctx_open(struct bfs_ctx *ctx, const char *path, bool use_color) {
- int error = 0;
-
- CFILE *cfile = cfopen(path, use_color ? ctx->colors : NULL);
- if (!cfile) {
- error = errno;
- goto out;
- }
-
+struct CFILE *bfs_ctx_dedup(struct bfs_ctx *ctx, CFILE *cfile, const char *path) {
struct bfs_stat sb;
if (bfs_stat(fileno(cfile->file), NULL, 0, &sb) != 0) {
- error = errno;
- goto out_close;
+ return NULL;
}
bfs_file_id id;
@@ -181,37 +172,60 @@ CFILE *bfs_ctx_open(struct bfs_ctx *ctx, const char *path, bool use_color) {
struct trie_leaf *leaf = trie_insert_mem(&ctx->files, id, sizeof(id));
if (!leaf) {
- error = errno;
- goto out_close;
+ return NULL;
}
- 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 = leaf->value;
+ if (ctx_file) {
+ ctx_file->path = path;
+ return ctx_file->cfile;
}
- struct bfs_ctx_file *ctx_file = malloc(sizeof(*ctx_file));
+ leaf->value = ctx_file = malloc(sizeof(*ctx_file));
if (!ctx_file) {
- error = errno;
trie_remove(&ctx->files, leaf);
- goto out_close;
+ return NULL;
}
ctx_file->cfile = cfile;
ctx_file->path = path;
- leaf->value = ctx_file;
++ctx->nfiles;
+ return cfile;
+}
+
+/** Close a file tracked by the bfs context. */
+static int bfs_ctx_close(struct bfs_ctx *ctx, struct bfs_ctx_file *ctx_file) {
+ CFILE *cfile = ctx_file->cfile;
+
+ if (cfile == ctx->cout) {
+ // Will be checked later
+ return 0;
+ } else if (cfile == ctx->cerr && !ctx_file->path) {
+ // Writes to stderr are allowed to fail silently, unless the same file was used by
+ // -fprint, -fls, etc.
+ return 0;
+ }
- goto out;
+ int ret = 0, error = 0;
+ if (ferror(cfile->file)) {
+ ret = -1;
+ error = EIO;
+ }
+
+ if (cfile == ctx->cerr) {
+ if (fflush(cfile->file) != 0) {
+ ret = -1;
+ error = errno;
+ }
+ } else {
+ if (cfclose(cfile) != 0) {
+ ret = -1;
+ error = errno;
+ }
+ }
-out_close:
- cfclose(cfile);
- cfile = NULL;
-out:
errno = error;
- return cfile;
+ return ret;
}
int bfs_ctx_free(struct bfs_ctx *ctx) {
@@ -233,7 +247,7 @@ int bfs_ctx_free(struct bfs_ctx *ctx) {
while ((leaf = trie_first_leaf(&ctx->files))) {
struct bfs_ctx_file *ctx_file = leaf->value;
- if (cfclose(ctx_file->cfile) != 0) {
+ if (bfs_ctx_close(ctx, ctx_file) != 0) {
if (cerr) {
bfs_error(ctx, "'%s': %m.\n", ctx_file->path);
}