| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 | /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.   This file is part of the GNU C Library.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Library General Public License as   published by the Free Software Foundation; either version 2 of the   License, or (at your option) any later version.   The GNU C Library is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   Library General Public License for more details.   You should have received a copy of the GNU Library General Public   License along with the GNU C Library; see the file COPYING.LIB.  If not,   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,   Boston, MA 02111-1307, USA.  */#include <stddef.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/time.h>/* Return nonzero if DIR is an existent directory.  */static int direxists (const char *dir){    struct stat buf;    return stat(dir, &buf) == 0 && S_ISDIR (buf.st_mode);}/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is   non-null and exists, uses it; otherwise uses the first of $TMPDIR,   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and   doesn't exist, none of the searched dirs exists, or there's not   enough space in TMPL. */int __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,	       int try_tmpdir){    //const char *d;    size_t dlen, plen;    if (!pfx || !pfx[0])    {	pfx = "file";	plen = 4;    }    else    {	plen = strlen (pfx);	if (plen > 5)	    plen = 5;    }#if 0    if (try_tmpdir)    {	d = __secure_getenv ("TMPDIR");	if (d != NULL && direxists (d))	    dir = d;	else if (dir != NULL && direxists (dir))	    /* nothing */ ;	else	    dir = NULL;    }#endif	    if (dir == NULL)    {	if (direxists (P_tmpdir))	    dir = P_tmpdir;	else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))	    dir = "/tmp";	else	{	    __set_errno (ENOENT);	    return -1;	}    }    dlen = strlen (dir);    while (dlen > 1 && dir[dlen - 1] == '/')	dlen--;			/* remove trailing slashes */    /* check we have room for "${dir}/${pfx}XXXXXX\0" */    if (tmpl_len < dlen + 1 + plen + 6 + 1)    {	__set_errno (EINVAL);	return -1;    }    sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);    return 0;}/* These are the characters used in temporary filenames.  */static const char letters[] ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";/* Generate a temporary file name based on TMPL.  TMPL must match the   rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed   does not exist at the time of the call to __gen_tempname.  TMPL is   overwritten with the result.  If OPENIT is nonzero, creates the   file and returns a read-write fd; the file is mode 0600 modulo   umask.  If LARGEFILE is nonzero, uses open64() instead of open().   We use a clever algorithm to get hard-to-predict names. */int __gen_tempname (char *tmpl, int openit){    int len;    char *XXXXXX;    static uint64_t value;    struct timeval tv;    int count, fd;    int save_errno = errno;    len = strlen (tmpl);    if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))    {	__set_errno (EINVAL);	return -1;    }    /* This is where the Xs start.  */    XXXXXX = &tmpl[len - 6];    /* Get some more or less random data.  */    gettimeofday (&tv, NULL);    value += ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();    for (count = 0; count < TMP_MAX; value += 7777, ++count)    {	uint64_t v = value;	/* Fill in the random bits.  */	XXXXXX[0] = letters[v % 62];	v /= 62;	XXXXXX[1] = letters[v % 62];	v /= 62;	XXXXXX[2] = letters[v % 62];	v /= 62;	XXXXXX[3] = letters[v % 62];	v /= 62;	XXXXXX[4] = letters[v % 62];	v /= 62;	XXXXXX[5] = letters[v % 62];	if (openit)	{	    fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, 0600);	    if (fd >= 0)	    {		__set_errno (save_errno);		return fd;	    }	    else if (errno != EEXIST)		/* Any other error will apply also to other names we might		   try, and there are 2^32 or so of them, so give up now. */		return -1;	}	else	{	    struct stat st;	    if (stat (tmpl, &st) < 0)	    {		if (errno == ENOENT)		{		    __set_errno (save_errno);		    return 0;		}		else		    /* Give up now. */		    return -1;	    }	}    }    /* We got out of the loop because we ran out of combinations to try.  */    __set_errno (EEXIST);    return -1;}
 |