Add support for tab-completion when selecting by rule
[alpine.git] / pith / osdep / temp_nam.c
blob98d536a158e755c696f7892e33bb641442df6975
1 /*
2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include <system.h>
17 #if HAVE_FCNTL_H
18 #include <fcntl.h>
19 #endif
21 #include "canaccess.h"
22 #include "temp_nam.h"
23 #include "../charconv/utf8.h"
24 #include "../charconv/filesys.h"
27 #ifdef _WINDOWS
29 #include <process.h>
31 #define ACCESSIBLE (WRITE_ACCESS)
32 #define PATH_SEP "\\"
34 #else /* UNIX */
36 #define ACCESSIBLE (WRITE_ACCESS|EXECUTE_ACCESS)
37 #define PATH_SEP "/"
39 #endif /* UNIX */
43 * Internal Prototypes
45 char *was_nonexistent_tmp_name(char *, size_t, char *);
50 * This routine is derived from BSD4.3 code,
51 * Copyright (c) 1987 Regents of the University of California.
52 * All rights reserved.
54 #if defined(LIBC_SCCS) && !defined(lint)
55 static char sccsid[] = "@(#)mktemp.c 5.7 (Berkeley) 6/27/88";
56 #endif /* LIBC_SCCS and not lint */
58 char *
59 was_nonexistent_tmp_name(char *as, size_t aslen, char *ext)
61 register char *start, *trv;
62 struct stat sbuf;
63 unsigned pid;
64 static unsigned n = 0;
65 int i;
66 int fd, tries = 0;
67 int f;
68 static unsigned long r = 0;
70 if(r == 0L)
71 r = (unsigned)getpid() + time((time_t *)0);
73 for(i = 5; i > 0; i--)
74 r = 1664525 * r + 1013904223;
76 pid = ((unsigned)getpid() * 100) + n++;
78 pid += (r % 50000L);
80 /* extra X's get set to 0's */
81 for(trv = as; *trv; ++trv)
85 * We should probably make the name random instead of having it
86 * be the pid.
88 while(*--trv == 'X'){
89 *trv = (pid % 10) + '0';
90 pid /= 10;
93 /* add the extension, enough room guaranteed by caller */
94 if(ext && *ext){
95 strncat(as, ".", aslen-strlen(as)-1);
96 as[aslen-1] = '\0';
97 strncat(as, ext, aslen-strlen(as)-1);
98 as[aslen-1] = '\0';
102 * Check for write permission on target directory; if you have
103 * six X's and you can't write the directory, this will run for
104 * a *very* long time.
106 for(start = ++trv; trv > as && *trv != PATH_SEP[0]; --trv)
109 if(*trv == PATH_SEP[0]){
110 #ifdef _WINDOWS
111 char treplace;
113 if((trv - as == 2) && isalpha(as[0]) && as[1] == ':')
114 trv++;
115 treplace = *trv;
116 *trv = '\0';
117 if(our_stat(as==trv ? PATH_SEP : as, &sbuf) || !(sbuf.st_mode & S_IFDIR))
118 return((char *)NULL);
120 *trv = treplace;
122 #else /* UNIX */
124 *trv = '\0';
126 if(our_stat(as==trv ? PATH_SEP : as, &sbuf) || !(sbuf.st_mode & S_IFDIR))
127 return((char *)NULL);
129 *trv = PATH_SEP[0];
131 #endif
133 else if (our_stat(".", &sbuf) == -1)
134 return((char *)NULL);
136 for(;;){
138 * Check with lstat to be sure we don't have
139 * a symlink. If lstat fails and no such file, then we
140 * have a winner. Otherwise, lstat shouldn't fail.
141 * If lstat succeeds, then skip it because it exists.
143 #ifndef _WINDOWS
144 if(our_lstat(as, &sbuf)){ /* lstat failed */
145 if(errno == ENOENT){ /* no such file, success */
146 #endif /* !_WINDOWS */
148 * Create the file so that the
149 * evil ones don't have a chance to put something there
150 * that they can read or write before we create it
151 * ourselves.
153 f = O_CREAT|O_EXCL|O_WRONLY|O_BINARY;
155 if((fd=our_open(as, f, 0600)) >= 0 && close(fd) == 0)
156 return(as);
157 else if(++tries > 3) /* open failed unexpectedly */
158 return((char *)NULL);
159 #ifndef _WINDOWS
161 else /* failed for unknown reason */
162 return((char *)NULL);
164 #endif /* !_WINDOWS */
166 for(trv = start;;){
167 if(!*trv)
168 return((char *)NULL);
171 * Change the digits from the initial values into
172 * lower case letters and try again.
174 if(*trv == 'z')
175 *trv++ = 'a';
176 else{
177 if(isdigit((unsigned char)*trv))
178 *trv = 'a';
179 else
180 ++*trv;
182 break;
186 /*NOTREACHED*/
191 * This routine is derived from BSD4.3 code,
192 * Copyright (c) 1988 Regents of the University of California.
193 * All rights reserved.
195 #if defined(LIBC_SCCS) && !defined(lint)
196 static char sccsid[] = "@(#)tmpnam.c 4.5 (Berkeley) 6/27/88";
197 #endif /* LIBC_SCCS and not lint */
198 /*----------------------------------------------------------------------
199 Return a unique file name in a given directory. This is not quite
200 the same as the usual tempnam() function, though it is similar.
201 We want it to use the TMPDIR/TMP/TEMP environment variable only if dir
202 is NULL, instead of using it regardless if it is set.
203 We also want it to be safer than tempnam().
204 If we return a filename, we are saying that the file did not exist
205 at the time this function was called (and it wasn't a symlink pointing
206 to a file that didn't exist, either).
207 If dir is NULL this is a temp file in a public directory. In that
208 case we create the file with permission 0600 before returning.
210 Args: dir -- The directory to create the name in
211 prefix -- Prefix of the name
213 Result: Malloc'd string equal to new name is returned. It must be free'd
214 by the caller. Returns the string on success and NULL on failure.
215 ----*/
216 char *
217 temp_nam(char *dir, char *prefix)
219 return(temp_nam_ext(dir, prefix, NULL));
223 /*----------------------------------------------------------------------
225 Like temp_nam but create a unique name with an extension.
227 Result: Malloc'd string equal to new name is returned. It must be free'd
228 by the caller. Returns the string on success and NULL on failure.
229 ----*/
230 char *
231 temp_nam_ext(char *dir, char *prefix, char *ext)
233 struct stat buf;
234 size_t l = 0, ll;
235 char *f, *name;
237 if(ext == NULL)
238 ext = "";
240 if(!(name = (char *)malloc(MAXPATH * sizeof(char))))
241 return((char *)NULL);
243 if(!dir && (f = getenv("TMPDIR")) && !our_stat(f, &buf) &&
244 (buf.st_mode&S_IFMT) == S_IFDIR &&
245 !can_access(f, ACCESSIBLE)){
246 strncpy(name, f, MAXPATH-1);
247 name[MAXPATH-1] = '\0';
248 goto done;
251 if(!dir && (f = getenv("TMP")) && !our_stat(f, &buf) &&
252 (buf.st_mode&S_IFMT) == S_IFDIR &&
253 !can_access(f, ACCESSIBLE)){
254 strncpy(name, f, MAXPATH-1);
255 name[MAXPATH-1] = '\0';
256 goto done;
259 if(!dir && (f = getenv("TEMP")) && !our_stat(f, &buf) &&
260 (buf.st_mode&S_IFMT) == S_IFDIR &&
261 !can_access(f, ACCESSIBLE)){
262 strncpy(name, f, MAXPATH-1);
263 name[MAXPATH-1] = '\0';
264 goto done;
267 if(dir){
268 strncpy(name, dir, MAXPATH-1);
269 name[MAXPATH-1] = '\0';
271 #ifdef _WINDOWS
272 if(!*dir || (isalpha(*dir) && *(dir+1) == ':' && !*(dir+2))){
273 strncat(name, PATH_SEP, MAXPATH-strlen(name)-1);
274 name[MAXPATH-1] = '\0';
276 #endif
278 if(!our_stat(name, &buf)
279 && (buf.st_mode&S_IFMT) == S_IFDIR
280 && !can_access(name, ACCESSIBLE)){
281 strncpy(name, dir, MAXPATH-1);
282 name[MAXPATH-1] = '\0';
283 goto done;
287 #ifndef P_tmpdir
288 #ifdef _WINDOWS
289 #define P_tmpdir "\\tmp"
290 #else /* UNIX */
291 #define P_tmpdir "/usr/tmp"
292 #endif /* UNIX */
293 #endif
295 if(!our_stat(P_tmpdir, &buf) &&
296 (buf.st_mode&S_IFMT) == S_IFDIR &&
297 !can_access(P_tmpdir, ACCESSIBLE)){
298 strncpy(name, P_tmpdir, MAXPATH-1);
299 name[MAXPATH-1] = '\0';
300 goto done;
303 #ifndef _WINDOWS
304 if(!our_stat("/tmp", &buf) &&
305 (buf.st_mode&S_IFMT) == S_IFDIR &&
306 !can_access("/tmp", ACCESSIBLE)){
307 strncpy(name, "/tmp", MAXPATH-1);
308 name[MAXPATH-1] = '\0';
309 goto done;
311 #endif
313 free((void *)name);
314 return((char *)NULL);
316 done:
317 f = NULL;
318 if(name[0] && *((f = &name[l=strlen(name)]) - 1) != PATH_SEP[0] && l+1 < MAXPATH){
319 *f++ = PATH_SEP[0];
320 *f = '\0';
321 l++;
324 if(prefix && (ll = strlen(prefix)) && l+ll < MAXPATH){
325 strncpy(f, prefix, MAXPATH-(f-name));
326 name[MAXPATH-1] = '\0';
327 f += ll;
328 l += ll;
331 if(l+5+(ext[0] ? strlen(ext)+1 : 0) < MAXPATH){
332 strncpy(f, "XXXXX", MAXPATH-(f-name));
333 name[MAXPATH-1] = '\0';
335 else{
336 free((void *)name);
337 return((char *)NULL);
340 return(was_nonexistent_tmp_name(name, MAXPATH, ext));