@@ -78,6 +78,23 @@ use libc::{
7878 stat64, unlinkat,
7979} ;
8080
81+ #[ cfg( any( target_os = "freebsd" , target_os = "aix" ) ) ]
82+ const TRAVERSE_DIRECTORY : i32 = libc:: O_EXEC ;
83+ #[ cfg( any( target_os = "linux" , target_os = "android" , target_os = "l4re" , target_os = "redox" ) ) ]
84+ const TRAVERSE_DIRECTORY : i32 = libc:: O_PATH ;
85+ #[ cfg( target_os = "illumos" ) ]
86+ const TRAVERSE_DIRECTORY : i32 = libc:: O_SEARCH ;
87+ #[ cfg( not( any(
88+ target_os = "aix" ,
89+ target_os = "android" ,
90+ target_os = "freebsd" ,
91+ target_os = "illumos" ,
92+ target_os = "l4re" ,
93+ target_os = "linux" ,
94+ target_os = "redox" ,
95+ ) ) ) ]
96+ const TRAVERSE_DIRECTORY : i32 = libc:: O_RDONLY ;
97+
8198use crate :: ffi:: { CStr , OsStr , OsString } ;
8299use crate :: fmt:: { self , Write as _} ;
83100use crate :: fs:: TryLockError ;
@@ -278,11 +295,15 @@ impl Dir {
278295 pub fn new < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
279296 let mut opts = OpenOptions :: new ( ) ;
280297 opts. read ( true ) ;
281- run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: open_c_dir ( path, & opts) )
298+ run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: new_with_c ( path, & opts) )
282299 }
283300
284301 pub fn new_with < P : AsRef < Path > > ( path : P , opts : & OpenOptions ) -> io:: Result < Self > {
285- run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: open_c_dir ( path, & opts) )
302+ run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: new_with_c ( path, opts) )
303+ }
304+
305+ pub fn new_for_traversal < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
306+ run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: new_c ( path) )
286307 }
287308
288309 pub fn open < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
@@ -299,6 +320,14 @@ impl Dir {
299320 run_path_with_cstr ( path. as_ref ( ) , & |path| self . create_dir_c ( path) )
300321 }
301322
323+ pub fn open_dir < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < Self > {
324+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c_dir ( path, & OpenOptions :: new ( ) ) )
325+ }
326+
327+ pub fn open_dir_with < P : AsRef < Path > > ( & self , path : P , opts : & OpenOptions ) -> io:: Result < Self > {
328+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c_dir ( path, opts) )
329+ }
330+
302331 pub fn remove_file < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < ( ) > {
303332 run_path_with_cstr ( path. as_ref ( ) , & |path| self . remove_c ( path, false ) )
304333 }
@@ -329,7 +358,25 @@ impl Dir {
329358 Ok ( File ( unsafe { FileDesc :: from_raw_fd ( fd) } ) )
330359 }
331360
332- pub fn open_c_dir ( path : & CStr , opts : & OpenOptions ) -> io:: Result < Self > {
361+ pub fn open_c_dir ( & self , path : & CStr , opts : & OpenOptions ) -> io:: Result < Self > {
362+ let flags = libc:: O_CLOEXEC
363+ | libc:: O_DIRECTORY
364+ | opts. get_access_mode ( ) ?
365+ | opts. get_creation_mode ( ) ?
366+ | ( opts. custom_flags as c_int & !libc:: O_ACCMODE ) ;
367+ let fd = cvt_r ( || unsafe {
368+ openat64 ( self . 0 . as_raw_fd ( ) , path. as_ptr ( ) , flags, opts. mode as c_int )
369+ } ) ?;
370+ Ok ( Self ( unsafe { OwnedFd :: from_raw_fd ( fd) } ) )
371+ }
372+
373+ pub fn new_c ( path : & CStr ) -> io:: Result < Self > {
374+ let flags = libc:: O_CLOEXEC | libc:: O_DIRECTORY | TRAVERSE_DIRECTORY ;
375+ let fd = cvt_r ( || unsafe { open64 ( path. as_ptr ( ) , flags, 0 ) } ) ?;
376+ Ok ( Self ( unsafe { OwnedFd :: from_raw_fd ( fd) } ) )
377+ }
378+
379+ pub fn new_with_c ( path : & CStr , opts : & OpenOptions ) -> io:: Result < Self > {
333380 let flags = libc:: O_CLOEXEC
334381 | libc:: O_DIRECTORY
335382 | opts. get_access_mode ( ) ?
@@ -467,6 +514,8 @@ impl fmt::Debug for Dir {
467514 }
468515}
469516
517+ // SAFETY: `int dirfd (DIR *dirstream)` is MT-safe, implying that the pointer
518+ // may be safely sent among threads.
470519unsafe impl Send for DirStream { }
471520unsafe impl Sync for DirStream { }
472521
0 commit comments