1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16/* 17 * Copyright (c) 1987, 1993 18 * The Regents of the University of California. All rights reserved. 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 3. All advertising materials mentioning features or use of this software 29 * must display the following acknowledgement: 30 * This product includes software developed by the University of 31 * California, Berkeley and its contributors. 32 * 4. Neither the name of the University nor the names of its contributors 33 * may be used to endorse or promote products derived from this software 34 * without specific prior written permission. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 39 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 */ 48 49#include "apr_private.h" 50#include "apr_file_io.h" /* prototype of apr_mkstemp() */ 51#include "apr_strings.h" /* prototype of apr_mkstemp() */ 52#include "apr_arch_file_io.h" /* prototype of apr_mkstemp() */ 53#include "apr_portable.h" /* for apr_os_file_put() */ 54#include "apr_arch_inherit.h" 55 56#ifndef HAVE_MKSTEMP 57 58#if defined(SVR4) || defined(WIN32) || defined(NETWARE) 59#ifdef SVR4 60#if HAVE_INTTYPES_H 61#include <inttypes.h> 62#endif 63#endif 64#define arc4random() rand() 65#define seedrandom(a) srand(a) 66#else 67#if APR_HAVE_STDINT_H 68#include <stdint.h> 69#endif 70#define arc4random() random() 71#define seedrandom(a) srandom(a) 72#endif 73 74#if APR_HAVE_SYS_TYPES_H 75#include <sys/types.h> 76#endif 77#ifdef HAVE_SYS_STAT_H 78#include <sys/stat.h> 79#endif 80#if APR_HAVE_FCNTL_H 81#include <fcntl.h> 82#endif 83#include <stdio.h> 84#include <stdlib.h> 85#include <string.h> 86#include <ctype.h> 87#ifdef HAVE_TIME_H 88#include <time.h> 89#endif 90 91static const unsigned char padchar[] = 92"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 93static apr_uint32_t randseed=0; 94 95static int gettemp(char *path, apr_file_t **doopen, apr_int32_t flags, apr_pool_t *p) 96{ 97 register char *start, *trv, *suffp; 98 char *pad; 99 apr_finfo_t sbuf; 100 apr_status_t rv; 101 apr_uint32_t randnum; 102 103 if (randseed==0) { 104 randseed = (int)apr_time_now(); 105 seedrandom(randseed); 106 } 107 108 for (trv = path; *trv; ++trv) 109 ; 110 suffp = trv; 111 --trv; 112 if (trv < path) { 113 return APR_EINVAL; 114 } 115 116 /* Fill space with random characters */ 117 while (*trv == 'X') { 118 randnum = arc4random() % (sizeof(padchar) - 1); 119 *trv-- = padchar[randnum]; 120 } 121 start = trv + 1; 122 123 /* 124 * check the target directory. 125 */ 126 for (;; --trv) { 127 if (trv <= path) 128 break; 129 if (*trv == '/') { 130 *trv = '\0'; 131 rv = apr_stat(&sbuf, path, APR_FINFO_TYPE, p); 132 *trv = '/'; 133 if (rv != APR_SUCCESS) 134 return rv; 135 if (sbuf.filetype != APR_DIR) { 136 return APR_ENOTDIR; 137 } 138 break; 139 } 140 } 141 142 for (;;) { 143 if ((rv = apr_file_open(doopen, path, flags, 144 APR_UREAD | APR_UWRITE, p)) == APR_SUCCESS) 145 return APR_SUCCESS; 146 if (!APR_STATUS_IS_EEXIST(rv)) 147 return rv; 148 149 /* If we have a collision, cycle through the space of filenames */ 150 for (trv = start;;) { 151 if (*trv == '\0' || trv == suffp) 152 return APR_EINVAL; /* XXX: is this the correct return code? */ 153 pad = strchr((char *)padchar, *trv); 154 if (pad == NULL || !*++pad) { 155 *trv++ = padchar[0]; 156 } 157 else { 158 *trv++ = *pad; 159 break; 160 } 161 } 162 } 163 /*NOTREACHED*/ 164} 165 166#else 167 168#if APR_HAVE_STDLIB_H 169#include <stdlib.h> /* for mkstemp() - Single Unix */ 170#endif 171#if APR_HAVE_UNISTD_H 172#include <unistd.h> /* for mkstemp() - FreeBSD */ 173#endif 174#endif /* !defined(HAVE_MKSTEMP) */ 175 176APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_int32_t flags, apr_pool_t *p) 177{ 178#ifdef HAVE_MKSTEMP 179 int fd; 180#endif 181 flags = (!flags) ? APR_FOPEN_CREATE | APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL | 182 APR_FOPEN_DELONCLOSE : flags; 183#ifndef HAVE_MKSTEMP 184 return gettemp(template, fp, flags, p); 185#else 186 187#ifdef HAVE_MKSTEMP64 188 fd = mkstemp64(template); 189#else 190 fd = mkstemp(template); 191#endif 192 193 if (fd == -1) { 194 return errno; 195 } 196 /* XXX: We must reset several flags values as passed-in, since 197 * mkstemp didn't subscribe to our preference flags. 198 * 199 * We either have to unset the flags, or fix up the fd and other 200 * xthread and inherit bits appropriately. Since gettemp() above 201 * calls apr_file_open, our flags are respected in that code path. 202 */ 203 apr_os_file_put(fp, &fd, flags, p); 204 (*fp)->fname = apr_pstrdup(p, template); 205 206 if (!(flags & APR_FOPEN_NOCLEANUP)) { 207 int flags; 208 209 if ((flags = fcntl(fd, F_GETFD)) == -1) 210 return errno; 211 212 flags |= FD_CLOEXEC; 213 if (fcntl(fd, F_SETFD, flags) == -1) 214 return errno; 215 216 apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), 217 apr_unix_file_cleanup, 218 apr_unix_child_file_cleanup); 219 } 220#endif 221 return APR_SUCCESS; 222} 223 224