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