• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 static int _gettemp(char *, int *, int, int);
19 
20 extern uint32_t  arc4random();
21 
22 int
mkstemps(char * path,int slen)23 mkstemps(char *path, int slen)
24 {
25 	int fd;
26 
27 	return (_gettemp(path, &fd, 0, slen) ? fd : -1);
28 }
29 
30 int
mkstemp(char * path)31 mkstemp(char *path)
32 {
33 	int fd;
34 
35 	return (_gettemp(path, &fd, 0, 0) ? fd : -1);
36 }
37 
38 char *
mkdtemp(char * path)39 mkdtemp(char *path)
40 {
41 	return(_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL);
42 }
43 
44 char *_mktemp(char *);
45 
46 char *
_mktemp(char * path)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 
57 char *
mktemp(char * path)58 mktemp(char *path)
59 {
60 	return(_mktemp(path));
61 }
62 
63 
64 static int
_gettemp(char * path,int * doopen,int domkdir,int slen)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