xref: /original-bsd/lib/libc/stdio/mktemp.c (revision ea3a8ee8)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)mktemp.c	5.11 (Berkeley) 07/12/92";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <ctype.h>
18 
19 static int _gettemp();
20 
21 mkstemp(path)
22 	char *path;
23 {
24 	int fd;
25 
26 	return (_gettemp(path, &fd) ? fd : -1);
27 }
28 
29 char *
30 mktemp(path)
31 	char *path;
32 {
33 	return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
34 }
35 
36 static
37 _gettemp(path, doopen)
38 	char *path;
39 	register int *doopen;
40 {
41 	extern int errno;
42 	register char *start, *trv;
43 	struct stat sbuf;
44 	u_int pid;
45 
46 	pid = getpid();
47 	for (trv = path; *trv; ++trv);		/* extra X's get set to 0's */
48 	while (*--trv == 'X') {
49 		*trv = (pid % 10) + '0';
50 		pid /= 10;
51 	}
52 
53 	/*
54 	 * check the target directory; if you have six X's and it
55 	 * doesn't exist this runs for a *very* long time.
56 	 */
57 	for (start = trv + 1;; --trv) {
58 		if (trv <= path)
59 			break;
60 		if (*trv == '/') {
61 			*trv = '\0';
62 			if (stat(path, &sbuf))
63 				return(0);
64 			if (!S_ISDIR(sbuf.st_mode)) {
65 				errno = ENOTDIR;
66 				return(0);
67 			}
68 			*trv = '/';
69 			break;
70 		}
71 	}
72 
73 	for (;;) {
74 		if (doopen) {
75 			if ((*doopen =
76 			    open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
77 				return(1);
78 			if (errno != EEXIST)
79 				return(0);
80 		}
81 		else if (stat(path, &sbuf))
82 			return(errno == ENOENT ? 1 : 0);
83 
84 		/* tricky little algorithm for backward compatibility */
85 		for (trv = start;;) {
86 			if (!*trv)
87 				return(0);
88 			if (*trv == 'z')
89 				*trv++ = 'a';
90 			else {
91 				if (isdigit(*trv))
92 					*trv = 'a';
93 				else
94 					++*trv;
95 				break;
96 			}
97 		}
98 	}
99 	/*NOTREACHED*/
100 }
101