@@ -53,7 +53,7 @@ use libc::{c_int, mode_t};
53
53
#[ cfg( target_os = "android" ) ]
54
54
use libc:: {
55
55
dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
56
- lstat as lstat64, off64_t, open as open64, stat as stat64,
56
+ lstat as lstat64, off64_t, open as open64, openat as openat64 , stat as stat64,
57
57
} ;
58
58
#[ cfg( not( any(
59
59
all( target_os = "linux" , not( target_env = "musl" ) ) ,
@@ -63,14 +63,14 @@ use libc::{
63
63
) ) ) ]
64
64
use libc:: {
65
65
dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64,
66
- lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
66
+ lstat as lstat64, off_t as off64_t, open as open64, openat as openat64 , stat as stat64,
67
67
} ;
68
68
#[ cfg( any(
69
69
all( target_os = "linux" , not( target_env = "musl" ) ) ,
70
70
target_os = "l4re" ,
71
71
target_os = "hurd"
72
72
) ) ]
73
- use libc:: { dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64} ;
73
+ use libc:: { dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, openat64 , stat64} ;
74
74
75
75
use crate :: ffi:: { CStr , OsStr , OsString } ;
76
76
use crate :: fmt:: { self , Write as _} ;
@@ -262,7 +262,154 @@ impl ReadDir {
262
262
}
263
263
}
264
264
265
- struct Dir ( * mut libc:: DIR ) ;
265
+ pub struct Dir ( * mut libc:: DIR ) ;
266
+
267
+ // dirfd isn't supported everywhere
268
+ #[ cfg( not( any(
269
+ miri,
270
+ target_os = "redox" ,
271
+ target_os = "nto" ,
272
+ target_os = "vita" ,
273
+ target_os = "hurd" ,
274
+ target_os = "espidf" ,
275
+ target_os = "horizon" ,
276
+ target_os = "vxworks" ,
277
+ target_os = "rtems" ,
278
+ target_os = "nuttx" ,
279
+ ) ) ) ]
280
+ impl Dir {
281
+ pub fn open < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
282
+ let mut opts = OpenOptions :: new ( ) ;
283
+ opts. read ( true ) ;
284
+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c ( path, & opts) )
285
+ }
286
+
287
+ pub fn open_with < P : AsRef < Path > > ( & self , path : P , opts : & OpenOptions ) -> io:: Result < File > {
288
+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c ( path, opts) )
289
+ }
290
+
291
+ pub fn open_c ( & self , path : & CStr , opts : & OpenOptions ) -> io:: Result < File > {
292
+ let flags = libc:: O_CLOEXEC
293
+ | opts. get_access_mode ( ) ?
294
+ | opts. get_creation_mode ( ) ?
295
+ | ( opts. custom_flags as c_int & !libc:: O_ACCMODE ) ;
296
+ let fd = cvt_r ( || unsafe {
297
+ openat64 ( libc:: dirfd ( self . 0 ) , path. as_ptr ( ) , flags, opts. mode as c_int )
298
+ } ) ?;
299
+ Ok ( File ( unsafe { FileDesc :: from_raw_fd ( fd) } ) )
300
+ }
301
+
302
+ // pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
303
+ // pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to_dir: &Self, to: Q) -> Result<()>
304
+ // pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()>
305
+ // pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
306
+ // pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(&self, original: P, link: Q)
307
+ }
308
+
309
+ fn get_path_from_fd ( fd : c_int ) -> Option < PathBuf > {
310
+ #[ cfg( any( target_os = "linux" , target_os = "illumos" , target_os = "solaris" ) ) ]
311
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
312
+ let mut p = PathBuf :: from ( "/proc/self/fd" ) ;
313
+ p. push ( & fd. to_string ( ) ) ;
314
+ run_path_with_cstr ( & p, & readlink) . ok ( )
315
+ }
316
+
317
+ #[ cfg( any( target_vendor = "apple" , target_os = "netbsd" ) ) ]
318
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
319
+ // FIXME: The use of PATH_MAX is generally not encouraged, but it
320
+ // is inevitable in this case because Apple targets and NetBSD define `fcntl`
321
+ // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
322
+ // alternatives. If a better method is invented, it should be used
323
+ // instead.
324
+ let mut buf = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
325
+ let n = unsafe { libc:: fcntl ( fd, libc:: F_GETPATH , buf. as_ptr ( ) ) } ;
326
+ if n == -1 {
327
+ cfg_if:: cfg_if! {
328
+ if #[ cfg( target_os = "netbsd" ) ] {
329
+ // fallback to procfs as last resort
330
+ let mut p = PathBuf :: from( "/proc/self/fd" ) ;
331
+ p. push( & fd. to_string( ) ) ;
332
+ return run_path_with_cstr( & p, & readlink) . ok( )
333
+ } else {
334
+ return None ;
335
+ }
336
+ }
337
+ }
338
+ let l = buf. iter ( ) . position ( |& c| c == 0 ) . unwrap ( ) ;
339
+ buf. truncate ( l as usize ) ;
340
+ buf. shrink_to_fit ( ) ;
341
+ Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
342
+ }
343
+
344
+ #[ cfg( target_os = "freebsd" ) ]
345
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
346
+ let info = Box :: < libc:: kinfo_file > :: new_zeroed ( ) ;
347
+ let mut info = unsafe { info. assume_init ( ) } ;
348
+ info. kf_structsize = size_of :: < libc:: kinfo_file > ( ) as libc:: c_int ;
349
+ let n = unsafe { libc:: fcntl ( fd, libc:: F_KINFO , & mut * info) } ;
350
+ if n == -1 {
351
+ return None ;
352
+ }
353
+ let buf = unsafe { CStr :: from_ptr ( info. kf_path . as_mut_ptr ( ) ) . to_bytes ( ) . to_vec ( ) } ;
354
+ Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
355
+ }
356
+
357
+ #[ cfg( target_os = "vxworks" ) ]
358
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
359
+ let mut buf = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
360
+ let n = unsafe { libc:: ioctl ( fd, libc:: FIOGETNAME , buf. as_ptr ( ) ) } ;
361
+ if n == -1 {
362
+ return None ;
363
+ }
364
+ let l = buf. iter ( ) . position ( |& c| c == 0 ) . unwrap ( ) ;
365
+ buf. truncate ( l as usize ) ;
366
+ Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
367
+ }
368
+
369
+ #[ cfg( not( any(
370
+ target_os = "linux" ,
371
+ target_os = "vxworks" ,
372
+ target_os = "freebsd" ,
373
+ target_os = "netbsd" ,
374
+ target_os = "illumos" ,
375
+ target_os = "solaris" ,
376
+ target_vendor = "apple" ,
377
+ ) ) ) ]
378
+ fn get_path ( _fd : c_int ) -> Option < PathBuf > {
379
+ // FIXME(#24570): implement this for other Unix platforms
380
+ None
381
+ }
382
+
383
+ get_path ( fd)
384
+ }
385
+
386
+ impl fmt:: Debug for Dir {
387
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
388
+ fn get_mode ( fd : c_int ) -> Option < ( bool , bool ) > {
389
+ let mode = unsafe { libc:: fcntl ( fd, libc:: F_GETFL ) } ;
390
+ if mode == -1 {
391
+ return None ;
392
+ }
393
+ match mode & libc:: O_ACCMODE {
394
+ libc:: O_RDONLY => Some ( ( true , false ) ) ,
395
+ libc:: O_RDWR => Some ( ( true , true ) ) ,
396
+ libc:: O_WRONLY => Some ( ( false , true ) ) ,
397
+ _ => None ,
398
+ }
399
+ }
400
+
401
+ let fd = unsafe { dirfd ( self . 0 ) } ;
402
+ let mut b = f. debug_struct ( "Dir" ) ;
403
+ b. field ( "fd" , & fd) ;
404
+ if let Some ( path) = get_path_from_fd ( fd) {
405
+ b. field ( "path" , & path) ;
406
+ }
407
+ if let Some ( ( read, write) ) = get_mode ( fd) {
408
+ b. field ( "read" , & read) . field ( "write" , & write) ;
409
+ }
410
+ b. finish ( )
411
+ }
412
+ }
266
413
267
414
unsafe impl Send for Dir { }
268
415
unsafe impl Sync for Dir { }
@@ -1653,79 +1800,6 @@ impl FromRawFd for File {
1653
1800
1654
1801
impl fmt:: Debug for File {
1655
1802
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1656
- #[ cfg( any( target_os = "linux" , target_os = "illumos" , target_os = "solaris" ) ) ]
1657
- fn get_path ( fd : c_int ) -> Option < PathBuf > {
1658
- let mut p = PathBuf :: from ( "/proc/self/fd" ) ;
1659
- p. push ( & fd. to_string ( ) ) ;
1660
- run_path_with_cstr ( & p, & readlink) . ok ( )
1661
- }
1662
-
1663
- #[ cfg( any( target_vendor = "apple" , target_os = "netbsd" ) ) ]
1664
- fn get_path ( fd : c_int ) -> Option < PathBuf > {
1665
- // FIXME: The use of PATH_MAX is generally not encouraged, but it
1666
- // is inevitable in this case because Apple targets and NetBSD define `fcntl`
1667
- // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
1668
- // alternatives. If a better method is invented, it should be used
1669
- // instead.
1670
- let mut buf = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
1671
- let n = unsafe { libc:: fcntl ( fd, libc:: F_GETPATH , buf. as_ptr ( ) ) } ;
1672
- if n == -1 {
1673
- cfg_if:: cfg_if! {
1674
- if #[ cfg( target_os = "netbsd" ) ] {
1675
- // fallback to procfs as last resort
1676
- let mut p = PathBuf :: from( "/proc/self/fd" ) ;
1677
- p. push( & fd. to_string( ) ) ;
1678
- return run_path_with_cstr( & p, & readlink) . ok( )
1679
- } else {
1680
- return None ;
1681
- }
1682
- }
1683
- }
1684
- let l = buf. iter ( ) . position ( |& c| c == 0 ) . unwrap ( ) ;
1685
- buf. truncate ( l as usize ) ;
1686
- buf. shrink_to_fit ( ) ;
1687
- Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
1688
- }
1689
-
1690
- #[ cfg( target_os = "freebsd" ) ]
1691
- fn get_path ( fd : c_int ) -> Option < PathBuf > {
1692
- let info = Box :: < libc:: kinfo_file > :: new_zeroed ( ) ;
1693
- let mut info = unsafe { info. assume_init ( ) } ;
1694
- info. kf_structsize = size_of :: < libc:: kinfo_file > ( ) as libc:: c_int ;
1695
- let n = unsafe { libc:: fcntl ( fd, libc:: F_KINFO , & mut * info) } ;
1696
- if n == -1 {
1697
- return None ;
1698
- }
1699
- let buf = unsafe { CStr :: from_ptr ( info. kf_path . as_mut_ptr ( ) ) . to_bytes ( ) . to_vec ( ) } ;
1700
- Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
1701
- }
1702
-
1703
- #[ cfg( target_os = "vxworks" ) ]
1704
- fn get_path ( fd : c_int ) -> Option < PathBuf > {
1705
- let mut buf = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
1706
- let n = unsafe { libc:: ioctl ( fd, libc:: FIOGETNAME , buf. as_ptr ( ) ) } ;
1707
- if n == -1 {
1708
- return None ;
1709
- }
1710
- let l = buf. iter ( ) . position ( |& c| c == 0 ) . unwrap ( ) ;
1711
- buf. truncate ( l as usize ) ;
1712
- Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
1713
- }
1714
-
1715
- #[ cfg( not( any(
1716
- target_os = "linux" ,
1717
- target_os = "vxworks" ,
1718
- target_os = "freebsd" ,
1719
- target_os = "netbsd" ,
1720
- target_os = "illumos" ,
1721
- target_os = "solaris" ,
1722
- target_vendor = "apple" ,
1723
- ) ) ) ]
1724
- fn get_path ( _fd : c_int ) -> Option < PathBuf > {
1725
- // FIXME(#24570): implement this for other Unix platforms
1726
- None
1727
- }
1728
-
1729
1803
fn get_mode ( fd : c_int ) -> Option < ( bool , bool ) > {
1730
1804
let mode = unsafe { libc:: fcntl ( fd, libc:: F_GETFL ) } ;
1731
1805
if mode == -1 {
@@ -1742,7 +1816,7 @@ impl fmt::Debug for File {
1742
1816
let fd = self . as_raw_fd ( ) ;
1743
1817
let mut b = f. debug_struct ( "File" ) ;
1744
1818
b. field ( "fd" , & fd) ;
1745
- if let Some ( path) = get_path ( fd) {
1819
+ if let Some ( path) = get_path_from_fd ( fd) {
1746
1820
b. field ( "path" , & path) ;
1747
1821
}
1748
1822
if let Some ( ( read, write) ) = get_mode ( fd) {
0 commit comments