90 lines
4.3 KiB
Diff
90 lines
4.3 KiB
Diff
|
From 78105a206a21133f87f5982f29d7aa3c4cc72b0d Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||
|
Date: Wed, 16 Mar 2022 09:28:46 +0100
|
||
|
Subject: [PATCH] shared/install: skip unnecessary chasing of symlinks in
|
||
|
disable
|
||
|
|
||
|
We use the symlink source name and destination names to decide whether to remove
|
||
|
the symlink. But if the source name is enough to decide to remove the symlink,
|
||
|
we'd still look up the destination for no good reason. This is a slow operation,
|
||
|
let's skip it.
|
||
|
|
||
|
(cherry picked from commit 7a6c73dabf6451d6ef22d0cdfbb1749a77450d5b)
|
||
|
|
||
|
Related: #2082131
|
||
|
---
|
||
|
src/shared/install.c | 43 +++++++++++++++++++++++++------------------
|
||
|
1 file changed, 25 insertions(+), 18 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/install.c b/src/shared/install.c
|
||
|
index ad0238ab50..08a9892260 100644
|
||
|
--- a/src/shared/install.c
|
||
|
+++ b/src/shared/install.c
|
||
|
@@ -599,8 +599,7 @@ static int remove_marked_symlinks_fd(
|
||
|
r = q;
|
||
|
|
||
|
} else if (de->d_type == DT_LNK) {
|
||
|
- _cleanup_free_ char *p = NULL, *dest = NULL;
|
||
|
- const char *rp;
|
||
|
+ _cleanup_free_ char *p = NULL;
|
||
|
bool found;
|
||
|
int q;
|
||
|
|
||
|
@@ -612,24 +611,32 @@ static int remove_marked_symlinks_fd(
|
||
|
return -ENOMEM;
|
||
|
path_simplify(p);
|
||
|
|
||
|
- q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL);
|
||
|
- if (q == -ENOENT)
|
||
|
- continue;
|
||
|
- if (q < 0) {
|
||
|
- log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p);
|
||
|
- unit_file_changes_add(changes, n_changes, q, p, NULL);
|
||
|
+ /* We remove all links pointing to a file or path that is marked, as well as all
|
||
|
+ * files sharing the same name as a file that is marked. Do path chasing only if
|
||
|
+ * we don't already know that we want to remove the symlink. */
|
||
|
+ found = set_contains(remove_symlinks_to, de->d_name);
|
||
|
|
||
|
- if (r == 0)
|
||
|
- r = q;
|
||
|
- continue;
|
||
|
- }
|
||
|
+ if (!found) {
|
||
|
+ _cleanup_free_ char *dest = NULL;
|
||
|
+
|
||
|
+
|
||
|
+ q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL);
|
||
|
+ if (q == -ENOENT)
|
||
|
+ continue;
|
||
|
+ if (q < 0) {
|
||
|
+ log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p);
|
||
|
+ unit_file_changes_add(changes, n_changes, q, p, NULL);
|
||
|
|
||
|
- /* We remove all links pointing to a file or path that is marked, as well as all files sharing
|
||
|
- * the same name as a file that is marked. */
|
||
|
+ if (r == 0)
|
||
|
+ r = q;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ found = set_contains(remove_symlinks_to, dest) ||
|
||
|
+ set_contains(remove_symlinks_to, basename(dest));
|
||
|
+
|
||
|
+ }
|
||
|
|
||
|
- found = set_contains(remove_symlinks_to, dest) ||
|
||
|
- set_contains(remove_symlinks_to, basename(dest)) ||
|
||
|
- set_contains(remove_symlinks_to, de->d_name);
|
||
|
|
||
|
if (!found)
|
||
|
continue;
|
||
|
@@ -650,7 +657,7 @@ static int remove_marked_symlinks_fd(
|
||
|
/* Now, remember the full path (but with the root prefix removed) of
|
||
|
* the symlink we just removed, and remove any symlinks to it, too. */
|
||
|
|
||
|
- rp = skip_root(lp->root_dir, p);
|
||
|
+ const char *rp = skip_root(lp->root_dir, p);
|
||
|
q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
|
||
|
if (q < 0)
|
||
|
return q;
|