diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
commit | 3950ffe2a485479f6561c27364d3d7df5a21d124 (patch) | |
tree | 468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/path/pathtemp.c | |
download | ksh-upstream.tar.gz |
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libast/path/pathtemp.c')
-rw-r--r-- | src/lib/libast/path/pathtemp.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/src/lib/libast/path/pathtemp.c b/src/lib/libast/path/pathtemp.c new file mode 100644 index 0000000..844c86a --- /dev/null +++ b/src/lib/libast/path/pathtemp.c @@ -0,0 +1,337 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * AT&T Research + * + * generate a temp file / name + * + * [<dir>/][<pfx>]<bas>.<suf> + * + * length(<pfx>)<=5 + * length(<bas>)==3 + * length(<suf>)==3 + * + * pathtmp(a,b,c,d) pathtemp(a,L_tmpnam,b,c,0) + * tmpfile() char*p=pathtemp(0,0,0,"tf",&sp); + * remove(p); + * free(p) + * tmpnam(0) static char p[L_tmpnam]; + * pathtemp(p,sizeof(p),0,"tn",0) + * tmpnam(p) pathtemp(p,L_tmpnam,0,"tn",0) + * tempnam(d,p) pathtemp(0,d,p,0) + * mktemp(p) pathtemp(0,0,p,0) + * + * if buf==0 then space is malloc'd + * buf size is size + * dir and pfx may be 0 + * if pfx contains trailing X's then it is a mktemp(3) template + * otherwise only first 5 chars of pfx are used + * if fdp!=0 then the path is opened O_EXCL and *fdp is the open fd + * malloc'd space returned by successful pathtemp() calls + * must be freed by the caller + * + * generated names are pseudo-randomized to avoid both + * collisions and predictions (same alg in sfio/sftmp.c) + * + * / as first pfx char provides tmp file generation control + * 0 returned for unknown ops + * + * /cycle dir specifies TMPPATH cycle control + * automatic (default) cycled with each tmp file + * manual cycled by application with dir=(nil) + * (nil) cycle TMPPATH + * /prefix dir specifies the default prefix (default ast) + * /private private file/dir modes + * /public public file/dir modes + * /seed dir specifies pseudo-random generator seed + * 0 or "0" to re-initialize + * /TMPPATH dir overrides the env value + * /TMPDIR dir overrides the env value + */ + +#include <ast.h> +#include <ls.h> +#include <tv.h> +#include <tm.h> + +#define ATTEMPT 10 + +#define TMP_ENV "TMPDIR" +#define TMP_PATH_ENV "TMPPATH" +#define TMP1 "/tmp" +#define TMP2 "/usr/tmp" + +#define VALID(d) (*(d)&&!eaccess(d,W_OK|X_OK)) + +static struct +{ + mode_t mode; + char** vec; + char** dir; + uint32_t key; + uint32_t rng; + pid_t pid; + int manual; + int seed; + char* pfx; + char* tmpdir; + char* tmppath; +} tmp = { S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH }; + +char* +pathtemp(char* buf, size_t len, const char* dir, const char* pfx, int* fdp) +{ + register char* d; + register char* b; + register char* s; + register char* x; + uint32_t key; + int m; + int n; + int l; + int r; + int z; + int attempt; + Tv_t tv; + char keybuf[16]; + + if (pfx && *pfx == '/') + { + pfx++; + if (streq(pfx, "cycle")) + { + if (!dir) + { + tmp.manual = 1; + if (tmp.dir && !*tmp.dir++) + tmp.dir = tmp.vec; + } + else + tmp.manual = streq(dir, "manual"); + return (char*)pfx; + } + else if (streq(pfx, "prefix")) + { + if (tmp.pfx) + free(tmp.pfx); + tmp.pfx = dir ? strdup(dir) : (char*)0; + return (char*)pfx; + } + else if (streq(pfx, "private")) + { + tmp.mode = S_IRUSR|S_IWUSR; + return (char*)pfx; + } + else if (streq(pfx, "public")) + { + tmp.mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + return (char*)pfx; + } + else if (streq(pfx, "seed")) + { + tmp.key = (tmp.seed = (tmp.rng = dir ? (uint32_t)strtoul(dir, NiL, 0) : (uint32_t)1) != 0)? (uint32_t)0x63c63cd9L : 0; + return (char*)pfx; + } + else if (streq(pfx, TMP_ENV)) + { + if (tmp.vec) + { + free(tmp.vec); + tmp.vec = 0; + } + if (tmp.tmpdir) + free(tmp.tmpdir); + tmp.tmpdir = dir ? strdup(dir) : (char*)0; + return (char*)pfx; + } + else if (streq(pfx, TMP_PATH_ENV)) + { + if (tmp.vec) + { + free(tmp.vec); + tmp.vec = 0; + } + if (tmp.tmppath) + free(tmp.tmppath); + tmp.tmppath = dir ? strdup(dir) : (char*)0; + return (char*)pfx; + } + return 0; + } + if (tmp.seed) + tv.tv_nsec = 0; + else + tvgettime(&tv); + if (!(d = (char*)dir) || *d && eaccess(d, W_OK|X_OK)) + { + if (!tmp.vec) + { + if ((x = tmp.tmppath) || (x = getenv(TMP_PATH_ENV))) + { + n = 2; + s = x; + while (s = strchr(s, ':')) + { + s++; + n++; + } + if (!(tmp.vec = newof(0, char*, n, strlen(x) + 1))) + return 0; + tmp.dir = tmp.vec; + x = strcpy((char*)(tmp.dir + n), x); + *tmp.dir++ = x; + while (x = strchr(x, ':')) + { + *x++ = 0; + if (!VALID(*(tmp.dir - 1))) + tmp.dir--; + *tmp.dir++ = x; + } + if (!VALID(*(tmp.dir - 1))) + tmp.dir--; + *tmp.dir = 0; + } + else + { + if (((d = tmp.tmpdir) || (d = getenv(TMP_ENV))) && !VALID(d)) + d = 0; + if (!(tmp.vec = newof(0, char*, 2, d ? (strlen(d) + 1) : 0))) + return 0; + if (d) + *tmp.vec = strcpy((char*)(tmp.vec + 2), d); + } + tmp.dir = tmp.vec; + } + if (!(d = *tmp.dir++)) + { + tmp.dir = tmp.vec; + d = *tmp.dir++; + } + 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)) + return 0; + } + if (!len) + len = PATH_MAX; + len--; + if (!(b = buf) && !(b = newof(0, char, len, 1))) + return 0; + z = 0; + if (!pfx && !(pfx = tmp.pfx)) + pfx = "ast"; + m = strlen(pfx); + if (buf && dir && (buf == (char*)dir && (buf + strlen(buf) + 1) == (char*)pfx || buf == (char*)pfx && !*dir) && !strcmp((char*)pfx + m + 1, "XXXXX")) + { + d = (char*)dir; + len = m += strlen(d) + 8; + l = 3; + r = 3; + } + else if (*pfx && pfx[m - 1] == 'X') + { + for (l = m; l && pfx[l - 1] == 'X'; l--); + r = m - l; + m = l; + l = r / 2; + r -= l; + } + else if (strchr(pfx, '.')) + { + m = 5; + l = 3; + r = 3; + } + else + { + z = '.'; + m = 5; + l = 2; + r = 3; + } + x = b + len; + s = b; + if (d) + { + while (s < x && (n = *d++)) + *s++ = n; + if (s < x && s > b && *(s - 1) != '/') + *s++ = '/'; + } + if ((x - s) > m) + x = s + m; + while (s < x && (n = *pfx++)) + { + if (n == '/' || n == '\\' || n == z) + n = '_'; + *s++ = n; + } + *s = 0; + len -= (s - b); + for (attempt = 0; attempt < ATTEMPT; attempt++) + { + if (!tmp.rng || !tmp.seed && (attempt || tmp.pid != getpid())) + { + register int r; + + /* + * get a quasi-random coefficient + */ + + tmp.pid = getpid(); + tmp.rng = (uint32_t)tmp.pid * ((uint32_t)time(NiL) ^ (((uint32_t)integralof(&attempt)) >> 3) ^ (((uint32_t)integralof(tmp.dir)) >> 3)); + if (!tmp.key) + tmp.key = (tmp.rng >> 16) | ((tmp.rng & 0xffff) << 16); + tmp.rng ^= tmp.key; + + /* + * Knuth vol.2, page.16, Thm.A + */ + + if ((r = (tmp.rng - 1) & 03)) + tmp.rng += 4 - r; + } + + /* + * generate a pseudo-random name + */ + + key = tmp.rng * tmp.key + tv.tv_nsec; + if (!tmp.seed) + tvgettime(&tv); + tmp.key = tmp.rng * key + tv.tv_nsec; + sfsprintf(keybuf, sizeof(keybuf), "%07.7.32I*u%07.7.32I*u", sizeof(key), key, sizeof(tmp.key), tmp.key); + sfsprintf(s, len, "%-.*s%s%-.*s", l, keybuf, z ? "." : "", r, keybuf + sizeof(keybuf) / 2); + if (fdp) + { + if ((n = open(b, O_CREAT|O_RDWR|O_EXCL|O_TEMPORARY, tmp.mode)) >= 0) + { + *fdp = n; + return b; + } + } + else if (access(b, F_OK)) + return b; + } + if (!buf) + free(b); + return 0; +} |