| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 | /* 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,   see <http://www.gnu.org/licenses/>.  *//* March 11, 2002       Manuel Novoa III * * Modify code to remove dependency on libgcc long long arith support funcs. *//* June 6, 2004       Erik Andersen * * Don't use brain damaged getpid() based randomness. *//* April 15, 2005     Mike Frysinger * * Use brain damaged getpid() if real random fails. */#include <stddef.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <assert.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include "tempname.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; */    /* dir and pfx lengths should always fit into an int,       so don't bother using size_t here.  Especially since       the printf func requires an int for precision (%*s).  */    int dlen, plen;    if (!pfx || !pfx[0])    {	pfx = "file";	plen = 4;    }    else    {	plen = strlen (pfx);	if (plen > 5)	    plen = 5;    }    /* Disable support for $TMPDIR */#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 < (size_t)dlen + 1 + plen + 6 + 1)    {	__set_errno (EINVAL);	return -1;    }    sprintf (tmpl, "%.*s/%.*sXXXXXX", dlen, dir, plen, pfx);    return 0;}/* These are the characters used in temporary filenames.  */static const char letters[] ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";#define NUM_LETTERS (62)static unsigned int fillrand(unsigned char *buf, unsigned int len){    int fd;    unsigned int result = -1;    fd = open("/dev/urandom", O_RDONLY);    if (fd < 0) {	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);    }    if (fd >= 0) {	result = read(fd, buf, len);	close(fd);    }    return result;}static void brain_damaged_fillrand(unsigned char *buf, unsigned int len){	unsigned int i, k;	struct timeval tv;	uint32_t high, low, rh;	static uint64_t value;	gettimeofday(&tv, NULL);	value += ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();	low = value & UINT32_MAX;	high = value >> 32;	for (i = 0; i < len; ++i) {		rh = high % NUM_LETTERS;		high /= NUM_LETTERS;#define L ((UINT32_MAX % NUM_LETTERS + 1) % NUM_LETTERS)		k = (low % NUM_LETTERS) + (L * rh);#undef L#define H ((UINT32_MAX / NUM_LETTERS) + ((UINT32_MAX % NUM_LETTERS + 1) / NUM_LETTERS))		low = (low / NUM_LETTERS) + (H * rh) + (k / NUM_LETTERS);#undef H		k %= NUM_LETTERS;		buf[i] = letters[k];	}}/* 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.   KIND may be one of:   __GT_NOCREATE:       simply verify that the name does not exist                        at the time of the call. mode argument is ignored.   __GT_FILE:           create the file using open(O_CREAT|O_EXCL)                        and return a read-write fd with given mode.   __GT_BIGFILE:        same as __GT_FILE but use open64().   __GT_DIR:            create a directory with given mode.*/int attribute_hidden __gen_tempname (char *tmpl, int kind, mode_t mode){    char *XXXXXX;    unsigned int i;    int fd, save_errno = errno;    unsigned char randomness[6];    size_t len;    len = strlen (tmpl);    /* This is where the Xs start.  */    XXXXXX = tmpl + len - 6;    if (len < 6 || strcmp (XXXXXX, "XXXXXX"))    {	__set_errno (EINVAL);	return -1;    }    for (i = 0; i < TMP_MAX; ++i) {	unsigned char j;	/* Get some random data.  */	if (fillrand(randomness, sizeof(randomness)) != sizeof(randomness)) {	    /* if random device nodes failed us, lets use the braindamaged ver */	    brain_damaged_fillrand(randomness, sizeof(randomness));	}	for (j = 0; j < sizeof(randomness); ++j)	    XXXXXX[j] = letters[randomness[j] % NUM_LETTERS];	switch (kind) {	    case __GT_NOCREATE:		{		    struct stat st;		    if (stat (tmpl, &st) < 0) {			if (errno == ENOENT) {			    fd = 0;			    goto restore_and_ret;			} else			    /* Give up now. */			    return -1;		    } else			fd = 0;		}	    case __GT_FILE:		fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);		break;#if defined __UCLIBC_HAS_LFS__	    case __GT_BIGFILE:		fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);		break;#endif	    case __GT_DIR:		fd = mkdir (tmpl, mode);		break;	    default:		fd = -1;		assert (! "invalid KIND in __gen_tempname");	}	if (fd >= 0) {restore_and_ret:	    __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;    }    /* We got out of the loop because we ran out of combinations to try.  */    __set_errno (EEXIST);    return -1;}
 |