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