1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 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 * 43 * if buf==0 then space is malloc'd 44 * buf size is size 45 * dir and pfx may be 0 46 * only first 5 chars of pfx are used 47 * if fdp!=0 then the path is opened O_EXCL and *fdp is the open fd 48 * malloc'd space returned by successful pathtemp() calls 49 * must be freed by the caller 50 * 51 * generated names are pseudo-randomized to avoid both 52 * collisions and predictions (same alg in sfio/sftmp.c) 53 * 54 * / as first pfx char provides tmp file generation control 55 * 0 returned for unknown ops 56 * 57 * /cycle dir specifies TMPPATH cycle control 58 * automatic (default) cycled with each tmp file 59 * manual cycled by application with dir=(nil) 60 * (nil) cycle TMPPATH 61 * /prefix dir specifies the default prefix (default ast) 62 * /TMPPATH dir overrides the env value 63 * /TMPDIR dir overrides the env value 64 */ 65 66 #include <ast.h> 67 #include <ls.h> 68 #include <tm.h> 69 70 #define ATTEMPT 10 71 72 #define TMP_ENV "TMPDIR" 73 #define TMP_PATH_ENV "TMPPATH" 74 #define TMP1 "/tmp" 75 #define TMP2 "/usr/tmp" 76 77 #define VALID(d) (*(d)&&!eaccess(d,W_OK|X_OK)) 78 79 static struct 80 { 81 mode_t mode; 82 char** vec; 83 char** dir; 84 unsigned long key; 85 unsigned long rng; 86 pid_t pid; 87 int manual; 88 char* pfx; 89 char* tmpdir; 90 char* tmppath; 91 } tmp = { S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH }; 92 93 char* 94 pathtemp(char* buf, size_t len, const char* dir, const char* pfx, int* fdp) 95 { 96 register char* d; 97 register char* b; 98 register char* s; 99 register char* x; 100 char* fmt; 101 int m; 102 int n; 103 int z; 104 int attempt; 105 106 if (pfx && *pfx == '/') 107 { 108 pfx++; 109 if (streq(pfx, "cycle")) 110 { 111 if (!dir) 112 { 113 tmp.manual = 1; 114 if (tmp.dir && !*tmp.dir++) 115 tmp.dir = tmp.vec; 116 } 117 else 118 tmp.manual = streq(dir, "manual"); 119 return (char*)pfx; 120 } 121 else if (streq(pfx, "prefix")) 122 { 123 if (tmp.pfx) 124 free(tmp.pfx); 125 tmp.pfx = dir ? strdup(dir) : (char*)0; 126 return (char*)pfx; 127 } 128 else if (streq(pfx, "private")) 129 tmp.mode = S_IRUSR|S_IWUSR; 130 else if (streq(pfx, "public")) 131 tmp.mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 132 else if (streq(pfx, TMP_ENV)) 133 { 134 if (tmp.vec) 135 { 136 free(tmp.vec); 137 tmp.vec = 0; 138 } 139 if (tmp.tmpdir) 140 free(tmp.tmpdir); 141 tmp.tmpdir = dir ? strdup(dir) : (char*)0; 142 return (char*)pfx; 143 } 144 else if (streq(pfx, TMP_PATH_ENV)) 145 { 146 if (tmp.vec) 147 { 148 free(tmp.vec); 149 tmp.vec = 0; 150 } 151 if (tmp.tmppath) 152 free(tmp.tmppath); 153 tmp.tmppath = dir ? strdup(dir) : (char*)0; 154 return (char*)pfx; 155 } 156 return 0; 157 } 158 if (!(d = (char*)dir) || *d && eaccess(d, W_OK|X_OK)) 159 { 160 if (!tmp.vec) 161 { 162 if ((x = tmp.tmppath) || (x = getenv(TMP_PATH_ENV))) 163 { 164 n = 2; 165 s = x; 166 while (s = strchr(s, ':')) 167 { 168 s++; 169 n++; 170 } 171 if (!(tmp.vec = newof(0, char*, n, strlen(x) + 1))) 172 return 0; 173 tmp.dir = tmp.vec; 174 x = strcpy((char*)(tmp.dir + n), x); 175 *tmp.dir++ = x; 176 while (x = strchr(x, ':')) 177 { 178 *x++ = 0; 179 if (!VALID(*(tmp.dir - 1))) 180 tmp.dir--; 181 *tmp.dir++ = x; 182 } 183 if (!VALID(*(tmp.dir - 1))) 184 tmp.dir--; 185 *tmp.dir = 0; 186 } 187 else 188 { 189 if (((d = tmp.tmpdir) || (d = getenv(TMP_ENV))) && !VALID(d)) 190 d = 0; 191 if (!(tmp.vec = newof(0, char*, 2, d ? (strlen(d) + 1) : 0))) 192 return 0; 193 if (d) 194 *tmp.vec = strcpy((char*)(tmp.vec + 2), d); 195 } 196 tmp.dir = tmp.vec; 197 } 198 if (!(d = *tmp.dir++)) 199 { 200 tmp.dir = tmp.vec; 201 d = *tmp.dir++; 202 } 203 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)) 204 return 0; 205 } 206 if (!len) 207 len = PATH_MAX; 208 len--; 209 if (!(b = buf) && !(b = newof(0, char, len, 1))) 210 return 0; 211 if (buf && dir && pfx && (buf == (char*)dir && (buf + strlen(buf) + 1) == (char*)pfx || buf == (char*)pfx && !*dir) && !strcmp((char*)pfx + strlen(pfx) + 1, "XXXXX")) 212 { 213 z = 0; 214 d = (char*)dir; 215 len = m = strlen(d) + strlen(pfx) + 8; 216 fmt = "%03.3.32lu%03.3.32lu"; 217 } 218 else 219 { 220 z = '.'; 221 m = 5; 222 fmt = "%02.2.32lu.%03.3.32lu"; 223 } 224 x = b + len; 225 s = b; 226 if (d) 227 { 228 while (s < x && (n = *d++)) 229 *s++ = n; 230 if (s < x && s > b && *(s - 1) != '/') 231 *s++ = '/'; 232 } 233 if (!pfx && !(pfx = tmp.pfx)) 234 pfx = "ast"; 235 if ((x - s) > m) 236 x = s + m; 237 while (s < x && (n = *pfx++)) 238 { 239 if (n == '/' || n == '\\' || n == z) 240 n = '_'; 241 *s++ = n; 242 } 243 *s = 0; 244 len -= (s - b); 245 for (attempt = 0; attempt < ATTEMPT; attempt++) 246 { 247 if (!tmp.rng || attempt || tmp.pid != getpid()) 248 { 249 register int r; 250 251 /* 252 * get a quasi-random coefficient 253 */ 254 255 tmp.pid = getpid(); 256 tmp.rng = (unsigned long)tmp.pid * ((unsigned long)time(NiL) ^ (((unsigned long)(&attempt)) >> 3) ^ (((unsigned long)tmp.dir) >> 3)); 257 if (!tmp.key) 258 tmp.key = (tmp.rng >> 16) | ((tmp.rng & 0xffff) << 16); 259 tmp.rng ^= tmp.key; 260 261 /* 262 * Knuth vol.2, page.16, Thm.A 263 */ 264 265 if ((r = (tmp.rng - 1) & 03)) 266 tmp.rng += 4 - r; 267 } 268 269 /* 270 * generate a pseudo-random name 271 */ 272 273 tmp.key = tmp.rng * tmp.key + 987654321L; 274 sfsprintf(s, len, fmt, (tmp.key >> 15) & 0x7fff, tmp.key & 0x7fff); 275 if (fdp) 276 { 277 if ((n = open(b, O_CREAT|O_RDWR|O_EXCL|O_TEMPORARY, tmp.mode)) >= 0) 278 { 279 *fdp = n; 280 return b; 281 } 282 } 283 else if (access(b, F_OK)) 284 return b; 285 } 286 if (!buf) 287 free(b); 288 return 0; 289 } 290