po: Update German man pages translation
[dpkg.git] / lib / dpkg / path-remove.c
blobe4d6ebe0192acf5e863dc16e073bce4cf3645400
1 /*
2 * libdpkg - Debian packaging suite library routines
3 * path-remove.c - path removal functions
5 * Copyright © 1994-1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2007-2015 Guillem Jover <guillem@debian.org>
8 * This is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 #include <config.h>
23 #include <compat.h>
25 #include <sys/stat.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <unistd.h>
31 #include <dpkg/i18n.h>
32 #include <dpkg/dpkg.h>
33 #include <dpkg/path.h>
34 #include <dpkg/debug.h>
35 #include <dpkg/subproc.h>
37 int
38 secure_unlink_statted(const char *pathname, const struct stat *stab)
40 mode_t mode = stab->st_mode;
42 if (S_ISREG(mode) ? (mode & 07000) :
43 !(S_ISLNK(mode) || S_ISDIR(mode) ||
44 S_ISFIFO(mode) || S_ISSOCK(mode))) {
45 if (chmod(pathname, 0600))
46 return -1;
49 if (unlink(pathname))
50 return -1;
52 return 0;
55 /**
56 * Securely unlink a pathname.
58 * If the pathname to remove is:
60 * 1. a sticky or set-id file, or
61 * 2. an unknown object (i.e., not a file, link, directory, fifo or socket)
63 * we change its mode so that a malicious user cannot use it, even if it's
64 * linked to another file.
66 int
67 secure_unlink(const char *pathname)
69 struct stat stab;
71 if (lstat(pathname, &stab))
72 return -1;
74 return secure_unlink_statted(pathname, &stab);
77 /**
78 * Securely remove a pathname.
80 * This is a secure version of remove(3) using secure_unlink() instead of
81 * unlink(2).
83 * @retval 0 On success.
84 * @retval -1 On failure, just like unlink(2) & rmdir(2).
86 int
87 secure_remove(const char *pathname)
89 int rc, e;
91 if (!rmdir(pathname)) {
92 debug(dbg_eachfiledetail, "secure_remove '%s' rmdir OK",
93 pathname);
94 return 0;
97 if (errno != ENOTDIR) {
98 e = errno;
99 debug(dbg_eachfiledetail, "secure_remove '%s' rmdir %s",
100 pathname, strerror(e));
101 errno = e;
102 return -1;
105 rc = secure_unlink(pathname);
106 e = errno;
107 debug(dbg_eachfiledetail, "secure_remove '%s' unlink %s",
108 pathname, rc ? strerror(e) : "OK");
109 errno = e;
111 return rc;
115 * Remove a pathname and anything below it.
117 * This function removes pathname and all its contents recursively.
119 void
120 path_remove_tree(const char *pathname)
122 pid_t pid;
123 const char *u;
125 u = path_skip_slash_dotslash(pathname);
126 if (u[0] == '\0')
127 internerr("pathname '%s' reduces to nothing", pathname);
129 debug(dbg_eachfile, "%s '%s'", __func__, pathname);
130 if (!rmdir(pathname))
131 return; /* Deleted it OK, it was a directory. */
132 if (errno == ENOENT || errno == ELOOP)
133 return;
134 if (errno == ENOTDIR) {
135 /* Either it's a file, or one of the path components is. If
136 * one of the path components is this will fail again ... */
137 if (secure_unlink(pathname) == 0)
138 return; /* OK, it was. */
139 if (errno == ENOTDIR)
140 return;
142 /* Trying to remove a directory or a file on a read-only filesystem,
143 * even if non-existent, always returns EROFS. */
144 if (errno == EROFS) {
145 if (access(pathname, F_OK) < 0 && errno == ENOENT)
146 return;
147 errno = EROFS;
149 if (errno != ENOTEMPTY && errno != EEXIST) /* Huh? */
150 ohshite(_("unable to securely remove '%.255s'"), pathname);
152 pid = subproc_fork();
153 if (pid == 0) {
154 execlp(RM, "rm", "-rf", "--", pathname, NULL);
155 ohshite(_("unable to execute %s (%s)"),
156 _("rm command for cleanup"), RM);
158 debug(dbg_eachfile, "%s running rm -rf '%s'", __func__, pathname);
159 subproc_reap(pid, _("rm command for cleanup"), 0);