1/* $NetBSD: mkstemp.c,v 1.5 2005/06/01 11:48:49 lukem Exp $ */ 2/* from NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp */ 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 "tnftp.h" 34 35int 36mkstemp(char *path) 37{ 38 char *start, *trv; 39 struct stat sbuf; 40 unsigned int pid; 41 int fd; 42 43 /* To guarantee multiple calls generate unique names even if 44 the file is not created. 676 different possibilities with 7 45 or more X's, 26 with 6 or less. */ 46 static char xtra[2] = "aa"; 47 int xcnt = 0; 48 49 pid = getpid(); 50 51 /* Move to end of path and count trailing X's. */ 52 for (trv = path; *trv; ++trv) 53 if (*trv == 'X') 54 xcnt++; 55 else 56 xcnt = 0; 57 58 /* Use at least one from xtra. Use 2 if more than 6 X's. */ 59 if (*(trv - 1) == 'X') 60 *--trv = xtra[0]; 61 if (xcnt > 6 && *(trv - 1) == 'X') 62 *--trv = xtra[1]; 63 64 /* Set remaining X's to pid digits with 0's to the left. */ 65 while (*--trv == 'X') { 66 *trv = (pid % 10) + '0'; 67 pid /= 10; 68 } 69 70 /* update xtra for next call. */ 71 if (xtra[0] != 'z') 72 xtra[0]++; 73 else { 74 xtra[0] = 'a'; 75 if (xtra[1] != 'z') 76 xtra[1]++; 77 else 78 xtra[1] = 'a'; 79 } 80 81 /* 82 * check the target directory; if you have six X's and it 83 * doesn't exist this runs for a *very* long time. 84 */ 85 for (start = trv + 1;; --trv) { 86 if (trv <= path) 87 break; 88 if (*trv == '/') { 89 *trv = '\0'; 90 if (stat(path, &sbuf)) 91 return (-1); 92 if (!S_ISDIR(sbuf.st_mode)) { 93 errno = ENOTDIR; 94 return (-1); 95 } 96 *trv = '/'; 97 break; 98 } 99 } 100 101 for (;;) { 102 if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0) 103 return (fd); 104 if (errno != EEXIST) 105 return (-1); 106 107 /* tricky little algorithm for backward compatibility */ 108 for (trv = start;;) { 109 if (!*trv) 110 return (-1); 111 if (*trv == 'z') 112 *trv++ = 'a'; 113 else { 114 if (isdigit((unsigned char)*trv)) 115 *trv = 'a'; 116 else 117 ++*trv; 118 break; 119 } 120 } 121 } 122 /*NOTREACHED*/ 123} 124