From: Jim Meyering Date: Thu, 28 Dec 2006 18:37:07 +0000 (+0100) Subject: When moving "up" the hierarchy, be careful to remove a just-emptied X-Git-Tag: COREUTILS-6_8~111 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=88891aef7e24be24b3de49c91c25dc2049d08ffd;p=thirdparty%2Fcoreutils.git When moving "up" the hierarchy, be careful to remove a just-emptied directory before opening ".", to avoid trouble with file system implementations that cache readdir results at opendir-time. * src/remove.c (AD_pop_and_chdir): Add a file descriptor parameter. Don't update **DIRP. Don't call fdopendir here. (remove_dir): Call fdopendir here instead. Report and patch from Mikulas Patocka: --- diff --git a/ChangeLog b/ChangeLog index 9e24a1c2c4..658076e594 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2006-12-28 Jim Meyering + + When moving "up" the hierarchy, be careful to remove a just-emptied + directory before opening ".", to avoid trouble with file system + implementations that cache readdir results at opendir-time. + * src/remove.c (AD_pop_and_chdir): Add a file descriptor parameter. + Don't update **DIRP. Don't call fdopendir here. + (remove_dir): Call fdopendir here instead. + Report and patch from Mikulas Patocka: + + 2006-12-27 Jim Meyering * src/tail.c (usage): Mention +N for --bytes and --lines. diff --git a/src/remove.c b/src/remove.c index f6d3f0c671..68cb2d11f7 100644 --- a/src/remove.c +++ b/src/remove.c @@ -432,7 +432,7 @@ ds_free (Dirstack_state *ds) directory (usually now empty) from which we're coming, and which corresponds to the input value of *DIRP. */ static char * -AD_pop_and_chdir (DIR **dirp, Dirstack_state *ds) +AD_pop_and_chdir (DIR **dirp, int *fdp, Dirstack_state *ds) { struct AD_ent *leaf_dir_ent = AD_stack_top(ds); struct dev_ino leaf_dev_ino = leaf_dir_ent->dev_ino; @@ -499,15 +499,6 @@ AD_pop_and_chdir (DIR **dirp, Dirstack_state *ds) { error (0, 0, _("FATAL: directory %s changed dev/ino"), quote (full_filename ("."))); - goto close_and_next; - } - - *dirp = fdopendir (fd); - if (*dirp == NULL) - { - error (0, errno, _("FATAL: cannot return to .. from %s"), - quote (full_filename ("."))); - close_and_next:; close (fd); @@ -515,6 +506,7 @@ AD_pop_and_chdir (DIR **dirp, Dirstack_state *ds) free (prev_dir); longjmp (ds->current_arg_jumpbuf, 1); } + *fdp = fd; } else { @@ -524,9 +516,10 @@ AD_pop_and_chdir (DIR **dirp, Dirstack_state *ds) quote (full_filename (prev_dir))); goto next_cmdline_arg; } - *dirp = NULL; + *fdp = AT_FDCWD; } + *dirp = NULL; return prev_dir; } @@ -1384,9 +1377,9 @@ remove_dir (int fd_cwd, Dirstack_state *ds, char const *dir, { /* The name of the directory that we have just processed, nominally removing all of its contents. */ - char *empty_dir = AD_pop_and_chdir (&dirp, ds); - int fd = (dirp != NULL ? dirfd (dirp) : AT_FDCWD); - assert (dirp != NULL || AD_stack_height (ds) == 1); + int fd; + char *empty_dir = AD_pop_and_chdir (&dirp, &fd, ds); + assert (fd != AT_FDCWD || AD_stack_height (ds) == 1); /* Try to remove EMPTY_DIR only if remove_cwd_entries succeeded. */ if (tmp_status == RM_OK) @@ -1405,6 +1398,8 @@ remove_dir (int fd_cwd, Dirstack_state *ds, char const *dir, { free (empty_dir); status = s; + if (fd != AT_FDCWD) + close (fd); goto closedir_and_return; } @@ -1426,7 +1421,18 @@ remove_dir (int fd_cwd, Dirstack_state *ds, char const *dir, free (empty_dir); - if (AD_stack_height (ds) == 1) + if (fd != AT_FDCWD) + { + dirp = fdopendir (fd); + if (dirp == NULL) + { + error (0, errno, _("FATAL: cannot return to .. from %s"), + quote (full_filename ("."))); + close (fd); + longjmp (ds->current_arg_jumpbuf, 1); + } + } + else break; } }