diff --git a/NEWS b/NEWS index 1825beccb..6cfe8bb1c 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,16 @@ GNU coreutils NEWS -*- outline -*- This makes rm -rf significantly faster (400-500%) in some pathological cases, and slightly slower (20%) in at least one pathological case. + rm -r deletes deep hierarchies more efficiently. Before, it took O(N^2) + time, now it takes O(N). However, this improvement is not as pronounced + as might be expected for very deep trees, because prior to this change, for + any relative name length longer than 8KiB, rm -r would sacrifice official + conformance to avoid the disproportionate O(N^2) performance penalty. + Leading to another improvement: + + rm -r is now slightly more standards-conformant when operating on + write-protected relative file names longer than 8KiB. + * Noteworthy changes in release 7.6 (2009-09-11) [stable] diff --git a/m4/jm-macros.m4 b/m4/jm-macros.m4 index f4d43f1dd..75ee75e2d 100644 --- a/m4/jm-macros.m4 +++ b/m4/jm-macros.m4 @@ -92,6 +92,9 @@ AC_DEFUN([coreutils_MACROS], # for cp.c AC_CHECK_FUNCS_ONCE([utimensat]) + # for remove.c + AC_CHECK_FUNCS_ONCE([faccessat]) + dnl This can't use AC_REQUIRE; I'm not quite sure why. cu_PREREQ_STAT_PROG diff --git a/src/remove.c b/src/remove.c index 32f67a181..2db385909 100644 --- a/src/remove.c +++ b/src/remove.c @@ -172,6 +172,13 @@ write_protected_non_symlink (int fd_cwd, mess up with long file names). */ { + /* Use faccessat if possible, so as to avoid the expense + of processing an N-component name. */ +#if HAVE_FACCESSAT && AT_EACCESS + if (faccessat (fd_cwd, file, W_OK, AT_EACCESS) == 0) + return 0; +#endif + /* This implements #5: */ size_t file_name_len = strlen (full_name);