diff options
Diffstat (limited to 'src/tet3/dtet2lib/tfname.c')
-rw-r--r-- | src/tet3/dtet2lib/tfname.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/tet3/dtet2lib/tfname.c b/src/tet3/dtet2lib/tfname.c new file mode 100644 index 00000000..e1c87fd4 --- /dev/null +++ b/src/tet3/dtet2lib/tfname.c @@ -0,0 +1,206 @@ +/* + * SCCS: @(#)tfname.c 1.11 (98/08/28) + * + * UniSoft Ltd., London, England + * + * (C) Copyright 1992 X/Open Company Limited + * + * All rights reserved. No part of this source code may be reproduced, + * stored in a retrieval system, or transmitted, in any form or by any + * means, electronic, mechanical, photocopying, recording or otherwise, + * except as stated in the end-user licence agreement, without the prior + * permission of the copyright owners. + * + * X/Open and the 'X' symbol are trademarks of X/Open Company Limited in + * the UK and other countries. + */ + +#ifndef lint +static char sccsid[] = "@(#)tfname.c 1.11 (98/08/28) TET3 release 3.3"; +#endif + +/************************************************************************ + +SCCS: @(#)tfname.c 1.11 98/08/28 TETware release 3.3 +NAME: tfname.c +PRODUCT: TETware +AUTHOR: Andrew Dingwall, UniSoft Ltd. +DATE CREATED: April 1992 + +DESCRIPTION: + function to generate a temporary file name with some guarantee that it + will be useful + +MODIFICATIONS: + Geoff Clare, UniSoft Ltd., August 1996 + Missing <unistd.h>. + + Andrew Dingwall, UniSoft Ltd., July 1998 + Added support for shared API libraries. + +************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +# include <unistd.h> +#include "dtmac.h" +#include "globals.h" +#include "error.h" +#include "ltoa.h" +#include "bstring.h" +#include "dtetlib.h" + +#ifdef NEEDsrcFile +static char srcFile[] = __FILE__; /* file name for error reporting */ +#endif + +static char *dirs[] = { (char *) 0, "/usr/tmp", "/tmp", (char *) 0 }; + +static char **tmpdirs; +static char salt[] = "\000AAA"; + +/* tryone() return codes */ +#define TR_OK 1 /* file could be created */ +#define TR_NEXTDIR 2 /* try again in next directory */ +#define TR_NEXTFNAME 3 /* try again with next file name */ +#define TR_ERROR -1 /* error - give up */ + +/* mode for the open() call */ +#define MODEANY \ + ((mode_t) (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) + + +/* static function declarations */ +static int tryone PROTOLIST((char *, char *, char **)); + + +/* +** tet_mktfname() - generate a temporary file name and return a pointer +** thereto +** +** return (char *) 0 on error +*/ + +char *tet_mktfname(prefix) +char *prefix; +{ + register char **tdp; + register char *p; + register int rc = TR_ERROR; + char *fname; + + /* do initial setup first time through */ + if (!tmpdirs) { + if ((p = getenv("TMPDIR")) == (char *) 0 || !*p) + tmpdirs = &dirs[1]; + else { + dirs[0] = p; + tmpdirs = &dirs[0]; + } + } + + /* generate the file name */ + for (;;) { + if (salt[0]) { + error(0, "out of tmp file names", (char *) 0); + break; + } + for (tdp = tmpdirs; *tdp; tdp++) + if ((rc = tryone(*tdp, prefix, &fname)) != TR_NEXTDIR) + break; + if (rc != TR_OK && rc != TR_NEXTFNAME) + break; + for (p = &salt[sizeof salt - 2]; p >= salt; p--) + if (++*p > 'Z') + *p = 'A'; + else + break; + if (rc == TR_OK) + return(fname); + } + + /* here to return after an error */ + return((char *) 0); +} + +/* +** tryone() - try to create a temporary file +** +** return TR_* return code to indicate success or failure +** if successful, the generated file name is stored indirectly through *np +** +** we try to make sure that there is a reasonable chance of being able to +** write some data to the file +*/ + +static int tryone(dir, prefix, np) +char *dir, *prefix; +char **np; +{ + register char *fname, *pidstr; + register int fd, n, rc; + size_t needlen; + char buf[1024]; + + /* work out how big a buffer is needed */ + pidstr = tet_i2a(tet_mypid); + needlen = strlen(dir) + strlen(prefix) + sizeof salt + strlen(pidstr); + + /* get a buffer for the file name */ + errno = 0; + if ((fname = malloc(needlen)) == (char *) 0) { + error(errno, "can't get tmp file name buffer", (char *) 0); + return(TR_ERROR); + } + TRACE2(tet_Tbuf, 6, "allocate tfname = %s", tet_i2x(fname)); + + /* generate the file name */ + (void) sprintf(fname, "%s/%s%s%s", dir, prefix, &salt[1], pidstr); + + /* try to open the file */ + if ((fd = OPEN(fname, O_RDWR|O_CREAT|O_EXCL|O_BINARY, MODEANY)) < 0) + switch (errno) { + case EMFILE: + case ENFILE: + /* caller will have to take his chances! */ + rc = TR_OK; + break; + case EEXIST: + case EISDIR: + case ENXIO: + rc = TR_NEXTFNAME; + break; + default: + rc = TR_NEXTDIR; + break; + } + else { + /* try to write a reasonable amount of data to the file */ + bzero(buf, sizeof buf); + rc = TR_OK; + for (n = 0; n < 10; n++) + if (WRITE(fd, buf, sizeof buf) != sizeof buf) { + rc = TR_NEXTDIR; + break; + } + /* close the file and unlink it */ + (void) CLOSE(fd); + if (UNLINK(fname) < 0) + error(errno, "can't unlink", fname); + } + + /* store the file name if ok, otherwise free the buffer */ + if (rc == TR_OK) + *np = fname; + else { + TRACE2(tet_Tbuf, 6, "free tfname = %s", tet_i2x(fname)); + free(fname); + } + + return(rc); +} + |