xref: /minix3/external/bsd/pkg_install/dist/lib/remove.c (revision a824f5a1008ee67499d167f8c48e64aae26960ca)
1*a824f5a1SJean-Baptiste Boric /*	$NetBSD: remove.c,v 1.1.1.2 2009/08/06 16:55:29 joerg Exp $	*/
2*a824f5a1SJean-Baptiste Boric 
3*a824f5a1SJean-Baptiste Boric /*-
4*a824f5a1SJean-Baptiste Boric  * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
5*a824f5a1SJean-Baptiste Boric  * All rights reserved.
6*a824f5a1SJean-Baptiste Boric  *
7*a824f5a1SJean-Baptiste Boric  * Redistribution and use in source and binary forms, with or without
8*a824f5a1SJean-Baptiste Boric  * modification, are permitted provided that the following conditions
9*a824f5a1SJean-Baptiste Boric  * are met:
10*a824f5a1SJean-Baptiste Boric  *
11*a824f5a1SJean-Baptiste Boric  * 1. Redistributions of source code must retain the above copyright
12*a824f5a1SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer.
13*a824f5a1SJean-Baptiste Boric  * 2. Redistributions in binary form must reproduce the above copyright
14*a824f5a1SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer in
15*a824f5a1SJean-Baptiste Boric  *    the documentation and/or other materials provided with the
16*a824f5a1SJean-Baptiste Boric  *    distribution.
17*a824f5a1SJean-Baptiste Boric  *
18*a824f5a1SJean-Baptiste Boric  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19*a824f5a1SJean-Baptiste Boric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20*a824f5a1SJean-Baptiste Boric  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21*a824f5a1SJean-Baptiste Boric  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22*a824f5a1SJean-Baptiste Boric  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23*a824f5a1SJean-Baptiste Boric  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*a824f5a1SJean-Baptiste Boric  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*a824f5a1SJean-Baptiste Boric  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26*a824f5a1SJean-Baptiste Boric  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27*a824f5a1SJean-Baptiste Boric  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28*a824f5a1SJean-Baptiste Boric  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*a824f5a1SJean-Baptiste Boric  * SUCH DAMAGE.
30*a824f5a1SJean-Baptiste Boric  */
31*a824f5a1SJean-Baptiste Boric 
32*a824f5a1SJean-Baptiste Boric #if HAVE_CONFIG_H
33*a824f5a1SJean-Baptiste Boric #include "config.h"
34*a824f5a1SJean-Baptiste Boric #endif
35*a824f5a1SJean-Baptiste Boric 
36*a824f5a1SJean-Baptiste Boric #include <nbcompat.h>
37*a824f5a1SJean-Baptiste Boric 
38*a824f5a1SJean-Baptiste Boric #if HAVE_SYS_CDEFS_H
39*a824f5a1SJean-Baptiste Boric #include <sys/cdefs.h>
40*a824f5a1SJean-Baptiste Boric #endif
41*a824f5a1SJean-Baptiste Boric 
42*a824f5a1SJean-Baptiste Boric __RCSID("$NetBSD: remove.c,v 1.1.1.2 2009/08/06 16:55:29 joerg Exp $");
43*a824f5a1SJean-Baptiste Boric 
44*a824f5a1SJean-Baptiste Boric #if HAVE_DIRENT_H
45*a824f5a1SJean-Baptiste Boric #include <dirent.h>
46*a824f5a1SJean-Baptiste Boric #endif
47*a824f5a1SJean-Baptiste Boric #if HAVE_ERR_H
48*a824f5a1SJean-Baptiste Boric #include <err.h>
49*a824f5a1SJean-Baptiste Boric #endif
50*a824f5a1SJean-Baptiste Boric #include <errno.h>
51*a824f5a1SJean-Baptiste Boric #if HAVE_FCNTL_H
52*a824f5a1SJean-Baptiste Boric #include <fcntl.h>
53*a824f5a1SJean-Baptiste Boric #endif
54*a824f5a1SJean-Baptiste Boric #include <limits.h>
55*a824f5a1SJean-Baptiste Boric #include <stdio.h>
56*a824f5a1SJean-Baptiste Boric #include <stdlib.h>
57*a824f5a1SJean-Baptiste Boric #include <string.h>
58*a824f5a1SJean-Baptiste Boric #include <unistd.h>
59*a824f5a1SJean-Baptiste Boric 
60*a824f5a1SJean-Baptiste Boric #include "lib.h"
61*a824f5a1SJean-Baptiste Boric 
62*a824f5a1SJean-Baptiste Boric static int
safe_fchdir(int cwd)63*a824f5a1SJean-Baptiste Boric safe_fchdir(int cwd)
64*a824f5a1SJean-Baptiste Boric {
65*a824f5a1SJean-Baptiste Boric 	int tmp_errno, rv;
66*a824f5a1SJean-Baptiste Boric 
67*a824f5a1SJean-Baptiste Boric 	tmp_errno = errno;
68*a824f5a1SJean-Baptiste Boric 	rv = fchdir(cwd);
69*a824f5a1SJean-Baptiste Boric 	errno = tmp_errno;
70*a824f5a1SJean-Baptiste Boric 
71*a824f5a1SJean-Baptiste Boric 	return rv;
72*a824f5a1SJean-Baptiste Boric }
73*a824f5a1SJean-Baptiste Boric 
74*a824f5a1SJean-Baptiste Boric static int
long_remove(const char ** path_ptr,int missing_ok,int * did_chdir)75*a824f5a1SJean-Baptiste Boric long_remove(const char **path_ptr, int missing_ok, int *did_chdir)
76*a824f5a1SJean-Baptiste Boric {
77*a824f5a1SJean-Baptiste Boric 	char tmp_path[PATH_MAX + 1];
78*a824f5a1SJean-Baptiste Boric 	const char *path;
79*a824f5a1SJean-Baptiste Boric 	size_t i, len;
80*a824f5a1SJean-Baptiste Boric 	int rv;
81*a824f5a1SJean-Baptiste Boric 
82*a824f5a1SJean-Baptiste Boric 	path = *path_ptr;
83*a824f5a1SJean-Baptiste Boric 	len = strlen(path);
84*a824f5a1SJean-Baptiste Boric 	*did_chdir = 0;
85*a824f5a1SJean-Baptiste Boric 
86*a824f5a1SJean-Baptiste Boric 	while (len >= PATH_MAX) {
87*a824f5a1SJean-Baptiste Boric 		for (i = PATH_MAX - 1; i > 0; --i) {
88*a824f5a1SJean-Baptiste Boric 			if (path[i] == '/')
89*a824f5a1SJean-Baptiste Boric 				break;
90*a824f5a1SJean-Baptiste Boric 		}
91*a824f5a1SJean-Baptiste Boric 		if (i == 0) {
92*a824f5a1SJean-Baptiste Boric 			errno = ENAMETOOLONG;
93*a824f5a1SJean-Baptiste Boric 			return -1; /* Assumes PATH_MAX > NAME_MAX */
94*a824f5a1SJean-Baptiste Boric 		}
95*a824f5a1SJean-Baptiste Boric 		memcpy(tmp_path, path, i);
96*a824f5a1SJean-Baptiste Boric 		tmp_path[i] = '\0';
97*a824f5a1SJean-Baptiste Boric 		if (chdir(tmp_path))
98*a824f5a1SJean-Baptiste Boric 			return -1;
99*a824f5a1SJean-Baptiste Boric 		*did_chdir = 1;
100*a824f5a1SJean-Baptiste Boric 		path += i + 1;
101*a824f5a1SJean-Baptiste Boric 		len -= i + 1;
102*a824f5a1SJean-Baptiste Boric 	}
103*a824f5a1SJean-Baptiste Boric 
104*a824f5a1SJean-Baptiste Boric 	if (remove(path) == 0 || (errno == ENOENT && missing_ok))
105*a824f5a1SJean-Baptiste Boric 		rv = 0;
106*a824f5a1SJean-Baptiste Boric 	else
107*a824f5a1SJean-Baptiste Boric 		rv = -1;
108*a824f5a1SJean-Baptiste Boric 
109*a824f5a1SJean-Baptiste Boric 	*path_ptr = path;
110*a824f5a1SJean-Baptiste Boric 
111*a824f5a1SJean-Baptiste Boric 	return rv;
112*a824f5a1SJean-Baptiste Boric }
113*a824f5a1SJean-Baptiste Boric 
114*a824f5a1SJean-Baptiste Boric static int
recursive_remove_internal(const char * path,int missing_ok,int cwd)115*a824f5a1SJean-Baptiste Boric recursive_remove_internal(const char *path, int missing_ok, int cwd)
116*a824f5a1SJean-Baptiste Boric {
117*a824f5a1SJean-Baptiste Boric 	DIR *dir;
118*a824f5a1SJean-Baptiste Boric 	struct dirent *de;
119*a824f5a1SJean-Baptiste Boric 	const char *sub_path;
120*a824f5a1SJean-Baptiste Boric 	char *subdir;
121*a824f5a1SJean-Baptiste Boric 	int did_chdir, rv;
122*a824f5a1SJean-Baptiste Boric 
123*a824f5a1SJean-Baptiste Boric 	/*
124*a824f5a1SJean-Baptiste Boric 	 * If the argument is longer than PATH_MAX, long_remove
125*a824f5a1SJean-Baptiste Boric 	 * will try to shorten it using chdir.  So before returning,
126*a824f5a1SJean-Baptiste Boric 	 * make sure to fchdir back to the original cwd.
127*a824f5a1SJean-Baptiste Boric 	 */
128*a824f5a1SJean-Baptiste Boric 	sub_path = path;
129*a824f5a1SJean-Baptiste Boric 	if (long_remove(&sub_path, missing_ok, &did_chdir) == 0)
130*a824f5a1SJean-Baptiste Boric 		rv = 0;
131*a824f5a1SJean-Baptiste Boric 	else if (errno != ENOTEMPTY) /* Other errors are terminal. */
132*a824f5a1SJean-Baptiste Boric 		rv = -1;
133*a824f5a1SJean-Baptiste Boric 	else
134*a824f5a1SJean-Baptiste Boric 		rv = 1;
135*a824f5a1SJean-Baptiste Boric 
136*a824f5a1SJean-Baptiste Boric 	if (rv != 1) {
137*a824f5a1SJean-Baptiste Boric 		if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
138*a824f5a1SJean-Baptiste Boric 			rv = -1;
139*a824f5a1SJean-Baptiste Boric 		return rv;
140*a824f5a1SJean-Baptiste Boric 	}
141*a824f5a1SJean-Baptiste Boric 
142*a824f5a1SJean-Baptiste Boric 	if ((dir = opendir(sub_path)) == NULL) {
143*a824f5a1SJean-Baptiste Boric 		if (errno == EMFILE)
144*a824f5a1SJean-Baptiste Boric 			warn("opendir failed");
145*a824f5a1SJean-Baptiste Boric 		return -1;
146*a824f5a1SJean-Baptiste Boric 	}
147*a824f5a1SJean-Baptiste Boric 
148*a824f5a1SJean-Baptiste Boric 	if (did_chdir && fchdir(cwd) == -1)
149*a824f5a1SJean-Baptiste Boric 		return -1;
150*a824f5a1SJean-Baptiste Boric 
151*a824f5a1SJean-Baptiste Boric 	rv = 0;
152*a824f5a1SJean-Baptiste Boric 
153*a824f5a1SJean-Baptiste Boric 	while ((de = readdir(dir)) != NULL) {
154*a824f5a1SJean-Baptiste Boric 		if (strcmp(de->d_name, ".") == 0)
155*a824f5a1SJean-Baptiste Boric 			continue;
156*a824f5a1SJean-Baptiste Boric 		if (strcmp(de->d_name, "..") == 0)
157*a824f5a1SJean-Baptiste Boric 			continue;
158*a824f5a1SJean-Baptiste Boric 		subdir = xasprintf("%s/%s", path, de->d_name);
159*a824f5a1SJean-Baptiste Boric 		rv = recursive_remove_internal(subdir, 1, cwd);
160*a824f5a1SJean-Baptiste Boric 		free(subdir);
161*a824f5a1SJean-Baptiste Boric 	}
162*a824f5a1SJean-Baptiste Boric 
163*a824f5a1SJean-Baptiste Boric 	closedir(dir);
164*a824f5a1SJean-Baptiste Boric 
165*a824f5a1SJean-Baptiste Boric 	safe_fchdir(cwd);
166*a824f5a1SJean-Baptiste Boric 
167*a824f5a1SJean-Baptiste Boric 	rv |= long_remove(&path, missing_ok, &did_chdir);
168*a824f5a1SJean-Baptiste Boric 
169*a824f5a1SJean-Baptiste Boric 	if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
170*a824f5a1SJean-Baptiste Boric 		rv = -1;
171*a824f5a1SJean-Baptiste Boric 
172*a824f5a1SJean-Baptiste Boric 	return rv;
173*a824f5a1SJean-Baptiste Boric }
174*a824f5a1SJean-Baptiste Boric 
175*a824f5a1SJean-Baptiste Boric int
recursive_remove(const char * path,int missing_ok)176*a824f5a1SJean-Baptiste Boric recursive_remove(const char *path, int missing_ok)
177*a824f5a1SJean-Baptiste Boric {
178*a824f5a1SJean-Baptiste Boric 	int orig_cwd, rv;
179*a824f5a1SJean-Baptiste Boric 
180*a824f5a1SJean-Baptiste Boric 	/* First try the easy case of regular file or empty directory. */
181*a824f5a1SJean-Baptiste Boric 	if (remove(path) == 0 || (errno == ENOENT && missing_ok))
182*a824f5a1SJean-Baptiste Boric 		return 0;
183*a824f5a1SJean-Baptiste Boric 
184*a824f5a1SJean-Baptiste Boric 	/*
185*a824f5a1SJean-Baptiste Boric 	 * If the path is too long, long_remove will use chdir to shorten it,
186*a824f5a1SJean-Baptiste Boric 	 * so remember the current directory first.
187*a824f5a1SJean-Baptiste Boric 	 */
188*a824f5a1SJean-Baptiste Boric 	if ((orig_cwd = open(".", O_RDONLY)) == -1)
189*a824f5a1SJean-Baptiste Boric 		return -1;
190*a824f5a1SJean-Baptiste Boric 
191*a824f5a1SJean-Baptiste Boric 	rv = recursive_remove_internal(path, missing_ok, orig_cwd);
192*a824f5a1SJean-Baptiste Boric 
193*a824f5a1SJean-Baptiste Boric 	close(orig_cwd);
194*a824f5a1SJean-Baptiste Boric 	return rv;
195*a824f5a1SJean-Baptiste Boric }
196