Bug report from luckboy: rm -f on a broken symlink didn't work because our "does...
authorRob Landley <rob@landley.net>
Sat, 13 Sep 2014 19:48:37 +0000 (14:48 -0500)
committerRob Landley <rob@landley.net>
Sat, 13 Sep 2014 19:48:37 +0000 (14:48 -0500)
The fix: replace the access() with unlink(), which produces the same "does not
exist" errno and has the added bonus of acting as a fastpath for rm -f on
non-directories. (And since it produces a different error on directories,
falls through to the old behavior there.)

Most of this commit is comment updates explaining being subtle. :)

toys/posix/rm.c

index 2f40106..6c98404 100644 (file)
@@ -88,11 +88,15 @@ void rm_main(void)
       continue;
     }
 
-    // There's a race here where a file removed between this access and
+    // Files that already don't exist aren't errors for -f, so try a quick
+    // unlink now to see if it succeeds or reports that it didn't exist.
+    if ((toys.optflags & FLAG_f) && (!unlink(*s) || errno == ENOENT))
+      continue;
+
+    // There's a race here where a file removed between the above check and
     // dirtree's stat would report the nonexistence as an error, but that's
     // not a normal "it didn't exist" so I'm ok with it.
-    if ((toys.optflags & FLAG_f) && (access(*s, F_OK) && errno == ENOENT))
-      continue;
+
     dirtree_read(*s, do_rm);
   }
 }