findutils-patches
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]