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>>, <<mkstemps>>,
26 <<mkostemps>>---generate unused file name
27
28 INDEX
29 mktemp
30 INDEX
31 mkstemp
32 INDEX
33 mkstemps
34 INDEX
35 mkostemps
36
37 SYNOPSIS
38 #include <stdlib.h>
39 char *mktemp(char *<[path]>);
40 int mkstemp(char *<[path]>);
41 int mkstemps(char *<[path]>, int suffixlen);
42 int mkostemps(char *<[path]>, int suffixlen, int flags);
43
44 DESCRIPTION
45 <<mktemp>>, <<mkstemp>>, <<mkstemps>>, and <<mkostemps>> attempt to
46 generate a file name that is not yet in use for any existing file.
47 <<mkstemp>>, <<mkstemps>> and <mkostemps>> create the file and open it
48 for reading and writing; <<mktemp>> simply generates the file name
49 (making <<mktemp>> a security risk). <<mkostemps>> allow the addition
50 of other <<open>> flags, such as <<O_CLOEXEC>>, <<O_APPEND>>, or
51 <<O_SYNC>>. On platforms with a separate text mode, <<mkstemp>>
52 forces <<O_BINARY>>, while <<mkostemp>> allows the choice between
53 <<O_BINARY>>, <<O_TEXT>>, or 0 for default.
54
55 You supply a simple pattern for the generated file name, as the string
56 at <[path]>. The pattern should be a valid filename (including path
57 information if you wish) ending with at least six `<<X>>' characters.
58 The generated filename will match the leading part of the name you
59 supply, with the trailing `<<X>>' characters replaced by some
60 combination of digits and letters. With <<mkstemps>> and
61 <mkostemps>>, the `<<X>>' characters end <[suffixlen]> bytes before
62 the end of the string.
63
64 RETURNS
65 <<mktemp>> returns the pointer <[path]> to the modified string
66 representing an unused filename, unless it could not generate one, or
67 the pattern you provided is not suitable for a filename; in that case,
68 it returns <<NULL>>. Be aware that there is an inherent race between
69 generating the name and attempting to create a file by that name;
70 you are advised to use <<O_EXCL|O_CREAT>>.
71
72 <<mkstemp>>, <<mkstemps>> and <<mkostemps>> return a file descriptor
73 to the newly created file, unless it could not generate an unused
74 filename, or the pattern you provided is not suitable for a filename;
75 in that case, it returns <<-1>>.
76
77 NOTES
78 Never use <<mktemp>>. The generated filenames are easy to guess and
79 there's a race between the test if the file exists and the creation
80 of the file. In combination this makes <<mktemp>> prone to attacks
81 and using it is a security risk. Whenever possible use <<mkstemp>>
82 instead. It doesn't suffer the race condition.
83
84 PORTABILITY
85 ANSI C does not require either <<mktemp>> or <<mkstemp>>; the System V
86 Interface Definition requires <<mktemp>> as of Issue 2. POSIX 2001
87 requires <<mkstemp>> while deprecating <<mktemp>>. <<mkstemps>>, and
88 <<mkostemps>> are not standardized.
89
90 Supporting OS subroutines required: <<open>>
91 */
92
93 #define _DEFAULT_SOURCE
94 #include <_ansi.h>
95 #include <stdlib.h>
96 #include <sys/types.h>
97 #include <fcntl.h>
98 #include <errno.h>
99 #include <stdio.h>
100 #include <unistd.h>
101 #include <string.h>
102
103 static int
_gettemp(char * path,int suffixlen,int * doopen,int flags)104 _gettemp (char *path,
105 int suffixlen,
106 int *doopen,
107 int flags)
108 {
109 char *start, *trv;
110 char *end;
111
112 end = path + strlen(path) - suffixlen;
113 trv = end;
114
115 /* Replace 'X' with 'a' */
116 while (path < trv && *--trv == 'X')
117 *trv = 'a';
118
119 /* Make sure we got six Xs */
120 if (end - trv < 6)
121 {
122 errno = EINVAL;
123 return 0;
124 }
125
126 start = trv + 1;
127
128 for (;;)
129 {
130 /*
131 * Use open to check if the file exists to avoid depending on
132 * stat or access. Don't rely on O_EXCL working, although if it
133 * doesn't, this introduces a race condition
134 */
135 int fd = open(path, O_RDONLY);
136 if (fd < 0) {
137 if (errno != EACCES) {
138 if (errno != ENOENT)
139 return 0;
140 if (doopen)
141 {
142 fd = open (path, flags | O_CREAT | O_EXCL | O_RDWR,
143 0600);
144 if (fd >= 0) {
145 *doopen = fd;
146 return 1;
147 }
148 if (errno != EEXIST)
149 return 0;
150 } else {
151 return 1;
152 }
153 }
154 } else
155 close(fd);
156
157 /* Increment the string of letters to generate another name */
158 trv = start;
159 for(;;)
160 {
161 if (trv == end)
162 return 0;
163 if (*trv == 'z')
164 *trv++ = 'a';
165 else {
166 ++ * trv;
167 break;
168 }
169 }
170 }
171 /*NOTREACHED*/
172 }
173
174 int
mkstemp(char * template)175 mkstemp (char *template)
176 {
177 int fd;
178
179 return (_gettemp (template, 0, &fd, 0) ? fd : -1);
180 }
181
182 char *
mktemp(char * template)183 mktemp (char *template)
184 {
185 return (_gettemp (template, 0, (int *) NULL, 0) ? template : (char *) NULL);
186 }
187
188 #ifndef O_BINARY
189 #define O_BINARY 0
190 #endif
191 #ifndef O_TEXT
192 #define O_TEXT 0
193 #endif
194
195 int
mkstemps(char * template,int suffixlen)196 mkstemps(char *template, int suffixlen)
197 {
198 int fd;
199
200 return (_gettemp (template, suffixlen, &fd, O_BINARY) ? fd : -1);
201 }
202
203 int
mkostemps(char * template,int suffixlen,int flags)204 mkostemps(char *template, int suffixlen, int flags)
205 {
206 int fd;
207
208 flags &= (O_APPEND | O_CLOEXEC | O_SYNC | O_BINARY | O_TEXT);
209 return (_gettemp (template, suffixlen, &fd, flags) ? fd : -1);
210 }
211