]> git.saurik.com Git - apple/libc.git/blame - stdio/FreeBSD/mktemp.c
Libc-1353.11.2.tar.gz
[apple/libc.git] / stdio / FreeBSD / mktemp.c
CommitLineData
e9ce8d39
A
1/*
2 * Copyright (c) 1987, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
974e3884 13 * 3. Neither the name of the University nor the names of its contributors
e9ce8d39
A
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
5b2abdfb 30#if defined(LIBC_SCCS) && !defined(lint)
5b2abdfb 31static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
5b2abdfb 32#endif /* LIBC_SCCS and not lint */
9385eb3d 33#include <sys/cdefs.h>
e9ce8d39 34
9385eb3d 35#include "namespace.h"
b061a43b 36#include <assert.h>
1f2f436a 37#include <sys/param.h>
e9ce8d39
A
38#include <sys/stat.h>
39#include <fcntl.h>
40#include <errno.h>
41#include <stdio.h>
5b2abdfb
A
42#include <stdlib.h>
43#include <string.h>
e9ce8d39 44#include <ctype.h>
5b2abdfb 45#include <unistd.h>
9385eb3d 46#include "un-namespace.h"
5b2abdfb 47
974e3884
A
48#define ALLOWED_MKOSTEMP_FLAGS (O_APPEND | O_SHLOCK | O_EXLOCK | O_CLOEXEC)
49
9385eb3d 50char *_mktemp(char *);
5b2abdfb 51
974e3884
A
52typedef enum {
53 FTPP_DONE, FTPP_TRY_NEXT, FTPP_ERROR
54} find_temp_path_progress_t;
55
56/* A contract for actions that find_temp_path performs for every path from
57 * the template.
58 *
59 * If the desired path was found, set result and return FTPP_DONE.
60 * If an IO/FS error ocurred, set errno and return FTPP_ERROR.
61 * Otherwise return FTPP_TRY_NEXT.
62 */
63typedef find_temp_path_progress_t (*find_temp_path_action_t)(
b061a43b 64 int dfd, char *path, void *ctx, void *result);
974e3884 65
b061a43b 66static int find_temp_path(int dfd, char *path, int slen, bool stat_base_dir,
974e3884
A
67 find_temp_path_action_t action, void *action_ctx, void *action_result);
68
69static find_temp_path_progress_t _mkostemps_action(
b061a43b 70 int dfd, char *path, void *ctx, void *result);
974e3884 71static find_temp_path_progress_t _mktemp_action(
b061a43b 72 int dfd, char *path, void *ctx, void *result);
974e3884 73static find_temp_path_progress_t _mkdtemp_action(
b061a43b 74 int dfd, char *path, void *ctx, void *result);
974e3884 75static find_temp_path_progress_t _mkstemp_dprotected_np_action(
b061a43b 76 int dfd, char *path, void *ctx, void *result);
5b2abdfb 77
ad3c9f2a 78static const char padchar[] =
5b2abdfb
A
79"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
80
81int
974e3884
A
82mkostemps(char *path, int slen, int oflags)
83{
84 int fd;
85 if (oflags & ~ALLOWED_MKOSTEMP_FLAGS) {
86 errno = EINVAL;
87 return -1;
88 }
b061a43b
A
89 return (find_temp_path(AT_FDCWD, path, slen, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
90}
91
92int
93mkostempsat_np(int dfd, char *path, int slen, int oflags)
94{
95 int fd;
96 if (oflags & ~ALLOWED_MKOSTEMP_FLAGS) {
97 errno = EINVAL;
98 return -1;
99 }
100 return (find_temp_path(dfd, path, slen, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
974e3884
A
101}
102
103int
104mkstemps(char *path, int slen)
5b2abdfb
A
105{
106 int fd;
e9ce8d39 107
b061a43b
A
108 return (find_temp_path(AT_FDCWD, path, slen, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
109}
110
111int
112mkstempsat_np(int dfd, char *path, int slen)
113{
114 int fd;
115
116 return (find_temp_path(dfd, path, slen, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
5b2abdfb 117}
e9ce8d39
A
118
119int
974e3884
A
120mkostemp(char *path, int oflags)
121{
122 int fd;
123 if (oflags & ~ALLOWED_MKOSTEMP_FLAGS) {
124 errno = EINVAL;
125 return -1;
126 }
b061a43b 127 return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkostemps_action, &oflags, &fd) ? fd : -1);
974e3884
A
128}
129
130int
131mkstemp(char *path)
e9ce8d39
A
132{
133 int fd;
134
b061a43b 135 return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkostemps_action, NULL, &fd) ? fd : -1);
5b2abdfb
A
136}
137
138char *
974e3884 139mkdtemp(char *path)
5b2abdfb 140{
b061a43b
A
141 return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkdtemp_action, NULL, NULL) ?
142 path : (char *)NULL);
143}
144
145char *
146mkdtempat_np(int dfd, char *path)
147{
148 return (find_temp_path(dfd, path, 0, TRUE, _mkdtemp_action, NULL, NULL) ?
974e3884 149 path : (char *)NULL);
5b2abdfb
A
150}
151
152char *
974e3884 153_mktemp(char *path)
5b2abdfb 154{
b061a43b 155 return (find_temp_path(AT_FDCWD, path, 0, FALSE, _mktemp_action, NULL, NULL) ?
974e3884 156 path : (char *)NULL);
e9ce8d39
A
157}
158
9385eb3d
A
159__warn_references(mktemp,
160 "warning: mktemp() possibly used unsafely; consider using mkstemp()");
161
e9ce8d39 162char *
974e3884 163mktemp(char *path)
e9ce8d39 164{
9385eb3d 165 return (_mktemp(path));
e9ce8d39
A
166}
167
974e3884
A
168int
169mkstemp_dprotected_np(char *path, int class, int dpflags)
170{
171 int fd;
172 int ctx[2] = { class, dpflags };
173
b061a43b 174 return (find_temp_path(AT_FDCWD, path, 0, TRUE, _mkstemp_dprotected_np_action, &ctx, &fd) ? fd : -1);
974e3884
A
175}
176
177/* For every path matching a given template, invoke an action. Depending on
178 * the progress reported by action, stops or tries the next path.
179 * Returns 1 if succeeds, 0 and sets errno if fails.
180 */
e9ce8d39 181static int
b061a43b 182find_temp_path(int dfd, char *path, int slen, bool stat_base_dir,
974e3884 183 find_temp_path_action_t action, void *action_ctx, void *action_result)
e9ce8d39 184{
1f2f436a 185 char *start, *trv, *suffp, *carryp;
5b2abdfb 186 char *pad;
e9ce8d39 187 struct stat sbuf;
5b2abdfb
A
188 int rval;
189 uint32_t rand;
1f2f436a 190 char carrybuf[MAXPATHLEN];
5b2abdfb 191
974e3884 192 if (slen < 0) {
5b2abdfb 193 errno = EINVAL;
9385eb3d 194 return (0);
5b2abdfb
A
195 }
196
9385eb3d 197 for (trv = path; *trv != '\0'; ++trv)
5b2abdfb 198 ;
1f2f436a
A
199 if (trv - path >= MAXPATHLEN) {
200 errno = ENAMETOOLONG;
201 return (0);
202 }
5b2abdfb
A
203 trv -= slen;
204 suffp = trv;
205 --trv;
1f2f436a 206 if (trv < path || NULL != strchr(suffp, '/')) {
5b2abdfb
A
207 errno = EINVAL;
208 return (0);
209 }
e9ce8d39 210
5b2abdfb
A
211 /* Fill space with random characters */
212 while (trv >= path && *trv == 'X') {
1f2f436a 213 rand = arc4random_uniform(sizeof(padchar) - 1);
5b2abdfb 214 *trv-- = padchar[rand];
e9ce8d39 215 }
5b2abdfb 216 start = trv + 1;
e9ce8d39 217
1f2f436a
A
218 /* save first combination of random characters */
219 memcpy(carrybuf, start, suffp - start);
220
e9ce8d39 221 /*
5b2abdfb 222 * check the target directory.
e9ce8d39 223 */
974e3884 224 if (stat_base_dir) {
9385eb3d 225 for (; trv > path; --trv) {
5b2abdfb
A
226 if (*trv == '/') {
227 *trv = '\0';
b061a43b 228 rval = fstatat(dfd, path, &sbuf, 0);
5b2abdfb
A
229 *trv = '/';
230 if (rval != 0)
9385eb3d 231 return (0);
5b2abdfb
A
232 if (!S_ISDIR(sbuf.st_mode)) {
233 errno = ENOTDIR;
9385eb3d 234 return (0);
5b2abdfb
A
235 }
236 break;
e9ce8d39 237 }
e9ce8d39
A
238 }
239 }
240
241 for (;;) {
b061a43b 242 switch (action(dfd, path, action_ctx, action_result)) {
974e3884
A
243 case FTPP_DONE:
244 return (1);
245 case FTPP_ERROR:
246 return (0); // errno must be set by the action
247 default:
248 ; // FTPP_TRY_NEXT, fall-through
249 }
e9ce8d39 250
5b2abdfb 251 /* If we have a collision, cycle through the space of filenames */
1f2f436a
A
252 for (trv = start, carryp = carrybuf;;) {
253 /* have we tried all possible permutations? */
974e3884
A
254 if (trv == suffp) {
255 /* yes - exit with EEXIST */
256 errno = EEXIST;
257 return (0);
258 }
5b2abdfb 259 pad = strchr(padchar, *trv);
1f2f436a
A
260 if (pad == NULL) {
261 /* this should never happen */
262 errno = EIO;
263 return (0);
264 }
265 /* increment character */
266 *trv = (*++pad == '\0') ? padchar[0] : *pad;
267 /* carry to next position? */
268 if (*trv == *carryp) {
269 /* increment position and loop */
270 ++trv;
271 ++carryp;
272 } else {
273 /* try with new name */
e9ce8d39
A
274 break;
275 }
276 }
277 }
278 /*NOTREACHED*/
279}
974e3884
A
280
281static find_temp_path_progress_t
b061a43b 282_mkostemps_action(int dfd, char *path, void *ctx, void *result)
974e3884
A
283{
284 int oflags = (ctx != NULL) ? *((int *) ctx) : 0;
b061a43b 285 int fd = openat(dfd, path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600);
974e3884
A
286 if (fd >= 0) {
287 *((int *) result) = fd;
288 return FTPP_DONE;
289 }
290 return (errno == EEXIST) ?
291 FTPP_TRY_NEXT :
292 FTPP_ERROR; // errno is set already
293}
294
295static find_temp_path_progress_t
b061a43b 296_mktemp_action(int dfd, char *path, void *ctx __unused, void *result __unused)
974e3884
A
297{
298 struct stat sbuf;
b061a43b 299 if (fstatat(dfd, path, &sbuf, AT_SYMLINK_NOFOLLOW)) {
974e3884
A
300 // stat failed
301 return (errno == ENOENT) ?
302 FTPP_DONE : // path is vacant, done
303 FTPP_ERROR; // errno is set already
304 }
305 return FTPP_TRY_NEXT;
306}
307
308static find_temp_path_progress_t
b061a43b 309_mkdtemp_action(int dfd, char *path, void *ctx __unused, void *result __unused)
974e3884 310{
b061a43b 311 if (mkdirat(dfd, path, 0700) == 0)
974e3884
A
312 return FTPP_DONE;
313 return (errno == EEXIST) ?
314 FTPP_TRY_NEXT :
315 FTPP_ERROR; // errno is set already
316}
317
318static find_temp_path_progress_t
b061a43b 319_mkstemp_dprotected_np_action(int dfd, char *path, void *ctx, void *result)
974e3884 320{
b061a43b
A
321 assert(dfd == AT_FDCWD);
322
974e3884
A
323 int class = ((int *) ctx)[0];
324 int dpflags = ((int *) ctx)[1];
325 int fd = open_dprotected_np(path, O_CREAT|O_EXCL|O_RDWR, class, dpflags, 0600);
326 if (fd >= 0) {
327 *((int *) result) = fd;
328 return FTPP_DONE;
329 }
330 return (errno == EEXIST) ?
331 FTPP_TRY_NEXT :
332 FTPP_ERROR; // errno is set already
333}
334
335