GNU bug report logs - #12339
Bug: rm -fr . doesn't dir depth first deletion yet it is documented to do so.

Previous Next

Package: coreutils;

Reported by: Linda Walsh <coreutils <at> tlinx.org>

Date: Mon, 3 Sep 2012 00:34:02 UTC

Severity: normal

Done: Assaf Gordon <assafgordon <at> gmail.com>

Bug is archived. No further changes may be made.

Full log


Message #173 received at 12339 <at> debbugs.gnu.org (full text, mbox):

From: Linda Walsh <coreutils <at> tlinx.org>
To: Eric Blake <eblake <at> redhat.com>
Cc: Paul Eggert <eggert <at> cs.ucla.edu>,
	Bernhard Voelker <mail <at> bernhard-voelker.de>,
	Jim Meyering <jim <at> meyering.net>,
	"12339 <at> debbugs.gnu.org" <12339 <at> debbugs.gnu.org>
Subject: Re: bug#12339: Bug: rm -fr . doesn't dir depth first deletion yet it
	is	documented to do so.
Date: Fri, 07 Sep 2012 08:02:58 -0700

Eric Blake wrote:
> 
> Then set up a shell alias or a wrapper script that comes first in your
> $PATH.  Then it is under your explicit control, while the default is
> still appropriate for everyone else.
> 
> Just because the defaults don't match your expectations doesn't mean you
> can't change the behavior _on your system_ to avoid extra typing on your
> part.
---
	Doesn't work for programs that need to call rm to remove all files
in a dir.

And I already have changed default behavior on MY systems.


I already added the patch below -- that only does my behavior if the
user isn't running in POSIXLY_CORRECT mode.


Now it's certainly easier to set an env var 1 place to control script
behavior than making changes in all the places...

I'm just trying to get the env var in so I don't have to distribute
a version of rm with my scripts that works.





-----

--- src/remove.c        2011-10-10 00:56:46.000000000 -0700
+++ src/remove.c.new    2012-09-06 14:28:07.816810683 -0700
@@ -173,6 +173,35 @@
   }
 }

+
+/* separate functions to check for next part of file name being dotdot or...*/
+
+static inline bool
+dotdot (char const *file_name)
+{
+  if (file_name[0] == '.' && file_name[1])
+    {
+      char sep = file_name[(file_name[1] == '.') + 1];
+      return (! sep || ISSLASH (sep));
+    }
+  else
+    return false;
+}
+
+/* dot */
+
+static inline bool
+dot (char const * file_name)
+{
+       if (file_name[0] == '.')
+               {
+                       char sep = file_name[1];
+                       return (! sep || ISSLASH(sep));
+               }
+       else
+               return false;
+}
+
 /* Prompt whether to remove FILENAME (ent->, if required via a combination of
    the options specified by X and/or file attributes.  If the file may
    be removed, return RM_OK.  If the user declines to remove the file,
@@ -203,6 +232,7 @@

   int dirent_type = is_dir ? DT_DIR : DT_UNKNOWN;
   int write_protected = 0;
+       int special_delete_content = 0;

   /* When nonzero, this indicates that we failed to remove a child entry,
      either because the user declined an interactive prompt, or due to
@@ -222,7 +252,11 @@
       wp_errno = errno;
     }

-  if (write_protected || x->interactive == RMI_ALWAYS)
+       if (!x->posix_correctly && dot(filename) && !x->force)
+               special_delete_content = 1;
+
+
+  if (write_protected || x->interactive == RMI_ALWAYS || special_delete_content)
     {
       if (0 <= write_protected && dirent_type == DT_UNKNOWN)
         {
@@ -281,11 +315,16 @@
       if (dirent_type == DT_DIR
           && mode == PA_DESCEND_INTO_DIR
           && !is_empty)
-        fprintf (stderr,
-                 (write_protected
-                  ? _("%s: descend into write-protected directory %s? ")
-                  : _("%s: descend into directory %s? ")),
-                 program_name, quoted_name);
+                               {
+                                       char * action = special_delete_content
+                                                                              ? 
_("delete contents of")
+                                                                              : 
_("descend into");
+                                       fprintf (stderr,
+ 
(write_protected
+                                                                              ? 
_("%s: %s write-protected directory %s? ")
+                                                                              : 
_("%s: %s directory %s? ")),
+                                                                        action, 
program_name, quoted_name);
+                               }
       else
         {
           if (cache_fstatat (fd_cwd, filename, sbuf, AT_SYMLINK_NOFOLLOW) != 0)
@@ -476,7 +515,8 @@

           /* If the basename of a command line argument is "." or "..",
              diagnose it and do nothing more with that argument.  */
-          if (dot_or_dotdot (last_component (ent->fts_accpath)))
+          if ( (x->posix_correctly ? dot_or_dotdot : dotdot)
+                                                       (last_component 
(ent->fts_accpath)))
             {
               error (0, 0, _("cannot remove directory: %s"),
                      quote (ent->fts_path));
--- src/remove.h        2011-07-28 03:38:27.000000000 -0700
+++ src/remove.h        2012-09-06 13:33:01.282362765 -0700
@@ -34,6 +34,14 @@
   /* If true, ignore nonexistent files.  */
   bool ignore_missing_files;

+       /* true if force (-f) was specified indicating user knows what they
+        * are doing and don't want to questioned or see errors from command */
+       bool force;
+
+       /* true for users wanting strict posix compliance of more flexible, lax,
+        * or useful behaviors */
+       bool posix_correctly;
+
   /* If true, query the user about whether to remove each file.  */
   enum rm_interactive interactive;

--- src/rm.c    2011-10-02 02:20:54.000000000 -0700
+++ src/rm.c    2012-09-06 13:33:04.132500554 -0700
@@ -206,6 +206,7 @@
   bool preserve_root = true;
   struct rm_options x;
   bool prompt_once = false;
+       x.posix_correctly = (getenv ("POSIXLY_CORRECT") != NULL );
   int c;

   initialize_main (&argc, &argv);
@@ -222,10 +226,11 @@
     {
       switch (c)
         {
-        case 'f':
+        case 'f':              /* suppress warnings/errors */
           x.interactive = RMI_NEVER;
           x.ignore_missing_files = true;
           prompt_once = false;
+                                       x.force = true;
           break;

         case 'i':






This bug report was last modified 6 years and 186 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.