diff options
-rw-r--r-- | project/common.mk | 1 | ||||
-rw-r--r-- | project/headers.mk | 1 | ||||
-rw-r--r-- | src/internal/tpax_tmpfile_impl.c | 74 | ||||
-rw-r--r-- | src/internal/tpax_tmpfile_impl.h | 6 |
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 |