1// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/file_util.h"
6
7#include <fcntl.h>
8
9#include <string>
10#include <vector>
11
12#include "base/eintr_wrapper.h"
13#include "base/file_path.h"
14#include "base/string_util.h"
15
16// just lifted off bionic, no should find out why it doesn't get linked in
17
18static int _gettemp(char *, int *, int, int);
19
20extern uint32_t  arc4random();
21
22int
23mkstemps(char *path, int slen)
24{
25	int fd;
26
27	return (_gettemp(path, &fd, 0, slen) ? fd : -1);
28}
29
30int
31mkstemp(char *path)
32{
33	int fd;
34
35	return (_gettemp(path, &fd, 0, 0) ? fd : -1);
36}
37
38char *
39mkdtemp(char *path)
40{
41	return(_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL);
42}
43
44char *_mktemp(char *);
45
46char *
47_mktemp(char *path)
48{
49	return(_gettemp(path, (int *)NULL, 0, 0) ? path : (char *)NULL);
50}
51
52#ifdef __BIONIC__
53__warn_references(mktemp,
54    "warning: mktemp() possibly used unsafely; consider using mkstemp()");
55#endif
56
57char *
58mktemp(char *path)
59{
60	return(_mktemp(path));
61}
62
63
64static int
65_gettemp(char *path, int *doopen, int domkdir, int slen)
66{
67	char *start, *trv, *suffp;
68	struct stat sbuf;
69	int rval;
70	pid_t pid;
71
72	if (doopen && domkdir) {
73		errno = EINVAL;
74		return(0);
75	}
76
77	for (trv = path; *trv; ++trv)
78		;
79	trv -= slen;
80	suffp = trv;
81	--trv;
82	if (trv < path) {
83		errno = EINVAL;
84		return (0);
85	}
86	pid = getpid();
87	while (trv >= path && *trv == 'X' && pid != 0) {
88		*trv-- = (pid % 10) + '0';
89		pid /= 10;
90	}
91	while (trv >= path && *trv == 'X') {
92		char c;
93
94		pid = (arc4random() & 0xffff) % (26+26);
95		if (pid < 26)
96			c = pid + 'A';
97		else
98			c = (pid - 26) + 'a';
99		*trv-- = c;
100	}
101	start = trv + 1;
102
103	/*
104	 * check the target directory; if you have six X's and it
105	 * doesn't exist this runs for a *very* long time.
106	 */
107	if (doopen || domkdir) {
108		for (;; --trv) {
109			if (trv <= path)
110				break;
111			if (*trv == '/') {
112				*trv = '\0';
113				rval = stat(path, &sbuf);
114				*trv = '/';
115				if (rval != 0)
116					return(0);
117				if (!S_ISDIR(sbuf.st_mode)) {
118					errno = ENOTDIR;
119					return(0);
120				}
121				break;
122			}
123		}
124	}
125
126	for (;;) {
127		if (doopen) {
128			if ((*doopen =
129			    open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
130				return(1);
131			if (errno != EEXIST)
132				return(0);
133		} else if (domkdir) {
134			if (mkdir(path, 0700) == 0)
135				return(1);
136			if (errno != EEXIST)
137				return(0);
138		} else if (lstat(path, &sbuf))
139			return(errno == ENOENT ? 1 : 0);
140
141		/* tricky little algorithm for backward compatibility */
142		for (trv = start;;) {
143			if (!*trv)
144				return (0);
145			if (*trv == 'Z') {
146				if (trv == suffp)
147					return (0);
148				*trv++ = 'a';
149			} else {
150				if (isdigit(*trv))
151					*trv = 'a';
152				else if (*trv == 'z')	/* inc from z to A */
153					*trv = 'A';
154				else {
155					if (trv == suffp)
156						return (0);
157					++*trv;
158				}
159				break;
160			}
161		}
162	}
163	/*NOTREACHED*/
164}
165