2 * Copyright (c) 1987 Regents of the University of California.
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.
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.
25 <<mktemp>>, <<mkstemp>>, <<mkostemp>>, <<mkstemps>>,
26 <<mkostemps>>---generate unused file name
27 <<mkdtemp>>---generate unused directory
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]>);
63 char *_mktemp_r(struct _reent *<[reent]>, char *<[path]>);
64 char *_mkdtemp_r(struct _reent *<[reent]>, char *<[path]>);
65 int *_mkstemp_r(struct _reent *<[reent]>, char *<[path]>);
66 int *_mkstemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>);
67 int *_mkostemp_r(struct _reent *<[reent]>, char *<[path]>,
69 int *_mkostemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>,
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.
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.
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
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>>.
105 <<mkdtemp>> returns the pointer <[path]> to the modified string if the
106 directory was created, otherwise it returns <<NULL>>.
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>>.
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.
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.
127 Supporting OS subroutines required: <<getpid>>, <<mkdir>>, <<open>>, <<stat>>.
133 #include <sys/types.h>
135 #include <sys/stat.h>
141 _gettemp (struct _reent
*ptr
,
143 register int *doopen
,
148 register char *start
, *trv
;
150 #ifdef __USE_INTERNAL_STAT64
157 pid
= _getpid_r (ptr
);
158 for (trv
= path
; *trv
; ++trv
) /* extra X's get set to 0's */
160 if (trv
- path
< suffixlen
)
162 _REENT_ERRNO(ptr
) = EINVAL
;
167 while (path
< trv
&& *--trv
== 'X')
169 *trv
= (pid
% 10) + '0';
174 _REENT_ERRNO(ptr
) = EINVAL
;
179 * Check the target directory; if you have six X's and it
180 * doesn't exist this runs for a *very* long time.
183 for (start
= trv
+ 1;; --trv
)
190 #ifdef __USE_INTERNAL_STAT64
191 if (_stat64_r (ptr
, path
, &sbuf
))
193 if (_stat_r (ptr
, path
, &sbuf
))
196 if (!(sbuf
.st_mode
& S_IFDIR
))
198 _REENT_ERRNO(ptr
) = ENOTDIR
;
208 #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
212 if (_mkdir_r (ptr
, path
, 0700) == 0)
214 if (_REENT_ERRNO(ptr
) != EEXIST
)
216 #else /* !HAVE_MKDIR */
217 _REENT_ERRNO(ptr
) = ENOSYS
;
219 #endif /* !HAVE_MKDIR */
222 #endif /* _ELIX_LEVEL */
225 if ((*doopen
= _open_r (ptr
, path
, O_CREAT
| O_EXCL
| O_RDWR
| flags
,
228 if (_REENT_ERRNO(ptr
) != EEXIST
)
231 #ifdef __USE_INTERNAL_STAT64
232 else if (_stat64_r (ptr
, path
, &sbuf
))
234 else if (_stat_r (ptr
, path
, &sbuf
))
236 return (_REENT_ERRNO(ptr
) == ENOENT
? 1 : 0);
238 /* tricky little algorithm for backward compatibility */
247 /* Safe, since it only encounters 7-bit characters. */
248 if (isdigit ((unsigned char) *trv
))
264 _mkstemp_r (struct _reent
*ptr
,
269 return (_gettemp (ptr
, path
, &fd
, 0, 0, O_BINARY
) ? fd
: -1);
272 #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
274 _mkdtemp_r (struct _reent
*ptr
,
277 return (_gettemp (ptr
, path
, (int *) NULL
, 1, 0, 0) ? path
: NULL
);
281 _mkstemps_r (struct _reent
*ptr
,
287 return (_gettemp (ptr
, path
, &fd
, 0, len
, O_BINARY
) ? fd
: -1);
291 _mkostemp_r (struct _reent
*ptr
,
297 return (_gettemp (ptr
, path
, &fd
, 0, 0, flags
& ~O_ACCMODE
) ? fd
: -1);
301 _mkostemps_r (struct _reent
*ptr
,
308 return (_gettemp (ptr
, path
, &fd
, 0, len
, flags
& ~O_ACCMODE
) ? fd
: -1);
310 #endif /* _ELIX_LEVEL */
313 _mktemp_r (struct _reent
*ptr
,
316 return (_gettemp (ptr
, path
, (int *) NULL
, 0, 0, 0) ? path
: (char *) NULL
);
326 return (_gettemp (_REENT
, path
, &fd
, 0, 0, O_BINARY
) ? fd
: -1);
329 # if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
333 return (_gettemp (_REENT
, path
, (int *) NULL
, 1, 0, 0) ? path
: NULL
);
337 mkstemps (char *path
,
342 return (_gettemp (_REENT
, path
, &fd
, 0, len
, O_BINARY
) ? fd
: -1);
346 mkostemp (char *path
,
351 return (_gettemp (_REENT
, path
, &fd
, 0, 0, flags
& ~O_ACCMODE
) ? fd
: -1);
355 mkostemps (char *path
,
361 return (_gettemp (_REENT
, path
, &fd
, 0, len
, flags
& ~O_ACCMODE
) ? fd
: -1);
363 # endif /* _ELIX_LEVEL */
368 return (_gettemp (_REENT
, path
, (int *) NULL
, 0, 0, 0) ? path
: (char *) NULL
);
371 #endif /* ! defined (_REENT_ONLY) */