summaryrefslogtreecommitdiff
path: root/src/internal/treebnf_tmpfile_impl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/treebnf_tmpfile_impl.c')
-rw-r--r--src/internal/treebnf_tmpfile_impl.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/internal/treebnf_tmpfile_impl.c b/src/internal/treebnf_tmpfile_impl.c
new file mode 100644
index 0000000..2a5eb45
--- /dev/null
+++ b/src/internal/treebnf_tmpfile_impl.c
@@ -0,0 +1,89 @@
+/**************************************************************/
+/* treebnf: a tree oriented bnf library */
+/* Copyright (C) 2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TREEBNF. */
+/**************************************************************/
+
+#define _GNU_SOURCE
+#include <time.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "treebnf_visibility_impl.h"
+
+#define PPRIX64 "%"PRIx64
+
+/* 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 tbnf_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 tbnf_tmpfile_by_kernel(void)
+{
+#ifdef O_TMPFILE
+ return openat(AT_FDCWD,"/tmp",O_RDWR|O_TMPFILE|O_CLOEXEC,0);
+#else
+ return (-1);
+#endif
+}
+
+/* mk{o}stemp() provides a non-private tmpfile */
+static int tbnf_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;
+}
+
+tbnf_hidden int tbnf_tmpfile(void)
+{
+ int fd;
+ void * addr;
+ char tmplate[128];
+
+ /* try with __fs_tmpfile() */
+ if ((fd = tbnf_tmpfile_by_framework()) >= 0)
+ return fd;
+
+ /* try with O_TMPFILE */
+ if ((fd = tbnf_tmpfile_by_kernel()) >= 0)
+ return fd;
+
+ /* fallback to mk{o}stemp */
+ addr = tmplate;
+ memset(tmplate,0,sizeof(tmplate));
+ snprintf(tmplate,sizeof(tmplate),
+ "/tmp/"
+ ".treebnf.tmpfile"
+ ".time."PPRIX64
+ ".salt.%p"
+ ".pid.%d"
+ ".XXXXXXXXXXXX",
+ time(0),
+ addr,
+ getpid());
+
+ return tbnf_mkostemp(tmplate);
+}