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