Home | History | Annotate | Line # | Download | only in stdio
gettemp.c revision 1.20.2.1
      1  1.20.2.1  pgoyette /*	$NetBSD: gettemp.c,v 1.20.2.1 2017/03/20 06:56:58 pgoyette Exp $	*/
      2       1.1   mycroft 
      3       1.1   mycroft /*
      4       1.1   mycroft  * Copyright (c) 1987, 1993
      5       1.1   mycroft  *	The Regents of the University of California.  All rights reserved.
      6       1.1   mycroft  *
      7       1.1   mycroft  * Redistribution and use in source and binary forms, with or without
      8       1.1   mycroft  * modification, are permitted provided that the following conditions
      9       1.1   mycroft  * are met:
     10       1.1   mycroft  * 1. Redistributions of source code must retain the above copyright
     11       1.1   mycroft  *    notice, this list of conditions and the following disclaimer.
     12       1.1   mycroft  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1   mycroft  *    notice, this list of conditions and the following disclaimer in the
     14       1.1   mycroft  *    documentation and/or other materials provided with the distribution.
     15      1.10       agc  * 3. Neither the name of the University nor the names of its contributors
     16       1.1   mycroft  *    may be used to endorse or promote products derived from this software
     17       1.1   mycroft  *    without specific prior written permission.
     18       1.1   mycroft  *
     19       1.1   mycroft  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20       1.1   mycroft  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21       1.1   mycroft  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22       1.1   mycroft  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23       1.1   mycroft  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24       1.1   mycroft  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25       1.1   mycroft  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26       1.1   mycroft  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27       1.1   mycroft  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28       1.1   mycroft  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29       1.1   mycroft  * SUCH DAMAGE.
     30       1.1   mycroft  */
     31       1.1   mycroft 
     32      1.18  christos #include "gettemp.h"
     33       1.8   thorpej 
     34      1.12     lukem #if !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP || !HAVE_MKDTEMP
     35       1.8   thorpej 
     36       1.1   mycroft #include <sys/cdefs.h>
     37       1.1   mycroft #if defined(LIBC_SCCS) && !defined(lint)
     38       1.1   mycroft #if 0
     39       1.1   mycroft static char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
     40       1.1   mycroft #else
     41  1.20.2.1  pgoyette __RCSID("$NetBSD: gettemp.c,v 1.20.2.1 2017/03/20 06:56:58 pgoyette Exp $");
     42       1.1   mycroft #endif
     43       1.1   mycroft #endif /* LIBC_SCCS and not lint */
     44       1.1   mycroft 
     45      1.18  christos #include <sys/param.h>
     46  1.20.2.1  pgoyette #include <sys/stat.h>
     47       1.1   mycroft #include <fcntl.h>
     48      1.18  christos #include <string.h>
     49       1.9   thorpej 
     50      1.18  christos static const unsigned char padchar[] =
     51      1.18  christos "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     52       1.1   mycroft 
     53       1.1   mycroft int
     54      1.18  christos GETTEMP(char *path, int *doopen, int domkdir, int slen, int oflags)
     55       1.1   mycroft {
     56      1.18  christos 	char *start, *trv, *suffp, *carryp;
     57      1.18  christos 	char *pad;
     58       1.1   mycroft 	struct stat sbuf;
     59      1.18  christos 	int rval;
     60      1.19   msaitoh 	uint32_t r;
     61      1.18  christos 	char carrybuf[MAXPATHLEN];
     62       1.4     lukem 
     63       1.4     lukem 	_DIAGASSERT(path != NULL);
     64       1.4     lukem 	/* doopen may be NULL */
     65      1.18  christos 	if ((doopen != NULL && domkdir) || slen < 0 ||
     66      1.18  christos 	    (oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
     67      1.18  christos 	    O_CLOEXEC)) != 0) {
     68      1.18  christos 		errno = EINVAL;
     69      1.18  christos 		return 0;
     70      1.18  christos 	}
     71       1.1   mycroft 
     72      1.18  christos 	for (trv = path; *trv != '\0'; ++trv)
     73      1.18  christos 		continue;
     74       1.1   mycroft 
     75      1.18  christos 	if (trv - path >= MAXPATHLEN) {
     76      1.18  christos 		errno = ENAMETOOLONG;
     77      1.18  christos 		return 0;
     78       1.1   mycroft 	}
     79      1.18  christos 	trv -= slen;
     80      1.18  christos 	suffp = trv;
     81      1.18  christos 	--trv;
     82      1.18  christos 	if (trv < path || NULL != strchr(suffp, '/')) {
     83      1.18  christos 		errno = EINVAL;
     84      1.18  christos 		return 0;
     85      1.18  christos 	}
     86      1.18  christos 
     87      1.18  christos 	/* Fill space with random characters */
     88      1.18  christos 	while (trv >= path && *trv == 'X') {
     89      1.20  christos 		r = arc4random_uniform((unsigned int)(sizeof(padchar) - 1));
     90      1.19   msaitoh 		*trv-- = padchar[r];
     91      1.18  christos 	}
     92      1.18  christos 	start = trv + 1;
     93      1.18  christos 
     94      1.18  christos 	/* save first combination of random characters */
     95      1.20  christos 	memcpy(carrybuf, start, (size_t)(suffp - start));
     96       1.1   mycroft 
     97       1.1   mycroft 	/*
     98      1.18  christos 	 * check the target directory.
     99       1.1   mycroft 	 */
    100      1.18  christos 	if (doopen != NULL || domkdir) {
    101      1.18  christos 		for (; trv > path; --trv) {
    102      1.18  christos 			if (*trv == '/') {
    103      1.18  christos 				*trv = '\0';
    104      1.18  christos 				rval = stat(path, &sbuf);
    105      1.18  christos 				*trv = '/';
    106      1.18  christos 				if (rval != 0)
    107      1.18  christos 					return 0;
    108      1.18  christos 				if (!S_ISDIR(sbuf.st_mode)) {
    109      1.18  christos 					errno = ENOTDIR;
    110      1.18  christos 					return 0;
    111      1.18  christos 				}
    112      1.18  christos 				break;
    113       1.1   mycroft 			}
    114       1.1   mycroft 		}
    115       1.1   mycroft 	}
    116       1.1   mycroft 
    117       1.1   mycroft 	for (;;) {
    118       1.1   mycroft 		if (doopen) {
    119      1.18  christos 			if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR|oflags,
    120      1.18  christos 			    0600)) != -1)
    121      1.15  christos 				return 1;
    122       1.1   mycroft 			if (errno != EEXIST)
    123      1.15  christos 				return 0;
    124       1.2   mycroft 		} else if (domkdir) {
    125      1.18  christos 			if (mkdir(path, 0700) != -1)
    126      1.15  christos 				return 1;
    127       1.2   mycroft 			if (errno != EEXIST)
    128      1.15  christos 				return 0;
    129       1.2   mycroft 		} else if (lstat(path, &sbuf))
    130      1.18  christos 			return errno == ENOENT;
    131       1.1   mycroft 
    132      1.18  christos 		/*
    133      1.18  christos 		 * If we have a collision,
    134      1.18  christos 		 * cycle through the space of filenames
    135      1.18  christos 		 */
    136      1.18  christos 		for (trv = start, carryp = carrybuf;;) {
    137      1.18  christos 			/* have we tried all possible permutations? */
    138      1.18  christos 			if (trv == suffp)
    139      1.18  christos 				return 0; /* yes - exit with EEXIST */
    140      1.18  christos 			pad = strchr((const char *)padchar, *trv);
    141      1.18  christos 			if (pad == NULL) {
    142      1.18  christos 				/* this should never happen */
    143      1.18  christos 				errno = EIO;
    144      1.15  christos 				return 0;
    145      1.18  christos 			}
    146      1.18  christos 			/* increment character */
    147      1.18  christos 			*trv = (*++pad == '\0') ? padchar[0] : *pad;
    148      1.18  christos 			/* carry to next position? */
    149      1.18  christos 			if (*trv == *carryp) {
    150      1.18  christos 				/* increment position and loop */
    151      1.18  christos 				++trv;
    152      1.18  christos 				++carryp;
    153      1.18  christos 			} else {
    154      1.18  christos 				/* try with new name */
    155       1.1   mycroft 				break;
    156       1.1   mycroft 			}
    157       1.1   mycroft 		}
    158       1.1   mycroft 	}
    159       1.1   mycroft 	/*NOTREACHED*/
    160       1.1   mycroft }
    161       1.8   thorpej 
    162      1.12     lukem #endif /* !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP || !HAVE_MKDTEMP */
    163