@@ -54,7 +54,7 @@ use libc::{c_int, mode_t};
54
54
#[ cfg( target_os = "android" ) ]
55
55
use libc:: {
56
56
dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
57
- lstat as lstat64, off64_t, open as open64, stat as stat64,
57
+ lstat as lstat64, off64_t, open as open64, openat as openat64 , stat as stat64,
58
58
} ;
59
59
#[ cfg( not( any(
60
60
all( target_os = "linux" , not( target_env = "musl" ) ) ,
@@ -64,14 +64,14 @@ use libc::{
64
64
) ) ) ]
65
65
use libc:: {
66
66
dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64,
67
- lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
67
+ lstat as lstat64, off_t as off64_t, open as open64, openat as openat64 , stat as stat64,
68
68
} ;
69
69
#[ cfg( any(
70
70
all( target_os = "linux" , not( target_env = "musl" ) ) ,
71
71
target_os = "l4re" ,
72
72
target_os = "hurd"
73
73
) ) ]
74
- use libc:: { dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64} ;
74
+ use libc:: { dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, openat64 , stat64} ;
75
75
76
76
use crate :: ffi:: { CStr , OsStr , OsString } ;
77
77
use crate :: fmt:: { self , Write as _} ;
@@ -264,7 +264,154 @@ impl ReadDir {
264
264
}
265
265
}
266
266
267
- struct Dir ( * mut libc:: DIR ) ;
267
+ pub struct Dir ( * mut libc:: DIR ) ;
268
+
269
+ // dirfd isn't supported everywhere
270
+ #[ cfg( not( any(
271
+ miri,
272
+ target_os = "redox" ,
273
+ target_os = "nto" ,
274
+ target_os = "vita" ,
275
+ target_os = "hurd" ,
276
+ target_os = "espidf" ,
277
+ target_os = "horizon" ,
278
+ target_os = "vxworks" ,
279
+ target_os = "rtems" ,
280
+ target_os = "nuttx" ,
281
+ ) ) ) ]
282
+ impl Dir {
283
+ pub fn open < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
284
+ let mut opts = OpenOptions :: new ( ) ;
285
+ opts. read ( true ) ;
286
+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c ( path, & opts) )
287
+ }
288
+
289
+ pub fn open_with < P : AsRef < Path > > ( & self , path : P , opts : & OpenOptions ) -> io:: Result < File > {
290
+ run_path_with_cstr ( path. as_ref ( ) , & |path| self . open_c ( path, opts) )
291
+ }
292
+
293
+ pub fn open_c ( & self , path : & CStr , opts : & OpenOptions ) -> io:: Result < File > {
294
+ let flags = libc:: O_CLOEXEC
295
+ | opts. get_access_mode ( ) ?
296
+ | opts. get_creation_mode ( ) ?
297
+ | ( opts. custom_flags as c_int & !libc:: O_ACCMODE ) ;
298
+ let fd = cvt_r ( || unsafe {
299
+ openat64 ( libc:: dirfd ( self . 0 ) , path. as_ptr ( ) , flags, opts. mode as c_int )
300
+ } ) ?;
301
+ Ok ( File ( unsafe { FileDesc :: from_raw_fd ( fd) } ) )
302
+ }
303
+
304
+ // pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
305
+ // pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to_dir: &Self, to: Q) -> Result<()>
306
+ // pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()>
307
+ // pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
308
+ // pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(&self, original: P, link: Q)
309
+ }
310
+
311
+ fn get_path_from_fd ( fd : c_int ) -> Option < PathBuf > {
312
+ #[ cfg( any( target_os = "linux" , target_os = "illumos" , target_os = "solaris" ) ) ]
313
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
314
+ let mut p = PathBuf :: from ( "/proc/self/fd" ) ;
315
+ p. push ( & fd. to_string ( ) ) ;
316
+ run_path_with_cstr ( & p, & readlink) . ok ( )
317
+ }
318
+
319
+ #[ cfg( any( target_vendor = "apple" , target_os = "netbsd" ) ) ]
320
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
321
+ // FIXME: The use of PATH_MAX is generally not encouraged, but it
322
+ // is inevitable in this case because Apple targets and NetBSD define `fcntl`
323
+ // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
324
+ // alternatives. If a better method is invented, it should be used
325
+ // instead.
326
+ let mut buf = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
327
+ let n = unsafe { libc:: fcntl ( fd, libc:: F_GETPATH , buf. as_ptr ( ) ) } ;
328
+ if n == -1 {
329
+ cfg_if:: cfg_if! {
330
+ if #[ cfg( target_os = "netbsd" ) ] {
331
+ // fallback to procfs as last resort
332
+ let mut p = PathBuf :: from( "/proc/self/fd" ) ;
333
+ p. push( & fd. to_string( ) ) ;
334
+ return run_path_with_cstr( & p, & readlink) . ok( )
335
+ } else {
336
+ return None ;
337
+ }
338
+ }
339
+ }
340
+ let l = buf. iter ( ) . position ( |& c| c == 0 ) . unwrap ( ) ;
341
+ buf. truncate ( l as usize ) ;
342
+ buf. shrink_to_fit ( ) ;
343
+ Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
344
+ }
345
+
346
+ #[ cfg( target_os = "freebsd" ) ]
347
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
348
+ let info = Box :: < libc:: kinfo_file > :: new_zeroed ( ) ;
349
+ let mut info = unsafe { info. assume_init ( ) } ;
350
+ info. kf_structsize = size_of :: < libc:: kinfo_file > ( ) as libc:: c_int ;
351
+ let n = unsafe { libc:: fcntl ( fd, libc:: F_KINFO , & mut * info) } ;
352
+ if n == -1 {
353
+ return None ;
354
+ }
355
+ let buf = unsafe { CStr :: from_ptr ( info. kf_path . as_mut_ptr ( ) ) . to_bytes ( ) . to_vec ( ) } ;
356
+ Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
357
+ }
358
+
359
+ #[ cfg( target_os = "vxworks" ) ]
360
+ fn get_path ( fd : c_int ) -> Option < PathBuf > {
361
+ let mut buf = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
362
+ let n = unsafe { libc:: ioctl ( fd, libc:: FIOGETNAME , buf. as_ptr ( ) ) } ;
363
+ if n == -1 {
364
+ return None ;
365
+ }
366
+ let l = buf. iter ( ) . position ( |& c| c == 0 ) . unwrap ( ) ;
367
+ buf. truncate ( l as usize ) ;
368
+ Some ( PathBuf :: from ( OsString :: from_vec ( buf) ) )
369
+ }
370
+
371
+ #[ cfg( not( any(
372
+ target_os = "linux" ,
373
+ target_os = "vxworks" ,
374
+ target_os = "freebsd" ,
375
+ target_os = "netbsd" ,
376
+ target_os = "illumos" ,
377
+ target_os = "solaris" ,
378
+ target_vendor = "apple" ,
379
+ ) ) ) ]
380
+ fn get_path ( _fd : c_int ) -> Option < PathBuf > {
381
+ // FIXME(#24570): implement this for other Unix platforms
382
+ None
383
+ }
384
+
385
+ get_path ( fd)
386
+ }
387
+
388
+ impl fmt:: Debug for Dir {
389
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
390
+ fn get_mode ( fd : c_int ) -> Option < ( bool , bool ) > {
391
+ let mode = unsafe { libc:: fcntl ( fd, libc:: F_GETFL ) } ;
392
+ if mode == -1 {
393
+ return None ;
394
+ }
395
+ match mode & libc:: O_ACCMODE {
396
+ libc:: O_RDONLY => Some ( ( true , false ) ) ,
397
+ libc:: O_RDWR => Some ( ( true , true ) ) ,
398
+ libc:: O_WRONLY => Some ( ( false , true ) ) ,
399
+ _ => None ,
400
+ }
401
+ }
402
+
403
+ let fd = unsafe { dirfd ( self . 0 ) } ;
404
+ let mut b = f. debug_struct ( "Dir" ) ;
405
+ b. field ( "fd" , & fd) ;
406
+ if let Some ( path) = get_path_from_fd ( fd) {
407
+ b. field ( "path" , & path) ;
408
+ }
409
+ if let Some ( ( read, write) ) = get_mode ( fd) {
410
+ b. field ( "read" , & read) . field ( "write" , & write) ;
411
+ }
412
+ b. finish ( )
413
+ }
414
+ }
268
415
269
416
unsafe impl Send for Dir { }
270
417
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