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