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