33
44use crate :: os:: unix:: prelude:: * ;
55
6- use crate :: ffi:: { CStr , CString , OsStr , OsString } ;
6+ use crate :: ffi:: { CStr , OsStr , OsString } ;
77use crate :: fmt;
88use crate :: io:: { self , BorrowedCursor , Error , IoSlice , IoSliceMut , SeekFrom } ;
99use crate :: mem;
@@ -86,7 +86,11 @@ use libc::{
8686 lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
8787} ;
8888#[ cfg( any( target_os = "linux" , target_os = "emscripten" , target_os = "l4re" ) ) ]
89- use libc:: { dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64} ;
89+ use libc:: { dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, stat64} ;
90+
91+ // FIXME: port this to other unices that support *at syscalls
92+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
93+ mod dir_fd;
9094
9195pub use crate :: sys_common:: fs:: try_exists;
9296
@@ -269,9 +273,25 @@ pub struct ReadDir {
269273}
270274
271275impl ReadDir {
276+ #[ cfg( not( any( target_os = "android" , target_os = "linux" ) ) ) ]
272277 fn new ( inner : InnerReadDir ) -> Self {
273278 Self { inner : Arc :: new ( inner) , end_of_stream : false }
274279 }
280+
281+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
282+ fn from_dirp ( ptr : * mut libc:: DIR , root : PathBuf ) -> ReadDir {
283+ let inner = InnerReadDir { dirp : Dir ( ptr) , root } ;
284+ ReadDir {
285+ inner : Arc :: new ( inner) ,
286+ #[ cfg( not( any(
287+ target_os = "solaris" ,
288+ target_os = "illumos" ,
289+ target_os = "fuchsia" ,
290+ target_os = "redox" ,
291+ ) ) ) ]
292+ end_of_stream : false ,
293+ }
294+ }
275295}
276296
277297struct Dir ( * mut libc:: DIR ) ;
@@ -1070,14 +1090,17 @@ impl File {
10701090 use crate :: io:: ErrorKind ;
10711091 match result {
10721092 Ok ( file) => Ok ( file) ,
1073- Err ( e) if e. kind ( ) == ErrorKind :: InvalidFilename => open_deep ( path, opts) ,
1093+ Err ( e) if e. kind ( ) == ErrorKind :: InvalidFilename => {
1094+ dir_fd:: open_deep ( None , path, opts)
1095+ }
10741096 Err ( e) => Err ( e) ,
10751097 }
10761098 } ;
10771099
10781100 result
10791101 }
10801102
1103+ #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
10811104 pub fn open_c (
10821105 dirfd : Option < BorrowedFd < ' _ > > ,
10831106 path : & CStr ,
@@ -1095,24 +1118,7 @@ impl File {
10951118 // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms).
10961119 cvt_r ( || unsafe { open64 ( path. as_ptr ( ) , flags, opts. mode as c_int ) } ) ?
10971120 }
1098- Some ( dirfd) => {
1099- cfg_if:: cfg_if! {
1100- if #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ] {
1101- use libc:: openat64;
1102- cvt_r( || unsafe {
1103- openat64(
1104- dirfd. as_raw_fd( ) ,
1105- path. as_ptr( ) ,
1106- flags,
1107- // see previous comment why this cast is necessary
1108- opts. mode as c_int
1109- )
1110- } ) ?
1111- } else {
1112- return super :: unsupported:: unsupported( )
1113- }
1114- }
1115- }
1121+ Some ( dirfd) => return super :: unsupported:: unsupported ( ) ,
11161122 } ;
11171123 Ok ( File ( unsafe { FileDesc :: from_raw_fd ( fd) } ) )
11181124 }
@@ -1555,15 +1561,14 @@ impl fmt::Debug for File {
15551561 }
15561562}
15571563
1558- pub fn readdir ( path : & Path ) -> io:: Result < ReadDir > {
1559-
1560- fn cvt_p < T > ( ptr : * mut T ) -> io:: Result < * mut T > {
1561- if ptr. is_null ( ) {
1562- return Err ( Error :: last_os_error ( ) ) ;
1563- }
1564- Ok ( ptr)
1564+ fn cvt_p < T > ( ptr : * mut T ) -> io:: Result < * mut T > {
1565+ if ptr. is_null ( ) {
1566+ return Err ( Error :: last_os_error ( ) ) ;
15651567 }
1568+ Ok ( ptr)
1569+ }
15661570
1571+ pub fn readdir ( path : & Path ) -> io:: Result < ReadDir > {
15671572 let root = path. to_path_buf ( ) ;
15681573 let ptr = cvt_p ( run_path_with_cstr ( path, |p| unsafe { Ok ( libc:: opendir ( p. as_ptr ( ) ) ) } ) ?) ;
15691574
@@ -1734,7 +1739,12 @@ pub fn lstat(path: &Path) -> io::Result<FileAttr> {
17341739 let result = cvt ( unsafe { lstat64 ( p. as_ptr ( ) , & mut stat) } ) ;
17351740 long_filename_fallback ! ( path, result, |dirfd, file_name| {
17361741 cvt( unsafe {
1737- fstatat64( dirfd. as_raw_fd( ) , file_name. as_ptr( ) , & mut stat, libc:: AT_SYMLINK_NOFOLLOW )
1742+ fstatat64(
1743+ dirfd. as_raw_fd( ) ,
1744+ file_name. as_ptr( ) ,
1745+ & mut stat,
1746+ libc:: AT_SYMLINK_NOFOLLOW ,
1747+ )
17381748 } )
17391749 } ) ?;
17401750 Ok ( FileAttr :: from_stat64 ( stat) )
@@ -1755,75 +1765,15 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
17551765 } ) ) )
17561766}
17571767
1758- #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
1759- fn open_deep ( path : & Path , opts : & OpenOptions ) -> io:: Result < File > {
1760- use super :: path:: is_sep_byte;
1761- use libc:: O_PATH ;
1762- const MAX_SLICE : usize = ( libc:: PATH_MAX - 1 ) as usize ;
1763-
1764- let mut raw_path = path. as_os_str ( ) . as_bytes ( ) ;
1765- let mut at_path = None ;
1766-
1767- let mut dir_flags = OpenOptions :: new ( ) ;
1768- dir_flags. read ( true ) ;
1769- dir_flags. custom_flags ( O_PATH ) ;
1770-
1771- while raw_path. len ( ) > MAX_SLICE {
1772- let sep_idx = match raw_path. iter ( ) . take ( MAX_SLICE ) . rposition ( |& byte| is_sep_byte ( byte) ) {
1773- Some ( idx) => idx,
1774- _ => return Err ( io:: Error :: from_raw_os_error ( libc:: ENAMETOOLONG ) ) ,
1775- } ;
1776-
1777- let ( left, right) = raw_path. split_at ( sep_idx + 1 ) ;
1778- raw_path = right;
1779-
1780- let to_open = CString :: new ( left) ?;
1781- let dirfd = at_path. as_ref ( ) . map ( AsFd :: as_fd) ;
1782-
1783- at_path = Some ( File :: open_c ( dirfd, & to_open, & dir_flags) ?) ;
1784- }
1785-
1786- let to_open = CString :: new ( raw_path) ?;
1787- let dirfd = at_path. as_ref ( ) . map ( AsFd :: as_fd) ;
1788-
1789- File :: open_c ( dirfd, & to_open, opts)
1790- }
1791-
1792- macro long_filename_fallback {
1793- ( $path: expr, $result: expr, $fallback: expr) => {
1794- {
1795- cfg_if:: cfg_if! {
1796- if #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ] {
1797- fn deep_fallback<T >( result: io:: Result <T >, path: & Path , mut fallback: impl FnMut ( File , & CStr ) -> io:: Result <T >) -> io:: Result <T > {
1798- use crate :: io:: ErrorKind ;
1799- match result {
1800- ok @ Ok ( _) => ok,
1801- Err ( e) if e. kind( ) == ErrorKind :: InvalidFilename => {
1802- if let Some ( parent) = path. parent( ) {
1803- let mut options = OpenOptions :: new( ) ;
1804- options. read( true ) ;
1805- options. custom_flags( libc:: O_PATH ) ;
1806- let dirfd = open_deep( parent, & options) ?;
1807- let file_name = path. file_name( ) . unwrap( ) ;
1808- return run_path_with_cstr( file_name, |file_name| {
1809- fallback( dirfd, file_name)
1810- } )
1811- }
1812-
1813- Err ( e)
1814- } ,
1815- Err ( e) => Err ( e)
1816- }
1817- }
1818-
1819- deep_fallback( $result, $path, $fallback)
1820- } else {
1821- $result
1822- }
1823- }
1768+ macro long_filename_fallback ( $path: expr, $result: expr, $fallback: expr) { {
1769+ cfg_if:: cfg_if! {
1770+ if #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ] {
1771+ dir_fd:: long_filename_fallback( $result, $path, $fallback)
1772+ } else {
1773+ $result
18241774 }
18251775 }
1826- }
1776+ } }
18271777
18281778fn open_from ( from : & Path ) -> io:: Result < ( crate :: fs:: File , crate :: fs:: Metadata ) > {
18291779 use crate :: fs:: File ;
@@ -1854,7 +1804,6 @@ fn open_to_and_set_permissions(
18541804 reader_metadata : crate :: fs:: Metadata ,
18551805) -> io:: Result < ( crate :: fs:: File , crate :: fs:: Metadata ) > {
18561806 use crate :: fs:: OpenOptions ;
1857- use crate :: os:: unix:: fs:: { OpenOptionsExt , PermissionsExt } ;
18581807
18591808 let perm = reader_metadata. permissions ( ) ;
18601809 let writer = OpenOptions :: new ( )
@@ -2059,13 +2008,20 @@ mod remove_dir_impl {
20592008 pub use crate :: sys_common:: fs:: remove_dir_all;
20602009}
20612010
2011+ #[ cfg( all( not( miri) , any( target_os = "linux" , target_os = "android" ) ) ) ]
2012+ mod remove_dir_impl {
2013+ pub use super :: dir_fd:: remove_dir_all;
2014+ }
2015+
20622016// Modern implementation using openat(), unlinkat() and fdopendir()
20632017#[ cfg( not( any(
20642018 target_os = "redox" ,
20652019 target_os = "espidf" ,
20662020 target_os = "horizon" ,
20672021 target_os = "vita" ,
20682022 target_os = "nto" ,
2023+ target_os = "linux" ,
2024+ target_os = "android" ,
20692025 miri
20702026) ) ) ]
20712027mod remove_dir_impl {
0 commit comments