summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch')
-rw-r--r--meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch318
1 files changed, 318 insertions, 0 deletions
diff --git a/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch b/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch
new file mode 100644
index 0000000000..f80e6433c6
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch
@@ -0,0 +1,318 @@
1Backport of the following upstream commit:
2From 96906b22417c65d70933976e0ee920c70c9113a4 Mon Sep 17 00:00:00 2001
3From: Lennart Poettering <lennart@poettering.net>
4Date: Tue, 26 Jan 2021 16:30:06 +0100
5Subject: [PATCH] rm-rf: refactor rm_rf_children(), split out body of directory
6 iteration loop
7
8This splits out rm_rf_children_inner() as body of the loop. We can use
9that to implement rm_rf_child() for deleting one specific entry in a
10directory.
11
12Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz]
13Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com>
14---
15 src/basic/rm-rf.c | 223 ++++++++++++++++++++++++++-------------------
16 src/basic/rm-rf.h | 3 +-
17 2 files changed, 131 insertions(+), 95 deletions(-)
18
19--- a/src/basic/rm-rf.c
20+++ b/src/basic/rm-rf.c
21@@ -19,138 +19,153 @@
22 #include "stat-util.h"
23 #include "string-util.h"
24
25+/* We treat tmpfs/ramfs + cgroupfs as non-physical file sytems. cgroupfs is similar to tmpfs in a way after
26+ * all: we can create arbitrary directory hierarchies in it, and hence can also use rm_rf() on it to remove
27+ * those again. */
28 static bool is_physical_fs(const struct statfs *sfs) {
29 return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs);
30 }
31
32-int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
33+static int rm_rf_children_inner(
34+ int fd,
35+ const char *fname,
36+ int is_dir,
37+ RemoveFlags flags,
38+ const struct stat *root_dev) {
39+
40+ struct stat st;
41+ int r;
42+
43+ assert(fd >= 0);
44+ assert(fname);
45+
46+ if (is_dir < 0 || (is_dir > 0 && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
47+
48+ r = fstatat(fd, fname, &st, AT_SYMLINK_NOFOLLOW);
49+ if (r < 0)
50+ return r;
51+
52+ is_dir = S_ISDIR(st.st_mode);
53+ }
54+
55+ if (is_dir) {
56+ _cleanup_close_ int subdir_fd = -1;
57+ int q;
58+
59+ /* if root_dev is set, remove subdirectories only if device is same */
60+ if (root_dev && st.st_dev != root_dev->st_dev)
61+ return 0;
62+
63+ /* Stop at mount points */
64+ r = fd_is_mount_point(fd, fname, 0);
65+ if (r < 0)
66+ return r;
67+ if (r > 0)
68+ return 0;
69+
70+ if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) {
71+
72+ /* This could be a subvolume, try to remove it */
73+
74+ r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
75+ if (r < 0) {
76+ if (!IN_SET(r, -ENOTTY, -EINVAL))
77+ return r;
78+
79+ /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
80+ } else
81+ /* It was a subvolume, done. */
82+ return 1;
83+ }
84+
85+ subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
86+ if (subdir_fd < 0)
87+ return -errno;
88+
89+ /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type
90+ * again for each directory */
91+ q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
92+
93+ r = unlinkat(fd, fname, AT_REMOVEDIR);
94+ if (r < 0)
95+ return r;
96+ if (q < 0)
97+ return q;
98+
99+ return 1;
100+
101+ } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
102+ r = unlinkat(fd, fname, 0);
103+ if (r < 0)
104+ return r;
105+
106+ return 1;
107+ }
108+
109+ return 0;
110+}
111+
112+int rm_rf_children(
113+ int fd,
114+ RemoveFlags flags,
115+ const struct stat *root_dev) {
116+
117 _cleanup_closedir_ DIR *d = NULL;
118 struct dirent *de;
119 int ret = 0, r;
120- struct statfs sfs;
121
122 assert(fd >= 0);
123
124 /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed
125- * fd, in all cases, including on failure.. */
126+ * fd, in all cases, including on failure. */
127+
128+ d = fdopendir(fd);
129+ if (!d) {
130+ safe_close(fd);
131+ return -errno;
132+ }
133
134 if (!(flags & REMOVE_PHYSICAL)) {
135+ struct statfs sfs;
136
137- r = fstatfs(fd, &sfs);
138- if (r < 0) {
139- safe_close(fd);
140+ if (fstatfs(dirfd(d), &sfs) < 0)
141 return -errno;
142 }
143
144 if (is_physical_fs(&sfs)) {
145- /* We refuse to clean physical file systems with this call,
146- * unless explicitly requested. This is extra paranoia just
147- * to be sure we never ever remove non-state data. */
148+ /* We refuse to clean physical file systems with this call, unless explicitly
149+ * requested. This is extra paranoia just to be sure we never ever remove non-state
150+ * data. */
151+
152 _cleanup_free_ char *path = NULL;
153
154 (void) fd_get_path(fd, &path);
155- log_error("Attempted to remove disk file system under \"%s\", and we can't allow that.",
156- strna(path));
157-
158- safe_close(fd);
159- return -EPERM;
160+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
161+ "Attempted to remove disk file system under \"%s\", and we can't allow that.",
162+ strna(path));
163 }
164 }
165
166- d = fdopendir(fd);
167- if (!d) {
168- safe_close(fd);
169- return errno == ENOENT ? 0 : -errno;
170- }
171-
172 FOREACH_DIRENT_ALL(de, d, return -errno) {
173- bool is_dir;
174- struct stat st;
175+ int is_dir;
176
177 if (dot_or_dot_dot(de->d_name))
178 continue;
179
180- if (de->d_type == DT_UNKNOWN ||
181- (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
182- if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
183- if (ret == 0 && errno != ENOENT)
184- ret = -errno;
185- continue;
186- }
187-
188- is_dir = S_ISDIR(st.st_mode);
189- } else
190- is_dir = de->d_type == DT_DIR;
191-
192- if (is_dir) {
193- _cleanup_close_ int subdir_fd = -1;
194-
195- /* if root_dev is set, remove subdirectories only if device is same */
196- if (root_dev && st.st_dev != root_dev->st_dev)
197- continue;
198-
199- subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
200- if (subdir_fd < 0) {
201- if (ret == 0 && errno != ENOENT)
202- ret = -errno;
203- continue;
204- }
205-
206- /* Stop at mount points */
207- r = fd_is_mount_point(fd, de->d_name, 0);
208- if (r < 0) {
209- if (ret == 0 && r != -ENOENT)
210- ret = r;
211-
212- continue;
213- }
214- if (r > 0)
215- continue;
216-
217- if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) {
218-
219- /* This could be a subvolume, try to remove it */
220-
221- r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
222- if (r < 0) {
223- if (!IN_SET(r, -ENOTTY, -EINVAL)) {
224- if (ret == 0)
225- ret = r;
226-
227- continue;
228- }
229-
230- /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
231- } else
232- /* It was a subvolume, continue. */
233- continue;
234- }
235-
236- /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file
237- * system type again for each directory */
238- r = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
239- if (r < 0 && ret == 0)
240- ret = r;
241-
242- if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
243- if (ret == 0 && errno != ENOENT)
244- ret = -errno;
245- }
246-
247- } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
248-
249- if (unlinkat(fd, de->d_name, 0) < 0) {
250- if (ret == 0 && errno != ENOENT)
251- ret = -errno;
252- }
253- }
254+ is_dir =
255+ de->d_type == DT_UNKNOWN ? -1 :
256+ de->d_type == DT_DIR;
257+
258+ r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev);
259+ if (r < 0 && r != -ENOENT && ret == 0)
260+ ret = r;
261 }
262+
263 return ret;
264 }
265
266 int rm_rf(const char *path, RemoveFlags flags) {
267 int fd, r;
268- struct statfs s;
269
270 assert(path);
271
272@@ -195,9 +210,10 @@
273 if (FLAGS_SET(flags, REMOVE_ROOT)) {
274
275 if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
276+ struct statfs s;
277+
278 if (statfs(path, &s) < 0)
279 return -errno;
280-
281 if (is_physical_fs(&s))
282 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
283 "Attempted to remove files from a disk file system under \"%s\", refusing.",
284@@ -225,3 +241,22 @@
285
286 return r;
287 }
288+
289+int rm_rf_child(int fd, const char *name, RemoveFlags flags) {
290+
291+ /* Removes one specific child of the specified directory */
292+
293+ if (fd < 0)
294+ return -EBADF;
295+
296+ if (!filename_is_valid(name))
297+ return -EINVAL;
298+
299+ if ((flags & (REMOVE_ROOT|REMOVE_MISSING_OK)) != 0) /* Doesn't really make sense here, we are not supposed to remove 'fd' anyway */
300+ return -EINVAL;
301+
302+ if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME))
303+ return -EINVAL;
304+
305+ return rm_rf_children_inner(fd, name, -1, flags, NULL);
306+}
307--- a/src/basic/rm-rf.h
308+++ b/src/basic/rm-rf.h
309@@ -13,7 +13,8 @@
310 REMOVE_MISSING_OK = 1 << 4, /* If the top-level directory is missing, ignore the ENOENT for it */
311 } RemoveFlags;
312
313-int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
314+int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev);
315+int rm_rf_child(int fd, const char *name, RemoveFlags flags);
316 int rm_rf(const char *path, RemoveFlags flags);
317
318 /* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */