1 /*
2 * Copyright (c) 1987 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that: (1) source distributions retain this entire copyright
7 * notice and comment, and (2) distributions including binaries display
8 * the following acknowledgement: ``This product includes software
9 * developed by the University of California, Berkeley and its contributors''
10 * in the documentation or other materials provided with the distribution
11 * and in all advertising materials mentioning features or use of this
12 * software. Neither the name of the University nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19 /* This is file MKTEMP.C */
20 /* This file may have been modified by DJ Delorie (Jan 1991). If so,
21 ** these modifications are Copyright (C) 1991 DJ Delorie.
22 */
23
24 /*
25 FUNCTION
26 <<mktemp>>, <<mkstemp>>, <<mkostemp>>, <<mkstemps>>,
27 <<mkostemps>>---generate unused file name
28 <<mkdtemp>>---generate unused directory
29
30 INDEX
31 mktemp
32 INDEX
33 mkdtemp
34 INDEX
35 mkstemp
36 INDEX
37 mkstemps
38 INDEX
39 mkostemp
40 INDEX
41 mkostemps
42 INDEX
43 _mktemp_r
44 INDEX
45 _mkdtemp_r
46 INDEX
47 _mkstemp_r
48 INDEX
49 _mkstemps_r
50 INDEX
51 _mkostemp_r
52 INDEX
53 _mkostemps_r
54
55 SYNOPSIS
56 #include <stdlib.h>
57 char *mktemp(char *<[path]>);
58 char *mkdtemp(char *<[path]>);
59 int mkstemp(char *<[path]>);
60 int mkstemps(char *<[path]>, int <[suffixlen]>);
61 int mkostemp(char *<[path]>, int <[flags]>);
62 int mkostemps(char *<[path]>, int <[suffixlen]>, int <[flags]>);
63
64 char *_mktemp_r(struct _reent *<[reent]>, char *<[path]>);
65 char *_mkdtemp_r(struct _reent *<[reent]>, char *<[path]>);
66 int *_mkstemp_r(struct _reent *<[reent]>, char *<[path]>);
67 int *_mkstemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>);
68 int *_mkostemp_r(struct _reent *<[reent]>, char *<[path]>,
69 int <[flags]>);
70 int *_mkostemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>,
71 int <[flags]>);
72
73 DESCRIPTION
74 <<mktemp>>, <<mkstemp>>, and <<mkstemps>> attempt to generate a file name
75 that is not yet in use for any existing file. <<mkstemp>> and <<mkstemps>>
76 create the file and open it for reading and writing; <<mktemp>> simply
77 generates the file name (making <<mktemp>> a security risk). <<mkostemp>>
78 and <<mkostemps>> allow the addition of other <<open>> flags, such
79 as <<O_CLOEXEC>>, <<O_APPEND>>, or <<O_SYNC>>. On platforms with a
80 separate text mode, <<mkstemp>> forces <<O_BINARY>>, while <<mkostemp>>
81 allows the choice between <<O_BINARY>>, <<O_TEXT>>, or 0 for default.
82 <<mkdtemp>> attempts to create a directory instead of a file, with a
83 permissions mask of 0700.
84
85 You supply a simple pattern for the generated file name, as the string
86 at <[path]>. The pattern should be a valid filename (including path
87 information if you wish) ending with at least six `<<X>>'
88 characters. The generated filename will match the leading part of the
89 name you supply, with the trailing `<<X>>' characters replaced by some
90 combination of digits and letters. With <<mkstemps>>, the `<<X>>'
91 characters end <[suffixlen]> bytes before the end of the string.
92
93 The alternate functions <<_mktemp_r>>, <<_mkdtemp_r>>, <<_mkstemp_r>>,
94 <<_mkostemp_r>>, <<_mkostemps_r>>, and <<_mkstemps_r>> are reentrant
95 versions. The extra argument <[reent]> is a pointer to a reentrancy
96 structure.
97
98 RETURNS
99 <<mktemp>> returns the pointer <[path]> to the modified string
100 representing an unused filename, unless it could not generate one, or
101 the pattern you provided is not suitable for a filename; in that case,
102 it returns <<NULL>>. Be aware that there is an inherent race between
103 generating the name and attempting to create a file by that name;
104 you are advised to use <<O_EXCL|O_CREAT>>.
105
106 <<mkdtemp>> returns the pointer <[path]> to the modified string if the
107 directory was created, otherwise it returns <<NULL>>.
108
109 <<mkstemp>>, <<mkstemps>>, <<mkostemp>>, and <<mkostemps>> return a file
110 descriptor to the newly created file, unless it could not generate an
111 unused filename, or the pattern you provided is not suitable for a
112 filename; in that case, it returns <<-1>>.
113
114 NOTES
115 Never use <<mktemp>>. The generated filenames are easy to guess and
116 there's a race between the test if the file exists and the creation
117 of the file. In combination this makes <<mktemp>> prone to attacks
118 and using it is a security risk. Whenever possible use <<mkstemp>>
119 instead. It doesn't suffer the race condition.
120
121 PORTABILITY
122 ANSI C does not require either <<mktemp>> or <<mkstemp>>; the System
123 V Interface Definition requires <<mktemp>> as of Issue 2. POSIX 2001
124 requires <<mkstemp>>, and POSIX 2008 requires <<mkdtemp>> while
125 deprecating <<mktemp>>. <<mkstemps>>, <<mkostemp>>, and <<mkostemps>>
126 are not standardized.
127
128 Supporting OS subroutines required: <<getpid>>, <<mkdir>>, <<open>>, <<stat>>.
129 */
130
131 #include <_ansi.h>
132 #include <stdlib.h>
133 #include <sys/types.h>
134 #include <fcntl.h>
135 #include <sys/stat.h>
136 #include <errno.h>
137 #include <stdio.h>
138 #include <ctype.h>
139 #include <unistd.h>
140
141 static int
_gettemp(struct _reent * ptr,char * path,register int * doopen,int domkdir,size_t suffixlen,int flags)142 _gettemp (struct _reent *ptr,
143 char *path,
144 register int *doopen,
145 int domkdir,
146 size_t suffixlen,
147 int flags)
148 {
149 register char *start, *trv;
150 char *end;
151 #ifdef __USE_INTERNAL_STAT64
152 struct stat64 sbuf;
153 #else
154 struct stat sbuf;
155 #endif
156 unsigned int pid;
157
158 pid = getpid ();
159 for (trv = path; *trv; ++trv) /* extra X's get set to 0's */
160 continue;
161 if (trv - path < suffixlen)
162 {
163 __errno_r(ptr) = EINVAL;
164 return 0;
165 }
166 trv -= suffixlen;
167 end = trv;
168 while (path < trv && *--trv == 'X')
169 {
170 *trv = (pid % 10) + '0';
171 pid /= 10;
172 }
173 if (end - trv < 6)
174 {
175 __errno_r(ptr) = EINVAL;
176 return 0;
177 }
178
179 /*
180 * Check the target directory; if you have six X's and it
181 * doesn't exist this runs for a *very* long time.
182 */
183
184 for (start = trv + 1;; --trv)
185 {
186 if (trv <= path)
187 break;
188 if (*trv == '/')
189 {
190 *trv = '\0';
191 #ifdef __USE_INTERNAL_STAT64
192 if (stat64 (path, &sbuf))
193 #else
194 if (stat (path, &sbuf))
195 #endif
196 return (0);
197 if (!(sbuf.st_mode & S_IFDIR))
198 {
199 __errno_r(ptr) = ENOTDIR;
200 return (0);
201 }
202 *trv = '/';
203 break;
204 }
205 }
206
207 for (;;)
208 {
209 #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
210 if (domkdir)
211 {
212 #ifdef HAVE_MKDIR
213 if (_mkdir_r (ptr, path, 0700) == 0)
214 return 1;
215 if (__errno_r(ptr) != EEXIST)
216 return 0;
217 #else /* !HAVE_MKDIR */
218 __errno_r(ptr) = ENOSYS;
219 return 0;
220 #endif /* !HAVE_MKDIR */
221 }
222 else
223 #endif /* _ELIX_LEVEL */
224 if (doopen)
225 {
226 if ((*doopen = open (path, O_CREAT | O_EXCL | O_RDWR | flags,
227 0600)) >= 0)
228 return 1;
229 if (__errno_r(ptr) != EEXIST)
230 return 0;
231 }
232 #ifdef __USE_INTERNAL_STAT64
233 else if (stat64 (path, &sbuf))
234 #else
235 else if (stat (path, &sbuf))
236 #endif
237 return (__errno_r(ptr) == ENOENT ? 1 : 0);
238
239 /* tricky little algorithm for backward compatibility */
240 for (trv = start;;)
241 {
242 if (trv == end)
243 return 0;
244 if (*trv == 'z')
245 *trv++ = 'a';
246 else
247 {
248 /* Safe, since it only encounters 7-bit characters. */
249 if (isdigit ((unsigned char) *trv))
250 *trv = 'a';
251 else
252 ++ * trv;
253 break;
254 }
255 }
256 }
257 /*NOTREACHED*/
258 }
259
260 #ifndef O_BINARY
261 # define O_BINARY 0
262 #endif
263
264 int
_mkstemp_r(struct _reent * ptr,char * path)265 _mkstemp_r (struct _reent *ptr,
266 char *path)
267 {
268 int fd;
269
270 return (_gettemp (ptr, path, &fd, 0, 0, O_BINARY) ? fd : -1);
271 }
272
273 #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
274 char *
_mkdtemp_r(struct _reent * ptr,char * path)275 _mkdtemp_r (struct _reent *ptr,
276 char *path)
277 {
278 return (_gettemp (ptr, path, (int *) NULL, 1, 0, 0) ? path : NULL);
279 }
280
281 int
_mkstemps_r(struct _reent * ptr,char * path,int len)282 _mkstemps_r (struct _reent *ptr,
283 char *path,
284 int len)
285 {
286 int fd;
287
288 return (_gettemp (ptr, path, &fd, 0, len, O_BINARY) ? fd : -1);
289 }
290
291 int
_mkostemp_r(struct _reent * ptr,char * path,int flags)292 _mkostemp_r (struct _reent *ptr,
293 char *path,
294 int flags)
295 {
296 int fd;
297
298 return (_gettemp (ptr, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
299 }
300
301 int
_mkostemps_r(struct _reent * ptr,char * path,int len,int flags)302 _mkostemps_r (struct _reent *ptr,
303 char *path,
304 int len,
305 int flags)
306 {
307 int fd;
308
309 return (_gettemp (ptr, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
310 }
311 #endif /* _ELIX_LEVEL */
312
313 char *
_mktemp_r(struct _reent * ptr,char * path)314 _mktemp_r (struct _reent *ptr,
315 char *path)
316 {
317 return (_gettemp (ptr, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
318 }
319
320 #ifndef _REENT_ONLY
321
322 int
mkstemp(char * path)323 mkstemp (char *path)
324 {
325 int fd;
326
327 return (_gettemp (_REENT, path, &fd, 0, 0, O_BINARY) ? fd : -1);
328 }
329
330 # if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
331 char *
mkdtemp(char * path)332 mkdtemp (char *path)
333 {
334 return (_gettemp (_REENT, path, (int *) NULL, 1, 0, 0) ? path : NULL);
335 }
336
337 int
mkstemps(char * path,int len)338 mkstemps (char *path,
339 int len)
340 {
341 int fd;
342
343 return (_gettemp (_REENT, path, &fd, 0, len, O_BINARY) ? fd : -1);
344 }
345
346 int
mkostemp(char * path,int flags)347 mkostemp (char *path,
348 int flags)
349 {
350 int fd;
351
352 return (_gettemp (_REENT, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
353 }
354
355 int
mkostemps(char * path,int len,int flags)356 mkostemps (char *path,
357 int len,
358 int flags)
359 {
360 int fd;
361
362 return (_gettemp (_REENT, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
363 }
364 # endif /* _ELIX_LEVEL */
365
366 char *
mktemp(char * path)367 mktemp (char *path)
368 {
369 return (_gettemp (_REENT, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
370 }
371
372 #endif /* ! defined (_REENT_ONLY) */
373