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