summaryrefslogtreecommitdiff
path: root/compat/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/open.c')
-rw-r--r--compat/open.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/compat/open.c b/compat/open.c
new file mode 100644
index 0000000000..37ae2b1aeb
--- /dev/null
+++ b/compat/open.c
@@ -0,0 +1,54 @@
+#include "git-compat-util.h"
+
+#ifdef OPEN_RETURNS_EINTR
+#undef open
+int git_open_with_retry(const char *path, int flags, ...)
+{
+ mode_t mode = 0;
+ int ret;
+
+ /*
+ * Also O_TMPFILE would take a mode, but it isn't defined everywhere.
+ * And anyway, we don't use it in our code base.
+ */
+ if (flags & O_CREAT) {
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ do {
+ ret = open(path, flags, mode);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+#endif
+
+int git_open_cloexec(const char *name, int flags)
+{
+ int fd;
+ static int o_cloexec = O_CLOEXEC;
+
+ fd = open(name, flags | o_cloexec);
+ if ((o_cloexec & O_CLOEXEC) && fd < 0 && errno == EINVAL) {
+ /* Try again w/o O_CLOEXEC: the kernel might not support it */
+ o_cloexec &= ~O_CLOEXEC;
+ fd = open(name, flags | o_cloexec);
+ }
+
+#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
+ {
+ static int fd_cloexec = FD_CLOEXEC;
+
+ if (!o_cloexec && 0 <= fd && fd_cloexec) {
+ /* Opened w/o O_CLOEXEC? try with fcntl(2) to add it */
+ int flags = fcntl(fd, F_GETFD);
+ if (fcntl(fd, F_SETFD, flags | fd_cloexec))
+ fd_cloexec = 0;
+ }
+ }
+#endif
+ return fd;
+}