diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2021-09-21 11:56:02 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2021-09-21 11:56:02 -0400 |
commit | 5353347f23f4a0cb044d1d87d7747dedc71f525c (patch) | |
tree | aed48680549c5f062f2f9bea8eae9ad5cb46fded /ctx.c | |
parent | 4bcb10a88e3d282494642c1fa10140b42f501e97 (diff) | |
download | bfs-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.c | 72 |
1 files changed, 43 insertions, 29 deletions
@@ -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); } |