summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--project/common.mk1
-rw-r--r--project/headers.mk1
-rw-r--r--src/internal/tpax_tmpfile_impl.c74
-rw-r--r--src/internal/tpax_tmpfile_impl.h6
4 files changed, 82 insertions, 0 deletions
diff --git a/project/common.mk b/project/common.mk
index da9fa26..1725163 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -12,6 +12,7 @@ API_SRCS = \
INTERNAL_SRCS = \
src/internal/$(PACKAGE)_dprintf_impl.c \
src/internal/$(PACKAGE)_errinfo_impl.c \
+ src/internal/$(PACKAGE)_tmpfile_impl.c \
APP_SRCS = \
src/tpax.c
diff --git a/project/headers.mk b/project/headers.mk
index 6346c7e..2d49c17 100644
--- a/project/headers.mk
+++ b/project/headers.mk
@@ -9,5 +9,6 @@ INTERNAL_HEADERS = \
$(SOURCE_DIR)/src/internal/tpax_driver_impl.h \
$(SOURCE_DIR)/src/internal/tpax_errinfo_impl.h \
$(SOURCE_DIR)/src/internal/tpax_readlink_impl.h \
+ $(SOURCE_DIR)/src/internal/tpax_tmpfile_impl.h \
ALL_HEADERS = $(API_HEADERS) $(INTERNAL_HEADERS)
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