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