3
3
4
4
use crate :: os:: unix:: prelude:: * ;
5
5
6
- use crate :: ffi:: { CStr , CString , OsStr , OsString } ;
6
+ use crate :: ffi:: { CStr , OsStr , OsString } ;
7
7
use crate :: fmt;
8
8
use crate :: io:: { self , BorrowedCursor , Error , IoSlice , IoSliceMut , SeekFrom } ;
9
9
use crate :: mem;
@@ -86,7 +86,11 @@ use libc::{
86
86
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
87
87
} ;
88
88
#[ 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;
90
94
91
95
pub use crate :: sys_common:: fs:: try_exists;
92
96
@@ -269,9 +273,25 @@ pub struct ReadDir {
269
273
}
270
274
271
275
impl ReadDir {
276
+ #[ cfg( not( any( target_os = "android" , target_os = "linux" ) ) ) ]
272
277
fn new ( inner : InnerReadDir ) -> Self {
273
278
Self { inner : Arc :: new ( inner) , end_of_stream : false }
274
279
}
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
+ }
275
295
}
276
296
277
297
struct Dir ( * mut libc:: DIR ) ;
@@ -1070,14 +1090,17 @@ impl File {
1070
1090
use crate :: io:: ErrorKind ;
1071
1091
match result {
1072
1092
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
+ }
1074
1096
Err ( e) => Err ( e) ,
1075
1097
}
1076
1098
} ;
1077
1099
1078
1100
result
1079
1101
}
1080
1102
1103
+ #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
1081
1104
pub fn open_c (
1082
1105
dirfd : Option < BorrowedFd < ' _ > > ,
1083
1106
path : & CStr ,
@@ -1095,24 +1118,7 @@ impl File {
1095
1118
// the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms).
1096
1119
cvt_r ( || unsafe { open64 ( path. as_ptr ( ) , flags, opts. mode as c_int ) } ) ?
1097
1120
}
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 ( ) ,
1116
1122
} ;
1117
1123
Ok ( File ( unsafe { FileDesc :: from_raw_fd ( fd) } ) )
1118
1124
}
@@ -1555,15 +1561,14 @@ impl fmt::Debug for File {
1555
1561
}
1556
1562
}
1557
1563
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 ( ) ) ;
1565
1567
}
1568
+ Ok ( ptr)
1569
+ }
1566
1570
1571
+ pub fn readdir ( path : & Path ) -> io:: Result < ReadDir > {
1567
1572
let root = path. to_path_buf ( ) ;
1568
1573
let ptr = cvt_p ( run_path_with_cstr ( path, |p| unsafe { Ok ( libc:: opendir ( p. as_ptr ( ) ) ) } ) ?) ;
1569
1574
@@ -1734,7 +1739,12 @@ pub fn lstat(path: &Path) -> io::Result<FileAttr> {
1734
1739
let result = cvt ( unsafe { lstat64 ( p. as_ptr ( ) , & mut stat) } ) ;
1735
1740
long_filename_fallback ! ( path, result, |dirfd, file_name| {
1736
1741
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
+ )
1738
1748
} )
1739
1749
} ) ?;
1740
1750
Ok ( FileAttr :: from_stat64 ( stat) )
@@ -1755,75 +1765,15 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
1755
1765
} ) ) )
1756
1766
}
1757
1767
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
1824
1774
}
1825
1775
}
1826
- }
1776
+ } }
1827
1777
1828
1778
fn open_from ( from : & Path ) -> io:: Result < ( crate :: fs:: File , crate :: fs:: Metadata ) > {
1829
1779
use crate :: fs:: File ;
@@ -1854,7 +1804,6 @@ fn open_to_and_set_permissions(
1854
1804
reader_metadata : crate :: fs:: Metadata ,
1855
1805
) -> io:: Result < ( crate :: fs:: File , crate :: fs:: Metadata ) > {
1856
1806
use crate :: fs:: OpenOptions ;
1857
- use crate :: os:: unix:: fs:: { OpenOptionsExt , PermissionsExt } ;
1858
1807
1859
1808
let perm = reader_metadata. permissions ( ) ;
1860
1809
let writer = OpenOptions :: new ( )
@@ -2059,13 +2008,20 @@ mod remove_dir_impl {
2059
2008
pub use crate :: sys_common:: fs:: remove_dir_all;
2060
2009
}
2061
2010
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
+
2062
2016
// Modern implementation using openat(), unlinkat() and fdopendir()
2063
2017
#[ cfg( not( any(
2064
2018
target_os = "redox" ,
2065
2019
target_os = "espidf" ,
2066
2020
target_os = "horizon" ,
2067
2021
target_os = "vita" ,
2068
2022
target_os = "nto" ,
2023
+ target_os = "linux" ,
2024
+ target_os = "android" ,
2069
2025
miri
2070
2026
) ) ) ]
2071
2027
mod remove_dir_impl {
0 commit comments