@@ -191,6 +191,13 @@ mod remove_dir_all_xat {
191
191
}
192
192
Ok ( ( ) )
193
193
}
194
+
195
+ fn is_open ( & self ) -> bool {
196
+ match self {
197
+ LazyReadDir :: OpenReadDir ( _, _) => true ,
198
+ _ => false ,
199
+ }
200
+ }
194
201
}
195
202
196
203
impl AsFd for LazyReadDir < ' _ > {
@@ -307,31 +314,29 @@ mod remove_dir_all_xat {
307
314
let parent_readdir = match readdir_cache. pop_back ( ) {
308
315
Some ( readdir) => readdir,
309
316
None => {
310
- // cache is empty - reopen parent and grandparent fd
311
-
317
+ // cache is empty - reopen parent
312
318
let parent_readdir = current_readdir. get_parent ( ) ?;
313
319
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
-
331
320
parent_readdir
332
321
}
333
322
} ;
334
323
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
+
335
340
// remove now empty directory
336
341
cvt ( unsafe {
337
342
unlinkat (
0 commit comments