1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: temp_nam.c 1012 2008-03-26 00:44:22Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2020 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
25 #include "canaccess.h"
27 #include "../charconv/utf8.h"
28 #include "../charconv/filesys.h"
35 #define ACCESSIBLE (WRITE_ACCESS)
40 #define ACCESSIBLE (WRITE_ACCESS|EXECUTE_ACCESS)
49 char *was_nonexistent_tmp_name(char *, size_t, char *);
54 * This routine is derived from BSD4.3 code,
55 * Copyright (c) 1987 Regents of the University of California.
56 * All rights reserved.
58 #if defined(LIBC_SCCS) && !defined(lint)
59 static char sccsid
[] = "@(#)mktemp.c 5.7 (Berkeley) 6/27/88";
60 #endif /* LIBC_SCCS and not lint */
63 was_nonexistent_tmp_name(char *as
, size_t aslen
, char *ext
)
65 register char *start
, *trv
;
68 static unsigned n
= 0;
72 static unsigned long r
= 0;
75 r
= (unsigned)getpid() + time((time_t *)0);
77 for(i
= 5; i
> 0; i
--)
78 r
= 1664525 * r
+ 1013904223;
80 pid
= ((unsigned)getpid() * 100) + n
++;
84 /* extra X's get set to 0's */
85 for(trv
= as
; *trv
; ++trv
)
89 * We should probably make the name random instead of having it
93 *trv
= (pid
% 10) + '0';
97 /* add the extension, enough room guaranteed by caller */
99 strncat(as
, ".", aslen
-strlen(as
)-1);
101 strncat(as
, ext
, aslen
-strlen(as
)-1);
106 * Check for write permission on target directory; if you have
107 * six X's and you can't write the directory, this will run for
108 * a *very* long time.
110 for(start
= ++trv
; trv
> as
&& *trv
!= PATH_SEP
[0]; --trv
)
113 if(*trv
== PATH_SEP
[0]){
117 if((trv
- as
== 2) && isalpha(as
[0]) && as
[1] == ':')
121 if(our_stat(as
==trv
? PATH_SEP
: as
, &sbuf
) || !(sbuf
.st_mode
& S_IFDIR
))
122 return((char *)NULL
);
130 if(our_stat(as
==trv
? PATH_SEP
: as
, &sbuf
) || !(sbuf
.st_mode
& S_IFDIR
))
131 return((char *)NULL
);
137 else if (our_stat(".", &sbuf
) == -1)
138 return((char *)NULL
);
142 * Check with lstat to be sure we don't have
143 * a symlink. If lstat fails and no such file, then we
144 * have a winner. Otherwise, lstat shouldn't fail.
145 * If lstat succeeds, then skip it because it exists.
148 if(our_lstat(as
, &sbuf
)){ /* lstat failed */
149 if(errno
== ENOENT
){ /* no such file, success */
150 #endif /* !_WINDOWS */
152 * Create the file so that the
153 * evil ones don't have a chance to put something there
154 * that they can read or write before we create it
157 f
= O_CREAT
|O_EXCL
|O_WRONLY
|O_BINARY
;
159 if((fd
=our_open(as
, f
, 0600)) >= 0 && close(fd
) == 0)
161 else if(++tries
> 3) /* open failed unexpectedly */
162 return((char *)NULL
);
165 else /* failed for unknown reason */
166 return((char *)NULL
);
168 #endif /* !_WINDOWS */
172 return((char *)NULL
);
175 * Change the digits from the initial values into
176 * lower case letters and try again.
181 if(isdigit((unsigned char)*trv
))
195 * This routine is derived from BSD4.3 code,
196 * Copyright (c) 1988 Regents of the University of California.
197 * All rights reserved.
199 #if defined(LIBC_SCCS) && !defined(lint)
200 static char sccsid
[] = "@(#)tmpnam.c 4.5 (Berkeley) 6/27/88";
201 #endif /* LIBC_SCCS and not lint */
202 /*----------------------------------------------------------------------
203 Return a unique file name in a given directory. This is not quite
204 the same as the usual tempnam() function, though it is similar.
205 We want it to use the TMPDIR/TMP/TEMP environment variable only if dir
206 is NULL, instead of using it regardless if it is set.
207 We also want it to be safer than tempnam().
208 If we return a filename, we are saying that the file did not exist
209 at the time this function was called (and it wasn't a symlink pointing
210 to a file that didn't exist, either).
211 If dir is NULL this is a temp file in a public directory. In that
212 case we create the file with permission 0600 before returning.
214 Args: dir -- The directory to create the name in
215 prefix -- Prefix of the name
217 Result: Malloc'd string equal to new name is returned. It must be free'd
218 by the caller. Returns the string on success and NULL on failure.
221 temp_nam(char *dir
, char *prefix
)
223 return(temp_nam_ext(dir
, prefix
, NULL
));
227 /*----------------------------------------------------------------------
229 Like temp_nam but create a unique name with an extension.
231 Result: Malloc'd string equal to new name is returned. It must be free'd
232 by the caller. Returns the string on success and NULL on failure.
235 temp_nam_ext(char *dir
, char *prefix
, char *ext
)
244 if(!(name
= (char *)malloc(MAXPATH
* sizeof(char))))
245 return((char *)NULL
);
247 if(!dir
&& (f
= getenv("TMPDIR")) && !our_stat(f
, &buf
) &&
248 (buf
.st_mode
&S_IFMT
) == S_IFDIR
&&
249 !can_access(f
, ACCESSIBLE
)){
250 strncpy(name
, f
, MAXPATH
-1);
251 name
[MAXPATH
-1] = '\0';
255 if(!dir
&& (f
= getenv("TMP")) && !our_stat(f
, &buf
) &&
256 (buf
.st_mode
&S_IFMT
) == S_IFDIR
&&
257 !can_access(f
, ACCESSIBLE
)){
258 strncpy(name
, f
, MAXPATH
-1);
259 name
[MAXPATH
-1] = '\0';
263 if(!dir
&& (f
= getenv("TEMP")) && !our_stat(f
, &buf
) &&
264 (buf
.st_mode
&S_IFMT
) == S_IFDIR
&&
265 !can_access(f
, ACCESSIBLE
)){
266 strncpy(name
, f
, MAXPATH
-1);
267 name
[MAXPATH
-1] = '\0';
272 strncpy(name
, dir
, MAXPATH
-1);
273 name
[MAXPATH
-1] = '\0';
276 if(!*dir
|| (isalpha(*dir
) && *(dir
+1) == ':' && !*(dir
+2))){
277 strncat(name
, PATH_SEP
, MAXPATH
-strlen(name
)-1);
278 name
[MAXPATH
-1] = '\0';
282 if(!our_stat(name
, &buf
)
283 && (buf
.st_mode
&S_IFMT
) == S_IFDIR
284 && !can_access(name
, ACCESSIBLE
)){
285 strncpy(name
, dir
, MAXPATH
-1);
286 name
[MAXPATH
-1] = '\0';
293 #define P_tmpdir "\\tmp"
295 #define P_tmpdir "/usr/tmp"
299 if(!our_stat(P_tmpdir
, &buf
) &&
300 (buf
.st_mode
&S_IFMT
) == S_IFDIR
&&
301 !can_access(P_tmpdir
, ACCESSIBLE
)){
302 strncpy(name
, P_tmpdir
, MAXPATH
-1);
303 name
[MAXPATH
-1] = '\0';
308 if(!our_stat("/tmp", &buf
) &&
309 (buf
.st_mode
&S_IFMT
) == S_IFDIR
&&
310 !can_access("/tmp", ACCESSIBLE
)){
311 strncpy(name
, "/tmp", MAXPATH
-1);
312 name
[MAXPATH
-1] = '\0';
318 return((char *)NULL
);
322 if(name
[0] && *((f
= &name
[l
=strlen(name
)]) - 1) != PATH_SEP
[0] && l
+1 < MAXPATH
){
328 if(prefix
&& (ll
= strlen(prefix
)) && l
+ll
< MAXPATH
){
329 strncpy(f
, prefix
, MAXPATH
-(f
-name
));
330 name
[MAXPATH
-1] = '\0';
335 if(l
+5+(ext
[0] ? strlen(ext
)+1 : 0) < MAXPATH
){
336 strncpy(f
, "XXXXX", MAXPATH
-(f
-name
));
337 name
[MAXPATH
-1] = '\0';
341 return((char *)NULL
);
344 return(was_nonexistent_tmp_name(name
, MAXPATH
, ext
));