1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter/* 17251875Speter * Copyright (c) 1987, 1993 18251875Speter * The Regents of the University of California. All rights reserved. 19251875Speter * 20251875Speter * Redistribution and use in source and binary forms, with or without 21251875Speter * modification, are permitted provided that the following conditions 22251875Speter * are met: 23251875Speter * 1. Redistributions of source code must retain the above copyright 24251875Speter * notice, this list of conditions and the following disclaimer. 25251875Speter * 2. Redistributions in binary form must reproduce the above copyright 26251875Speter * notice, this list of conditions and the following disclaimer in the 27251875Speter * documentation and/or other materials provided with the distribution. 28251875Speter * 3. All advertising materials mentioning features or use of this software 29251875Speter * must display the following acknowledgement: 30251875Speter * This product includes software developed by the University of 31251875Speter * California, Berkeley and its contributors. 32251875Speter * 4. Neither the name of the University nor the names of its contributors 33251875Speter * may be used to endorse or promote products derived from this software 34251875Speter * without specific prior written permission. 35251875Speter * 36251875Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 37251875Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38251875Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 39251875Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 40251875Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41251875Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 42251875Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43251875Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 44251875Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 45251875Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46251875Speter * SUCH DAMAGE. 47251875Speter */ 48251875Speter 49251875Speter#include "apr_private.h" 50251875Speter#include "apr_file_io.h" /* prototype of apr_mkstemp() */ 51251875Speter#include "apr_strings.h" /* prototype of apr_mkstemp() */ 52251875Speter#include "apr_arch_file_io.h" /* prototype of apr_mkstemp() */ 53251875Speter#include "apr_portable.h" /* for apr_os_file_put() */ 54251875Speter#include "apr_arch_inherit.h" 55251875Speter 56251875Speter#ifndef HAVE_MKSTEMP 57251875Speter 58251875Speter#if defined(SVR4) || defined(WIN32) || defined(NETWARE) 59251875Speter#ifdef SVR4 60251875Speter#if HAVE_INTTYPES_H 61251875Speter#include <inttypes.h> 62251875Speter#endif 63251875Speter#endif 64251875Speter#define arc4random() rand() 65251875Speter#define seedrandom(a) srand(a) 66251875Speter#else 67251875Speter#if APR_HAVE_STDINT_H 68251875Speter#include <stdint.h> 69251875Speter#endif 70251875Speter#define arc4random() random() 71251875Speter#define seedrandom(a) srandom(a) 72251875Speter#endif 73251875Speter 74251875Speter#if APR_HAVE_SYS_TYPES_H 75251875Speter#include <sys/types.h> 76251875Speter#endif 77251875Speter#if APR_HAVE_SYS_STAT_H 78251875Speter#include <sys/stat.h> 79251875Speter#endif 80251875Speter#if APR_HAVE_FCNTL_H 81251875Speter#include <fcntl.h> 82251875Speter#endif 83251875Speter#include <stdio.h> 84251875Speter#include <stdlib.h> 85251875Speter#include <string.h> 86251875Speter#include <ctype.h> 87251875Speter#ifdef HAVE_TIME_H 88251875Speter#include <time.h> 89251875Speter#endif 90251875Speter 91251875Speterstatic const unsigned char padchar[] = 92251875Speter"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 93251875Speterstatic apr_uint32_t randseed=0; 94251875Speter 95251875Speterstatic int gettemp(char *path, apr_file_t **doopen, apr_int32_t flags, apr_pool_t *p) 96251875Speter{ 97251875Speter register char *start, *trv, *suffp; 98251875Speter char *pad; 99251875Speter apr_finfo_t sbuf; 100251875Speter apr_status_t rv; 101251875Speter apr_uint32_t randnum; 102251875Speter 103251875Speter if (randseed==0) { 104251875Speter randseed = (int)apr_time_now(); 105251875Speter seedrandom(randseed); 106251875Speter } 107251875Speter 108251875Speter for (trv = path; *trv; ++trv) 109251875Speter ; 110251875Speter suffp = trv; 111251875Speter --trv; 112251875Speter if (trv < path) { 113251875Speter return APR_EINVAL; 114251875Speter } 115251875Speter 116251875Speter /* Fill space with random characters */ 117251875Speter while (*trv == 'X') { 118251875Speter randnum = arc4random() % (sizeof(padchar) - 1); 119251875Speter *trv-- = padchar[randnum]; 120251875Speter } 121251875Speter start = trv + 1; 122251875Speter 123251875Speter /* 124251875Speter * check the target directory. 125251875Speter */ 126251875Speter for (;; --trv) { 127251875Speter if (trv <= path) 128251875Speter break; 129251875Speter if (*trv == '/') { 130251875Speter *trv = '\0'; 131251875Speter rv = apr_stat(&sbuf, path, APR_FINFO_TYPE, p); 132251875Speter *trv = '/'; 133251875Speter if (rv != APR_SUCCESS) 134251875Speter return rv; 135251875Speter if (sbuf.filetype != APR_DIR) { 136251875Speter return APR_ENOTDIR; 137251875Speter } 138251875Speter break; 139251875Speter } 140251875Speter } 141251875Speter 142251875Speter for (;;) { 143251875Speter if ((rv = apr_file_open(doopen, path, flags, 144251875Speter APR_UREAD | APR_UWRITE, p)) == APR_SUCCESS) 145251875Speter return APR_SUCCESS; 146251875Speter if (!APR_STATUS_IS_EEXIST(rv)) 147251875Speter return rv; 148251875Speter 149251875Speter /* If we have a collision, cycle through the space of filenames */ 150251875Speter for (trv = start;;) { 151251875Speter if (*trv == '\0' || trv == suffp) 152251875Speter return APR_EINVAL; /* XXX: is this the correct return code? */ 153251875Speter pad = strchr((char *)padchar, *trv); 154251875Speter if (pad == NULL || !*++pad) { 155251875Speter *trv++ = padchar[0]; 156251875Speter } 157251875Speter else { 158251875Speter *trv++ = *pad; 159251875Speter break; 160251875Speter } 161251875Speter } 162251875Speter } 163251875Speter /*NOTREACHED*/ 164251875Speter} 165251875Speter 166251875Speter#else 167251875Speter 168251875Speter#if APR_HAVE_STDLIB_H 169251875Speter#include <stdlib.h> /* for mkstemp() - Single Unix */ 170251875Speter#endif 171251875Speter#if APR_HAVE_UNISTD_H 172251875Speter#include <unistd.h> /* for mkstemp() - FreeBSD */ 173251875Speter#endif 174251875Speter#endif /* !defined(HAVE_MKSTEMP) */ 175251875Speter 176251875SpeterAPR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_int32_t flags, apr_pool_t *p) 177251875Speter{ 178251875Speter#ifdef HAVE_MKSTEMP 179251875Speter int fd; 180251875Speter#endif 181251875Speter flags = (!flags) ? APR_FOPEN_CREATE | APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL | 182251875Speter APR_FOPEN_DELONCLOSE : flags; 183251875Speter#ifndef HAVE_MKSTEMP 184251875Speter return gettemp(template, fp, flags, p); 185251875Speter#else 186251875Speter 187251875Speter#ifdef HAVE_MKSTEMP64 188251875Speter fd = mkstemp64(template); 189251875Speter#else 190251875Speter fd = mkstemp(template); 191251875Speter#endif 192251875Speter 193251875Speter if (fd == -1) { 194251875Speter return errno; 195251875Speter } 196251875Speter /* XXX: We must reset several flags values as passed-in, since 197251875Speter * mkstemp didn't subscribe to our preference flags. 198251875Speter * 199251875Speter * We either have to unset the flags, or fix up the fd and other 200251875Speter * xthread and inherit bits appropriately. Since gettemp() above 201251875Speter * calls apr_file_open, our flags are respected in that code path. 202251875Speter */ 203251875Speter apr_os_file_put(fp, &fd, flags, p); 204251875Speter (*fp)->fname = apr_pstrdup(p, template); 205251875Speter 206251875Speter if (!(flags & APR_FOPEN_NOCLEANUP)) { 207251875Speter int flags; 208251875Speter 209251875Speter if ((flags = fcntl(fd, F_GETFD)) == -1) 210251875Speter return errno; 211251875Speter 212251875Speter flags |= FD_CLOEXEC; 213251875Speter if (fcntl(fd, F_SETFD, flags) == -1) 214251875Speter return errno; 215251875Speter 216251875Speter apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), 217251875Speter apr_unix_file_cleanup, 218251875Speter apr_unix_child_file_cleanup); 219251875Speter } 220251875Speter#endif 221251875Speter return APR_SUCCESS; 222251875Speter} 223251875Speter 224