-
Notifications
You must be signed in to change notification settings - Fork 0
/
tempfile-linux.c
105 lines (98 loc) · 3.12 KB
/
tempfile-linux.c
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <paths.h>
#include <unistd.h>
#include "tempfile.h"
struct TempFile* make_temp_file(const char* format) {
// No standardised way to getting the temporary directory on Linux, however
// the most common way is to use the first available directory out of
// $TMPDIR, P_tmpdir, _PATH_TMP or /tmp/ in that order.
const char* temp_dir = getenv("TMPDIR");
#ifdef P_tmpdir
if(temp_dir == NULL || temp_dir[0] == '\0') {
temp_dir = P_tmpdir;
}
#endif
#ifdef _PATH_TMP
if(temp_dir == NULL || temp_dir[0] == '\0') {
temp_dir = _PATH_TMP;
}
#endif
if(temp_dir == NULL || temp_dir[0] == '\0') {
temp_dir = "/tmp/";
}
size_t temp_dir_len = strlen(temp_dir);
size_t temp_file_len = temp_dir_len + strlen(format) + 5;
char* temp_file;
if(temp_dir[temp_dir_len - 1] != '/') {
// Add trailing slash if it doesn't exist.
temp_file_len += 1;
temp_dir_len += 1;
temp_file = malloc((temp_file_len + 1) * sizeof(char));
strcpy(temp_file, temp_dir);
temp_file[temp_dir_len - 1] = '/';
temp_file[temp_dir_len] = '\0';
} else {
temp_file = malloc((temp_file_len + 1) * sizeof(char));
strcpy(temp_file, temp_dir);
}
strcpy(temp_file + temp_dir_len, format);
// Find the wildcard ('%'), and replace it with 'XXXXXX' for mkstemp().
size_t wildcard_i;
size_t suffix_len;
for(wildcard_i = temp_dir_len; wildcard_i < temp_file_len - 5;
++wildcard_i) {
if(temp_file[wildcard_i] == '%') {
suffix_len = strlen(temp_file + wildcard_i + 1);
if(suffix_len) {
// Can't use memcpy since regions overlap, so manually do a
// backwards copy.
for(size_t j = 0; j < suffix_len; ++j) {
temp_file[temp_file_len - j - 1] = temp_file[
wildcard_i + suffix_len - j
];
}
}
temp_file[wildcard_i] = 'X';
temp_file[wildcard_i + 1] = 'X';
temp_file[wildcard_i + 2] = 'X';
temp_file[wildcard_i + 3] = 'X';
temp_file[wildcard_i + 4] = 'X';
temp_file[wildcard_i + 5] = 'X';
temp_file[temp_file_len] = '\0';
break;
}
}
if(wildcard_i == temp_file_len - 5) {
free(temp_file);
return NULL;
}
// Open the temporary file
int fd;
if(suffix_len == 0) {
fd = mkstemp(temp_file);
} else {
fd = mkstemps(temp_file, suffix_len);
}
if(fd == -1) {
free(temp_file);
return NULL;
}
FILE* file = fdopen(fd, "w+b");
if(file == NULL) {
close(fd);
unlink(temp_file);
free(temp_file);
return NULL;
}
setvbuf(file, NULL, _IOFBF, FileBufferLen);
struct TempFile* result = malloc(sizeof(struct TempFile));
result->file = file;
result->filename = temp_file;
return result;
}
void free_temp_file(struct TempFile* temp) {
free((char*)temp->filename);
free(temp);
}