@@ -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 ;
@@ -277,11 +294,15 @@ impl Dir {
277294 pub fn new < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
278295 let mut opts = OpenOptions :: new ( ) ;
279296 opts. read ( true ) ;
280- run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: open_c_dir ( path, & opts) )
297+ run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: new_with_c ( path, & opts) )
281298 }
282299
283300 pub fn new_with < P : AsRef < Path > > ( path : P , opts : & OpenOptions ) -> io:: Result < Self > {
284- run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: open_c_dir ( path, & opts) )
301+ run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: new_with_c ( path, opts) )
302+ }
303+
304+ pub fn new_for_traversal < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
305+ run_path_with_cstr ( path. as_ref ( ) , & |path| Self :: new_c ( path) )
285306 }
286307
287308 pub fn open < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
@@ -298,6 +319,14 @@ impl Dir {
298319 run_path_with_cstr ( path. as_ref ( ) , & |path| self . create_dir_c ( path) )
299320 }
300321
322+ pub fn open_dir < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < Self > {
323+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c_dir ( path, & OpenOptions :: new ( ) ) )
324+ }
325+
326+ pub fn open_dir_with < P : AsRef < Path > > ( & self , path : P , opts : & OpenOptions ) -> io:: Result < Self > {
327+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c_dir ( path, opts) )
328+ }
329+
301330 pub fn remove_file < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < ( ) > {
302331 run_path_with_cstr ( path. as_ref ( ) , & |path| self . remove_c ( path, false ) )
303332 }
@@ -328,7 +357,25 @@ impl Dir {
328357 Ok ( File ( unsafe { FileDesc :: from_raw_fd ( fd) } ) )
329358 }
330359
331- pub fn open_c_dir ( path : & CStr , opts : & OpenOptions ) -> io:: Result < Self > {
360+ pub fn open_c_dir ( & self , path : & CStr , opts : & OpenOptions ) -> io:: Result < Self > {
361+ let flags = libc:: O_CLOEXEC
362+ | libc:: O_DIRECTORY
363+ | opts. get_access_mode ( ) ?
364+ | opts. get_creation_mode ( ) ?
365+ | ( opts. custom_flags as c_int & !libc:: O_ACCMODE ) ;
366+ let fd = cvt_r ( || unsafe {
367+ openat64 ( self . 0 . as_raw_fd ( ) , path. as_ptr ( ) , flags, opts. mode as c_int )
368+ } ) ?;
369+ Ok ( Self ( unsafe { OwnedFd :: from_raw_fd ( fd) } ) )
370+ }
371+
372+ pub fn new_c ( path : & CStr ) -> io:: Result < Self > {
373+ let flags = libc:: O_CLOEXEC | libc:: O_DIRECTORY | TRAVERSE_DIRECTORY ;
374+ let fd = cvt_r ( || unsafe { open64 ( path. as_ptr ( ) , flags, 0 ) } ) ?;
375+ Ok ( Self ( unsafe { OwnedFd :: from_raw_fd ( fd) } ) )
376+ }
377+
378+ pub fn new_with_c ( path : & CStr , opts : & OpenOptions ) -> io:: Result < Self > {
332379 let flags = libc:: O_CLOEXEC
333380 | libc:: O_DIRECTORY
334381 | opts. get_access_mode ( ) ?
@@ -466,6 +513,8 @@ impl fmt::Debug for Dir {
466513 }
467514}
468515
516+ // SAFETY: `int dirfd (DIR *dirstream)` is MT-safe, implying that the pointer
517+ // may be safely sent among threads.
469518unsafe impl Send for DirStream { }
470519unsafe impl Sync for DirStream { }
471520
0 commit comments