1 /* 2 * Copyright (c) 1987, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if defined(LIBC_SCCS) && !defined(lint) 35 #if 0 36 static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; 37 #endif 38 static const char rcsid[] = 39 "$Id: mktemp.c,v 1.11 1998/10/20 12:36:36 peter Exp $"; 40 #endif /* LIBC_SCCS and not lint */ 41 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <fcntl.h> 45 #include <errno.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <ctype.h> 49 #include <unistd.h> 50 51 char *_mktemp __P((char *)); 52 53 static int _gettemp __P((char *, int *, int)); 54 55 int 56 mkstemp(path) 57 char *path; 58 { 59 int fd; 60 61 return (_gettemp(path, &fd, 0) ? fd : -1); 62 } 63 64 char * 65 mkdtemp(path) 66 char *path; 67 { 68 return(_gettemp(path, (int *)NULL, 1) ? path : (char *)NULL); 69 } 70 71 char * 72 _mktemp(path) 73 char *path; 74 { 75 return(_gettemp(path, (int *)NULL, 0) ? path : (char *)NULL); 76 } 77 78 #ifdef UNSAFE_WARN 79 __warn_references(mktemp, 80 "warning: mktemp() possibly used unsafely; consider using mkstemp()"); 81 #endif 82 83 char * 84 mktemp(path) 85 char *path; 86 { 87 return(_mktemp(path)); 88 } 89 90 static int 91 _gettemp(path, doopen, domkdir) 92 char *path; 93 register int *doopen; 94 int domkdir; 95 { 96 register char *start, *trv; 97 struct stat sbuf; 98 int pid, rval; 99 100 if (doopen && domkdir) { 101 errno = EINVAL; 102 return(0); 103 } 104 105 pid = getpid(); 106 for (trv = path; *trv; ++trv) 107 ; 108 --trv; 109 while (*trv == 'X' && pid != 0) { 110 *trv-- = (pid % 10) + '0'; 111 pid /= 10; 112 } 113 while (*trv == 'X') { 114 char c; 115 116 pid = (arc4random() & 0xffff) % (26+26); 117 if (pid < 26) 118 c = pid + 'A'; 119 else 120 c = (pid - 26) + 'a'; 121 *trv-- = c; 122 } 123 start = trv + 1; 124 125 /* 126 * check the target directory; if you have six X's and it 127 * doesn't exist this runs for a *very* long time. 128 */ 129 if (doopen || domkdir) { 130 for (;; --trv) { 131 if (trv <= path) 132 break; 133 if (*trv == '/') { 134 *trv = '\0'; 135 rval = stat(path, &sbuf); 136 *trv = '/'; 137 if (rval != 0) 138 return(0); 139 if (!S_ISDIR(sbuf.st_mode)) { 140 errno = ENOTDIR; 141 return(0); 142 } 143 break; 144 } 145 } 146 } 147 148 for (;;) { 149 if (doopen) { 150 if ((*doopen = 151 open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) 152 return(1); 153 if (errno != EEXIST) 154 return(0); 155 } else if (domkdir) { 156 if (mkdir(path, 0700) == 0) 157 return(1); 158 if (errno != EEXIST) 159 return(0); 160 } else if (lstat(path, &sbuf)) 161 return(errno == ENOENT ? 1 : 0); 162 163 /* tricky little algorithm for backward compatibility */ 164 for (trv = start;;) { 165 if (!*trv) 166 return(0); 167 if (*trv == 'Z') 168 *trv++ = 'a'; 169 else { 170 if (isdigit(*trv)) 171 *trv = 'a'; 172 else if (*trv == 'z') /* inc from z to A */ 173 *trv = 'A'; 174 else 175 ++*trv; 176 break; 177 } 178 } 179 } 180 /*NOTREACHED*/ 181 } 182