Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdio / mktemp.c
blob265968198c35c8bcfbc98038ec47c07d7502d79d
1 /*
2 * Copyright (c) 1987 Regents of the University of California.
3 * All rights reserved.
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.
24 FUNCTION
25 <<mktemp>>, <<mkstemp>>, <<mkostemp>>, <<mkstemps>>,
26 <<mkostemps>>---generate unused file name
27 <<mkdtemp>>---generate unused directory
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
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]>);
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]>,
68 int <[flags]>);
69 int *_mkostemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>,
70 int <[flags]>);
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.
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
95 structure.
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>>.
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>>.
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.
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.
127 Supporting OS subroutines required: <<getpid>>, <<mkdir>>, <<open>>, <<stat>>.
130 #include <_ansi.h>
131 #include <stdlib.h>
132 #include <reent.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>
140 static int
141 _gettemp (struct _reent *ptr,
142 char *path,
143 register int *doopen,
144 int domkdir,
145 size_t suffixlen,
146 int flags)
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;
157 pid = _getpid_r (ptr);
158 for (trv = path; *trv; ++trv) /* extra X's get set to 0's */
159 continue;
160 if (trv - path < suffixlen)
162 _REENT_ERRNO(ptr) = EINVAL;
163 return 0;
165 trv -= suffixlen;
166 end = trv;
167 while (path < trv && *--trv == 'X')
169 *trv = (pid % 10) + '0';
170 pid /= 10;
172 if (end - trv < 6)
174 _REENT_ERRNO(ptr) = EINVAL;
175 return 0;
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)
185 if (trv <= path)
186 break;
187 if (*trv == '/')
189 *trv = '\0';
190 #ifdef __USE_INTERNAL_STAT64
191 if (_stat64_r (ptr, path, &sbuf))
192 #else
193 if (_stat_r (ptr, path, &sbuf))
194 #endif
195 return (0);
196 if (!(sbuf.st_mode & S_IFDIR))
198 _REENT_ERRNO(ptr) = ENOTDIR;
199 return (0);
201 *trv = '/';
202 break;
206 for (;;)
208 #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
209 if (domkdir)
211 #ifdef HAVE_MKDIR
212 if (_mkdir_r (ptr, 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 */
221 else
222 #endif /* _ELIX_LEVEL */
223 if (doopen)
225 if ((*doopen = _open_r (ptr, path, O_CREAT | O_EXCL | O_RDWR | flags,
226 0600)) >= 0)
227 return 1;
228 if (_REENT_ERRNO(ptr) != EEXIST)
229 return 0;
231 #ifdef __USE_INTERNAL_STAT64
232 else if (_stat64_r (ptr, path, &sbuf))
233 #else
234 else if (_stat_r (ptr, path, &sbuf))
235 #endif
236 return (_REENT_ERRNO(ptr) == ENOENT ? 1 : 0);
238 /* tricky little algorithm for backward compatibility */
239 for (trv = start;;)
241 if (trv == end)
242 return 0;
243 if (*trv == 'z')
244 *trv++ = 'a';
245 else
247 /* Safe, since it only encounters 7-bit characters. */
248 if (isdigit ((unsigned char) *trv))
249 *trv = 'a';
250 else
251 ++ * trv;
252 break;
256 /*NOTREACHED*/
259 #ifndef O_BINARY
260 # define O_BINARY 0
261 #endif
264 _mkstemp_r (struct _reent *ptr,
265 char *path)
267 int fd;
269 return (_gettemp (ptr, path, &fd, 0, 0, O_BINARY) ? fd : -1);
272 #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
273 char *
274 _mkdtemp_r (struct _reent *ptr,
275 char *path)
277 return (_gettemp (ptr, path, (int *) NULL, 1, 0, 0) ? path : NULL);
281 _mkstemps_r (struct _reent *ptr,
282 char *path,
283 int len)
285 int fd;
287 return (_gettemp (ptr, path, &fd, 0, len, O_BINARY) ? fd : -1);
291 _mkostemp_r (struct _reent *ptr,
292 char *path,
293 int flags)
295 int fd;
297 return (_gettemp (ptr, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
301 _mkostemps_r (struct _reent *ptr,
302 char *path,
303 int len,
304 int flags)
306 int fd;
308 return (_gettemp (ptr, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
310 #endif /* _ELIX_LEVEL */
312 char *
313 _mktemp_r (struct _reent *ptr,
314 char *path)
316 return (_gettemp (ptr, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
319 #ifndef _REENT_ONLY
322 mkstemp (char *path)
324 int fd;
326 return (_gettemp (_REENT, path, &fd, 0, 0, O_BINARY) ? fd : -1);
329 # if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
330 char *
331 mkdtemp (char *path)
333 return (_gettemp (_REENT, path, (int *) NULL, 1, 0, 0) ? path : NULL);
337 mkstemps (char *path,
338 int len)
340 int fd;
342 return (_gettemp (_REENT, path, &fd, 0, len, O_BINARY) ? fd : -1);
346 mkostemp (char *path,
347 int flags)
349 int fd;
351 return (_gettemp (_REENT, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
355 mkostemps (char *path,
356 int len,
357 int flags)
359 int fd;
361 return (_gettemp (_REENT, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
363 # endif /* _ELIX_LEVEL */
365 char *
366 mktemp (char *path)
368 return (_gettemp (_REENT, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
371 #endif /* ! defined (_REENT_ONLY) */