1/* Adapted from NetBSB libc by Dieter Baron */
2
3/*  NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp   */
4
5/*
6 * Copyright (c) 1987, 1993
7 *  The Regents of the University of California.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/types.h>
35#include <sys/stat.h>
36
37#include <assert.h>
38#include <ctype.h>
39#include <errno.h>
40#include <fcntl.h>
41#ifdef _WIN32
42#include <io.h>
43#endif
44#include <stdio.h>
45#include <stdlib.h>
46
47#ifndef O_BINARY
48#define O_BINARY 0
49#endif
50
51
52int
53_zip_mkstemp(char *path)
54{
55#ifdef _WIN32
56    int ret;
57    ret = _creat(_mktemp(path), _S_IREAD|_S_IWRITE);
58    if (ret == -1) {
59        return 0;
60    } else {
61        return ret;
62    }
63#else
64    int fd;
65    char *start, *trv;
66    struct stat sbuf;
67    pid_t pid;
68
69    /* To guarantee multiple calls generate unique names even if
70       the file is not created. 676 different possibilities with 7
71       or more X's, 26 with 6 or less. */
72    static char xtra[2] = "aa";
73    int xcnt = 0;
74
75    pid = getpid();
76
77    /* Move to end of path and count trailing X's. */
78    for (trv = path; *trv; ++trv)
79        if (*trv == 'X')
80            xcnt++;
81        else
82            xcnt = 0;
83
84    /* Use at least one from xtra.  Use 2 if more than 6 X's. */
85    if (*(trv - 1) == 'X')
86        *--trv = xtra[0];
87    if (xcnt > 6 && *(trv - 1) == 'X')
88        *--trv = xtra[1];
89
90    /* Set remaining X's to pid digits with 0's to the left. */
91    while (*--trv == 'X') {
92        *trv = (pid % 10) + '0';
93        pid /= 10;
94    }
95
96    /* update xtra for next call. */
97    if (xtra[0] != 'z')
98        xtra[0]++;
99    else {
100        xtra[0] = 'a';
101        if (xtra[1] != 'z')
102            xtra[1]++;
103        else
104            xtra[1] = 'a';
105    }
106
107    /*
108     * check the target directory; if you have six X's and it
109     * doesn't exist this runs for a *very* long time.
110     */
111    for (start = trv + 1;; --trv) {
112        if (trv <= path)
113            break;
114        if (*trv == '/') {
115            *trv = '\0';
116            if (stat(path, &sbuf))
117                return (0);
118            if (!S_ISDIR(sbuf.st_mode)) {
119                errno = ENOTDIR;
120                return (0);
121            }
122            *trv = '/';
123            break;
124        }
125    }
126
127    for (;;) {
128        if ((fd=open(path, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600)) >= 0)
129            return (fd);
130        if (errno != EEXIST)
131            return (0);
132
133        /* tricky little algorithm for backward compatibility */
134        for (trv = start;;) {
135            if (!*trv)
136                return (0);
137            if (*trv == 'z')
138                *trv++ = 'a';
139            else {
140                if (isdigit((unsigned char)*trv))
141                    *trv = 'a';
142                else
143                    ++*trv;
144                break;
145            }
146        }
147    }
148    /*NOTREACHED*/
149#endif
150}
151