file_util_android.cc revision 00d26a728db2814620f390b418a7d6325ce5aca6
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__warn_references(mktemp,
53    "warning: mktemp() possibly used unsafely; consider using mkstemp()");
54
55char *
56mktemp(char *path)
57{
58	return(_mktemp(path));
59}
60
61
62static int
63_gettemp(char *path, int *doopen, int domkdir, int slen)
64{
65	char *start, *trv, *suffp;
66	struct stat sbuf;
67	int rval;
68	pid_t pid;
69
70	if (doopen && domkdir) {
71		errno = EINVAL;
72		return(0);
73	}
74
75	for (trv = path; *trv; ++trv)
76		;
77	trv -= slen;
78	suffp = trv;
79	--trv;
80	if (trv < path) {
81		errno = EINVAL;
82		return (0);
83	}
84	pid = getpid();
85	while (trv >= path && *trv == 'X' && pid != 0) {
86		*trv-- = (pid % 10) + '0';
87		pid /= 10;
88	}
89	while (trv >= path && *trv == 'X') {
90		char c;
91
92		pid = (arc4random() & 0xffff) % (26+26);
93		if (pid < 26)
94			c = pid + 'A';
95		else
96			c = (pid - 26) + 'a';
97		*trv-- = c;
98	}
99	start = trv + 1;
100
101	/*
102	 * check the target directory; if you have six X's and it
103	 * doesn't exist this runs for a *very* long time.
104	 */
105	if (doopen || domkdir) {
106		for (;; --trv) {
107			if (trv <= path)
108				break;
109			if (*trv == '/') {
110				*trv = '\0';
111				rval = stat(path, &sbuf);
112				*trv = '/';
113				if (rval != 0)
114					return(0);
115				if (!S_ISDIR(sbuf.st_mode)) {
116					errno = ENOTDIR;
117					return(0);
118				}
119				break;
120			}
121		}
122	}
123
124	for (;;) {
125		if (doopen) {
126			if ((*doopen =
127			    open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
128				return(1);
129			if (errno != EEXIST)
130				return(0);
131		} else if (domkdir) {
132			if (mkdir(path, 0700) == 0)
133				return(1);
134			if (errno != EEXIST)
135				return(0);
136		} else if (lstat(path, &sbuf))
137			return(errno == ENOENT ? 1 : 0);
138
139		/* tricky little algorithm for backward compatibility */
140		for (trv = start;;) {
141			if (!*trv)
142				return (0);
143			if (*trv == 'Z') {
144				if (trv == suffp)
145					return (0);
146				*trv++ = 'a';
147			} else {
148				if (isdigit(*trv))
149					*trv = 'a';
150				else if (*trv == 'z')	/* inc from z to A */
151					*trv = 'A';
152				else {
153					if (trv == suffp)
154						return (0);
155					++*trv;
156				}
157				break;
158			}
159		}
160	}
161	/*NOTREACHED*/
162}
163