summaryrefslogtreecommitdiffstats
path: root/write-or-die.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 14:47:53 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 14:47:53 +0000
commitc8bae7493d2f2910b57f13ded012e86bdcfb0532 (patch)
tree24e09d9f84dec336720cf393e156089ca2835791 /write-or-die.c
parentInitial commit. (diff)
downloadgit-c8bae7493d2f2910b57f13ded012e86bdcfb0532.tar.xz
git-c8bae7493d2f2910b57f13ded012e86bdcfb0532.zip
Adding upstream version 1:2.39.2.upstream/1%2.39.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'write-or-die.c')
-rw-r--r--write-or-die.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/write-or-die.c b/write-or-die.c
new file mode 100644
index 0000000..aaa0318
--- /dev/null
+++ b/write-or-die.c
@@ -0,0 +1,111 @@
+#include "cache.h"
+#include "config.h"
+#include "run-command.h"
+
+/*
+ * Some cases use stdio, but want to flush after the write
+ * to get error handling (and to get better interactive
+ * behaviour - not buffering excessively).
+ *
+ * Of course, if the flush happened within the write itself,
+ * we've already lost the error code, and cannot report it any
+ * more. So we just ignore that case instead (and hope we get
+ * the right error code on the flush).
+ *
+ * If the file handle is stdout, and stdout is a file, then skip the
+ * flush entirely since it's not needed.
+ */
+void maybe_flush_or_die(FILE *f, const char *desc)
+{
+ static int skip_stdout_flush = -1;
+ struct stat st;
+ char *cp;
+
+ if (f == stdout) {
+ if (skip_stdout_flush < 0) {
+ /* NEEDSWORK: make this a normal Boolean */
+ cp = getenv("GIT_FLUSH");
+ if (cp)
+ skip_stdout_flush = (atoi(cp) == 0);
+ else if ((fstat(fileno(stdout), &st) == 0) &&
+ S_ISREG(st.st_mode))
+ skip_stdout_flush = 1;
+ else
+ skip_stdout_flush = 0;
+ }
+ if (skip_stdout_flush && !ferror(f))
+ return;
+ }
+ if (fflush(f)) {
+ check_pipe(errno);
+ die_errno("write failure on '%s'", desc);
+ }
+}
+
+void fprintf_or_die(FILE *f, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vfprintf(f, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0) {
+ check_pipe(errno);
+ die_errno("write error");
+ }
+}
+
+static int maybe_fsync(int fd)
+{
+ if (use_fsync < 0)
+ use_fsync = git_env_bool("GIT_TEST_FSYNC", 1);
+ if (!use_fsync)
+ return 0;
+
+ if (fsync_method == FSYNC_METHOD_WRITEOUT_ONLY &&
+ git_fsync(fd, FSYNC_WRITEOUT_ONLY) >= 0)
+ return 0;
+
+ return git_fsync(fd, FSYNC_HARDWARE_FLUSH);
+}
+
+void fsync_or_die(int fd, const char *msg)
+{
+ if (maybe_fsync(fd) < 0)
+ die_errno("fsync error on '%s'", msg);
+}
+
+int fsync_component(enum fsync_component component, int fd)
+{
+ if (fsync_components & component)
+ return maybe_fsync(fd);
+ return 0;
+}
+
+void fsync_component_or_die(enum fsync_component component, int fd, const char *msg)
+{
+ if (fsync_components & component)
+ fsync_or_die(fd, msg);
+}
+
+void write_or_die(int fd, const void *buf, size_t count)
+{
+ if (write_in_full(fd, buf, count) < 0) {
+ check_pipe(errno);
+ die_errno("write error");
+ }
+}
+
+void fwrite_or_die(FILE *f, const void *buf, size_t count)
+{
+ if (fwrite(buf, 1, count, f) != count)
+ die_errno("fwrite error");
+}
+
+void fflush_or_die(FILE *f)
+{
+ if (fflush(f))
+ die_errno("fflush error");
+}