summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/internal/tpax_tmpfile_impl.c74
-rw-r--r--src/internal/tpax_tmpfile_impl.h6
2 files changed, 80 insertions, 0 deletions
diff --git a/src/internal/tpax_tmpfile_impl.c b/src/internal/tpax_tmpfile_impl.c
new file mode 100644
index 0000000..0c0bcc1
--- /dev/null
+++ b/src/internal/tpax_tmpfile_impl.c
@@ -0,0 +1,74 @@
+/******************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/******************************************************/
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+/* mkostemp might be guarded by non-standard macros */
+/* unless HAVE_NO_MKOSTEMP, assume it is available */
+extern int mkstemp(char *);
+extern int mkostemp(char *, int);
+
+/* __fs_tmpfile() atomically provides a private tmpfile */
+static int tpax_tmpfile_by_framework(void)
+{
+#ifdef _MIDIPIX_ABI
+ extern int __fs_tmpfile(int);
+ return __fs_tmpfile(O_CLOEXEC);
+#else
+ return (-1);
+#endif
+}
+
+/* O_TMPFILE atomically provides a private tmpfile */
+static int tpax_tmpfile_by_kernel(void)
+{
+#ifdef O_TMPFILE
+ return open("/tmp",O_RDWR|O_TMPFILE|O_CLOEXEC,0);
+#else
+ return (-1);
+#endif
+}
+
+/* mk{o}stemp() provides a non-private tmpfile */
+static int tpax_mkostemp(char * tmplate)
+{
+ int fd;
+#ifdef HAVE_NO_MKOSTEMP
+ if ((fd = mkstemp(tmplate)) >= 0)
+ fcntl(fd,F_SETFD,FD_CLOEXEC);
+#else
+ fd = mkostemp(tmplate,O_CLOEXEC);
+#endif
+ return fd;
+}
+
+int tpax_tmpfile(void)
+{
+ int fd;
+ unsigned seed;
+ char tmplate[64];
+
+ /* try with __fs_tmpfile() */
+ if ((fd = tpax_tmpfile_by_framework()) >= 0)
+ return fd;
+
+ /* try with O_TMPFILE */
+ if ((fd = tpax_tmpfile_by_kernel()) >= 0)
+ return fd;
+
+ /* fallback to mk{o}stemp */
+ seed = getpid();
+ memset(tmplate,0,sizeof(tmplate));
+ snprintf(tmplate,sizeof(tmplate),"/tmp/tpax_%d_%d_%d_XXXXXXXXXXXX",
+ getppid(),getpid(),rand_r(&seed));
+
+ return tpax_mkostemp(tmplate);
+}
diff --git a/src/internal/tpax_tmpfile_impl.h b/src/internal/tpax_tmpfile_impl.h
new file mode 100644
index 0000000..f146326
--- /dev/null
+++ b/src/internal/tpax_tmpfile_impl.h
@@ -0,0 +1,6 @@
+#ifndef TPAX_TMPFILE_IMPL_H
+#define TPAX_TMPFILE_IMPL_H
+
+int tpax_tmpfile(void);
+
+#endif