[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] find: fix -L and -delete removing symlinks to directories
From: |
raf |
Subject: |
[PATCH] find: fix -L and -delete removing symlinks to directories |
Date: |
Sun, 23 Oct 2022 09:37:35 +1100 |
Fixes https://savannah.gnu.org/bugs/?46305
* NEWS (Bug Fixes): Mention the change.
* doc/find.texi (-delete action): Add explanation of the issue.
* find/find.1 (-delete action): Add explanation of the issue.
* find/pred.c (pred_delete): Do unlink when rmdir fails (ENOTDIR).
* find/testsuite/Makefile.am: Add new test and output files.
* find/testsuite/find.gnu/deletedirsymlink.exp: New test.
* find/testsuite/find.gnu/deletedirsymlink.xo: New test output.
---
NEWS | 2 ++
doc/find.texi | 10 ++++++++++
find/find.1 | 15 +++++++++++++++
find/pred.c | 10 ++++++++++
find/testsuite/Makefile.am | 2 ++
find/testsuite/find.gnu/deletedirsymlink.exp | 10 ++++++++++
find/testsuite/find.gnu/deletedirsymlink.xo | 2 ++
7 files changed, 51 insertions(+)
create mode 100644 find/testsuite/find.gnu/deletedirsymlink.exp
create mode 100644 find/testsuite/find.gnu/deletedirsymlink.xo
diff --git a/NEWS b/NEWS
index dffca5aa..6dec7342 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ GNU findutils NEWS - User visible changes. -*- outline -*-
(allout)
to match the root directory "/". Previously, a diagnostic falsely claimed
that this pattern would not match anything. [#62227]
+ #46305: 'find -L . -delete' now successfully deletes symlinks to directories.
+
** Changes to the build process
findutils now builds again on systems with musl-libc.
diff --git a/doc/find.texi b/doc/find.texi
index 1f295837..e6da6b7b 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -3001,6 +3001,16 @@ change the exit code to nonzero, and the return code of
the @samp{-delete}
action will be true.
@end deffn
+When @samp{-delete} is used with the @samp{-L} or @samp{-H} option, and a
+symlink to a directory is followed, the symlink's ultimate target
+directory's contents are searched, and any matches found there are deleted,
+but the target directory itself is never deleted. It's not possible to
+delete a filesystem entry via a symlink to it. If the directory itself
+matches the search criteria, the symlink is deleted. Similarly, when a
+symlink to a non-directory is followed, and the symlink's ultimate target
+matches the search criteria, the symlink is deleted, never the ultimate
+target.
+
@node Adding Tests
@section Adding Tests
diff --git a/find/find.1 b/find/find.1
index 429aa2f0..510390b0 100644
--- a/find/find.1
+++ b/find/find.1
@@ -1224,6 +1224,21 @@ nonzero, and the return code of the
.B \-delete
action will be true.
+When
+.B \-delete
+is used with the
+.B \-L
+or
+.B \-H
+option, and a symlink to a directory is followed, the symlink's ultimate
+target directory's contents are searched, and any matches found there are
+deleted, but the target directory itself is never deleted. It's not possible
+to delete a filesystem entry via a symlink to it. If the directory itself
+matches the search criteria, the symlink is deleted. Similarly, when a
+symlink to a non-directory is followed, and the symlink's ultimate target
+matches the search criteria, the symlink is deleted, never the ultimate
+target.
+
.IP "\-exec \fIcommand\fR ;"
Execute
diff --git a/find/pred.c b/find/pred.c
index f9f42fac..c6643f7b 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -256,6 +256,16 @@ pred_delete (const char *pathname, struct stat *stat_buf,
struct predicate *pred
return true;
}
}
+ if (ENOTDIR == errno)
+ {
+ if ((flags & AT_REMOVEDIR) != 0)
+ {
+ /* rmdir() operation failed because we should have done
unlink(). */
+ flags &= ~AT_REMOVEDIR;
+ if (perform_delete (flags))
+ return true;
+ }
+ }
}
error (0, errno, _("cannot delete %s"),
safely_quote_err_filename (0, pathname));
diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am
index 568f3841..a305ca9d 100644
--- a/find/testsuite/Makefile.am
+++ b/find/testsuite/Makefile.am
@@ -30,6 +30,7 @@ find.gnu/comma.xo \
find.gnu/delete.xo \
find.gnu/deletedir.xo \
find.gnu/deletefile.xo \
+find.gnu/deletedirsymlink.xo \
find.gnu/depth.xo \
find.gnu/depth-d.xo \
find.gnu/empty.xo \
@@ -129,6 +130,7 @@ find.gnu/comma.exp \
find.gnu/delete.exp \
find.gnu/deletedir.exp \
find.gnu/deletefile.exp \
+find.gnu/deletedirsymlink.exp \
find.gnu/depth.exp \
find.gnu/depth-d.exp \
find.gnu/empty.exp \
diff --git a/find/testsuite/find.gnu/deletedirsymlink.exp
b/find/testsuite/find.gnu/deletedirsymlink.exp
new file mode 100644
index 00000000..f3d7a1ef
--- /dev/null
+++ b/find/testsuite/find.gnu/deletedirsymlink.exp
@@ -0,0 +1,10 @@
+# Test that symlinks to directories are deleted even with -L
+# (necessarily so), not the target directories (and not an error)
+global FTSFIND
+global FINDFLAGS
+exec rm -rf tmp
+exec mkdir tmp tmp/t tmp/dd tmp/dd/d
+exec ln -s ../dd tmp/t/ld
+eval exec $FTSFIND -L tmp/t $FINDFLAGS -delete
+find_start p {tmp -print}
+exec rm -rf tmp
diff --git a/find/testsuite/find.gnu/deletedirsymlink.xo
b/find/testsuite/find.gnu/deletedirsymlink.xo
new file mode 100644
index 00000000..a09bfee5
--- /dev/null
+++ b/find/testsuite/find.gnu/deletedirsymlink.xo
@@ -0,0 +1,2 @@
+tmp
+tmp/dd
--
2.30.2