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
21static char	 mgcwd[NFILEN];
22
23/*
24 * Initialize anything the directory management routines need.
25 */
26void
27dirinit(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 */
39int
40changedir(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 */
71int
72showcwdir(int f, int n)
73{
74	ewprintf("Current directory: %s", mgcwd);
75	return (TRUE);
76}
77
78int
79getcwdir(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. */
88int
89makedir(int f, int n)
90{
91	return (ask_makedir());
92}
93
94int
95ask_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
112int
113do_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