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 static int _gettemp(char *, int *, int, int); 44 45 int 46 mkstemps(path, slen) 47 char *path; 48 int slen; 49 { 50 int fd; 51 52 return (_gettemp(path, &fd, 0, slen) ? fd : -1); 53 } 54 55 int 56 mkstemp(path) 57 char *path; 58 { 59 int fd; 60 61 return (_gettemp(path, &fd, 0, 0) ? fd : -1); 62 } 63 64 char * 65 mkdtemp(path) 66 char *path; 67 { 68 return(_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL); 69 } 70 71 static int 72 _gettemp(path, doopen, domkdir, slen) 73 char *path; 74 register int *doopen; 75 int domkdir; 76 int slen; 77 { 78 register char *start, *trv, *suffp; 79 struct stat sbuf; 80 int rval; 81 pid_t pid; 82 83 if (doopen && domkdir) { 84 errno = EINVAL; 85 return(0); 86 } 87 88 for (trv = path; *trv; ++trv) 89 ; 90 trv -= slen; 91 suffp = trv; 92 --trv; 93 if (trv < path) { 94 errno = EINVAL; 95 return (0); 96 } 97 pid = getpid(); 98 while (trv >= path && *trv == 'X' && pid != 0) { 99 *trv-- = (pid % 10) + '0'; 100 pid /= 10; 101 } 102 while (trv >= path && *trv == 'X') { 103 char c; 104 105 pid = (arc4random() & 0xffff) % (26+26); 106 if (pid < 26) 107 c = pid + 'A'; 108 else 109 c = (pid - 26) + 'a'; 110 *trv-- = c; 111 } 112 start = trv + 1; 113 114 /* 115 * check the target directory; if you have six X's and it 116 * doesn't exist this runs for a *very* long time. 117 */ 118 if (doopen || domkdir) { 119 for (;; --trv) { 120 if (trv <= path) 121 break; 122 if (*trv == '/') { 123 *trv = '\0'; 124 rval = stat(path, &sbuf); 125 *trv = '/'; 126 if (rval != 0) 127 return(0); 128 if (!S_ISDIR(sbuf.st_mode)) { 129 errno = ENOTDIR; 130 return(0); 131 } 132 break; 133 } 134 } 135 } 136 137 for (;;) { 138 if (doopen) { 139 if ((*doopen = 140 open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) 141 return(1); 142 if (errno != EEXIST) 143 return(0); 144 } else if (domkdir) { 145 if (mkdir(path, 0700) == 0) 146 return(1); 147 if (errno != EEXIST) 148 return(0); 149 } else if (lstat(path, &sbuf)) 150 return(errno == ENOENT ? 1 : 0); 151 152 /* tricky little algorithm for backward compatibility */ 153 for (trv = start;;) { 154 if (!*trv) 155 return (0); 156 if (*trv == 'Z') { 157 if (trv == suffp) 158 return (0); 159 *trv++ = 'a'; 160 } else { 161 if (isdigit(*trv)) 162 *trv = 'a'; 163 else if (*trv == 'z') /* inc from z to A */ 164 *trv = 'A'; 165 else { 166 if (trv == suffp) 167 return (0); 168 ++*trv; 169 } 170 break; 171 } 172 } 173 } 174 /*NOTREACHED*/ 175 } 176 177 #endif /* !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) */ 178