summaryrefslogtreecommitdiff
path: root/src/internal/tpax_tmpfile_impl.c
blob: aa78e40ca82dab5494832a5ee394230729d8e3ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/**************************************************************/
/*  tpax: a topological pax implementation                    */
/*  Copyright (C) 2020--2024  SysDeer Technologies, LLC       */
/*  Released under GPLv2 and GPLv3; see COPYING.TPAX.         */
/**************************************************************/

#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 "tpax_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 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 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 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;
}

tpax_hidden int tpax_tmpfile(void)
{
	int             fd;
	void *          addr;
	char            tmplate[128];

	/* 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 */
	addr = tmplate;
	memset(tmplate,0,sizeof(tmplate));
	snprintf(tmplate,sizeof(tmplate),
		"/tmp/"
		".tpax.tmpfile"
		".time."PPRIX64
		".salt.%p"
		".pid.%d"
		".XXXXXXXXXXXX",
		time(0),
		addr,
		getpid());

	return tpax_mkostemp(tmplate);
}