@@ -17,6 +17,7 @@ use crate::{Dir, AsPath};
17
17
#[ cfg( any( target_os = "linux" , target_os = "freebsd" ) ) ]
18
18
const BASE_OPEN_FLAGS : libc:: c_int = libc:: O_DIRECTORY | libc:: O_CLOEXEC ;
19
19
// NOTE(cehteh): O_DIRECTORY is defined in posix, what is the reason for not using it?
20
+ // TODO(cehteh): on systems that do not support O_DIRECTORY a runtime stat-check is required
20
21
#[ cfg( not( any( target_os = "linux" , target_os = "freebsd" ) ) ) ]
21
22
const BASE_OPEN_FLAGS : libc:: c_int = libc:: O_CLOEXEC ;
22
23
@@ -72,10 +73,11 @@ impl Dir {
72
73
/// List this dir
73
74
// TODO(cehteh): may be deprecated in favor of list()
74
75
pub fn list_self ( & self ) -> io:: Result < DirIter > {
75
- self . try_clone ( ) ?. list ( )
76
+ self . clone_upgrade ( ) ?. list ( )
76
77
}
77
78
78
79
/// Create a DirIter from a Dir
80
+ /// Dir must not be a 'Lite' handle
79
81
pub fn list ( self ) -> io:: Result < DirIter > {
80
82
let fd = self . 0 ;
81
83
std:: mem:: forget ( self ) ;
@@ -477,11 +479,21 @@ impl Dir {
477
479
}
478
480
479
481
/// Creates a new independently owned handle to the underlying directory.
482
+ /// The new handle has the same (Normal/Lite) semantics as the original handle.
480
483
pub fn try_clone ( & self ) -> io:: Result < Self > {
481
484
Ok ( Dir ( clone_dirfd ( self . 0 ) ?) )
482
485
}
483
486
484
- //TODO(cehteh): clone/conversion full<->lite
487
+ /// Creates a new 'Normal' independently owned handle to the underlying directory.
488
+ pub fn clone_upgrade ( & self ) -> io:: Result < Self > {
489
+ Ok ( Dir ( clone_dirfd_upgrade ( self . 0 ) ?) )
490
+ }
491
+
492
+ /// Creates a new 'Lite' independently owned handle to the underlying directory.
493
+ pub fn clone_downgrade ( & self ) -> io:: Result < Self > {
494
+ Ok ( Dir ( clone_dirfd_downgrade ( self . 0 ) ?) )
495
+ }
496
+
485
497
}
486
498
487
499
const CURRENT_DIRECTORY : [ libc:: c_char ; 2 ] = [ b'.' as libc:: c_char , 0 ] ;
@@ -501,6 +513,41 @@ fn clone_dirfd(fd: libc::c_int) -> io::Result<libc::c_int> {
501
513
}
502
514
}
503
515
516
+ fn clone_dirfd_upgrade ( fd : libc:: c_int ) -> io:: Result < libc:: c_int > {
517
+ unsafe {
518
+ match fd_type ( fd) ? {
519
+ FdType :: NormalDir | FdType :: LiteDir => libc_ok ( libc:: openat (
520
+ fd,
521
+ & CURRENT_DIRECTORY as * const libc:: c_char ,
522
+ BASE_OPEN_FLAGS ,
523
+ ) ) ,
524
+ _ => Err ( io:: Error :: from_raw_os_error ( libc:: ENOTDIR ) ) ,
525
+ }
526
+ }
527
+ }
528
+
529
+ fn clone_dirfd_downgrade ( fd : libc:: c_int ) -> io:: Result < libc:: c_int > {
530
+ unsafe {
531
+ match fd_type ( fd) ? {
532
+ #[ cfg( target_os = "linux" ) ]
533
+ FdType :: NormalDir => libc_ok ( libc:: openat (
534
+ fd,
535
+ & CURRENT_DIRECTORY as * const libc:: c_char ,
536
+ libc:: O_PATH | BASE_OPEN_FLAGS ,
537
+ ) ) ,
538
+ #[ cfg( not( target_os = "linux" ) ) ]
539
+ FdType :: NormalDir => libc_ok ( libc:: openat (
540
+ fd,
541
+ & CURRENT_DIRECTORY as * const libc:: c_char ,
542
+ libc:: O_PATH | BASE_OPEN_FLAGS ,
543
+ ) ) ,
544
+ #[ cfg( target_os = "linux" ) ]
545
+ FdType :: LiteDir => libc_ok ( libc:: dup ( fd) ) ,
546
+ _ => Err ( io:: Error :: from_raw_os_error ( libc:: ENOTDIR ) ) ,
547
+ }
548
+ }
549
+ }
550
+
504
551
enum FdType {
505
552
NormalDir ,
506
553
LiteDir ,
0 commit comments