xref: /openbsd/usr.bin/mg/dir.c (revision 5b133f3f)
1 /*	$OpenBSD: dir.c,v 1.33 2023/03/08 04:43:11 guenther Exp $	*/
2 
3 /* This file is in the public domain. */
4 
5 /*
6  * Name:	MG 2a
7  *		Directory management functions
8  * Created:	Ron Flax (ron@vsedev.vse.com)
9  *		Modified for MG 2a by Mic Kaczmarczik 03-Aug-1987
10  */
11 
12 #include <sys/queue.h>
13 #include <sys/stat.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <unistd.h>
18 
19 #include "def.h"
20 
21 static char	 mgcwd[NFILEN];
22 
23 /*
24  * Initialize anything the directory management routines need.
25  */
26 void
dirinit(void)27 dirinit(void)
28 {
29 	mgcwd[0] = '\0';
30 	if (getcwd(mgcwd, sizeof(mgcwd)) == NULL)
31 		ewprintf("Can't get current directory!");
32 	if (mgcwd[0] != '\0' && !(mgcwd[0] == '/' && mgcwd[1] == '\0'))
33 		(void)strlcat(mgcwd, "/", sizeof(mgcwd));
34 }
35 
36 /*
37  * Change current working directory.
38  */
39 int
changedir(int f,int n)40 changedir(int f, int n)
41 {
42 	char	bufc[NFILEN], *bufp;
43 
44 	(void)strlcpy(bufc, mgcwd, sizeof(bufc));
45 	if ((bufp = eread("Change default directory: ", bufc, NFILEN,
46 	    EFDEF | EFNEW | EFCR | EFFILE)) == NULL)
47 		return (ABORT);
48 	else if (bufp[0] == '\0')
49 		return (FALSE);
50 	/* Append trailing slash */
51 	if (chdir(bufc) == -1) {
52 		dobeep();
53 		ewprintf("Can't change dir to %s", bufc);
54 		return (FALSE);
55 	}
56 	if ((bufp = getcwd(mgcwd, sizeof(mgcwd))) == NULL) {
57 		if (bufc[0] == '/')
58 			(void)strlcpy(mgcwd, bufc, sizeof(mgcwd));
59 		else
60 			(void)strlcat(mgcwd, bufc, sizeof(mgcwd));
61 	}
62 	if (mgcwd[strlen(mgcwd) - 1] != '/')
63 		(void)strlcat(mgcwd, "/", sizeof(mgcwd));
64 	ewprintf("Current directory is now %s", mgcwd);
65 	return (TRUE);
66 }
67 
68 /*
69  * Show current directory.
70  */
71 int
showcwdir(int f,int n)72 showcwdir(int f, int n)
73 {
74 	ewprintf("Current directory: %s", mgcwd);
75 	return (TRUE);
76 }
77 
78 int
getcwdir(char * buf,size_t len)79 getcwdir(char *buf, size_t len)
80 {
81 	if (strlcpy(buf, mgcwd, len) >= len)
82 		return (FALSE);
83 
84 	return (TRUE);
85 }
86 
87 /* Create the directory and its parents. */
88 int
makedir(int f,int n)89 makedir(int f, int n)
90 {
91 	return (ask_makedir());
92 }
93 
94 int
ask_makedir(void)95 ask_makedir(void)
96 {
97 
98 	char		 bufc[NFILEN];
99 	char		*path;
100 
101 	if (getbufcwd(bufc, sizeof(bufc)) != TRUE)
102 		return (ABORT);
103 	if ((path = eread("Make directory: ", bufc, NFILEN,
104 	    EFDEF | EFNEW | EFCR | EFFILE)) == NULL)
105 		return (ABORT);
106 	else if (path[0] == '\0')
107 		return (FALSE);
108 
109 	return (do_makedir(path));
110 }
111 
112 int
do_makedir(char * path)113 do_makedir(char *path)
114 {
115 	struct stat	 sb;
116 	int		 finished, ishere;
117 	mode_t		 dir_mode, f_mode, oumask;
118 	char		*slash;
119 
120 	if ((path = adjustname(path, TRUE)) == NULL)
121 		return (FALSE);
122 
123 	/* Remove trailing slashes */
124 	slash = strrchr(path, '\0');
125 	while (--slash > path && *slash == '/')
126 		*slash = '\0';
127 
128 	slash = path;
129 
130 	oumask = umask(0);
131 	f_mode = 0777 & ~oumask;
132 	dir_mode = f_mode | S_IWUSR | S_IXUSR;
133 
134 	for (;;) {
135 		slash += strspn(slash, "/");
136 		slash += strcspn(slash, "/");
137 
138 		finished = (*slash == '\0');
139 		*slash = '\0';
140 
141 		ishere = !stat(path, &sb);
142 		if (finished && ishere) {
143 			dobeep();
144 			ewprintf("Cannot create directory %s: file exists",
145 			     path);
146 			return(FALSE);
147 		} else if (!finished && ishere && S_ISDIR(sb.st_mode)) {
148 			*slash = '/';
149 			continue;
150 		}
151 
152 		if (mkdir(path, finished ? f_mode : dir_mode) == 0) {
153 			if (f_mode > 0777 && chmod(path, f_mode) == -1) {
154 				umask(oumask);
155 				return (ABORT);
156 			}
157 		} else {
158 			if (!ishere || !S_ISDIR(sb.st_mode)) {
159 				if (!ishere) {
160 					dobeep();
161 					ewprintf("Creating directory: "
162 					    "permission denied, %s", path);
163 				} else
164 					eerase();
165 
166 				umask(oumask);
167 				return (FALSE);
168 			}
169 		}
170 
171 		if (finished)
172 			break;
173 
174 		*slash = '/';
175 	}
176 
177 	eerase();
178 	umask(oumask);
179 	return (TRUE);
180 }
181