1 1.24 kre /* $NetBSD: gettemp.c,v 1.24 2025/08/06 23:51:16 kre Exp $ */ 2 1.1 mycroft 3 1.1 mycroft /* 4 1.1 mycroft * Copyright (c) 1987, 1993 5 1.1 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 mycroft * 7 1.1 mycroft * Redistribution and use in source and binary forms, with or without 8 1.1 mycroft * modification, are permitted provided that the following conditions 9 1.1 mycroft * are met: 10 1.1 mycroft * 1. Redistributions of source code must retain the above copyright 11 1.1 mycroft * notice, this list of conditions and the following disclaimer. 12 1.1 mycroft * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 mycroft * notice, this list of conditions and the following disclaimer in the 14 1.1 mycroft * documentation and/or other materials provided with the distribution. 15 1.10 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 mycroft * may be used to endorse or promote products derived from this software 17 1.1 mycroft * without specific prior written permission. 18 1.1 mycroft * 19 1.1 mycroft * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 mycroft * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 mycroft * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 mycroft * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 mycroft * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 mycroft * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 mycroft * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 mycroft * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 mycroft * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 mycroft * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 mycroft * SUCH DAMAGE. 30 1.1 mycroft */ 31 1.1 mycroft 32 1.18 christos #include "gettemp.h" 33 1.8 thorpej 34 1.12 lukem #if !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP || !HAVE_MKDTEMP 35 1.8 thorpej 36 1.1 mycroft #include <sys/cdefs.h> 37 1.1 mycroft #if defined(LIBC_SCCS) && !defined(lint) 38 1.1 mycroft #if 0 39 1.1 mycroft static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; 40 1.1 mycroft #else 41 1.24 kre __RCSID("$NetBSD: gettemp.c,v 1.24 2025/08/06 23:51:16 kre Exp $"); 42 1.1 mycroft #endif 43 1.1 mycroft #endif /* LIBC_SCCS and not lint */ 44 1.1 mycroft 45 1.18 christos #include <sys/param.h> 46 1.21 christos #include <sys/stat.h> 47 1.1 mycroft #include <fcntl.h> 48 1.18 christos #include <string.h> 49 1.9 thorpej 50 1.18 christos static const unsigned char padchar[] = 51 1.18 christos "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 52 1.1 mycroft 53 1.1 mycroft int 54 1.18 christos GETTEMP(char *path, int *doopen, int domkdir, int slen, int oflags) 55 1.1 mycroft { 56 1.18 christos char *start, *trv, *suffp, *carryp; 57 1.22 christos const char *pad; 58 1.1 mycroft struct stat sbuf; 59 1.18 christos int rval; 60 1.19 msaitoh uint32_t r; 61 1.18 christos char carrybuf[MAXPATHLEN]; 62 1.4 lukem 63 1.4 lukem _DIAGASSERT(path != NULL); 64 1.4 lukem /* doopen may be NULL */ 65 1.18 christos if ((doopen != NULL && domkdir) || slen < 0 || 66 1.18 christos (oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC | 67 1.23 kre O_CLOEXEC | O_CLOFORK)) != 0) { 68 1.18 christos errno = EINVAL; 69 1.18 christos return 0; 70 1.18 christos } 71 1.1 mycroft 72 1.18 christos for (trv = path; *trv != '\0'; ++trv) 73 1.18 christos continue; 74 1.1 mycroft 75 1.18 christos if (trv - path >= MAXPATHLEN) { 76 1.18 christos errno = ENAMETOOLONG; 77 1.18 christos return 0; 78 1.1 mycroft } 79 1.18 christos trv -= slen; 80 1.18 christos suffp = trv; 81 1.18 christos --trv; 82 1.18 christos if (trv < path || NULL != strchr(suffp, '/')) { 83 1.18 christos errno = EINVAL; 84 1.18 christos return 0; 85 1.18 christos } 86 1.18 christos 87 1.18 christos /* Fill space with random characters */ 88 1.18 christos while (trv >= path && *trv == 'X') { 89 1.20 christos r = arc4random_uniform((unsigned int)(sizeof(padchar) - 1)); 90 1.19 msaitoh *trv-- = padchar[r]; 91 1.18 christos } 92 1.18 christos start = trv + 1; 93 1.18 christos 94 1.18 christos /* save first combination of random characters */ 95 1.20 christos memcpy(carrybuf, start, (size_t)(suffp - start)); 96 1.1 mycroft 97 1.1 mycroft /* 98 1.18 christos * check the target directory. 99 1.1 mycroft */ 100 1.18 christos if (doopen != NULL || domkdir) { 101 1.18 christos for (; trv > path; --trv) { 102 1.18 christos if (*trv == '/') { 103 1.18 christos *trv = '\0'; 104 1.18 christos rval = stat(path, &sbuf); 105 1.18 christos *trv = '/'; 106 1.18 christos if (rval != 0) 107 1.18 christos return 0; 108 1.18 christos if (!S_ISDIR(sbuf.st_mode)) { 109 1.18 christos errno = ENOTDIR; 110 1.18 christos return 0; 111 1.18 christos } 112 1.18 christos break; 113 1.1 mycroft } 114 1.1 mycroft } 115 1.1 mycroft } 116 1.1 mycroft 117 1.1 mycroft for (;;) { 118 1.1 mycroft if (doopen) { 119 1.18 christos if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR|oflags, 120 1.18 christos 0600)) != -1) 121 1.15 christos return 1; 122 1.1 mycroft if (errno != EEXIST) 123 1.15 christos return 0; 124 1.2 mycroft } else if (domkdir) { 125 1.18 christos if (mkdir(path, 0700) != -1) 126 1.15 christos return 1; 127 1.2 mycroft if (errno != EEXIST) 128 1.15 christos return 0; 129 1.2 mycroft } else if (lstat(path, &sbuf)) 130 1.18 christos return errno == ENOENT; 131 1.1 mycroft 132 1.18 christos /* 133 1.18 christos * If we have a collision, 134 1.18 christos * cycle through the space of filenames 135 1.18 christos */ 136 1.18 christos for (trv = start, carryp = carrybuf;;) { 137 1.18 christos /* have we tried all possible permutations? */ 138 1.18 christos if (trv == suffp) 139 1.18 christos return 0; /* yes - exit with EEXIST */ 140 1.18 christos pad = strchr((const char *)padchar, *trv); 141 1.18 christos if (pad == NULL) { 142 1.18 christos /* this should never happen */ 143 1.18 christos errno = EIO; 144 1.15 christos return 0; 145 1.18 christos } 146 1.18 christos /* increment character */ 147 1.18 christos *trv = (*++pad == '\0') ? padchar[0] : *pad; 148 1.18 christos /* carry to next position? */ 149 1.18 christos if (*trv == *carryp) { 150 1.18 christos /* increment position and loop */ 151 1.18 christos ++trv; 152 1.18 christos ++carryp; 153 1.18 christos } else { 154 1.18 christos /* try with new name */ 155 1.1 mycroft break; 156 1.1 mycroft } 157 1.1 mycroft } 158 1.1 mycroft } 159 1.1 mycroft /*NOTREACHED*/ 160 1.1 mycroft } 161 1.8 thorpej 162 1.12 lukem #endif /* !HAVE_NBTOOL_CONFIG_H || !HAVE_MKSTEMP || !HAVE_MKDTEMP */ 163