Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/path/pathtemp.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1985-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
/*
24
* AT&T Research
25
*
26
* generate a temp file / name
27
*
28
* [<dir>/][<pfx>]<bas>.<suf>
29
*
30
* length(<pfx>)<=5
31
* length(<bas>)==3
32
* length(<suf>)==3
33
*
34
* pathtmp(a,b,c,d) pathtemp(a,L_tmpnam,b,c,0)
35
* tmpfile() char*p=pathtemp(0,0,0,"tf",&sp);
36
* remove(p);
37
* free(p)
38
* tmpnam(0) static char p[L_tmpnam];
39
* pathtemp(p,sizeof(p),0,"tn",0)
40
* tmpnam(p) pathtemp(p,L_tmpnam,0,"tn",0)
41
* tempnam(d,p) pathtemp(0,d,p,0)
42
* mktemp(p) pathtemp(0,0,p,0)
43
*
44
* if buf==0 then space is malloc'd
45
* buf size is size
46
* dir and pfx may be 0
47
* if pfx contains trailing X's then it is a mktemp(3) template
48
* otherwise only first 5 chars of pfx are used
49
* if fdp!=0 then the path is opened O_EXCL and *fdp is the open fd
50
* malloc'd space returned by successful pathtemp() calls
51
* must be freed by the caller
52
*
53
* generated names are pseudo-randomized to avoid both
54
* collisions and predictions (same alg in sfio/sftmp.c)
55
*
56
* / as first pfx char provides tmp file generation control
57
* 0 returned for unknown ops
58
*
59
* /cycle dir specifies TMPPATH cycle control
60
* automatic (default) cycled with each tmp file
61
* manual cycled by application with dir=(nil)
62
* (nil) cycle TMPPATH
63
* /prefix dir specifies the default prefix (default ast)
64
* /private private file/dir modes
65
* /public public file/dir modes
66
* /seed dir specifies pseudo-random generator seed
67
* 0 or "0" to re-initialize
68
* /TMPPATH dir overrides the env value
69
* /TMPDIR dir overrides the env value
70
*/
71
72
#include <ast.h>
73
#include <ls.h>
74
#include <tv.h>
75
#include <tm.h>
76
77
#define ATTEMPT 10
78
79
#define TMP_ENV "TMPDIR"
80
#define TMP_PATH_ENV "TMPPATH"
81
#define TMP1 "/tmp"
82
#define TMP2 "/usr/tmp"
83
84
#define VALID(d) (*(d)&&!eaccess(d,W_OK|X_OK))
85
86
static struct
87
{
88
mode_t mode;
89
char** vec;
90
char** dir;
91
uint32_t key;
92
uint32_t rng;
93
pid_t pid;
94
int manual;
95
int seed;
96
char* pfx;
97
char* tmpdir;
98
char* tmppath;
99
} tmp = { S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH };
100
101
char*
102
pathtemp(char* buf, size_t len, const char* dir, const char* pfx, int* fdp)
103
{
104
register char* d;
105
register char* b;
106
register char* s;
107
register char* x;
108
uint32_t key;
109
int m;
110
int n;
111
int l;
112
int r;
113
int z;
114
int attempt;
115
Tv_t tv;
116
char keybuf[16];
117
118
if (pfx && *pfx == '/')
119
{
120
pfx++;
121
if (streq(pfx, "cycle"))
122
{
123
if (!dir)
124
{
125
tmp.manual = 1;
126
if (tmp.dir && !*tmp.dir++)
127
tmp.dir = tmp.vec;
128
}
129
else
130
tmp.manual = streq(dir, "manual");
131
return (char*)pfx;
132
}
133
else if (streq(pfx, "prefix"))
134
{
135
if (tmp.pfx)
136
free(tmp.pfx);
137
tmp.pfx = dir ? strdup(dir) : (char*)0;
138
return (char*)pfx;
139
}
140
else if (streq(pfx, "private"))
141
{
142
tmp.mode = S_IRUSR|S_IWUSR;
143
return (char*)pfx;
144
}
145
else if (streq(pfx, "public"))
146
{
147
tmp.mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
148
return (char*)pfx;
149
}
150
else if (streq(pfx, "seed"))
151
{
152
tmp.key = (tmp.seed = (tmp.rng = dir ? (uint32_t)strtoul(dir, NiL, 0) : (uint32_t)1) != 0)? (uint32_t)0x63c63cd9L : 0;
153
return (char*)pfx;
154
}
155
else if (streq(pfx, TMP_ENV))
156
{
157
if (tmp.vec)
158
{
159
free(tmp.vec);
160
tmp.vec = 0;
161
}
162
if (tmp.tmpdir)
163
free(tmp.tmpdir);
164
tmp.tmpdir = dir ? strdup(dir) : (char*)0;
165
return (char*)pfx;
166
}
167
else if (streq(pfx, TMP_PATH_ENV))
168
{
169
if (tmp.vec)
170
{
171
free(tmp.vec);
172
tmp.vec = 0;
173
}
174
if (tmp.tmppath)
175
free(tmp.tmppath);
176
tmp.tmppath = dir ? strdup(dir) : (char*)0;
177
return (char*)pfx;
178
}
179
return 0;
180
}
181
if (tmp.seed)
182
tv.tv_nsec = 0;
183
else
184
tvgettime(&tv);
185
if (!(d = (char*)dir) || *d && eaccess(d, W_OK|X_OK))
186
{
187
if (!tmp.vec)
188
{
189
if ((x = tmp.tmppath) || (x = getenv(TMP_PATH_ENV)))
190
{
191
n = 2;
192
s = x;
193
while (s = strchr(s, ':'))
194
{
195
s++;
196
n++;
197
}
198
if (!(tmp.vec = newof(0, char*, n, strlen(x) + 1)))
199
return 0;
200
tmp.dir = tmp.vec;
201
x = strcpy((char*)(tmp.dir + n), x);
202
*tmp.dir++ = x;
203
while (x = strchr(x, ':'))
204
{
205
*x++ = 0;
206
if (!VALID(*(tmp.dir - 1)))
207
tmp.dir--;
208
*tmp.dir++ = x;
209
}
210
if (!VALID(*(tmp.dir - 1)))
211
tmp.dir--;
212
*tmp.dir = 0;
213
}
214
else
215
{
216
if (((d = tmp.tmpdir) || (d = getenv(TMP_ENV))) && !VALID(d))
217
d = 0;
218
if (!(tmp.vec = newof(0, char*, 2, d ? (strlen(d) + 1) : 0)))
219
return 0;
220
if (d)
221
*tmp.vec = strcpy((char*)(tmp.vec + 2), d);
222
}
223
tmp.dir = tmp.vec;
224
}
225
if (!(d = *tmp.dir++))
226
{
227
tmp.dir = tmp.vec;
228
d = *tmp.dir++;
229
}
230
if (!d && (!*(d = astconf("TMP", NiL, NiL)) || eaccess(d, W_OK|X_OK)) && eaccess(d = TMP1, W_OK|X_OK) && eaccess(d = TMP2, W_OK|X_OK))
231
return 0;
232
}
233
if (!len)
234
len = PATH_MAX;
235
len--;
236
if (!(b = buf) && !(b = newof(0, char, len, 1)))
237
return 0;
238
z = 0;
239
if (!pfx && !(pfx = tmp.pfx))
240
pfx = "ast";
241
m = strlen(pfx);
242
if (buf && dir && (buf == (char*)dir && (buf + strlen(buf) + 1) == (char*)pfx || buf == (char*)pfx && !*dir) && !strcmp((char*)pfx + m + 1, "XXXXX"))
243
{
244
d = (char*)dir;
245
len = m += strlen(d) + 8;
246
l = 3;
247
r = 3;
248
}
249
else if (*pfx && pfx[m - 1] == 'X')
250
{
251
for (l = m; l && pfx[l - 1] == 'X'; l--);
252
r = m - l;
253
m = l;
254
l = r / 2;
255
r -= l;
256
}
257
else if (strchr(pfx, '.'))
258
{
259
m = 5;
260
l = 3;
261
r = 3;
262
}
263
else
264
{
265
z = '.';
266
m = 5;
267
l = 2;
268
r = 3;
269
}
270
x = b + len;
271
s = b;
272
if (d)
273
{
274
while (s < x && (n = *d++))
275
*s++ = n;
276
if (s < x && s > b && *(s - 1) != '/')
277
*s++ = '/';
278
}
279
if ((x - s) > m)
280
x = s + m;
281
while (s < x && (n = *pfx++))
282
{
283
if (n == '/' || n == '\\' || n == z)
284
n = '_';
285
*s++ = n;
286
}
287
*s = 0;
288
len -= (s - b);
289
for (attempt = 0; attempt < ATTEMPT; attempt++)
290
{
291
if (!tmp.rng || !tmp.seed && (attempt || tmp.pid != getpid()))
292
{
293
register int r;
294
295
/*
296
* get a quasi-random coefficient
297
*/
298
299
tmp.pid = getpid();
300
tmp.rng = (uint32_t)tmp.pid * ((uint32_t)time(NiL) ^ (((uint32_t)integralof(&attempt)) >> 3) ^ (((uint32_t)integralof(tmp.dir)) >> 3));
301
if (!tmp.key)
302
tmp.key = (tmp.rng >> 16) | ((tmp.rng & 0xffff) << 16);
303
tmp.rng ^= tmp.key;
304
305
/*
306
* Knuth vol.2, page.16, Thm.A
307
*/
308
309
if ((r = (tmp.rng - 1) & 03))
310
tmp.rng += 4 - r;
311
}
312
313
/*
314
* generate a pseudo-random name
315
*/
316
317
key = tmp.rng * tmp.key + tv.tv_nsec;
318
if (!tmp.seed)
319
tvgettime(&tv);
320
tmp.key = tmp.rng * key + tv.tv_nsec;
321
sfsprintf(keybuf, sizeof(keybuf), "%07.7.32I*u%07.7.32I*u", sizeof(key), key, sizeof(tmp.key), tmp.key);
322
sfsprintf(s, len, "%-.*s%s%-.*s", l, keybuf, z ? "." : "", r, keybuf + sizeof(keybuf) / 2);
323
if (fdp)
324
{
325
if ((n = open(b, O_CREAT|O_RDWR|O_EXCL|O_TEMPORARY, tmp.mode)) >= 0)
326
{
327
*fdp = n;
328
return b;
329
}
330
}
331
else if (access(b, F_OK))
332
return b;
333
}
334
if (!buf)
335
free(b);
336
return 0;
337
}
338
339