1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
26 * generate a temp file / name
28 * [<dir>/][<pfx>]<bas>.<suf>
34 * pathtmp(a,b,c,d) pathtemp(a,L_tmpnam,b,c,0)
35 * tmpfile() char*p=pathtemp(0,0,0,"tf",&sp);
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)
44 * if buf==0 then space is malloc'd
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
53 * generated names are pseudo-randomized to avoid both
54 * collisions and predictions (same alg in sfio/sftmp.c)
56 * / as first pfx char provides tmp file generation control
57 * 0 returned for unknown ops
59 * /cycle dir specifies TMPPATH cycle control
60 * automatic (default) cycled with each tmp file
61 * manual cycled by application with dir=(nil)
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
79 #define TMP_ENV "TMPDIR"
80 #define TMP_PATH_ENV "TMPPATH"
82 #define TMP2 "/usr/tmp"
84 #define VALID(d) (*(d)&&!eaccess(d,W_OK|X_OK))
99 } tmp
= { S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
};
102 pathtemp(char* buf
, size_t len
, const char* dir
, const char* pfx
, int* fdp
)
118 if (pfx
&& *pfx
== '/')
121 if (streq(pfx
, "cycle"))
126 if (tmp
.dir
&& !*tmp
.dir
++)
130 tmp
.manual
= streq(dir
, "manual");
133 else if (streq(pfx
, "prefix"))
137 tmp
.pfx
= dir
? strdup(dir
) : (char*)0;
140 else if (streq(pfx
, "private"))
142 tmp
.mode
= S_IRUSR
|S_IWUSR
;
145 else if (streq(pfx
, "public"))
147 tmp
.mode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
;
150 else if (streq(pfx
, "seed"))
152 tmp
.key
= (tmp
.seed
= (tmp
.rng
= dir
? (uint32_t)strtoul(dir
, NiL
, 0) : (uint32_t)1) != 0)? (uint32_t)0x63c63cd9L
: 0;
155 else if (streq(pfx
, TMP_ENV
))
164 tmp
.tmpdir
= dir
? strdup(dir
) : (char*)0;
167 else if (streq(pfx
, TMP_PATH_ENV
))
176 tmp
.tmppath
= dir
? strdup(dir
) : (char*)0;
185 if (!(d
= (char*)dir
) || *d
&& eaccess(d
, W_OK
|X_OK
))
189 if ((x
= tmp
.tmppath
) || (x
= getenv(TMP_PATH_ENV
)))
193 while (s
= strchr(s
, ':'))
198 if (!(tmp
.vec
= newof(0, char*, n
, strlen(x
) + 1)))
201 x
= strcpy((char*)(tmp
.dir
+ n
), x
);
203 while (x
= strchr(x
, ':'))
206 if (!VALID(*(tmp
.dir
- 1)))
210 if (!VALID(*(tmp
.dir
- 1)))
216 if (((d
= tmp
.tmpdir
) || (d
= getenv(TMP_ENV
))) && !VALID(d
))
218 if (!(tmp
.vec
= newof(0, char*, 2, d
? (strlen(d
) + 1) : 0)))
221 *tmp
.vec
= strcpy((char*)(tmp
.vec
+ 2), d
);
225 if (!(d
= *tmp
.dir
++))
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
))
236 if (!(b
= buf
) && !(b
= newof(0, char, len
, 1)))
239 if (!pfx
&& !(pfx
= tmp
.pfx
))
242 if (buf
&& dir
&& (buf
== (char*)dir
&& (buf
+ strlen(buf
) + 1) == (char*)pfx
|| buf
== (char*)pfx
&& !*dir
) && !strcmp((char*)pfx
+ m
+ 1, "XXXXX"))
245 len
= m
+= strlen(d
) + 8;
249 else if (*pfx
&& pfx
[m
- 1] == 'X')
251 for (l
= m
; l
&& pfx
[l
- 1] == 'X'; l
--);
257 else if (strchr(pfx
, '.'))
274 while (s
< x
&& (n
= *d
++))
276 if (s
< x
&& s
> b
&& *(s
- 1) != '/')
281 while (s
< x
&& (n
= *pfx
++))
283 if (n
== '/' || n
== '\\' || n
== z
)
289 for (attempt
= 0; attempt
< ATTEMPT
; attempt
++)
291 if (!tmp
.rng
|| !tmp
.seed
&& (attempt
|| tmp
.pid
!= getpid()))
296 * get a quasi-random coefficient
300 tmp
.rng
= (uintptr_t)tmp
.pid
* ((uintptr_t)time(NiL
) ^ (((uintptr_t)(&attempt
)) >> 3) ^ (((uintptr_t)tmp
.dir
) >> 3));
302 tmp
.key
= (tmp
.rng
>> 16) | ((tmp
.rng
& 0xffff) << 16);
306 * Knuth vol.2, page.16, Thm.A
309 if ((r
= (tmp
.rng
- 1) & 03))
314 * generate a pseudo-random name
317 key
= tmp
.rng
* tmp
.key
+ tv
.tv_nsec
;
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);
325 if ((n
= open(b
, O_CREAT
|O_RDWR
|O_EXCL
|O_TEMPORARY
, tmp
.mode
)) >= 0)
331 else if (access(b
, F_OK
))