@@ -191,6 +191,13 @@ mod remove_dir_all_xat {
191191 }
192192 Ok ( ( ) )
193193 }
194+
195+ fn is_open ( & self ) -> bool {
196+ match self {
197+ LazyReadDir :: OpenReadDir ( _, _) => true ,
198+ _ => false ,
199+ }
200+ }
194201 }
195202
196203 impl AsFd for LazyReadDir < ' _ > {
@@ -307,31 +314,29 @@ mod remove_dir_all_xat {
307314 let parent_readdir = match readdir_cache. pop_back ( ) {
308315 Some ( readdir) => readdir,
309316 None => {
310- // cache is empty - reopen parent and grandparent fd
311-
317+ // cache is empty - reopen parent
312318 let parent_readdir = current_readdir. get_parent ( ) ?;
313319 parent_component. verify_dev_ino ( parent_readdir. as_fd ( ) ) ?;
314-
315- // We are about to delete the now empty "child directory".
316- // To make sure the that the child directory was not moved somewhere
317- // else and that the parent just happens to have the same reused
318- // (dev, inode) pair, that we found descending, we verify the
319- // grandparent directory (dev, inode) as well.
320- let grandparent_readdir = parent_readdir. get_parent ( ) ?;
321- if let Some ( grandparent_component) = path_components. last ( ) {
322- grandparent_component
323- . verify_dev_ino ( grandparent_readdir. as_fd ( ) ) ?;
324- readdir_cache. push_back ( grandparent_readdir) ;
325- } else {
326- // verify parent of the deletion root directory
327- root_parent_component
328- . verify_dev_ino ( grandparent_readdir. as_fd ( ) ) ?;
329- }
330-
331320 parent_readdir
332321 }
333322 } ;
334323
324+ // If `parent_readdir` was now or previously opened via `get_parent()`
325+ // we need to verify the grandparent (dev, inode) pair as well to protect
326+ // against the situation that the child directory was moved somewhere
327+ // else and that the parent just happens to have the same reused
328+ // (dev, inode) pair, that we found descending.
329+ if !parent_readdir. is_open ( ) && readdir_cache. is_empty ( ) {
330+ let grandparent_readdir = parent_readdir. get_parent ( ) ?;
331+ if let Some ( grandparent_component) = path_components. last ( ) {
332+ grandparent_component. verify_dev_ino ( grandparent_readdir. as_fd ( ) ) ?;
333+ readdir_cache. push_back ( grandparent_readdir) ;
334+ } else {
335+ // verify parent of the deletion root directory
336+ root_parent_component. verify_dev_ino ( grandparent_readdir. as_fd ( ) ) ?;
337+ }
338+ }
339+
335340 // remove now empty directory
336341 cvt ( unsafe {
337342 unlinkat (
0 commit comments