xref: /original-bsd/lib/libc/stdio/mktemp.c (revision 1a56dd2c)
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 this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific written prior permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #if defined(LIBC_SCCS) && !defined(lint)
14 static char sccsid[] = "@(#)mktemp.c	5.5 (Berkeley) 11/30/87";
15 #endif LIBC_SCCS and not lint
16 
17 #include <sys/types.h>
18 #include <sys/file.h>
19 #include <sys/stat.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <ctype.h>
23 
24 #define	YES	1
25 #define	NO	0
26 
27 mkstemp(as)
28 	char	*as;
29 {
30 	int	fd;
31 
32 	return (_gettemp(as, &fd) ? fd : -1);
33 }
34 
35 char *
36 mktemp(as)
37 	char	*as;
38 {
39 	return(_gettemp(as, (int *)NULL) ? as : (char *)NULL);
40 }
41 
42 static
43 _gettemp(as, doopen)
44 	char	*as;
45 	register int	*doopen;
46 {
47 	extern int	errno;
48 	register char	*start, *trv;
49 	struct stat	sbuf;
50 	u_int	pid;
51 
52 	pid = getpid();
53 
54 	/* extra X's get set to 0's */
55 	for (trv = as; *trv; ++trv);
56 	while (*--trv == 'X') {
57 		*trv = (pid % 10) + '0';
58 		pid /= 10;
59 	}
60 
61 	/*
62 	 * check for write permission on target directory; if you have
63 	 * six X's and you can't write the directory, this will run for
64 	 * a *very* long time.
65 	 */
66 	for (start = ++trv; trv > as && *trv != '/'; --trv);
67 	if (*trv == '/') {
68 		*trv = '\0';
69 		if (stat(as, &sbuf) || !(sbuf.st_mode & S_IFDIR))
70 			return(NO);
71 		*trv = '/';
72 	}
73 	else if (stat(".", &sbuf) == -1)
74 		return(NO);
75 
76 	for (;;) {
77 		if (doopen) {
78 		    if ((*doopen = open(as, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
79 			return(YES);
80 		    if (errno != EEXIST)
81 			return(NO);
82 		}
83 		else if (stat(as, &sbuf))
84 			return(errno == ENOENT ? YES : NO);
85 
86 		/* tricky little algorithm for backward compatibility */
87 		for (trv = start;;) {
88 			if (!*trv)
89 				return(NO);
90 			if (*trv == 'z')
91 				*trv++ = 'a';
92 			else {
93 				if (isdigit(*trv))
94 					*trv = 'a';
95 				else
96 					++*trv;
97 				break;
98 			}
99 		}
100 	}
101 	/*NOTREACHED*/
102 }
103