summaryrefslogtreecommitdiffstats
path: root/library/std/src/os
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /library/std/src/os
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std/src/os')
-rw-r--r--library/std/src/os/android/fs.rs117
-rw-r--r--library/std/src/os/android/mod.rs6
-rw-r--r--library/std/src/os/android/raw.rs219
-rw-r--r--library/std/src/os/dragonfly/fs.rs132
-rw-r--r--library/std/src/os/dragonfly/mod.rs6
-rw-r--r--library/std/src/os/dragonfly/raw.rs83
-rw-r--r--library/std/src/os/emscripten/fs.rs117
-rw-r--r--library/std/src/os/emscripten/mod.rs6
-rw-r--r--library/std/src/os/emscripten/raw.rs80
-rw-r--r--library/std/src/os/espidf/fs.rs117
-rw-r--r--library/std/src/os/espidf/mod.rs6
-rw-r--r--library/std/src/os/espidf/raw.rs69
-rw-r--r--library/std/src/os/fd/mod.rs16
-rw-r--r--library/std/src/os/fd/net.rs46
-rw-r--r--library/std/src/os/fd/owned.rs388
-rw-r--r--library/std/src/os/fd/raw.rs259
-rw-r--r--library/std/src/os/fd/tests.rs53
-rw-r--r--library/std/src/os/fortanix_sgx/arch.rs80
-rw-r--r--library/std/src/os/fortanix_sgx/ffi.rs41
-rw-r--r--library/std/src/os/fortanix_sgx/io.rs144
-rw-r--r--library/std/src/os/fortanix_sgx/mod.rs53
-rw-r--r--library/std/src/os/freebsd/fs.rs154
-rw-r--r--library/std/src/os/freebsd/mod.rs6
-rw-r--r--library/std/src/os/freebsd/raw.rs86
-rw-r--r--library/std/src/os/fuchsia/fs.rs95
-rw-r--r--library/std/src/os/fuchsia/mod.rs6
-rw-r--r--library/std/src/os/fuchsia/raw.rs293
-rw-r--r--library/std/src/os/haiku/fs.rs127
-rw-r--r--library/std/src/os/haiku/mod.rs6
-rw-r--r--library/std/src/os/haiku/raw.rs79
-rw-r--r--library/std/src/os/hermit/ffi.rs41
-rw-r--r--library/std/src/os/hermit/mod.rs13
-rw-r--r--library/std/src/os/horizon/fs.rs95
-rw-r--r--library/std/src/os/horizon/mod.rs6
-rw-r--r--library/std/src/os/horizon/raw.rs70
-rw-r--r--library/std/src/os/illumos/fs.rs116
-rw-r--r--library/std/src/os/illumos/mod.rs6
-rw-r--r--library/std/src/os/illumos/raw.rs74
-rw-r--r--library/std/src/os/ios/fs.rs142
-rw-r--r--library/std/src/os/ios/mod.rs6
-rw-r--r--library/std/src/os/ios/raw.rs83
-rw-r--r--library/std/src/os/l4re/fs.rs382
-rw-r--r--library/std/src/os/l4re/mod.rs7
-rw-r--r--library/std/src/os/l4re/raw.rs365
-rw-r--r--library/std/src/os/linux/fs.rs397
-rw-r--r--library/std/src/os/linux/mod.rs8
-rw-r--r--library/std/src/os/linux/process.rs165
-rw-r--r--library/std/src/os/linux/raw.rs366
-rw-r--r--library/std/src/os/macos/fs.rs148
-rw-r--r--library/std/src/os/macos/mod.rs6
-rw-r--r--library/std/src/os/macos/raw.rs83
-rw-r--r--library/std/src/os/mod.rs150
-rw-r--r--library/std/src/os/netbsd/fs.rs137
-rw-r--r--library/std/src/os/netbsd/mod.rs6
-rw-r--r--library/std/src/os/netbsd/raw.rs83
-rw-r--r--library/std/src/os/openbsd/fs.rs137
-rw-r--r--library/std/src/os/openbsd/mod.rs6
-rw-r--r--library/std/src/os/openbsd/raw.rs81
-rw-r--r--library/std/src/os/raw/mod.rs31
-rw-r--r--library/std/src/os/raw/tests.rs15
-rw-r--r--library/std/src/os/redox/fs.rs382
-rw-r--r--library/std/src/os/redox/mod.rs6
-rw-r--r--library/std/src/os/redox/raw.rs78
-rw-r--r--library/std/src/os/solaris/fs.rs117
-rw-r--r--library/std/src/os/solaris/mod.rs6
-rw-r--r--library/std/src/os/solaris/raw.rs76
-rw-r--r--library/std/src/os/solid/ffi.rs41
-rw-r--r--library/std/src/os/solid/io.rs113
-rw-r--r--library/std/src/os/solid/mod.rs17
-rw-r--r--library/std/src/os/unix/ffi/mod.rs42
-rw-r--r--library/std/src/os/unix/ffi/os_str.rs70
-rw-r--r--library/std/src/os/unix/fs.rs1022
-rw-r--r--library/std/src/os/unix/io/fd.rs8
-rw-r--r--library/std/src/os/unix/io/fd/tests.rs11
-rw-r--r--library/std/src/os/unix/io/mod.rs86
-rw-r--r--library/std/src/os/unix/io/raw.rs6
-rw-r--r--library/std/src/os/unix/mod.rs126
-rw-r--r--library/std/src/os/unix/net/addr.rs350
-rw-r--r--library/std/src/os/unix/net/ancillary.rs674
-rw-r--r--library/std/src/os/unix/net/datagram.rs987
-rw-r--r--library/std/src/os/unix/net/listener.rs385
-rw-r--r--library/std/src/os/unix/net/mod.rs26
-rw-r--r--library/std/src/os/unix/net/stream.rs711
-rw-r--r--library/std/src/os/unix/net/tests.rs753
-rw-r--r--library/std/src/os/unix/process.rs466
-rw-r--r--library/std/src/os/unix/raw.rs33
-rw-r--r--library/std/src/os/unix/thread.rs41
-rw-r--r--library/std/src/os/unix/ucred.rs136
-rw-r--r--library/std/src/os/unix/ucred/tests.rs39
-rw-r--r--library/std/src/os/vxworks/fs.rs99
-rw-r--r--library/std/src/os/vxworks/mod.rs6
-rw-r--r--library/std/src/os/vxworks/raw.rs10
-rw-r--r--library/std/src/os/wasi/ffi.rs11
-rw-r--r--library/std/src/os/wasi/fs.rs558
-rw-r--r--library/std/src/os/wasi/io/fd.rs9
-rw-r--r--library/std/src/os/wasi/io/fd/tests.rs11
-rw-r--r--library/std/src/os/wasi/io/mod.rs12
-rw-r--r--library/std/src/os/wasi/io/raw.rs20
-rw-r--r--library/std/src/os/wasi/mod.rs57
-rw-r--r--library/std/src/os/wasi/net/mod.rs23
-rw-r--r--library/std/src/os/windows/ffi.rs136
-rw-r--r--library/std/src/os/windows/fs.rs605
-rw-r--r--library/std/src/os/windows/io/handle.rs576
-rw-r--r--library/std/src/os/windows/io/mod.rs65
-rw-r--r--library/std/src/os/windows/io/raw.rs305
-rw-r--r--library/std/src/os/windows/io/socket.rs338
-rw-r--r--library/std/src/os/windows/io/tests.rs21
-rw-r--r--library/std/src/os/windows/mod.rs58
-rw-r--r--library/std/src/os/windows/process.rs259
-rw-r--r--library/std/src/os/windows/raw.rs16
-rw-r--r--library/std/src/os/windows/thread.rs25
111 files changed, 16143 insertions, 0 deletions
diff --git a/library/std/src/os/android/fs.rs b/library/std/src/os/android/fs.rs
new file mode 100644
index 000000000..1beb3cf6e
--- /dev/null
+++ b/library/std/src/os/android/fs.rs
@@ -0,0 +1,117 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::android::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/android/mod.rs b/library/std/src/os/android/mod.rs
new file mode 100644
index 000000000..dbb0127f3
--- /dev/null
+++ b/library/std/src/os/android/mod.rs
@@ -0,0 +1,6 @@
+//! Android-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/android/raw.rs b/library/std/src/os/android/raw.rs
new file mode 100644
index 000000000..a255d0320
--- /dev/null
+++ b/library/std/src/os/android/raw.rs
@@ -0,0 +1,219 @@
+//! Android-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_long;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, stat, time_t};
+
+#[cfg(any(target_arch = "arm", target_arch = "x86"))]
+mod arch {
+ use crate::os::raw::{c_longlong, c_uchar, c_uint, c_ulong, c_ulonglong};
+ use crate::os::unix::raw::{gid_t, uid_t};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type dev_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type mode_t = u32;
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: c_longlong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: c_ulonglong,
+ }
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use crate::os::raw::{c_uchar, c_ulong};
+ use crate::os::unix::raw::{gid_t, uid_t};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type dev_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type mode_t = u32;
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ }
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch {
+ use crate::os::raw::{c_long, c_uint, c_ulong};
+ use crate::os::unix::raw::{gid_t, uid_t};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type dev_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type mode_t = u32;
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ __unused: [c_long; 3],
+ }
+}
diff --git a/library/std/src/os/dragonfly/fs.rs b/library/std/src/os/dragonfly/fs.rs
new file mode 100644
index 000000000..1424fc4c6
--- /dev/null
+++ b/library/std/src/os/dragonfly/fs.rs
@@ -0,0 +1,132 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::dragonfly::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+}
diff --git a/library/std/src/os/dragonfly/mod.rs b/library/std/src/os/dragonfly/mod.rs
new file mode 100644
index 000000000..350b5fca7
--- /dev/null
+++ b/library/std/src/os/dragonfly/mod.rs
@@ -0,0 +1,6 @@
+//! Dragonfly-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/dragonfly/raw.rs b/library/std/src/os/dragonfly/raw.rs
new file mode 100644
index 000000000..071bf6199
--- /dev/null
+++ b/library/std/src/os/dragonfly/raw.rs
@@ -0,0 +1,83 @@
+//! Dragonfly-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+}
diff --git a/library/std/src/os/emscripten/fs.rs b/library/std/src/os/emscripten/fs.rs
new file mode 100644
index 000000000..d5ec8e03c
--- /dev/null
+++ b/library/std/src/os/emscripten/fs.rs
@@ -0,0 +1,117 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::emscripten::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/emscripten/mod.rs b/library/std/src/os/emscripten/mod.rs
new file mode 100644
index 000000000..d35307162
--- /dev/null
+++ b/library/std/src/os/emscripten/mod.rs
@@ -0,0 +1,6 @@
+//! Linux-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/emscripten/raw.rs b/library/std/src/os/emscripten/raw.rs
new file mode 100644
index 000000000..d23011c73
--- /dev/null
+++ b/library/std/src/os/emscripten/raw.rs
@@ -0,0 +1,80 @@
+//! Emscripten-specific raw type definitions
+//! This is basically exactly the same as the linux definitions,
+//! except using the musl-specific stat64 structure in liblibc.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::{c_long, c_short, c_uint, c_ulong};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = c_long;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+}
diff --git a/library/std/src/os/espidf/fs.rs b/library/std/src/os/espidf/fs.rs
new file mode 100644
index 000000000..88701dafe
--- /dev/null
+++ b/library/std/src/os/espidf/fs.rs
@@ -0,0 +1,117 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::espidf::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_spare4(&self) -> [u32; 2];
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ 0
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ 0
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ 0
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_spare4(&self) -> [u32; 2] {
+ let spare4 = self.as_inner().as_inner().st_spare4;
+ [spare4[0] as u32, spare4[1] as u32]
+ }
+}
diff --git a/library/std/src/os/espidf/mod.rs b/library/std/src/os/espidf/mod.rs
new file mode 100644
index 000000000..a9cef9709
--- /dev/null
+++ b/library/std/src/os/espidf/mod.rs
@@ -0,0 +1,6 @@
+//! Definitions for the ESP-IDF framework.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/espidf/raw.rs b/library/std/src/os/espidf/raw.rs
new file mode 100644
index 000000000..7df0e74b2
--- /dev/null
+++ b/library/std/src/os/espidf/raw.rs
@@ -0,0 +1,69 @@
+//! Raw type definitions for the ESP-IDF framework.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{gid_t, uid_t};
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = libc::pthread_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = libc::blkcnt_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = libc::blksize_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = libc::dev_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = libc::ino_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = libc::mode_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = libc::nlink_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = libc::off_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = libc::time_t;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_spare4: [c_long; 2usize],
+}
diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs
new file mode 100644
index 000000000..a45694753
--- /dev/null
+++ b/library/std/src/os/fd/mod.rs
@@ -0,0 +1,16 @@
+//! Owned and borrowed Unix-like file descriptors.
+
+#![stable(feature = "io_safety", since = "1.63.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+// `RawFd`, `AsRawFd`, etc.
+pub mod raw;
+
+// `OwnedFd`, `AsFd`, etc.
+pub mod owned;
+
+// Implementations for `AsRawFd` etc. for network types.
+mod net;
+
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/os/fd/net.rs b/library/std/src/os/fd/net.rs
new file mode 100644
index 000000000..843f45f7f
--- /dev/null
+++ b/library/std/src/os/fd/net.rs
@@ -0,0 +1,46 @@
+use crate::os::fd::owned::OwnedFd;
+use crate::os::fd::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+use crate::{net, sys};
+
+macro_rules! impl_as_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl AsRawFd for net::$t {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().socket().as_raw_fd()
+ }
+ }
+ )*};
+}
+impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_from_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ impl FromRawFd for net::$t {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
+ unsafe {
+ let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
+ net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+ }
+ }
+ }
+ )*};
+}
+impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_into_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ impl IntoRawFd for net::$t {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner().into_inner().into_raw_fd()
+ }
+ }
+ )*};
+}
+impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
new file mode 100644
index 000000000..a463bc41d
--- /dev/null
+++ b/library/std/src/os/fd/owned.rs
@@ -0,0 +1,388 @@
+//! Owned and borrowed Unix-like file descriptors.
+
+#![stable(feature = "io_safety", since = "1.63.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::fmt;
+use crate::fs;
+use crate::marker::PhantomData;
+use crate::mem::forget;
+#[cfg(not(any(target_arch = "wasm32", target_env = "sgx")))]
+use crate::sys::cvt;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// A borrowed file descriptor.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the file descriptor.
+///
+/// This uses `repr(transparent)` and has the representation of a host file
+/// descriptor, so it can be used in FFI in places where a file descriptor is
+/// passed as an argument, it is not captured or consumed, and it never has the
+/// value `-1`.
+///
+/// This type's `.to_owned()` implementation returns another `BorrowedFd`
+/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file
+/// descriptor, which is then borrowed under the same lifetime.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct BorrowedFd<'fd> {
+ fd: RawFd,
+ _phantom: PhantomData<&'fd OwnedFd>,
+}
+
+/// An owned file descriptor.
+///
+/// This closes the file descriptor on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host file
+/// descriptor, so it can be used in FFI in places where a file descriptor is
+/// passed as a consumed argument or returned as an owned value, and it never
+/// has the value `-1`.
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct OwnedFd {
+ fd: RawFd,
+}
+
+impl BorrowedFd<'_> {
+ /// Return a `BorrowedFd` holding the given raw file descriptor.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `fd` must remain open for the duration of
+ /// the returned `BorrowedFd`, and it must not have the value `-1`.
+ #[inline]
+ #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
+ assert!(fd != u32::MAX as RawFd);
+ // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { Self { fd, _phantom: PhantomData } }
+ }
+}
+
+impl OwnedFd {
+ /// Creates a new `OwnedFd` instance that shares the same underlying file
+ /// description as the existing `OwnedFd` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ self.as_fd().try_clone_to_owned()
+ }
+}
+
+impl BorrowedFd<'_> {
+ /// Creates a new `OwnedFd` instance that shares the same underlying file
+ /// description as the existing `BorrowedFd` instance.
+ #[cfg(not(target_arch = "wasm32"))]
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
+ // We want to atomically duplicate this file descriptor and set the
+ // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
+ // is a POSIX flag that was added to Linux in 2.6.24.
+ #[cfg(not(target_os = "espidf"))]
+ let cmd = libc::F_DUPFD_CLOEXEC;
+
+ // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
+ // will never be supported, as this is a bare metal framework with
+ // no capabilities for multi-process execution. While F_DUPFD is also
+ // not supported yet, it might be (currently it returns ENOSYS).
+ #[cfg(target_os = "espidf")]
+ let cmd = libc::F_DUPFD;
+
+ let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
+ Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+ }
+
+ /// Creates a new `OwnedFd` instance that shares the same underlying file
+ /// description as the existing `BorrowedFd` instance.
+ #[cfg(target_arch = "wasm32")]
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
+ Err(crate::io::const_io_error!(
+ crate::io::ErrorKind::Unsupported,
+ "operation not supported on WASI yet",
+ ))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawFd for BorrowedFd<'_> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawFd for OwnedFd {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl IntoRawFd for OwnedFd {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ let fd = self.fd;
+ forget(self);
+ fd
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl FromRawFd for OwnedFd {
+ /// Constructs a new instance of `Self` from the given raw file descriptor.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `fd` must be open and suitable for assuming
+ /// ownership. The resource must not require any cleanup other than `close`.
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self {
+ assert_ne!(fd, u32::MAX as RawFd);
+ // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { Self { fd } }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl Drop for OwnedFd {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ // Note that errors are ignored when closing a file descriptor. The
+ // reason for this is that if an error occurs we don't actually know if
+ // the file descriptor was closed or not, and if we retried (for
+ // something like EINTR), we might close another valid file descriptor
+ // opened after we closed ours.
+ let _ = libc::close(self.fd);
+ }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for BorrowedFd<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for OwnedFd {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
+ }
+}
+
+/// A trait to borrow the file descriptor from an underlying object.
+///
+/// This is only available on unix platforms and must be imported in order to
+/// call the method. Windows platforms have a corresponding `AsHandle` and
+/// `AsSocket` set of traits.
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub trait AsFd {
+ /// Borrows the file descriptor.
+ ///
+ /// # Example
+ ///
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// # use std::io;
+ /// # #[cfg(target_os = "wasi")]
+ /// # use std::os::wasi::io::{AsFd, BorrowedFd};
+ /// # #[cfg(unix)]
+ /// # use std::os::unix::io::{AsFd, BorrowedFd};
+ ///
+ /// let mut f = File::open("foo.txt")?;
+ /// # #[cfg(any(unix, target_os = "wasi"))]
+ /// let borrowed_fd: BorrowedFd<'_> = f.as_fd();
+ /// # Ok::<(), io::Error>(())
+ /// ```
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ fn as_fd(&self) -> BorrowedFd<'_>;
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsFd> AsFd for &T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsFd> AsFd for &mut T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for BorrowedFd<'_> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ *self
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for OwnedFd {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ // Safety: `OwnedFd` and `BorrowedFd` have the same validity
+ // invariants, and the `BorrowdFd` is bounded by the lifetime
+ // of `&self`.
+ unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for fs::File {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<fs::File> for OwnedFd {
+ #[inline]
+ fn from(file: fs::File) -> OwnedFd {
+ file.into_inner().into_inner().into_inner()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for fs::File {
+ #[inline]
+ fn from(owned_fd: OwnedFd) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::net::TcpStream {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().socket().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::TcpStream> for OwnedFd {
+ #[inline]
+ fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
+ tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for crate::net::TcpStream {
+ #[inline]
+ fn from(owned_fd: OwnedFd) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
+ owned_fd,
+ ))))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::net::TcpListener {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().socket().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::TcpListener> for OwnedFd {
+ #[inline]
+ fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
+ tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for crate::net::TcpListener {
+ #[inline]
+ fn from(owned_fd: OwnedFd) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
+ owned_fd,
+ ))))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::net::UdpSocket {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().socket().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::UdpSocket> for OwnedFd {
+ #[inline]
+ fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
+ udp_socket.into_inner().into_socket().into_inner().into_inner().into()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for crate::net::UdpSocket {
+ #[inline]
+ fn from(owned_fd: OwnedFd) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
+ owned_fd,
+ ))))
+ }
+}
+
+#[stable(feature = "asfd_ptrs", since = "1.64.0")]
+/// This impl allows implementing traits that require `AsFd` on Arc.
+/// ```
+/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
+/// # #[cfg(target_os = "wasi")]
+/// # use std::os::wasi::io::AsFd;
+/// # #[cfg(unix)]
+/// # use std::os::unix::io::AsFd;
+/// use std::net::UdpSocket;
+/// use std::sync::Arc;
+///
+/// trait MyTrait: AsFd {}
+/// impl MyTrait for Arc<UdpSocket> {}
+/// impl MyTrait for Box<UdpSocket> {}
+/// # }
+/// ```
+impl<T: AsFd> AsFd for crate::sync::Arc<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
+#[stable(feature = "asfd_ptrs", since = "1.64.0")]
+impl<T: AsFd> AsFd for Box<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
new file mode 100644
index 000000000..081915ed1
--- /dev/null
+++ b/library/std/src/os/fd/raw.rs
@@ -0,0 +1,259 @@
+//! Raw Unix-like file descriptors.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::io;
+use crate::os::raw;
+#[cfg(all(doc, not(target_arch = "wasm32")))]
+use crate::os::unix::io::AsFd;
+#[cfg(unix)]
+use crate::os::unix::io::OwnedFd;
+#[cfg(target_os = "wasi")]
+use crate::os::wasi::io::OwnedFd;
+use crate::sys_common::{AsInner, IntoInner};
+
+/// Raw file descriptors.
+#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw file descriptor from an underlying object.
+///
+/// This is only available on unix and WASI platforms and must be imported in
+/// order to call the method. Windows platforms have a corresponding
+/// `AsRawHandle` and `AsRawSocket` set of traits.
+#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This function is typically used to **borrow** an owned file descriptor.
+ /// When used in this way, this method does **not** pass ownership of the
+ /// raw file descriptor to the caller, and the file descriptor is only
+ /// guaranteed to be valid while the original object has not yet been
+ /// destroyed.
+ ///
+ /// However, borrowing is not strictly required. See [`AsFd::as_fd`]
+ /// for an API which strictly borrows a file descriptor.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// # use std::io;
+ /// #[cfg(unix)]
+ /// use std::os::unix::io::{AsRawFd, RawFd};
+ /// #[cfg(target_os = "wasi")]
+ /// use std::os::wasi::io::{AsRawFd, RawFd};
+ ///
+ /// let mut f = File::open("foo.txt")?;
+ /// // Note that `raw_fd` is only valid as long as `f` exists.
+ /// #[cfg(any(unix, target_os = "wasi"))]
+ /// let raw_fd: RawFd = f.as_raw_fd();
+ /// # Ok::<(), io::Error>(())
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function is typically used to **consume ownership** of the
+ /// specified file descriptor. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
+ ///
+ /// However, consuming ownership is not strictly required. Use a
+ /// [`From<OwnedFd>::from`] implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `fd` passed in must be a valid and open file descriptor.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// # use std::io;
+ /// #[cfg(unix)]
+ /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
+ /// #[cfg(target_os = "wasi")]
+ /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd};
+ ///
+ /// let f = File::open("foo.txt")?;
+ /// # #[cfg(any(unix, target_os = "wasi"))]
+ /// let raw_fd: RawFd = f.into_raw_fd();
+ /// // SAFETY: no other functions should call `from_raw_fd`, so there
+ /// // is only one owner for the file descriptor.
+ /// # #[cfg(any(unix, target_os = "wasi"))]
+ /// let f = unsafe { File::from_raw_fd(raw_fd) };
+ /// # Ok::<(), io::Error>(())
+ /// ```
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function is typically used to **transfer ownership** of the underlying
+ /// file descriptor to the caller. When used in this way, callers are then the unique
+ /// owners of the file descriptor and must close it once it's no longer needed.
+ ///
+ /// However, transferring ownership is not strictly required. Use a
+ /// [`Into<OwnedFd>::into`] implementation for an API which strictly
+ /// transfers ownership.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// # use std::io;
+ /// #[cfg(unix)]
+ /// use std::os::unix::io::{IntoRawFd, RawFd};
+ /// #[cfg(target_os = "wasi")]
+ /// use std::os::wasi::io::{IntoRawFd, RawFd};
+ ///
+ /// let f = File::open("foo.txt")?;
+ /// #[cfg(any(unix, target_os = "wasi"))]
+ /// let raw_fd: RawFd = f.into_raw_fd();
+ /// # Ok::<(), io::Error>(())
+ /// ```
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ *self
+ }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self
+ }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+ fd
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+ unsafe { fs::File::from(OwnedFd::from_raw_fd(fd)) }
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDIN_FILENO
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDOUT_FILENO
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDERR_FILENO
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdinLock<'a> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDIN_FILENO
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDOUT_FILENO
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StderrLock<'a> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ libc::STDERR_FILENO
+ }
+}
+
+/// This impl allows implementing traits that require `AsRawFd` on Arc.
+/// ```
+/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
+/// # #[cfg(target_os = "wasi")]
+/// # use std::os::wasi::io::AsRawFd;
+/// # #[cfg(unix)]
+/// # use std::os::unix::io::AsRawFd;
+/// use std::net::UdpSocket;
+/// use std::sync::Arc;
+/// trait MyTrait: AsRawFd {
+/// }
+/// impl MyTrait for Arc<UdpSocket> {}
+/// impl MyTrait for Box<UdpSocket> {}
+/// # }
+/// ```
+#[stable(feature = "asrawfd_ptrs", since = "1.63.0")]
+impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ (**self).as_raw_fd()
+ }
+}
+
+#[stable(feature = "asrawfd_ptrs", since = "1.63.0")]
+impl<T: AsRawFd> AsRawFd for Box<T> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ (**self).as_raw_fd()
+ }
+}
diff --git a/library/std/src/os/fd/tests.rs b/library/std/src/os/fd/tests.rs
new file mode 100644
index 000000000..b39863644
--- /dev/null
+++ b/library/std/src/os/fd/tests.rs
@@ -0,0 +1,53 @@
+#[cfg(any(unix, target_os = "wasi"))]
+#[test]
+fn test_raw_fd() {
+ #[cfg(unix)]
+ use crate::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+ #[cfg(target_os = "wasi")]
+ use crate::os::wasi::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+
+ let raw_fd: RawFd = crate::io::stdin().as_raw_fd();
+
+ let stdin_as_file = unsafe { crate::fs::File::from_raw_fd(raw_fd) };
+ assert_eq!(stdin_as_file.as_raw_fd(), raw_fd);
+ assert_eq!(unsafe { BorrowedFd::borrow_raw(raw_fd).as_raw_fd() }, raw_fd);
+ assert_eq!(stdin_as_file.into_raw_fd(), 0);
+}
+
+#[cfg(any(unix, target_os = "wasi"))]
+#[test]
+fn test_fd() {
+ #[cfg(unix)]
+ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+ #[cfg(target_os = "wasi")]
+ use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+
+ let stdin = crate::io::stdin();
+ let fd: BorrowedFd<'_> = stdin.as_fd();
+ let raw_fd: RawFd = fd.as_raw_fd();
+ let owned_fd: OwnedFd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
+
+ let stdin_as_file = crate::fs::File::from(owned_fd);
+
+ assert_eq!(stdin_as_file.as_fd().as_raw_fd(), raw_fd);
+ assert_eq!(Into::<OwnedFd>::into(stdin_as_file).into_raw_fd(), raw_fd);
+}
+
+#[cfg(any(unix, target_os = "wasi"))]
+#[test]
+fn test_niche_optimizations() {
+ use crate::mem::size_of;
+ #[cfg(unix)]
+ use crate::os::unix::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+ #[cfg(target_os = "wasi")]
+ use crate::os::wasi::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+
+ assert_eq!(size_of::<Option<OwnedFd>>(), size_of::<RawFd>());
+ assert_eq!(size_of::<Option<BorrowedFd<'static>>>(), size_of::<RawFd>());
+ unsafe {
+ assert_eq!(OwnedFd::from_raw_fd(RawFd::MIN).into_raw_fd(), RawFd::MIN);
+ assert_eq!(OwnedFd::from_raw_fd(RawFd::MAX).into_raw_fd(), RawFd::MAX);
+ assert_eq!(Some(OwnedFd::from_raw_fd(RawFd::MIN)).unwrap().into_raw_fd(), RawFd::MIN);
+ assert_eq!(Some(OwnedFd::from_raw_fd(RawFd::MAX)).unwrap().into_raw_fd(), RawFd::MAX);
+ }
+}
diff --git a/library/std/src/os/fortanix_sgx/arch.rs b/library/std/src/os/fortanix_sgx/arch.rs
new file mode 100644
index 000000000..8358cb9e8
--- /dev/null
+++ b/library/std/src/os/fortanix_sgx/arch.rs
@@ -0,0 +1,80 @@
+//! SGX-specific access to architectural features.
+//!
+//! The functionality in this module is further documented in the Intel
+//! Software Developer's Manual, Volume 3, Chapter 40.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use crate::mem::MaybeUninit;
+use core::arch::asm;
+
+/// Wrapper struct to force 16-byte alignment.
+#[repr(align(16))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align16<T>(pub T);
+
+/// Wrapper struct to force 128-byte alignment.
+#[repr(align(128))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align128<T>(pub T);
+
+/// Wrapper struct to force 512-byte alignment.
+#[repr(align(512))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align512<T>(pub T);
+
+const ENCLU_EREPORT: u32 = 0;
+const ENCLU_EGETKEY: u32 = 1;
+
+/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
+ unsafe {
+ let mut out = MaybeUninit::uninit();
+ let error;
+
+ asm!(
+ // rbx is reserved by LLVM
+ "xchg %rbx, {0}",
+ "enclu",
+ "mov {0}, %rbx",
+ inout(reg) request => _,
+ inlateout("eax") ENCLU_EGETKEY => error,
+ in("rcx") out.as_mut_ptr(),
+ options(att_syntax, nostack),
+ );
+
+ match error {
+ 0 => Ok(out.assume_init()),
+ err => Err(err),
+ }
+ }
+}
+
+/// Call the `EREPORT` instruction.
+///
+/// This creates a cryptographic report describing the contents of the current
+/// enclave. The report may be verified by the enclave described in
+/// `targetinfo`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn ereport(
+ targetinfo: &Align512<[u8; 512]>,
+ reportdata: &Align128<[u8; 64]>,
+) -> Align512<[u8; 432]> {
+ unsafe {
+ let mut report = MaybeUninit::uninit();
+
+ asm!(
+ // rbx is reserved by LLVM
+ "xchg %rbx, {0}",
+ "enclu",
+ "mov {0}, %rbx",
+ inout(reg) targetinfo => _,
+ in("eax") ENCLU_EREPORT,
+ in("rcx") reportdata,
+ in("rdx") report.as_mut_ptr(),
+ options(att_syntax, preserves_flags, nostack),
+ );
+
+ report.assume_init()
+ }
+}
diff --git a/library/std/src/os/fortanix_sgx/ffi.rs b/library/std/src/os/fortanix_sgx/ffi.rs
new file mode 100644
index 000000000..ac1db0e5e
--- /dev/null
+++ b/library/std/src/os/fortanix_sgx/ffi.rs
@@ -0,0 +1,41 @@
+//! SGX-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::fortanix_sgx::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::fortanix_sgx::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub use self::os_str::{OsStrExt, OsStringExt};
diff --git a/library/std/src/os/fortanix_sgx/io.rs b/library/std/src/os/fortanix_sgx/io.rs
new file mode 100644
index 000000000..7223ade68
--- /dev/null
+++ b/library/std/src/os/fortanix_sgx/io.rs
@@ -0,0 +1,144 @@
+//! SGX-specific extensions to general I/O primitives
+//!
+//! SGX file descriptors behave differently from Unix file descriptors. See the
+//! description of [`TryIntoRawFd`] for more details.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use crate::net;
+pub use crate::sys::abi::usercalls::raw::Fd as RawFd;
+use crate::sys::{self, AsInner, FromInner, IntoInner, TryIntoInner};
+
+/// A trait to extract the raw SGX file descriptor from an underlying
+/// object.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait FromRawFd {
+ /// An associated type that contains relevant metadata for `Self`.
+ type Metadata: Default;
+
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor and metadata.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait TryIntoRawFd: Sized {
+ /// Consumes this object, returning the raw underlying file descriptor, if
+ /// this object is not cloned.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ ///
+ /// Unlike other platforms, on SGX, the file descriptor is shared between
+ /// all clones of an object. To avoid race conditions, this function will
+ /// only return `Ok` when called on the final clone.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ fn try_into_raw_fd(self) -> Result<RawFd, Self>;
+}
+
+impl AsRawFd for net::TcpStream {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ *self.as_inner().as_inner().as_inner().as_inner()
+ }
+}
+
+impl AsRawFd for net::TcpListener {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ *self.as_inner().as_inner().as_inner().as_inner()
+ }
+}
+
+/// Metadata for `TcpStream`.
+#[derive(Debug, Clone, Default)]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct TcpStreamMetadata {
+ /// Local address of the TCP stream
+ pub local_addr: Option<String>,
+ /// Peer address of the TCP stream
+ pub peer_addr: Option<String>,
+}
+
+impl FromRawFd for net::TcpStream {
+ type Metadata = TcpStreamMetadata;
+
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
+ net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, metadata.peer_addr)))
+ }
+}
+
+/// Metadata for `TcpListener`.
+#[derive(Debug, Clone, Default)]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct TcpListenerMetadata {
+ /// Local address of the TCP listener
+ pub local_addr: Option<String>,
+}
+
+impl FromRawFd for net::TcpListener {
+ type Metadata = TcpListenerMetadata;
+
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
+ net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket))
+ }
+}
+
+impl TryIntoRawFd for net::TcpStream {
+ #[inline]
+ fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+ let (socket, peer_addr) = self.into_inner().into_inner();
+ match socket.try_into_inner() {
+ Ok(fd) => Ok(fd.into_inner()),
+ Err(socket) => {
+ let sys = sys::net::TcpStream::from_inner((socket, peer_addr));
+ Err(net::TcpStream::from_inner(sys))
+ }
+ }
+ }
+}
+
+impl TryIntoRawFd for net::TcpListener {
+ #[inline]
+ fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+ match self.into_inner().into_inner().try_into_inner() {
+ Ok(fd) => Ok(fd.into_inner()),
+ Err(socket) => {
+ let sys = sys::net::TcpListener::from_inner(socket);
+ Err(net::TcpListener::from_inner(sys))
+ }
+ }
+ }
+}
diff --git a/library/std/src/os/fortanix_sgx/mod.rs b/library/std/src/os/fortanix_sgx/mod.rs
new file mode 100644
index 000000000..a40dabe19
--- /dev/null
+++ b/library/std/src/os/fortanix_sgx/mod.rs
@@ -0,0 +1,53 @@
+//! Functionality specific to the `x86_64-fortanix-unknown-sgx` target.
+//!
+//! This includes functions to deal with memory isolation, usercalls, and the
+//! SGX instruction set.
+
+#![deny(missing_docs)]
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+/// Low-level interfaces to usercalls. See the [ABI documentation] for more
+/// information.
+///
+/// [ABI documentation]: https://docs.rs/fortanix-sgx-abi/
+pub mod usercalls {
+ pub use crate::sys::abi::usercalls::*;
+
+ /// Primitives for allocating memory in userspace as well as copying data
+ /// to and from user memory.
+ pub mod alloc {
+ pub use crate::sys::abi::usercalls::alloc::*;
+ }
+
+ /// Lowest-level interfaces to usercalls and usercall ABI type definitions.
+ pub mod raw {
+ pub use crate::sys::abi::usercalls::raw::{
+ accept_stream, alloc, async_queues, bind_stream, close, connect_stream, exit, flush,
+ free, insecure_time, launch_thread, read, read_alloc, send, wait, write,
+ };
+ pub use crate::sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs};
+
+ // fortanix-sgx-abi re-exports
+ pub use crate::sys::abi::usercalls::raw::Error;
+ pub use crate::sys::abi::usercalls::raw::{ByteBuffer, FifoDescriptor, Return, Usercall};
+ pub use crate::sys::abi::usercalls::raw::{Fd, Result, Tcs};
+ pub use crate::sys::abi::usercalls::raw::{
+ EV_RETURNQ_NOT_EMPTY, EV_UNPARK, EV_USERCALLQ_NOT_FULL, FD_STDERR, FD_STDIN, FD_STDOUT,
+ RESULT_SUCCESS, USERCALL_USER_DEFINED, WAIT_INDEFINITE, WAIT_NO,
+ };
+ }
+}
+
+/// Functions for querying mapping information for pointers.
+pub mod mem {
+ pub use crate::sys::abi::mem::*;
+}
+
+pub mod arch;
+pub mod ffi;
+pub mod io;
+
+/// Functions for querying thread-related information.
+pub mod thread {
+ pub use crate::sys::abi::thread::current;
+}
diff --git a/library/std/src/os/freebsd/fs.rs b/library/std/src/os/freebsd/fs.rs
new file mode 100644
index 000000000..8db3a950c
--- /dev/null
+++ b/library/std/src/os/freebsd/fs.rs
@@ -0,0 +1,154 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::freebsd::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ // The methods below use libc::stat, so they work fine when libc is built with FreeBSD 12 ABI.
+ // This method would just return nonsense.
+ #[cfg(freebsd12)]
+ panic!("as_raw_stat not supported with FreeBSD 12 ABI");
+ #[cfg(not(freebsd12))]
+ unsafe {
+ &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ #[cfg(freebsd12)]
+ fn st_lspare(&self) -> u32 {
+ panic!("st_lspare not supported with FreeBSD 12 ABI");
+ }
+ #[cfg(not(freebsd12))]
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+}
diff --git a/library/std/src/os/freebsd/mod.rs b/library/std/src/os/freebsd/mod.rs
new file mode 100644
index 000000000..c072fae55
--- /dev/null
+++ b/library/std/src/os/freebsd/mod.rs
@@ -0,0 +1,6 @@
+//! FreeBSD-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/freebsd/raw.rs b/library/std/src/os/freebsd/raw.rs
new file mode 100644
index 000000000..ab0bf7923
--- /dev/null
+++ b/library/std/src/os/freebsd/raw.rs
@@ -0,0 +1,86 @@
+//! FreeBSD-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[cfg(target_arch = "x86")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [u8; 8],
+}
diff --git a/library/std/src/os/fuchsia/fs.rs b/library/std/src/os/fuchsia/fs.rs
new file mode 100644
index 000000000..b48a46f91
--- /dev/null
+++ b/library/std/src/os/fuchsia/fs.rs
@@ -0,0 +1,95 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/fuchsia/mod.rs b/library/std/src/os/fuchsia/mod.rs
new file mode 100644
index 000000000..cd1b8233e
--- /dev/null
+++ b/library/std/src/os/fuchsia/mod.rs
@@ -0,0 +1,6 @@
+//! Fuchsia-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/fuchsia/raw.rs b/library/std/src/os/fuchsia/raw.rs
new file mode 100644
index 000000000..060d6e86b
--- /dev/null
+++ b/library/std/src/os/fuchsia/raw.rs
@@ -0,0 +1,293 @@
+//! Fuchsia-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+
+#[cfg(any(
+ target_arch = "x86",
+ target_arch = "le32",
+ target_arch = "powerpc",
+ target_arch = "arm"
+))]
+mod arch {
+ use crate::os::raw::{c_long, c_short, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ }
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ use crate::os::raw::{c_long, c_ulong};
+
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad1: [c_long; 3],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad2: [c_long; 2],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad5: [c_long; 14],
+ }
+}
+
+#[cfg(target_arch = "mips64")]
+mod arch {
+ pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use crate::os::raw::{c_int, c_long};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_int; 2],
+ }
+}
+
+#[cfg(target_arch = "x86_64")]
+mod arch {
+ use crate::os::raw::{c_int, c_long};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_long; 3],
+ }
+}
diff --git a/library/std/src/os/haiku/fs.rs b/library/std/src/os/haiku/fs.rs
new file mode 100644
index 000000000..a23a2af8f
--- /dev/null
+++ b/library/std/src/os/haiku/fs.rs
@@ -0,0 +1,127 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::haiku::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_crtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_crtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_crtime(&self) -> i64 {
+ self.as_inner().as_inner().st_crtime as i64
+ }
+ fn st_crtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_crtime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/haiku/mod.rs b/library/std/src/os/haiku/mod.rs
new file mode 100644
index 000000000..73f500cad
--- /dev/null
+++ b/library/std/src/os/haiku/mod.rs
@@ -0,0 +1,6 @@
+//! Haiku-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/haiku/raw.rs b/library/std/src/os/haiku/raw.rs
new file mode 100644
index 000000000..afbb66ccb
--- /dev/null
+++ b/library/std/src/os/haiku/raw.rs
@@ -0,0 +1,79 @@
+//! Haiku-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.53.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{gid_t, uid_t};
+
+// Use the direct definition of usize, instead of uintptr_t like in libc
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = i64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i32;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_crtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_crtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_type: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+}
diff --git a/library/std/src/os/hermit/ffi.rs b/library/std/src/os/hermit/ffi.rs
new file mode 100644
index 000000000..19761fd99
--- /dev/null
+++ b/library/std/src/os/hermit/ffi.rs
@@ -0,0 +1,41 @@
+//! HermitCore-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::hermit::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::hermit::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
diff --git a/library/std/src/os/hermit/mod.rs b/library/std/src/os/hermit/mod.rs
new file mode 100644
index 000000000..4657b545a
--- /dev/null
+++ b/library/std/src/os/hermit/mod.rs
@@ -0,0 +1,13 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+}
diff --git a/library/std/src/os/horizon/fs.rs b/library/std/src/os/horizon/fs.rs
new file mode 100644
index 000000000..132552210
--- /dev/null
+++ b/library/std/src/os/horizon/fs.rs
@@ -0,0 +1,95 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_sec
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_sec
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_sec
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/horizon/mod.rs b/library/std/src/os/horizon/mod.rs
new file mode 100644
index 000000000..326d0ae9c
--- /dev/null
+++ b/library/std/src/os/horizon/mod.rs
@@ -0,0 +1,6 @@
+//! Definitions for Horizon OS
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub(crate) mod raw;
diff --git a/library/std/src/os/horizon/raw.rs b/library/std/src/os/horizon/raw.rs
new file mode 100644
index 000000000..929fa7db1
--- /dev/null
+++ b/library/std/src/os/horizon/raw.rs
@@ -0,0 +1,70 @@
+//! Horizon OS raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{gid_t, uid_t};
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = libc::pthread_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = libc::blkcnt_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = libc::blksize_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = libc::dev_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = libc::ino_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = libc::mode_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = libc::nlink_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = libc::off_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = libc::time_t;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_spare4: [c_long; 2usize],
+}
diff --git a/library/std/src/os/illumos/fs.rs b/library/std/src/os/illumos/fs.rs
new file mode 100644
index 000000000..63be48b81
--- /dev/null
+++ b/library/std/src/os/illumos/fs.rs
@@ -0,0 +1,116 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::illumos::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/illumos/mod.rs b/library/std/src/os/illumos/mod.rs
new file mode 100644
index 000000000..e61926f89
--- /dev/null
+++ b/library/std/src/os/illumos/mod.rs
@@ -0,0 +1,6 @@
+//! illumos-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/illumos/raw.rs b/library/std/src/os/illumos/raw.rs
new file mode 100644
index 000000000..2bea9ebb3
--- /dev/null
+++ b/library/std/src/os/illumos/raw.rs
@@ -0,0 +1,74 @@
+//! illumos-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by the standard library, the `libc` \
+ crate on crates.io should be used instead for the correct definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{gid_t, uid_t};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = u32;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [u8; 16],
+}
diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs
new file mode 100644
index 000000000..4a4637ce0
--- /dev/null
+++ b/library/std/src/os/ios/fs.rs
@@ -0,0 +1,142 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::ios::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+}
diff --git a/library/std/src/os/ios/mod.rs b/library/std/src/os/ios/mod.rs
new file mode 100644
index 000000000..fdefa1f6b
--- /dev/null
+++ b/library/std/src/os/ios/mod.rs
@@ -0,0 +1,6 @@
+//! iOS-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/ios/raw.rs b/library/std/src/os/ios/raw.rs
new file mode 100644
index 000000000..af12aeebe
--- /dev/null
+++ b/library/std/src/os/ios/raw.rs
@@ -0,0 +1,83 @@
+//! iOS-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_qspare: [i64; 2],
+}
diff --git a/library/std/src/os/l4re/fs.rs b/library/std/src/os/l4re/fs.rs
new file mode 100644
index 000000000..6d6a535b1
--- /dev/null
+++ b/library/std/src/os/l4re/fs.rs
@@ -0,0 +1,382 @@
+//! L4Re-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::l4re::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned [`stat`] are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ ///
+ /// [`stat`]: struct@crate::os::linux::raw::stat
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let stat = meta.as_raw_stat();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(since = "1.8.0", note = "other methods of this trait are now preferred")]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+ ///
+ /// [`st_atime`]: Self::st_atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+ ///
+ /// [`st_mtime`]: Self::st_mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+ ///
+ /// [`st_ctime`]: Self::st_ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" block size for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/l4re/mod.rs b/library/std/src/os/l4re/mod.rs
new file mode 100644
index 000000000..14c2425c1
--- /dev/null
+++ b/library/std/src/os/l4re/mod.rs
@@ -0,0 +1,7 @@
+//! L4Re-specific definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![doc(cfg(target_os = "l4re"))]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs
new file mode 100644
index 000000000..699e8be33
--- /dev/null
+++ b/library/std/src/os/l4re/raw.rs
@@ -0,0 +1,365 @@
+//! L4Re-specific raw type definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+
+#[cfg(any(
+ target_arch = "x86",
+ target_arch = "le32",
+ target_arch = "m68k",
+ target_arch = "powerpc",
+ target_arch = "sparc",
+ target_arch = "arm",
+ target_arch = "asmjs",
+ target_arch = "wasm32"
+))]
+mod arch {
+ use crate::os::raw::{c_long, c_short, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ }
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ use crate::os::raw::{c_long, c_ulong};
+
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad1: [c_long; 3],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad2: [c_long; 2],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad5: [c_long; 14],
+ }
+}
+
+#[cfg(target_arch = "hexagon")]
+mod arch {
+ use crate::os::raw::{c_int, c_long, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = c_long;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = c_uint;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_int; 2],
+ }
+}
+
+#[cfg(any(
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "sparc64",
+ target_arch = "riscv64",
+ target_arch = "riscv32"
+))]
+mod arch {
+ pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use crate::os::raw::{c_int, c_long};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = i32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = c_long;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_int; 2],
+ }
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))]
+mod arch {
+ use crate::os::raw::{c_int, c_long};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_long; 3],
+ }
+}
diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs
new file mode 100644
index 000000000..479bbcc17
--- /dev/null
+++ b/library/std/src/os/linux/fs.rs
@@ -0,0 +1,397 @@
+//! Linux-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::linux::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned [`stat`] are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ ///
+ /// [`stat`]: struct@crate::os::linux::raw::stat
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let stat = meta.as_raw_stat();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(since = "1.8.0", note = "other methods of this trait are now preferred")]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+ ///
+ /// [`st_atime`]: Self::st_atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+ ///
+ /// [`st_mtime`]: Self::st_mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+ ///
+ /// [`st_ctime`]: Self::st_ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" block size for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ let file_attr = self.as_inner();
+ #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+ if let Some(atime) = file_attr.stx_atime() {
+ return atime.tv_sec;
+ }
+ file_attr.as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ let file_attr = self.as_inner();
+ #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+ if let Some(mtime) = file_attr.stx_mtime() {
+ return mtime.tv_sec;
+ }
+ file_attr.as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ let file_attr = self.as_inner();
+ #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+ if let Some(ctime) = file_attr.stx_ctime() {
+ return ctime.tv_sec;
+ }
+ file_attr.as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs
new file mode 100644
index 000000000..8e7776f66
--- /dev/null
+++ b/library/std/src/os/linux/mod.rs
@@ -0,0 +1,8 @@
+//! Linux-specific definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![doc(cfg(target_os = "linux"))]
+
+pub mod fs;
+pub mod process;
+pub mod raw;
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
new file mode 100644
index 000000000..540363c03
--- /dev/null
+++ b/library/std/src/os/linux/process.rs
@@ -0,0 +1,165 @@
+//! Linux-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
+
+#![unstable(feature = "linux_pidfd", issue = "82971")]
+
+use crate::io::Result;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::process;
+use crate::sealed::Sealed;
+#[cfg(not(doc))]
+use crate::sys::fd::FileDesc;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[cfg(doc)]
+struct FileDesc;
+
+/// This type represents a file descriptor that refers to a process.
+///
+/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
+/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
+/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
+///
+/// Example:
+/// ```no_run
+/// #![feature(linux_pidfd)]
+/// use std::os::linux::process::{CommandExt, ChildExt};
+/// use std::process::Command;
+///
+/// let mut child = Command::new("echo")
+/// .create_pidfd(true)
+/// .spawn()
+/// .expect("Failed to spawn child");
+///
+/// let pidfd = child
+/// .take_pidfd()
+/// .expect("Failed to retrieve pidfd");
+///
+/// // The file descriptor will be closed when `pidfd` is dropped.
+/// ```
+/// Refer to the man page of [`pidfd_open(2)`] for further details.
+///
+/// [`Command`]: process::Command
+/// [`create_pidfd`]: CommandExt::create_pidfd
+/// [`Child`]: process::Child
+/// [`pidfd`]: fn@ChildExt::pidfd
+/// [`take_pidfd`]: ChildExt::take_pidfd
+/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
+#[derive(Debug)]
+pub struct PidFd {
+ inner: FileDesc,
+}
+
+impl AsInner<FileDesc> for PidFd {
+ fn as_inner(&self) -> &FileDesc {
+ &self.inner
+ }
+}
+
+impl FromInner<FileDesc> for PidFd {
+ fn from_inner(inner: FileDesc) -> PidFd {
+ PidFd { inner }
+ }
+}
+
+impl IntoInner<FileDesc> for PidFd {
+ fn into_inner(self) -> FileDesc {
+ self.inner
+ }
+}
+
+impl AsRawFd for PidFd {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+
+impl FromRawFd for PidFd {
+ unsafe fn from_raw_fd(fd: RawFd) -> Self {
+ Self::from_inner(FileDesc::from_raw_fd(fd))
+ }
+}
+
+impl IntoRawFd for PidFd {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_raw_fd()
+ }
+}
+
+impl AsFd for PidFd {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+impl From<OwnedFd> for PidFd {
+ fn from(fd: OwnedFd) -> Self {
+ Self::from_inner(FileDesc::from_inner(fd))
+ }
+}
+
+impl From<PidFd> for OwnedFd {
+ fn from(pid_fd: PidFd) -> Self {
+ pid_fd.into_inner().into_inner()
+ }
+}
+
+/// Os-specific extensions for [`Child`]
+///
+/// [`Child`]: process::Child
+pub trait ChildExt: Sealed {
+ /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
+ ///
+ /// A pidfd will only be available if its creation was requested with
+ /// [`create_pidfd`] when the corresponding [`Command`] was created.
+ ///
+ /// Even if requested, a pidfd may not be available due to an older
+ /// version of Linux being in use, or if some other error occurred.
+ ///
+ /// [`Command`]: process::Command
+ /// [`create_pidfd`]: CommandExt::create_pidfd
+ /// [`Child`]: process::Child
+ fn pidfd(&self) -> Result<&PidFd>;
+
+ /// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
+ ///
+ /// A pidfd will only be available if its creation was requested with
+ /// [`create_pidfd`] when the corresponding [`Command`] was created.
+ ///
+ /// Even if requested, a pidfd may not be available due to an older
+ /// version of Linux being in use, or if some other error occurred.
+ ///
+ /// [`Command`]: process::Command
+ /// [`create_pidfd`]: CommandExt::create_pidfd
+ /// [`Child`]: process::Child
+ fn take_pidfd(&mut self) -> Result<PidFd>;
+}
+
+/// Os-specific extensions for [`Command`]
+///
+/// [`Command`]: process::Command
+pub trait CommandExt: Sealed {
+ /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
+ /// spawned by this [`Command`].
+ /// By default, no pidfd will be created.
+ ///
+ /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
+ ///
+ /// A pidfd will only be created if it is possible to do so
+ /// in a guaranteed race-free manner (e.g. if the `clone3` system call
+ /// is supported). Otherwise, [`pidfd`] will return an error.
+ ///
+ /// [`Command`]: process::Command
+ /// [`Child`]: process::Child
+ /// [`pidfd`]: fn@ChildExt::pidfd
+ /// [`take_pidfd`]: ChildExt::take_pidfd
+ fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
+}
+
+impl CommandExt for process::Command {
+ fn create_pidfd(&mut self, val: bool) -> &mut process::Command {
+ self.as_inner_mut().create_pidfd(val);
+ self
+ }
+}
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
new file mode 100644
index 000000000..c73791d14
--- /dev/null
+++ b/library/std/src/os/linux/raw.rs
@@ -0,0 +1,366 @@
+//! Linux-specific raw type definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+
+#[cfg(any(
+ target_arch = "x86",
+ target_arch = "le32",
+ target_arch = "m68k",
+ target_arch = "powerpc",
+ target_arch = "sparc",
+ target_arch = "arm",
+ target_arch = "asmjs",
+ target_arch = "wasm32"
+))]
+mod arch {
+ use crate::os::raw::{c_long, c_short, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: c_short,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ }
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+ use crate::os::raw::{c_long, c_ulong};
+
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[cfg(target_env = "musl")]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[cfg(not(target_env = "musl"))]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad1: [c_long; 3],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad2: [c_long; 2],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_pad5: [c_long; 14],
+ }
+}
+
+#[cfg(target_arch = "hexagon")]
+mod arch {
+ use crate::os::raw::{c_int, c_long, c_uint};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = c_long;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = c_uint;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_int; 2],
+ }
+}
+
+#[cfg(any(
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "sparc64",
+ target_arch = "riscv64",
+ target_arch = "riscv32"
+))]
+mod arch {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use crate::os::raw::{c_int, c_long};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = i32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u32;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = i64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = c_long;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad1: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad2: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_int; 2],
+ }
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))]
+mod arch {
+ use crate::os::raw::{c_int, c_long};
+
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blkcnt_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type blksize_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type ino_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type nlink_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type off_t = u64;
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[derive(Clone)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: c_int,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [c_long; 3],
+ }
+}
diff --git a/library/std/src/os/macos/fs.rs b/library/std/src/os/macos/fs.rs
new file mode 100644
index 000000000..91915da6a
--- /dev/null
+++ b/library/std/src/os/macos/fs.rs
@@ -0,0 +1,148 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::macos::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_lspare(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_qspare(&self) -> [u64; 2];
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+ fn st_lspare(&self) -> u32 {
+ self.as_inner().as_inner().st_lspare as u32
+ }
+ fn st_qspare(&self) -> [u64; 2] {
+ let qspare = self.as_inner().as_inner().st_qspare;
+ [qspare[0] as u64, qspare[1] as u64]
+ }
+}
diff --git a/library/std/src/os/macos/mod.rs b/library/std/src/os/macos/mod.rs
new file mode 100644
index 000000000..791d703b1
--- /dev/null
+++ b/library/std/src/os/macos/mod.rs
@@ -0,0 +1,6 @@
+//! macOS-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/macos/raw.rs b/library/std/src/os/macos/raw.rs
new file mode 100644
index 000000000..0b21f6ee5
--- /dev/null
+++ b/library/std/src/os/macos/raw.rs
@@ -0,0 +1,83 @@
+//! macOS-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u16,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_lspare: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_qspare: [i64; 2],
+}
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
new file mode 100644
index 000000000..6fbaa42c7
--- /dev/null
+++ b/library/std/src/os/mod.rs
@@ -0,0 +1,150 @@
+//! OS-specific functionality.
+
+#![stable(feature = "os", since = "1.0.0")]
+#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
+
+pub mod raw;
+
+// The code below could be written clearer using `cfg_if!`. However, the items below are
+// publicly exported by `std` and external tools can have trouble analysing them because of the use
+// of a macro that is not vendored by Rust and included in the toolchain.
+// See https://github.com/rust-analyzer/rust-analyzer/issues/6038.
+
+// On certain platforms right now the "main modules" modules that are
+// documented don't compile (missing things in `libc` which is empty),
+// so just omit them with an empty module and add the "unstable" attribute.
+
+// Unix, linux, wasi and windows are handled a bit differently.
+#[cfg(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+))]
+#[unstable(issue = "none", feature = "std_internals")]
+pub mod unix {}
+#[cfg(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+))]
+#[unstable(issue = "none", feature = "std_internals")]
+pub mod linux {}
+#[cfg(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+))]
+#[unstable(issue = "none", feature = "std_internals")]
+pub mod wasi {}
+#[cfg(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+))]
+#[unstable(issue = "none", feature = "std_internals")]
+pub mod windows {}
+
+// unix
+#[cfg(not(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+)))]
+#[cfg(target_os = "hermit")]
+#[path = "hermit/mod.rs"]
+pub mod unix;
+#[cfg(not(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+)))]
+#[cfg(all(not(target_os = "hermit"), any(unix, doc)))]
+pub mod unix;
+
+// linux
+#[cfg(not(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+)))]
+#[cfg(any(target_os = "linux", doc))]
+pub mod linux;
+
+// wasi
+#[cfg(not(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+)))]
+#[cfg(any(target_os = "wasi", doc))]
+pub mod wasi;
+
+// windows
+#[cfg(not(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+)))]
+#[cfg(any(windows, doc))]
+pub mod windows;
+
+// Others.
+#[cfg(target_os = "android")]
+pub mod android;
+#[cfg(target_os = "dragonfly")]
+pub mod dragonfly;
+#[cfg(target_os = "emscripten")]
+pub mod emscripten;
+#[cfg(target_os = "espidf")]
+pub mod espidf;
+#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
+pub mod fortanix_sgx;
+#[cfg(target_os = "freebsd")]
+pub mod freebsd;
+#[cfg(target_os = "fuchsia")]
+pub mod fuchsia;
+#[cfg(target_os = "haiku")]
+pub mod haiku;
+#[cfg(target_os = "horizon")]
+pub mod horizon;
+#[cfg(target_os = "illumos")]
+pub mod illumos;
+#[cfg(target_os = "ios")]
+pub mod ios;
+#[cfg(target_os = "l4re")]
+pub mod l4re;
+#[cfg(target_os = "macos")]
+pub mod macos;
+#[cfg(target_os = "netbsd")]
+pub mod netbsd;
+#[cfg(target_os = "openbsd")]
+pub mod openbsd;
+#[cfg(target_os = "redox")]
+pub mod redox;
+#[cfg(target_os = "solaris")]
+pub mod solaris;
+#[cfg(target_os = "solid_asp3")]
+pub mod solid;
+#[cfg(target_os = "vxworks")]
+pub mod vxworks;
+
+#[cfg(any(unix, target_os = "wasi", doc))]
+mod fd;
diff --git a/library/std/src/os/netbsd/fs.rs b/library/std/src/os/netbsd/fs.rs
new file mode 100644
index 000000000..fe0be069e
--- /dev/null
+++ b/library/std/src/os/netbsd/fs.rs
@@ -0,0 +1,137 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::netbsd::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atimensec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtimensec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctimensec as i64
+ }
+ fn st_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtimensec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+}
diff --git a/library/std/src/os/netbsd/mod.rs b/library/std/src/os/netbsd/mod.rs
new file mode 100644
index 000000000..497a51a1d
--- /dev/null
+++ b/library/std/src/os/netbsd/mod.rs
@@ -0,0 +1,6 @@
+//! OpenBSD-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/netbsd/raw.rs b/library/std/src/os/netbsd/raw.rs
new file mode 100644
index 000000000..18057291f
--- /dev/null
+++ b/library/std/src/os/netbsd/raw.rs
@@ -0,0 +1,83 @@
+//! NetBSD-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{gid_t, uid_t};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ st_spare: [u32; 2],
+}
diff --git a/library/std/src/os/openbsd/fs.rs b/library/std/src/os/openbsd/fs.rs
new file mode 100644
index 000000000..b8d8d31c5
--- /dev/null
+++ b/library/std/src/os/openbsd/fs.rs
@@ -0,0 +1,137 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::openbsd::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_birthtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_flags(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gen(&self) -> u32;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_birthtime(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime as i64
+ }
+ fn st_birthtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_birthtime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_gen(&self) -> u32 {
+ self.as_inner().as_inner().st_gen as u32
+ }
+ fn st_flags(&self) -> u32 {
+ self.as_inner().as_inner().st_flags as u32
+ }
+}
diff --git a/library/std/src/os/openbsd/mod.rs b/library/std/src/os/openbsd/mod.rs
new file mode 100644
index 000000000..497a51a1d
--- /dev/null
+++ b/library/std/src/os/openbsd/mod.rs
@@ -0,0 +1,6 @@
+//! OpenBSD-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/openbsd/raw.rs b/library/std/src/os/openbsd/raw.rs
new file mode 100644
index 000000000..6711fb51b
--- /dev/null
+++ b/library/std/src/os/openbsd/raw.rs
@@ -0,0 +1,81 @@
+//! OpenBSD-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: u64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: i32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_flags: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gen: u32,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: i64,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+}
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
new file mode 100644
index 000000000..19d0ffb2e
--- /dev/null
+++ b/library/std/src/os/raw/mod.rs
@@ -0,0 +1,31 @@
+//! Compatibility module for C platform-specific types. Use [`core::ffi`] instead.
+
+#![stable(feature = "raw_os", since = "1.1.0")]
+
+#[cfg(test)]
+mod tests;
+
+macro_rules! alias_core_ffi {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "raw_os", since = "1.1.0")]
+ #[doc = include_str!(concat!("../../../../core/src/ffi/", stringify!($t), ".md"))]
+ // Make this type alias appear cfg-dependent so that Clippy does not suggest
+ // replacing expressions like `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be
+ // removed after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
+ // is fixed.
+ #[cfg(all())]
+ #[doc(cfg(all()))]
+ pub type $t = core::ffi::$t;
+ )*}
+}
+
+alias_core_ffi! {
+ c_char c_schar c_uchar
+ c_short c_ushort
+ c_int c_uint
+ c_long c_ulong
+ c_longlong c_ulonglong
+ c_float
+ c_double
+ c_void
+}
diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs
new file mode 100644
index 000000000..e7bb7d7e7
--- /dev/null
+++ b/library/std/src/os/raw/tests.rs
@@ -0,0 +1,15 @@
+use crate::any::TypeId;
+
+macro_rules! ok {
+ ($($t:ident)*) => {$(
+ assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
+ "{} is wrong", stringify!($t));
+ )*}
+}
+
+#[test]
+fn same() {
+ use crate::os::raw;
+ ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
+ c_longlong c_ulonglong c_float c_double);
+}
diff --git a/library/std/src/os/redox/fs.rs b/library/std/src/os/redox/fs.rs
new file mode 100644
index 000000000..682ca6a2c
--- /dev/null
+++ b/library/std/src/os/redox/fs.rs
@@ -0,0 +1,382 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::redox::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned [`stat`] are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ ///
+ /// [`stat`]: crate::os::redox::raw::stat
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let stat = meta.as_raw_stat();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+ ///
+ /// [`st_atime`]: Self::st_atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+ ///
+ /// [`st_mtime`]: Self::st_mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+ ///
+ /// [`st_ctime`]: Self::st_ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" block size for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::redox::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/redox/mod.rs b/library/std/src/os/redox/mod.rs
new file mode 100644
index 000000000..d786759c6
--- /dev/null
+++ b/library/std/src/os/redox/mod.rs
@@ -0,0 +1,6 @@
+//! Redox-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/redox/raw.rs b/library/std/src/os/redox/raw.rs
new file mode 100644
index 000000000..7b1cd8ae8
--- /dev/null
+++ b/library/std/src/os/redox/raw.rs
@@ -0,0 +1,78 @@
+//! Redox-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::{c_char, c_int, c_long, c_ulong, c_void};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = c_long;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type gid_t = c_int;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = c_int;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type uid_t = c_int;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = *mut c_void;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = c_long;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = c_long;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub _pad: [c_char; 24],
+}
diff --git a/library/std/src/os/solaris/fs.rs b/library/std/src/os/solaris/fs.rs
new file mode 100644
index 000000000..093143737
--- /dev/null
+++ b/library/std/src/os/solaris/fs.rs
@@ -0,0 +1,117 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::solaris::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned `stat` are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[deprecated(
+ since = "1.8.0",
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
+ )]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/solaris/mod.rs b/library/std/src/os/solaris/mod.rs
new file mode 100644
index 000000000..e4cfd5329
--- /dev/null
+++ b/library/std/src/os/solaris/mod.rs
@@ -0,0 +1,6 @@
+//! Solaris-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/solaris/raw.rs b/library/std/src/os/solaris/raw.rs
new file mode 100644
index 000000000..63426c969
--- /dev/null
+++ b/library/std/src/os/solaris/raw.rs
@@ -0,0 +1,76 @@
+//! Solaris-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_long;
+use crate::os::unix::raw::{gid_t, uid_t};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type fflags_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = i64;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = u32;
+
+#[repr(C)]
+#[derive(Clone)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __unused: [u8; 16],
+}
diff --git a/library/std/src/os/solid/ffi.rs b/library/std/src/os/solid/ffi.rs
new file mode 100644
index 000000000..aaa2070a6
--- /dev/null
+++ b/library/std/src/os/solid/ffi.rs
@@ -0,0 +1,41 @@
+//! SOLID-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::solid::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::solid::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
new file mode 100644
index 000000000..33cc5a015
--- /dev/null
+++ b/library/std/src/os/solid/io.rs
@@ -0,0 +1,113 @@
+//! SOLID-specific extensions to general I/O primitives
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "solid_ext", issue = "none")]
+
+use crate::net;
+use crate::sys;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+pub type RawFd = i32;
+
+/// A trait to extract the raw SOLID Sockets file descriptor from an underlying
+/// object.
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ *self
+ }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self
+ }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+ fd
+ }
+}
+
+macro_rules! impl_as_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl AsRawFd for net::$t {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ *self.as_inner().socket().as_inner()
+ }
+ }
+ )*};
+}
+impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_from_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ impl FromRawFd for net::$t {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+ }
+ }
+ )*};
+}
+impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_into_raw_fd {
+ ($($t:ident)*) => {$(
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ impl IntoRawFd for net::$t {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+ }
+ )*};
+}
+impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
diff --git a/library/std/src/os/solid/mod.rs b/library/std/src/os/solid/mod.rs
new file mode 100644
index 000000000..4328ba7c3
--- /dev/null
+++ b/library/std/src/os/solid/mod.rs
@@ -0,0 +1,17 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+pub mod io;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+}
diff --git a/library/std/src/os/unix/ffi/mod.rs b/library/std/src/os/unix/ffi/mod.rs
new file mode 100644
index 000000000..5b49f5076
--- /dev/null
+++ b/library/std/src/os/unix/ffi/mod.rs
@@ -0,0 +1,42 @@
+//! Unix-specific extensions to primitives in the [`std::ffi`] module.
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::unix::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::unix::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! [`std::ffi`]: crate::ffi
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
diff --git a/library/std/src/os/unix/ffi/os_str.rs b/library/std/src/os/unix/ffi/os_str.rs
new file mode 100644
index 000000000..650f712bc
--- /dev/null
+++ b/library/std/src/os/unix/ffi/os_str.rs
@@ -0,0 +1,70 @@
+use crate::ffi::{OsStr, OsString};
+use crate::mem;
+use crate::sealed::Sealed;
+use crate::sys::os_str::Buf;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+// Note: this file is currently reused in other `std::os::{platform}::ffi` modules to reduce duplication.
+// Keep this in mind when applying changes to this file that only apply to `unix`.
+
+/// Platform-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt: Sealed {
+ /// Creates an [`OsString`] from a byte vector.
+ ///
+ /// See the module documentation for an example.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_vec(vec: Vec<u8>) -> Self;
+
+ /// Yields the underlying byte vector of this [`OsString`].
+ ///
+ /// See the module documentation for an example.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn into_vec(self) -> Vec<u8>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+ #[inline]
+ fn from_vec(vec: Vec<u8>) -> OsString {
+ FromInner::from_inner(Buf { inner: vec })
+ }
+ #[inline]
+ fn into_vec(self) -> Vec<u8> {
+ self.into_inner().inner
+ }
+}
+
+/// Platform-specific extensions to [`OsStr`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt: Sealed {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ /// Creates an [`OsStr`] from a byte slice.
+ ///
+ /// See the module documentation for an example.
+ fn from_bytes(slice: &[u8]) -> &Self;
+
+ /// Gets the underlying byte view of the [`OsStr`] slice.
+ ///
+ /// See the module documentation for an example.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_bytes(&self) -> &[u8];
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+ #[inline]
+ fn from_bytes(slice: &[u8]) -> &OsStr {
+ unsafe { mem::transmute(slice) }
+ }
+ #[inline]
+ fn as_bytes(&self) -> &[u8] {
+ &self.as_inner().inner
+ }
+}
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
new file mode 100644
index 000000000..3fc6cc44c
--- /dev/null
+++ b/library/std/src/os/unix/fs.rs
@@ -0,0 +1,1022 @@
+//! Unix-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use super::platform::fs::MetadataExt as _;
+use crate::fs::{self, OpenOptions, Permissions};
+use crate::io;
+use crate::os::unix::io::{AsFd, AsRawFd};
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+// Used for `File::read` on intra-doc links
+use crate::ffi::OsStr;
+use crate::sealed::Sealed;
+#[allow(unused_imports)]
+use io::{Read, Write};
+
+/// Unix-specific extensions to [`fs::File`].
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+ /// Reads a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Note that similar to [`File::read`], it is not an error to return with a
+ /// short read.
+ ///
+ /// [`File::read`]: fs::File::read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs::File;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut buf = [0u8; 8];
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now read 8 bytes from the offset 10.
+ /// let num_bytes_read = file.read_at(&mut buf, 10)?;
+ /// println!("read {num_bytes_read} bytes: {buf:?}");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Reads the exact number of byte required to fill `buf` from the given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
+ ///
+ /// [`read_at`]: FileExt::read_at
+ ///
+ /// # Errors
+ ///
+ /// If this function encounters an error of the kind
+ /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
+ /// will continue.
+ ///
+ /// If this function encounters an "end of file" before completely filling
+ /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
+ /// The contents of `buf` are unspecified in this case.
+ ///
+ /// If any other read error is encountered then this function immediately
+ /// returns. The contents of `buf` are unspecified in this case.
+ ///
+ /// If this function returns an error, it is unspecified how many bytes it
+ /// has read, but it will never read more than would be necessary to
+ /// completely fill the buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs::File;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut buf = [0u8; 8];
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now read exactly 8 bytes from the offset 10.
+ /// file.read_exact_at(&mut buf, 10)?;
+ /// println!("read {} bytes: {:?}", buf.len(), buf);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.read_at(buf, offset) {
+ Ok(0) => break,
+ Ok(n) => {
+ let tmp = buf;
+ buf = &mut tmp[n..];
+ offset += n as u64;
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ if !buf.is_empty() {
+ Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Writes a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are initialized with the value 0.
+ ///
+ /// Note that similar to [`File::write`], it is not an error to return a
+ /// short write.
+ ///
+ /// [`File::write`]: fs::File::write
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now write at the offset 10.
+ /// file.write_at(b"sushi", 10)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+
+ /// Attempts to write an entire buffer starting from a given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// This method will continuously call [`write_at`] until there is no more data
+ /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
+ ///
+ /// # Errors
+ ///
+ /// This function will return the first error of
+ /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
+ ///
+ /// [`write_at`]: FileExt::write_at
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now write at the offset 10.
+ /// file.write_all_at(b"sushi", 10)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.write_at(buf, offset) {
+ Ok(0) => {
+ return Err(io::const_io_error!(
+ io::ErrorKind::WriteZero,
+ "failed to write whole buffer",
+ ));
+ }
+ Ok(n) => {
+ buf = &buf[n..];
+ offset += n as u64
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ Ok(())
+ }
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
+/// Unix-specific extensions to [`fs::Permissions`].
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+ /// Returns the underlying raw `st_mode` bits that contain the standard
+ /// Unix permissions for this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let permissions = metadata.permissions();
+ ///
+ /// println!("permissions: {:o}", permissions.mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+
+ /// Sets the underlying raw bits for this set of permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_mode(0o644); // Read/write for owner and read for others.
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn set_mode(&mut self, mode: u32);
+
+ /// Creates a new instance of `Permissions` from the given set of Unix
+ /// permission bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::Permissions;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// // Read/write for owner and read for others.
+ /// let permissions = Permissions::from_mode(0o644);
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+ fn mode(&self) -> u32 {
+ self.as_inner().mode()
+ }
+
+ fn set_mode(&mut self, mode: u32) {
+ *self = Permissions::from_inner(FromInner::from_inner(mode));
+ }
+
+ fn from_mode(mode: u32) -> Permissions {
+ Permissions::from_inner(FromInner::from_inner(mode))
+ }
+}
+
+/// Unix-specific extensions to [`fs::OpenOptions`].
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+ /// Sets the mode bits that a new file will be created with.
+ ///
+ /// If a new file is created as part of an `OpenOptions::open` call then this
+ /// specified `mode` will be used as the permission bits for the new file.
+ /// If no `mode` is set, the default of `0o666` will be used.
+ /// The operating system masks out bits with the system's `umask`, to produce
+ /// the final permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.mode(0o644); // Give read/write for owner and read for others.
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+
+ /// Pass custom flags to the `flags` argument of `open`.
+ ///
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+ /// ensure they do not interfere with the access mode set by Rusts options.
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(rustc_private)]
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.write(true);
+ /// if cfg!(unix) {
+ /// options.custom_flags(libc::O_NOFOLLOW);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+ self.as_inner_mut().mode(mode);
+ self
+ }
+
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags);
+ self
+ }
+}
+
+/// Unix-specific extensions to [`fs::Metadata`].
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the ID of the device containing the file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let dev_id = meta.dev();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let inode = meta.ino();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+ /// Returns the rights applied to this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let mode = meta.mode();
+ /// let user_has_write_access = mode & 0o200;
+ /// let user_has_read_write_access = mode & 0o600;
+ /// let group_has_read_access = mode & 0o040;
+ /// let others_have_exec_access = mode & 0o001;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+ /// Returns the number of hard links pointing to this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nb_hard_links = meta.nlink();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn nlink(&self) -> u64;
+ /// Returns the user ID of the owner of this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let user_id = meta.uid();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn uid(&self) -> u32;
+ /// Returns the group ID of the owner of this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let group_id = meta.gid();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn gid(&self) -> u32;
+ /// Returns the device ID of this file (if it is a special one).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let device_id = meta.rdev();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn rdev(&self) -> u64;
+ /// Returns the total size of this file in bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let file_size = meta.size();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn size(&self) -> u64;
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_access_time = meta.atime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime(&self) -> i64;
+ /// Returns the last access time of the file, in nanoseconds since [`atime`].
+ ///
+ /// [`atime`]: MetadataExt::atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_access_time = meta.atime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime_nsec(&self) -> i64;
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_modification_time = meta.mtime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime(&self) -> i64;
+ /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
+ ///
+ /// [`mtime`]: MetadataExt::mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_modification_time = meta.mtime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime_nsec(&self) -> i64;
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_status_change_time = meta.ctime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime(&self) -> i64;
+ /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
+ ///
+ /// [`ctime`]: MetadataExt::ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_status_change_time = meta.ctime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime_nsec(&self) -> i64;
+ /// Returns the block size for filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let block_size = meta.blksize();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, in 512-byte units.
+ ///
+ /// Please note that this may be smaller than `st_size / 512` when the file has holes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let blocks = meta.blocks();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blocks(&self) -> u64;
+ #[cfg(target_os = "vxworks")]
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn attrib(&self) -> u8;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+ fn dev(&self) -> u64 {
+ self.st_dev()
+ }
+ fn ino(&self) -> u64 {
+ self.st_ino()
+ }
+ fn mode(&self) -> u32 {
+ self.st_mode()
+ }
+ fn nlink(&self) -> u64 {
+ self.st_nlink()
+ }
+ fn uid(&self) -> u32 {
+ self.st_uid()
+ }
+ fn gid(&self) -> u32 {
+ self.st_gid()
+ }
+ fn rdev(&self) -> u64 {
+ self.st_rdev()
+ }
+ fn size(&self) -> u64 {
+ self.st_size()
+ }
+ fn atime(&self) -> i64 {
+ self.st_atime()
+ }
+ fn atime_nsec(&self) -> i64 {
+ self.st_atime_nsec()
+ }
+ fn mtime(&self) -> i64 {
+ self.st_mtime()
+ }
+ fn mtime_nsec(&self) -> i64 {
+ self.st_mtime_nsec()
+ }
+ fn ctime(&self) -> i64 {
+ self.st_ctime()
+ }
+ fn ctime_nsec(&self) -> i64 {
+ self.st_ctime_nsec()
+ }
+ fn blksize(&self) -> u64 {
+ self.st_blksize()
+ }
+ fn blocks(&self) -> u64 {
+ self.st_blocks()
+ }
+ #[cfg(target_os = "vxworks")]
+ fn attrib(&self) -> u8 {
+ self.st_attrib()
+ }
+}
+
+/// Unix-specific extensions for [`fs::FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+ /// Returns `true` if this file type is a block device.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("block_device_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_block_device());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_block_device(&self) -> bool;
+ /// Returns `true` if this file type is a char device.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("char_device_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_char_device());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_char_device(&self) -> bool;
+ /// Returns `true` if this file type is a fifo.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("fifo_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_fifo());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_fifo(&self) -> bool;
+ /// Returns `true` if this file type is a socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("unix.socket")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_socket());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+ fn is_block_device(&self) -> bool {
+ self.as_inner().is(libc::S_IFBLK)
+ }
+ fn is_char_device(&self) -> bool {
+ self.as_inner().is(libc::S_IFCHR)
+ }
+ fn is_fifo(&self) -> bool {
+ self.as_inner().is(libc::S_IFIFO)
+ }
+ fn is_socket(&self) -> bool {
+ self.as_inner().is(libc::S_IFSOCK)
+ }
+}
+
+/// Unix-specific extension methods for [`fs::DirEntry`].
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+pub trait DirEntryExt {
+ /// Returns the underlying `d_ino` field in the contained `dirent`
+ /// structure.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::unix::fs::DirEntryExt;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// println!("{:?}: {}", entry.file_name(), entry.ino());
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+}
+
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+impl DirEntryExt for fs::DirEntry {
+ fn ino(&self) -> u64 {
+ self.as_inner().ino()
+ }
+}
+
+/// Sealed Unix-specific extension methods for [`fs::DirEntry`].
+#[unstable(feature = "dir_entry_ext2", issue = "85573")]
+pub trait DirEntryExt2: Sealed {
+ /// Returns a reference to the underlying `OsStr` of this entry's filename.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(dir_entry_ext2)]
+ /// use std::os::unix::fs::DirEntryExt2;
+ /// use std::{fs, io};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
+ /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
+ ///
+ /// for p in entries {
+ /// println!("{p:?}");
+ /// }
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ fn file_name_ref(&self) -> &OsStr;
+}
+
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl Sealed for fs::DirEntry {}
+
+#[unstable(feature = "dir_entry_ext2", issue = "85573")]
+impl DirEntryExt2 for fs::DirEntry {
+ fn file_name_ref(&self) -> &OsStr {
+ self.as_inner().file_name_os_str()
+ }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `link` path will be a symbolic link pointing to the `original` path.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink(original.as_ref(), link.as_ref())
+}
+
+/// Unix-specific extensions to [`fs::DirBuilder`].
+#[stable(feature = "dir_builder", since = "1.6.0")]
+pub trait DirBuilderExt {
+ /// Sets the mode to create new directories with. This option defaults to
+ /// 0o777.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::DirBuilder;
+ /// use std::os::unix::fs::DirBuilderExt;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.mode(0o755);
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+ fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+ self.as_inner_mut().set_mode(mode);
+ self
+ }
+}
+
+/// Change the owner and group of the specified path.
+///
+/// Specifying either the uid or gid as `None` will leave it unchanged.
+///
+/// Changing the owner typically requires privileges, such as root or a specific capability.
+/// Changing the group typically requires either being the owner and a member of the group, or
+/// having privileges.
+///
+/// If called on a symbolic link, this will change the owner and group of the link target. To
+/// change the owner and group of the link itself, see [`lchown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::chown("/sandbox", Some(0), Some(0))?;
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+ sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the file referenced by the specified open file descriptor.
+///
+/// For semantics and required privileges, see [`chown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// let f = std::fs::File::open("/file")?;
+/// fs::fchown(&f, Some(0), Some(0))?;
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+ sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the specified path, without dereferencing symbolic links.
+///
+/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
+/// and group of the link itself rather than the owner and group of the link target.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::lchown("/symlink", Some(0), Some(0))?;
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+ sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the root directory of the current process to the specified path.
+///
+/// This typically requires privileges, such as root or a specific capability.
+///
+/// This does not change the current working directory; you should call
+/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::chroot("/sandbox")?;
+/// std::env::set_current_dir("/")?;
+/// // continue working in sandbox
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_chroot", since = "1.56.0")]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
+pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
+ sys::fs::chroot(dir.as_ref())
+}
diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs
new file mode 100644
index 000000000..d4cb69645
--- /dev/null
+++ b/library/std/src/os/unix/io/fd.rs
@@ -0,0 +1,8 @@
+//! Owned and borrowed file descriptors.
+
+// Tests for this module
+#[cfg(test)]
+mod tests;
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use crate::os::fd::owned::*;
diff --git a/library/std/src/os/unix/io/fd/tests.rs b/library/std/src/os/unix/io/fd/tests.rs
new file mode 100644
index 000000000..84d2a7a1a
--- /dev/null
+++ b/library/std/src/os/unix/io/fd/tests.rs
@@ -0,0 +1,11 @@
+use crate::mem::size_of;
+use crate::os::unix::io::RawFd;
+
+#[test]
+fn test_raw_fd_layout() {
+ // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
+ // and `rustc_layout_scalar_valid_range_end`, with values that depend on
+ // the bit width of `RawFd`. If this ever changes, those values will need
+ // to be updated.
+ assert_eq!(size_of::<RawFd>(), 4);
+}
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
new file mode 100644
index 000000000..3ab5606f8
--- /dev/null
+++ b/library/std/src/os/unix/io/mod.rs
@@ -0,0 +1,86 @@
+//! Unix-specific extensions to general I/O primitives.
+//!
+//! Just like raw pointers, raw file descriptors point to resources with
+//! dynamic lifetimes, and they can dangle if they outlive their resources
+//! or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing file descriptors,
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type | Analogous to |
+//! | ------------------ | ------------ |
+//! | [`RawFd`] | `*const _` |
+//! | [`BorrowedFd<'a>`] | `&'a _` |
+//! | [`OwnedFd`] | `Box<_>` |
+//!
+//! Like raw pointers, `RawFd` values are primitive values. And in new code,
+//! they should be considered unsafe to do I/O on (analogous to dereferencing
+//! them). Rust did not always provide this guidance, so existing code in the
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
+//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
+//! using to `BorrowedFd` or `OwnedFd` instead.
+//!
+//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
+//! that they don't outlive the resource they point to. These are safe to
+//! use. `BorrowedFd` values may be used in APIs which provide safe access to
+//! any system call except for:
+//!
+//! - `close`, because that would end the dynamic lifetime of the resource
+//! without ending the lifetime of the file descriptor.
+//!
+//! - `dup2`/`dup3`, in the second argument, because this argument is
+//! closed and assigned a new resource, which may break the assumptions
+//! other code using that file descriptor.
+//!
+//! `BorrowedFd` values may be used in APIs which provide safe access to `dup`
+//! system calls, so types implementing `AsFd` or `From<OwnedFd>` should not
+//! assume they always have exclusive access to the underlying file
+//! description.
+//!
+//! `BorrowedFd` values may also be used with `mmap`, since `mmap` uses the
+//! provided file descriptor in a manner similar to `dup` and does not require
+//! the `BorrowedFd` passed to it to live for the lifetime of the resulting
+//! mapping. That said, `mmap` is unsafe for other reasons: it operates on raw
+//! pointers, and it can have undefined behavior if the underlying storage is
+//! mutated. Mutations may come from other processes, or from the same process
+//! if the API provides `BorrowedFd` access, since as mentioned earlier,
+//! `BorrowedFd` values may be used in APIs which provide safe access to any
+//! system call. Consequently, code using `mmap` and presenting a safe API must
+//! take full responsibility for ensuring that safe Rust code cannot evoke
+//! undefined behavior through it.
+//!
+//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
+//! and free (close) it when they are dropped.
+//!
+//! ## `/proc/self/mem` and similar OS features
+//!
+//! Some platforms have special files, such as `/proc/self/mem`, which
+//! provide read and write access to the process's memory. Such reads
+//! and writes happen outside the control of the Rust compiler, so they do not
+//! uphold Rust's memory safety guarantees.
+//!
+//! This does not mean that all APIs that might allow `/proc/self/mem`
+//! to be opened and read from or written must be `unsafe`. Rust's safety guarantees
+//! only cover what the program itself can do, and not what entities outside
+//! the program can do to it. `/proc/self/mem` is considered to be such an
+//! external entity, along with debugging interfaces, and people with physical access to
+//! the hardware. This is true even in cases where the program is controlling
+//! the external entity.
+//!
+//! If you desire to comprehensively prevent programs from reaching out and
+//! causing external entities to reach back in and violate memory safety, it's
+//! necessary to use *sandboxing*, which is outside the scope of `std`.
+//!
+//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod fd;
+mod raw;
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use fd::*;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::*;
diff --git a/library/std/src/os/unix/io/raw.rs b/library/std/src/os/unix/io/raw.rs
new file mode 100644
index 000000000..a4d2ba797
--- /dev/null
+++ b/library/std/src/os/unix/io/raw.rs
@@ -0,0 +1,6 @@
+//! Unix-specific extensions to general I/O primitives.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
new file mode 100644
index 000000000..411cc0925
--- /dev/null
+++ b/library/std/src/os/unix/mod.rs
@@ -0,0 +1,126 @@
+//! Platform-specific extensions to `std` for Unix platforms.
+//!
+//! Provides access to platform-level information on Unix platforms, and
+//! exposes Unix-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings ([`OsStr`],
+//! [`OsString`]), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//! let f = File::create("foo.txt")?;
+//! let fd = f.as_raw_fd();
+//!
+//! // use fd with native unix bindings
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! [`OsStr`]: crate::ffi::OsStr
+//! [`OsString`]: crate::ffi::OsString
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(unix))]
+
+// Use linux as the default platform when documenting on other platforms like Windows
+#[cfg(doc)]
+use crate::os::linux as platform;
+
+#[cfg(not(doc))]
+mod platform {
+ #[cfg(target_os = "android")]
+ pub use crate::os::android::*;
+ #[cfg(target_os = "dragonfly")]
+ pub use crate::os::dragonfly::*;
+ #[cfg(target_os = "emscripten")]
+ pub use crate::os::emscripten::*;
+ #[cfg(target_os = "espidf")]
+ pub use crate::os::espidf::*;
+ #[cfg(target_os = "freebsd")]
+ pub use crate::os::freebsd::*;
+ #[cfg(target_os = "fuchsia")]
+ pub use crate::os::fuchsia::*;
+ #[cfg(target_os = "haiku")]
+ pub use crate::os::haiku::*;
+ #[cfg(target_os = "horizon")]
+ pub use crate::os::horizon::*;
+ #[cfg(target_os = "illumos")]
+ pub use crate::os::illumos::*;
+ #[cfg(target_os = "ios")]
+ pub use crate::os::ios::*;
+ #[cfg(target_os = "l4re")]
+ pub use crate::os::l4re::*;
+ #[cfg(target_os = "linux")]
+ pub use crate::os::linux::*;
+ #[cfg(target_os = "macos")]
+ pub use crate::os::macos::*;
+ #[cfg(target_os = "netbsd")]
+ pub use crate::os::netbsd::*;
+ #[cfg(target_os = "openbsd")]
+ pub use crate::os::openbsd::*;
+ #[cfg(target_os = "redox")]
+ pub use crate::os::redox::*;
+ #[cfg(target_os = "solaris")]
+ pub use crate::os::solaris::*;
+ #[cfg(target_os = "vxworks")]
+ pub use crate::os::vxworks::*;
+}
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod net;
+pub mod process;
+pub mod raw;
+pub mod thread;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+pub mod ucred;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::DirEntryExt;
+ #[doc(no_inline)]
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ pub use super::fs::FileExt;
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::process::{CommandExt, ExitStatusExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::thread::JoinHandleExt;
+}
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
new file mode 100644
index 000000000..9aeae4b2c
--- /dev/null
+++ b/library/std/src/os/unix/net/addr.rs
@@ -0,0 +1,350 @@
+use crate::ffi::OsStr;
+use crate::os::unix::ffi::OsStrExt;
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::{ascii, fmt, io, mem, ptr};
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(not(unix))]
+#[allow(non_camel_case_types)]
+mod libc {
+ pub use libc::c_int;
+ pub type socklen_t = u32;
+ pub struct sockaddr;
+ #[derive(Clone)]
+ pub struct sockaddr_un;
+}
+
+fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
+ // Work with an actual instance of the type since using a null pointer is UB
+ let base = (addr as *const libc::sockaddr_un).addr();
+ let path = (&addr.sun_path as *const libc::c_char).addr();
+ path - base
+}
+
+pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+ // SAFETY: All zeros is a valid representation for `sockaddr_un`.
+ let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
+ addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+ let bytes = path.as_os_str().as_bytes();
+
+ if bytes.contains(&0) {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "paths must not contain interior null bytes",
+ ));
+ }
+
+ if bytes.len() >= addr.sun_path.len() {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "path must be shorter than SUN_LEN",
+ ));
+ }
+ // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
+ // both point to valid memory.
+ // NOTE: We zeroed the memory above, so the path is already null
+ // terminated.
+ unsafe {
+ ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
+ };
+
+ let mut len = sun_path_offset(&addr) + bytes.len();
+ match bytes.get(0) {
+ Some(&0) | None => {}
+ Some(_) => len += 1,
+ }
+ Ok((addr, len as libc::socklen_t))
+}
+
+enum AddressKind<'a> {
+ Unnamed,
+ Pathname(&'a Path),
+ Abstract(&'a [u8]),
+}
+
+struct AsciiEscaped<'a>(&'a [u8]);
+
+impl<'a> fmt::Display for AsciiEscaped<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "\"")?;
+ for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
+ write!(fmt, "{}", byte as char)?;
+ }
+ write!(fmt, "\"")
+ }
+}
+
+/// An address associated with a Unix socket.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::net::UnixListener;
+///
+/// let socket = match UnixListener::bind("/tmp/sock") {
+/// Ok(sock) => sock,
+/// Err(e) => {
+/// println!("Couldn't bind: {e:?}");
+/// return
+/// }
+/// };
+/// let addr = socket.local_addr().expect("Couldn't get local address");
+/// ```
+#[derive(Clone)]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct SocketAddr {
+ pub(super) addr: libc::sockaddr_un,
+ pub(super) len: libc::socklen_t,
+}
+
+impl SocketAddr {
+ pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
+ where
+ F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
+ {
+ unsafe {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
+ cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
+ SocketAddr::from_parts(addr, len)
+ }
+ }
+
+ pub(super) fn from_parts(
+ addr: libc::sockaddr_un,
+ mut len: libc::socklen_t,
+ ) -> io::Result<SocketAddr> {
+ if len == 0 {
+ // When there is a datagram from unnamed unix socket
+ // linux returns zero bytes of address
+ len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
+ } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "file descriptor did not correspond to a Unix socket",
+ ));
+ }
+
+ Ok(SocketAddr { addr, len })
+ }
+
+ /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the path is longer than `SUN_LEN` or if it contains
+ /// NULL bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::SocketAddr;
+ /// use std::path::Path;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let address = SocketAddr::from_pathname("/path/to/socket")?;
+ /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// Creating a `SocketAddr` with a NULL byte results in an error.
+ ///
+ /// ```
+ /// use std::os::unix::net::SocketAddr;
+ ///
+ /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
+ /// ```
+ #[stable(feature = "unix_socket_creation", since = "1.61.0")]
+ pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
+ where
+ P: AsRef<Path>,
+ {
+ sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
+ }
+
+ /// Returns `true` if the address is unnamed.
+ ///
+ /// # Examples
+ ///
+ /// A named address:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixListener::bind("/tmp/sock")?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), false);
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// An unnamed address:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), true);
+ /// Ok(())
+ /// }
+ /// ```
+ #[must_use]
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn is_unnamed(&self) -> bool {
+ matches!(self.address(), AddressKind::Unnamed)
+ }
+
+ /// Returns the contents of this address if it is a `pathname` address.
+ ///
+ /// # Examples
+ ///
+ /// With a pathname:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ /// use std::path::Path;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixListener::bind("/tmp/sock")?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// Without a pathname:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), None);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ #[must_use]
+ pub fn as_pathname(&self) -> Option<&Path> {
+ if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
+ }
+
+ /// Returns the contents of this address if it is an abstract namespace
+ /// without the leading null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener, SocketAddr};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let namespace = b"hidden";
+ /// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?;
+ /// let socket = UnixListener::bind_addr(&namespace_addr)?;
+ /// let local_addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..]));
+ /// Ok(())
+ /// }
+ /// ```
+ #[doc(cfg(any(target_os = "android", target_os = "linux")))]
+ #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
+ if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
+ }
+
+ fn address(&self) -> AddressKind<'_> {
+ let len = self.len as usize - sun_path_offset(&self.addr);
+ let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
+
+ // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
+ if len == 0
+ || (cfg!(not(any(target_os = "linux", target_os = "android")))
+ && self.addr.sun_path[0] == 0)
+ {
+ AddressKind::Unnamed
+ } else if self.addr.sun_path[0] == 0 {
+ AddressKind::Abstract(&path[1..len])
+ } else {
+ AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
+ }
+ }
+
+ /// Creates an abstract domain socket address from a namespace
+ ///
+ /// An abstract address does not create a file unlike traditional path-based
+ /// Unix sockets. The advantage of this is that the address will disappear when
+ /// the socket bound to it is closed, so no filesystem clean up is required.
+ ///
+ /// The leading null byte for the abstract namespace is automatically added.
+ ///
+ /// This is a Linux-specific extension. See more at [`unix(7)`].
+ ///
+ /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html
+ ///
+ /// # Errors
+ ///
+ /// This will return an error if the given namespace is too long
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener, SocketAddr};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?;
+ /// let listener = match UnixListener::bind_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(err) => {
+ /// println!("Couldn't bind: {err:?}");
+ /// return Err(err);
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[doc(cfg(any(target_os = "android", target_os = "linux")))]
+ #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> {
+ unsafe {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+ if namespace.len() + 1 > addr.sun_path.len() {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "namespace must be shorter than SUN_LEN",
+ ));
+ }
+
+ crate::ptr::copy_nonoverlapping(
+ namespace.as_ptr(),
+ addr.sun_path.as_mut_ptr().offset(1) as *mut u8,
+ namespace.len(),
+ );
+ let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t;
+ SocketAddr::from_parts(addr, len)
+ }
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for SocketAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.address() {
+ AddressKind::Unnamed => write!(fmt, "(unnamed)"),
+ AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
+ AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
+ }
+ }
+}
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
new file mode 100644
index 000000000..7cc901a79
--- /dev/null
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -0,0 +1,674 @@
+// FIXME: This is currently disabled on *BSD.
+
+use super::{sockaddr_un, SocketAddr};
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::marker::PhantomData;
+use crate::mem::{size_of, zeroed};
+use crate::os::unix::io::RawFd;
+use crate::path::Path;
+use crate::ptr::{eq, read_unaligned};
+use crate::slice::from_raw_parts;
+use crate::sys::net::Socket;
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))]
+#[allow(non_camel_case_types)]
+mod libc {
+ pub use libc::c_int;
+ pub struct ucred;
+ pub struct cmsghdr;
+ pub type pid_t = i32;
+ pub type gid_t = u32;
+ pub type uid_t = u32;
+}
+
+pub(super) fn recv_vectored_with_ancillary_from(
+ socket: &Socket,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
+ unsafe {
+ let mut msg_name: libc::sockaddr_un = zeroed();
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_name = &mut msg_name as *mut _ as *mut _;
+ msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
+ msg.msg_iov = bufs.as_mut_ptr().cast();
+ msg.msg_iovlen = bufs.len() as _;
+ msg.msg_controllen = ancillary.buffer.len() as _;
+ // macos requires that the control pointer is null when the len is 0.
+ if msg.msg_controllen > 0 {
+ msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+ }
+
+ let count = socket.recv_msg(&mut msg)?;
+
+ ancillary.length = msg.msg_controllen as usize;
+ ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
+
+ let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
+ let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
+
+ Ok((count, truncated, addr))
+ }
+}
+
+pub(super) fn send_vectored_with_ancillary_to(
+ socket: &Socket,
+ path: Option<&Path>,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<usize> {
+ unsafe {
+ let (mut msg_name, msg_namelen) =
+ if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
+
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_name = &mut msg_name as *mut _ as *mut _;
+ msg.msg_namelen = msg_namelen;
+ msg.msg_iov = bufs.as_ptr() as *mut _;
+ msg.msg_iovlen = bufs.len() as _;
+ msg.msg_controllen = ancillary.length as _;
+ // macos requires that the control pointer is null when the len is 0.
+ if msg.msg_controllen > 0 {
+ msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+ }
+
+ ancillary.truncated = false;
+
+ socket.send_msg(&mut msg)
+ }
+}
+
+fn add_to_ancillary_data<T>(
+ buffer: &mut [u8],
+ length: &mut usize,
+ source: &[T],
+ cmsg_level: libc::c_int,
+ cmsg_type: libc::c_int,
+) -> bool {
+ let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
+ if let Ok(source_len) = u32::try_from(source_len) {
+ source_len
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ };
+
+ unsafe {
+ let additional_space = libc::CMSG_SPACE(source_len) as usize;
+
+ let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
+ new_length
+ } else {
+ return false;
+ };
+
+ if new_length > buffer.len() {
+ return false;
+ }
+
+ buffer[*length..new_length].fill(0);
+
+ *length = new_length;
+
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_control = buffer.as_mut_ptr().cast();
+ msg.msg_controllen = *length as _;
+
+ let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
+ let mut previous_cmsg = cmsg;
+ while !cmsg.is_null() {
+ previous_cmsg = cmsg;
+ cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
+
+ // Most operating systems, but not Linux or emscripten, return the previous pointer
+ // when its length is zero. Therefore, check if the previous pointer is the same as
+ // the current one.
+ if eq(cmsg, previous_cmsg) {
+ break;
+ }
+ }
+
+ if previous_cmsg.is_null() {
+ return false;
+ }
+
+ (*previous_cmsg).cmsg_level = cmsg_level;
+ (*previous_cmsg).cmsg_type = cmsg_type;
+ (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
+
+ let data = libc::CMSG_DATA(previous_cmsg).cast();
+
+ libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
+ }
+ true
+}
+
+struct AncillaryDataIter<'a, T> {
+ data: &'a [u8],
+ phantom: PhantomData<T>,
+}
+
+impl<'a, T> AncillaryDataIter<'a, T> {
+ /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
+ ///
+ /// # Safety
+ ///
+ /// `data` must contain a valid control message.
+ unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
+ AncillaryDataIter { data, phantom: PhantomData }
+ }
+}
+
+impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ if size_of::<T>() <= self.data.len() {
+ unsafe {
+ let unit = read_unaligned(self.data.as_ptr().cast());
+ self.data = &self.data[size_of::<T>()..];
+ Some(unit)
+ }
+ } else {
+ None
+ }
+ }
+}
+
+#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(());
+
+/// Unix credential.
+#[cfg(any(target_os = "android", target_os = "linux",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(libc::ucred);
+
+#[cfg(target_os = "netbsd")]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(libc::sockcred);
+
+#[doc(cfg(any(target_os = "android", target_os = "linux")))]
+#[cfg(any(target_os = "android", target_os = "linux"))]
+impl SocketCred {
+ /// Create a Unix credential struct.
+ ///
+ /// PID, UID and GID is set to 0.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ #[must_use]
+ pub fn new() -> SocketCred {
+ SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
+ }
+
+ /// Set the PID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_pid(&mut self, pid: libc::pid_t) {
+ self.0.pid = pid;
+ }
+
+ /// Get the current PID.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_pid(&self) -> libc::pid_t {
+ self.0.pid
+ }
+
+ /// Set the UID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_uid(&mut self, uid: libc::uid_t) {
+ self.0.uid = uid;
+ }
+
+ /// Get the current UID.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_uid(&self) -> libc::uid_t {
+ self.0.uid
+ }
+
+ /// Set the GID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_gid(&mut self, gid: libc::gid_t) {
+ self.0.gid = gid;
+ }
+
+ /// Get the current GID.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_gid(&self) -> libc::gid_t {
+ self.0.gid
+ }
+}
+
+#[cfg(target_os = "netbsd")]
+impl SocketCred {
+ /// Create a Unix credential struct.
+ ///
+ /// PID, UID and GID is set to 0.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn new() -> SocketCred {
+ SocketCred(libc::sockcred {
+ sc_pid: 0,
+ sc_uid: 0,
+ sc_euid: 0,
+ sc_gid: 0,
+ sc_egid: 0,
+ sc_ngroups: 0,
+ sc_groups: [0u32; 1],
+ })
+ }
+
+ /// Set the PID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_pid(&mut self, pid: libc::pid_t) {
+ self.0.sc_pid = pid;
+ }
+
+ /// Get the current PID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_pid(&self) -> libc::pid_t {
+ self.0.sc_pid
+ }
+
+ /// Set the UID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_uid(&mut self, uid: libc::uid_t) {
+ self.0.sc_uid = uid;
+ }
+
+ /// Get the current UID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_uid(&self) -> libc::uid_t {
+ self.0.sc_uid
+ }
+
+ /// Set the GID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_gid(&mut self, gid: libc::gid_t) {
+ self.0.sc_gid = gid;
+ }
+
+ /// Get the current GID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_gid(&self) -> libc::gid_t {
+ self.0.sc_gid
+ }
+}
+
+/// This control message contains file descriptors.
+///
+/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
+
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for ScmRights<'a> {
+ type Item = RawFd;
+
+ fn next(&mut self) -> Option<RawFd> {
+ self.0.next()
+ }
+}
+
+#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
+
+/// This control message contains unix credentials.
+///
+/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
+#[cfg(any(target_os = "android", target_os = "linux",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
+
+#[cfg(target_os = "netbsd")]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
+
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for ScmCredentials<'a> {
+ type Item = SocketCred;
+
+ fn next(&mut self) -> Option<SocketCred> {
+ Some(SocketCred(self.0.next()?))
+ }
+}
+
+/// The error type which is returned from parsing the type a control message.
+#[non_exhaustive]
+#[derive(Debug)]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub enum AncillaryError {
+ Unknown { cmsg_level: i32, cmsg_type: i32 },
+}
+
+/// This enum represent one control message of variable type.
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub enum AncillaryData<'a> {
+ ScmRights(ScmRights<'a>),
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ ScmCredentials(ScmCredentials<'a>),
+}
+
+impl<'a> AncillaryData<'a> {
+ /// Create an `AncillaryData::ScmRights` variant.
+ ///
+ /// # Safety
+ ///
+ /// `data` must contain a valid control message and the control message must be type of
+ /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
+ unsafe fn as_rights(data: &'a [u8]) -> Self {
+ let ancillary_data_iter = AncillaryDataIter::new(data);
+ let scm_rights = ScmRights(ancillary_data_iter);
+ AncillaryData::ScmRights(scm_rights)
+ }
+
+ /// Create an `AncillaryData::ScmCredentials` variant.
+ ///
+ /// # Safety
+ ///
+ /// `data` must contain a valid control message and the control message must be type of
+ /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ unsafe fn as_credentials(data: &'a [u8]) -> Self {
+ let ancillary_data_iter = AncillaryDataIter::new(data);
+ let scm_credentials = ScmCredentials(ancillary_data_iter);
+ AncillaryData::ScmCredentials(scm_credentials)
+ }
+
+ fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
+ unsafe {
+ let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
+ let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
+ let data = libc::CMSG_DATA(cmsg).cast();
+ let data = from_raw_parts(data, data_len);
+
+ match (*cmsg).cmsg_level {
+ libc::SOL_SOCKET => match (*cmsg).cmsg_type {
+ libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
+ #[cfg(any(target_os = "android", target_os = "linux",))]
+ libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
+ #[cfg(target_os = "netbsd")]
+ libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
+ cmsg_type => {
+ Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
+ }
+ },
+ cmsg_level => {
+ Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
+ }
+ }
+ }
+ }
+}
+
+/// This struct is used to iterate through the control messages.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct Messages<'a> {
+ buffer: &'a [u8],
+ current: Option<&'a libc::cmsghdr>,
+}
+
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for Messages<'a> {
+ type Item = Result<AncillaryData<'a>, AncillaryError>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ unsafe {
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_control = self.buffer.as_ptr() as *mut _;
+ msg.msg_controllen = self.buffer.len() as _;
+
+ let cmsg = if let Some(current) = self.current {
+ libc::CMSG_NXTHDR(&msg, current)
+ } else {
+ libc::CMSG_FIRSTHDR(&msg)
+ };
+
+ let cmsg = cmsg.as_ref()?;
+
+ // Most operating systems, but not Linux or emscripten, return the previous pointer
+ // when its length is zero. Therefore, check if the previous pointer is the same as
+ // the current one.
+ if let Some(current) = self.current {
+ if eq(current, cmsg) {
+ return None;
+ }
+ }
+
+ self.current = Some(cmsg);
+ let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
+ Some(ancillary_result)
+ }
+ }
+}
+
+/// A Unix socket Ancillary data struct.
+///
+/// # Example
+/// ```no_run
+/// #![feature(unix_socket_ancillary_data)]
+/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+/// use std::io::IoSliceMut;
+///
+/// fn main() -> std::io::Result<()> {
+/// let sock = UnixStream::connect("/tmp/sock")?;
+///
+/// let mut fds = [0; 8];
+/// let mut ancillary_buffer = [0; 128];
+/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+///
+/// let mut buf = [1; 8];
+/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+///
+/// for ancillary_result in ancillary.messages() {
+/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+/// for fd in scm_rights {
+/// println!("receive file descriptor: {fd}");
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Debug)]
+pub struct SocketAncillary<'a> {
+ buffer: &'a mut [u8],
+ length: usize,
+ truncated: bool,
+}
+
+impl<'a> SocketAncillary<'a> {
+ /// Create an ancillary data with the given buffer.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # #![allow(unused_mut)]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::SocketAncillary;
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ```
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn new(buffer: &'a mut [u8]) -> Self {
+ SocketAncillary { buffer, length: 0, truncated: false }
+ }
+
+ /// Returns the capacity of the buffer.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn capacity(&self) -> usize {
+ self.buffer.len()
+ }
+
+ /// Returns `true` if the ancillary data is empty.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn is_empty(&self) -> bool {
+ self.length == 0
+ }
+
+ /// Returns the number of used bytes.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn len(&self) -> usize {
+ self.length
+ }
+
+ /// Returns the iterator of the control messages.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn messages(&self) -> Messages<'_> {
+ Messages { buffer: &self.buffer[..self.length], current: None }
+ }
+
+ /// Is `true` if during a recv operation the ancillary was truncated.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixStream::connect("/tmp/sock")?;
+ ///
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ ///
+ /// let mut buf = [1; 8];
+ /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+ /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ ///
+ /// println!("Is truncated: {}", ancillary.truncated());
+ /// Ok(())
+ /// }
+ /// ```
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn truncated(&self) -> bool {
+ self.truncated
+ }
+
+ /// Add file descriptors to the ancillary data.
+ ///
+ /// The function returns `true` if there was enough space in the buffer.
+ /// If there was not enough space then no file descriptors was appended.
+ /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+ /// and type `SCM_RIGHTS`.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary};
+ /// use std::os::unix::io::AsRawFd;
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixStream::connect("/tmp/sock")?;
+ ///
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
+ ///
+ /// let buf = [1; 8];
+ /// let mut bufs = &mut [IoSlice::new(&buf[..])][..];
+ /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
+ self.truncated = false;
+ add_to_ancillary_data(
+ &mut self.buffer,
+ &mut self.length,
+ fds,
+ libc::SOL_SOCKET,
+ libc::SCM_RIGHTS,
+ )
+ }
+
+ /// Add credentials to the ancillary data.
+ ///
+ /// The function returns `true` if there was enough space in the buffer.
+ /// If there was not enough space then no credentials was appended.
+ /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+ /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
+ ///
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
+ self.truncated = false;
+ add_to_ancillary_data(
+ &mut self.buffer,
+ &mut self.length,
+ creds,
+ libc::SOL_SOCKET,
+ #[cfg(not(target_os = "netbsd"))]
+ libc::SCM_CREDENTIALS,
+ #[cfg(target_os = "netbsd")]
+ libc::SCM_CREDS,
+ )
+ }
+
+ /// Clears the ancillary data, removing all values.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixStream::connect("/tmp/sock")?;
+ ///
+ /// let mut fds1 = [0; 8];
+ /// let mut fds2 = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ ///
+ /// let mut buf = [1; 8];
+ /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+ ///
+ /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ ///
+ /// ancillary.clear();
+ ///
+ /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn clear(&mut self) {
+ self.length = 0;
+ self.truncated = false;
+ }
+}
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
new file mode 100644
index 000000000..8008acfd1
--- /dev/null
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -0,0 +1,987 @@
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
+use super::{sockaddr_un, SocketAddr};
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+use crate::io::{IoSlice, IoSliceMut};
+use crate::net::Shutdown;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+use crate::{fmt, io};
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "haiku"
+))]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(any(
+ target_os = "linux",
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "haiku"
+)))]
+const MSG_NOSIGNAL: libc::c_int = 0x0;
+
+/// A Unix datagram socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixDatagram;
+///
+/// fn main() -> std::io::Result<()> {
+/// let socket = UnixDatagram::bind("/path/to/my/socket")?;
+/// socket.send_to(b"hello world", "/path/to/other/socket")?;
+/// let mut buf = [0; 100];
+/// let (count, address) = socket.recv_from(&mut buf)?;
+/// println!("socket {:?} sent {:?}", address, &buf[..count]);
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixDatagram(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixDatagram {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixDatagram");
+ builder.field("fd", self.0.as_inner());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ if let Ok(addr) = self.peer_addr() {
+ builder.field("peer", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixDatagram {
+ /// Creates a Unix datagram socket bound to the given path.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't bind: {e:?}");
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
+ unsafe {
+ let socket = UnixDatagram::unbound()?;
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::bind(socket.as_raw_fd(), &addr as *const _ as *const _, len as _))?;
+
+ Ok(socket)
+ }
+ }
+
+ /// Creates a Unix datagram socket bound to an address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixDatagram};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock1 = UnixDatagram::bind("path/to/socket")?;
+ /// let addr = sock1.local_addr()?;
+ ///
+ /// let sock2 = match UnixDatagram::bind_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(err) => {
+ /// println!("Couldn't bind: {err:?}");
+ /// return Err(err);
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> {
+ unsafe {
+ let socket = UnixDatagram::unbound()?;
+ cvt(libc::bind(
+ socket.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len as _,
+ ))?;
+ Ok(socket)
+ }
+ }
+
+ /// Creates a Unix Datagram socket which is not bound to any address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = match UnixDatagram::unbound() {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't unbound: {e:?}");
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn unbound() -> io::Result<UnixDatagram> {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+ Ok(UnixDatagram(inner))
+ }
+
+ /// Creates an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixDatagrams`s which are connected to each other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let (sock1, sock2) = match UnixDatagram::pair() {
+ /// Ok((sock1, sock2)) => (sock1, sock2),
+ /// Err(e) => {
+ /// println!("Couldn't unbound: {e:?}");
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
+ let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+ Ok((UnixDatagram(i1), UnixDatagram(i2)))
+ }
+
+ /// Connects the socket to the specified path address.
+ ///
+ /// The [`send`] method may be used to send data to the specified address.
+ /// [`recv`] and [`recv_from`] will only receive data from that address.
+ ///
+ /// [`send`]: UnixDatagram::send
+ /// [`recv`]: UnixDatagram::recv
+ /// [`recv_from`]: UnixDatagram::recv_from
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// match sock.connect("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return Err(e)
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::connect(self.as_raw_fd(), &addr as *const _ as *const _, len))?;
+ }
+ Ok(())
+ }
+
+ /// Connects the socket to an address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixDatagram};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let bound = UnixDatagram::bind("/path/to/socket")?;
+ /// let addr = bound.local_addr()?;
+ ///
+ /// let sock = UnixDatagram::unbound()?;
+ /// match sock.connect_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return Err(e)
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> {
+ unsafe {
+ cvt(libc::connect(
+ self.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len,
+ ))?;
+ }
+ Ok(())
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixDatagram` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one side will affect the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::bind("/path/to/the/socket")?;
+ /// let sock_copy = sock.try_clone().expect("try_clone failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn try_clone(&self) -> io::Result<UnixDatagram> {
+ self.0.duplicate().map(UnixDatagram)
+ }
+
+ /// Returns the address of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::bind("/path/to/the/socket")?;
+ /// let addr = sock.local_addr().expect("Couldn't get local address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Returns the address of this socket's peer.
+ ///
+ /// The [`connect`] method will connect the socket to a peer.
+ ///
+ /// [`connect`]: UnixDatagram::connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.connect("/path/to/the/socket")?;
+ ///
+ /// let addr = sock.peer_addr().expect("Couldn't get peer address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) })
+ }
+
+ fn recv_from_flags(
+ &self,
+ buf: &mut [u8],
+ flags: libc::c_int,
+ ) -> io::Result<(usize, SocketAddr)> {
+ let mut count = 0;
+ let addr = SocketAddr::new(|addr, len| unsafe {
+ count = libc::recvfrom(
+ self.as_raw_fd(),
+ buf.as_mut_ptr() as *mut _,
+ buf.len(),
+ flags,
+ addr,
+ len,
+ );
+ if count > 0 {
+ 1
+ } else if count == 0 {
+ 0
+ } else {
+ -1
+ }
+ })?;
+
+ Ok((count as usize, addr))
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read and the address from
+ /// whence the data came.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let mut buf = vec![0; 10];
+ /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?;
+ /// println!("received {size} bytes from {sender:?}");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_flags(buf, 0)
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::bind("/path/to/the/socket")?;
+ /// let mut buf = vec![0; 10];
+ /// sock.recv(buf.as_mut_slice()).expect("recv function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ /// Receives data and ancillary data from socket.
+ ///
+ /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let mut buf1 = [1; 8];
+ /// let mut buf2 = [2; 16];
+ /// let mut buf3 = [3; 8];
+ /// let mut bufs = &mut [
+ /// IoSliceMut::new(&mut buf1),
+ /// IoSliceMut::new(&mut buf2),
+ /// IoSliceMut::new(&mut buf3),
+ /// ][..];
+ /// let mut fds = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
+ /// println!("received {size}");
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn recv_vectored_with_ancillary_from(
+ &self,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<(usize, bool, SocketAddr)> {
+ let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+ let addr = addr?;
+
+ Ok((count, truncated, addr))
+ }
+
+ /// Receives data and ancillary data from socket.
+ ///
+ /// On success, returns the number of bytes read and if the data was truncated.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let mut buf1 = [1; 8];
+ /// let mut buf2 = [2; 16];
+ /// let mut buf3 = [3; 8];
+ /// let mut bufs = &mut [
+ /// IoSliceMut::new(&mut buf1),
+ /// IoSliceMut::new(&mut buf2),
+ /// IoSliceMut::new(&mut buf3),
+ /// ][..];
+ /// let mut fds = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// println!("received {size}");
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn recv_vectored_with_ancillary(
+ &self,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<(usize, bool)> {
+ let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+ addr?;
+
+ Ok((count, truncated))
+ }
+
+ /// Sends data on the socket to the specified address.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ let count = cvt(libc::sendto(
+ self.as_raw_fd(),
+ buf.as_ptr() as *const _,
+ buf.len(),
+ MSG_NOSIGNAL,
+ &addr as *const _ as *const _,
+ len,
+ ))?;
+ Ok(count as usize)
+ }
+ }
+
+ /// Sends data on the socket to the specified [SocketAddr].
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// [SocketAddr]: crate::os::unix::net::SocketAddr
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixDatagram};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let bound = UnixDatagram::bind("/path/to/socket")?;
+ /// let addr = bound.local_addr()?;
+ ///
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> {
+ unsafe {
+ let count = cvt(libc::sendto(
+ self.as_raw_fd(),
+ buf.as_ptr() as *const _,
+ buf.len(),
+ MSG_NOSIGNAL,
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len,
+ ))?;
+ Ok(count as usize)
+ }
+ }
+
+ /// Sends data on the socket to the socket's peer.
+ ///
+ /// The peer address may be set by the `connect` method, and this method
+ /// will return an error if the socket has not already been connected.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.connect("/some/sock").expect("Couldn't connect");
+ /// sock.send(b"omelette au fromage").expect("send_to function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ /// Sends data and ancillary data on the socket to the specified address.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
+ /// let bufs = &[
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
+ /// ][..];
+ /// let fds = [0, 1, 2];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&fds[..]);
+ /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock")
+ /// .expect("send_vectored_with_ancillary_to function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
+ &self,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ path: P,
+ ) -> io::Result<usize> {
+ send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary)
+ }
+
+ /// Sends data and ancillary data on the socket.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
+ /// let bufs = &[
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
+ /// ][..];
+ /// let fds = [0, 1, 2];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&fds[..]);
+ /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)
+ /// .expect("send_vectored_with_ancillary function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn send_vectored_with_ancillary(
+ &self,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<usize> {
+ send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+ }
+
+ /// Sets the read timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
+ /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
+ /// is passed to this method.
+ ///
+ /// [`recv`]: UnixDatagram::recv
+ /// [`recv_from`]: UnixDatagram::recv_from
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_read_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_read_timeout function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+ }
+
+ /// Sets the write timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
+ /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method.
+ ///
+ /// [`send`]: UnixDatagram::send
+ /// [`send_to`]: UnixDatagram::send_to
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_read_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_read_timeout function failed");
+ /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_RCVTIMEO)
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_SNDTIMEO)
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_nonblocking(true).expect("set_nonblocking function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
+ ///
+ /// Set the socket option `SO_PASSCRED`.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_passcred(true).expect("set_passcred function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
+ self.0.set_passcred(passcred)
+ }
+
+ /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
+ /// This value can be change by [`set_passcred`].
+ ///
+ /// Get the socket option `SO_PASSCRED`.
+ ///
+ /// [`set_passcred`]: UnixDatagram::set_passcred
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn passcred(&self) -> io::Result<bool> {
+ self.0.passcred()
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// if let Ok(Some(err)) = sock.take_error() {
+ /// println!("Got error: {err:?}");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Shut down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of [`Shutdown`]).
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::net::Shutdown;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+
+ /// Receives data on the socket from the remote address to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_peek)]
+ ///
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::bind("/tmp/sock")?;
+ /// let mut buf = [0; 10];
+ /// let len = socket.peek(&mut buf).expect("peek failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_peek", issue = "76923")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
+ /// Receives a single datagram message on the socket, without removing it from the
+ /// queue. On success, returns the number of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
+ ///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_peek)]
+ ///
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::bind("/tmp/sock")?;
+ /// let mut buf = [0; 10];
+ /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_peek", issue = "76923")]
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_flags(buf, libc::MSG_PEEK)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixDatagram {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixDatagram {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
+ UnixDatagram(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixDatagram {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for UnixDatagram {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<UnixDatagram> for OwnedFd {
+ #[inline]
+ fn from(unix_datagram: UnixDatagram) -> OwnedFd {
+ unsafe { OwnedFd::from_raw_fd(unix_datagram.into_raw_fd()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for UnixDatagram {
+ #[inline]
+ fn from(owned: OwnedFd) -> Self {
+ unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
+ }
+}
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
new file mode 100644
index 000000000..7c0d53950
--- /dev/null
+++ b/library/std/src/os/unix/net/listener.rs
@@ -0,0 +1,385 @@
+use super::{sockaddr_un, SocketAddr, UnixStream};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::{fmt, io, mem};
+
+/// A structure representing a Unix domain socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// fn main() -> std::io::Result<()> {
+/// let listener = UnixListener::bind("/path/to/the/socket")?;
+///
+/// // accept connections and process them, spawning a new thread for each one
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// /* connection succeeded */
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// /* connection failed */
+/// break;
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixListener(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixListener {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixListener");
+ builder.field("fd", self.0.as_inner());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixListener {
+ /// Creates a new `UnixListener` bound to the specified socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = match UnixListener::bind("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
+ cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?;
+
+ Ok(UnixListener(inner))
+ }
+ }
+
+ /// Creates a new `UnixListener` bound to the specified [`socket address`].
+ ///
+ /// [`socket address`]: crate::os::unix::net::SocketAddr
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener1 = UnixListener::bind("path/to/socket")?;
+ /// let addr = listener1.local_addr()?;
+ ///
+ /// let listener2 = match UnixListener::bind_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(err) => {
+ /// println!("Couldn't bind: {err:?}");
+ /// return Err(err);
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ cvt(libc::bind(
+ inner.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len as _,
+ ))?;
+ cvt(libc::listen(inner.as_raw_fd(), 128))?;
+ Ok(UnixListener(inner))
+ }
+ }
+
+ /// Accepts a new incoming connection to this listener.
+ ///
+ /// This function will block the calling thread until a new Unix connection
+ /// is established. When established, the corresponding [`UnixStream`] and
+ /// the remote peer's address will be returned.
+ ///
+ /// [`UnixStream`]: crate::os::unix::net::UnixStream
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ ///
+ /// match listener.accept() {
+ /// Ok((socket, addr)) => println!("Got a client: {addr:?}"),
+ /// Err(e) => println!("accept function failed: {e:?}"),
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+ let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
+ let mut len = mem::size_of_val(&storage) as libc::socklen_t;
+ let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
+ let addr = SocketAddr::from_parts(storage, len)?;
+ Ok((UnixStream(sock), addr))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixListener` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// let listener_copy = listener.try_clone().expect("try_clone failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn try_clone(&self) -> io::Result<UnixListener> {
+ self.0.duplicate().map(UnixListener)
+ }
+
+ /// Returns the local socket address of this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// let addr = listener.local_addr().expect("Couldn't get local address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// This will result in the `accept` operation becoming nonblocking,
+ /// i.e., immediately returning from their calls. If the IO operation is
+ /// successful, `Ok` is returned and no further action is required. If the
+ /// IO operation could not be completed and needs to be retried, an error
+ /// with kind [`io::ErrorKind::WouldBlock`] is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/tmp/sock")?;
+ ///
+ /// if let Ok(Some(err)) = listener.take_error() {
+ /// println!("Got error: {err:?}");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns `None`.
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Returns an iterator over incoming connections.
+ ///
+ /// The iterator will never return [`None`] and will also not yield the
+ /// peer's [`SocketAddr`] structure.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::os::unix::net::{UnixStream, UnixListener};
+ ///
+ /// fn handle_client(stream: UnixStream) {
+ /// // ...
+ /// }
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ ///
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(stream) => {
+ /// thread::spawn(|| handle_client(stream));
+ /// }
+ /// Err(err) => {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn incoming(&self) -> Incoming<'_> {
+ Incoming { listener: self }
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixListener {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixListener {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+ UnixListener(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixListener {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for UnixListener {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for UnixListener {
+ #[inline]
+ fn from(fd: OwnedFd) -> UnixListener {
+ UnixListener(Socket::from_inner(FromInner::from_inner(fd)))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<UnixListener> for OwnedFd {
+ #[inline]
+ fn from(listener: UnixListener) -> OwnedFd {
+ listener.0.into_inner().into_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> IntoIterator for &'a UnixListener {
+ type Item = io::Result<UnixStream>;
+ type IntoIter = Incoming<'a>;
+
+ fn into_iter(self) -> Incoming<'a> {
+ self.incoming()
+ }
+}
+
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// fn main() -> std::io::Result<()> {
+/// let listener = UnixListener::bind("/path/to/the/socket")?;
+///
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// break;
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+#[derive(Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct Incoming<'a> {
+ listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> Iterator for Incoming<'a> {
+ type Item = io::Result<UnixStream>;
+
+ fn next(&mut self) -> Option<io::Result<UnixStream>> {
+ Some(self.listener.accept().map(|s| s.0))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (usize::MAX, None)
+ }
+}
diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs
new file mode 100644
index 000000000..6da3e350b
--- /dev/null
+++ b/library/std/src/os/unix/net/mod.rs
@@ -0,0 +1,26 @@
+//! Unix-specific networking functionality.
+
+#![allow(irrefutable_let_patterns)]
+#![stable(feature = "unix_socket", since = "1.10.0")]
+
+mod addr;
+#[doc(cfg(any(target_os = "android", target_os = "linux")))]
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+mod ancillary;
+mod datagram;
+mod listener;
+mod stream;
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::addr::*;
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub use self::ancillary::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::datagram::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::listener::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::stream::*;
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
new file mode 100644
index 000000000..cc3a88587
--- /dev/null
+++ b/library/std/src/os/unix/net/stream.rs
@@ -0,0 +1,711 @@
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
+use super::{sockaddr_un, SocketAddr};
+use crate::fmt;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::Shutdown;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+use crate::os::unix::ucred;
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner};
+use crate::time::Duration;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+pub use ucred::UCred;
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut stream = UnixStream::connect("/path/to/my/socket")?;
+/// stream.write_all(b"hello world")?;
+/// let mut response = String::new();
+/// stream.read_to_string(&mut response)?;
+/// println!("{response}");
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixStream(pub(super) Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixStream {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixStream");
+ builder.field("fd", self.0.as_inner());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ if let Ok(addr) = self.peer_addr() {
+ builder.field("peer", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixStream {
+ /// Connects to the socket named by `path`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = match UnixStream::connect("/tmp/sock") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::connect(inner.as_raw_fd(), &addr as *const _ as *const _, len))?;
+ Ok(UnixStream(inner))
+ }
+ }
+
+ /// Connects to the socket specified by [`address`].
+ ///
+ /// [`address`]: crate::os::unix::net::SocketAddr
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener, UnixStream};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// let addr = listener.local_addr()?;
+ ///
+ /// let sock = match UnixStream::connect_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return Err(e)
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ````
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ cvt(libc::connect(
+ inner.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len,
+ ))?;
+ Ok(UnixStream(inner))
+ }
+ }
+
+ /// Creates an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixStream`s which are connected to each other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let (sock1, sock2) = match UnixStream::pair() {
+ /// Ok((sock1, sock2)) => (sock1, sock2),
+ /// Err(e) => {
+ /// println!("Couldn't create a pair of sockets: {e:?}");
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+ let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ Ok((UnixStream(i1), UnixStream(i2)))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixStream` is a reference to the same stream that this
+ /// object references. Both handles will read and write the same stream of
+ /// data, and options set on one stream will be propagated to the other
+ /// stream.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn try_clone(&self) -> io::Result<UnixStream> {
+ self.0.duplicate().map(UnixStream)
+ }
+
+ /// Returns the socket address of the local half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Returns the socket address of the remote half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Gets the peer credentials for this Unix domain socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(peer_credentials_unix_socket)]
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ pub fn peer_cred(&self) -> io::Result<UCred> {
+ ucred::peer_cred(self)
+ }
+
+ /// Sets the read timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`read`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method.
+ ///
+ /// [`read`]: io::Read::read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+ }
+
+ /// Sets the write timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`write`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// [`read`]: io::Read::read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("Couldn't set write timeout");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UdpSocket::bind("127.0.0.1:34254")?;
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_RCVTIMEO)
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("Couldn't set write timeout");
+ /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_SNDTIMEO)
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
+ ///
+ /// Set the socket option `SO_PASSCRED`.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_passcred(true).expect("Couldn't set passcred");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
+ self.0.set_passcred(passcred)
+ }
+
+ /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
+ /// This value can be change by [`set_passcred`].
+ ///
+ /// Get the socket option `SO_PASSCRED`.
+ ///
+ /// [`set_passcred`]: UnixStream::set_passcred
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn passcred(&self) -> io::Result<bool> {
+ self.0.passcred()
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// if let Ok(Some(err)) = socket.take_error() {
+ /// println!("Got error: {err:?}");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns `None`.
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of [`Shutdown`]).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::net::Shutdown;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+
+ /// Receives data on the socket from the remote address to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_peek)]
+ ///
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let mut buf = [0; 10];
+ /// let len = socket.peek(&mut buf).expect("peek failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_peek", issue = "76923")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
+ /// Receives data and ancillary data from socket.
+ ///
+ /// On success, returns the number of bytes read.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let mut buf1 = [1; 8];
+ /// let mut buf2 = [2; 16];
+ /// let mut buf3 = [3; 8];
+ /// let mut bufs = &mut [
+ /// IoSliceMut::new(&mut buf1),
+ /// IoSliceMut::new(&mut buf2),
+ /// IoSliceMut::new(&mut buf3),
+ /// ][..];
+ /// let mut fds = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// println!("received {size}");
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn recv_vectored_with_ancillary(
+ &self,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<usize> {
+ let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+
+ Ok(count)
+ }
+
+ /// Sends data and ancillary data on the socket.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary};
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
+ /// let bufs = &[
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
+ /// ][..];
+ /// let fds = [0, 1, 2];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&fds[..]);
+ /// socket.send_vectored_with_ancillary(bufs, &mut ancillary)
+ /// .expect("send_vectored_with_ancillary function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn send_vectored_with_ancillary(
+ &self,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<usize> {
+ send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Read for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ io::Read::read(&mut &*self, buf)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ io::Read::read_vectored(&mut &*self, bufs)
+ }
+
+ #[inline]
+ fn is_read_vectored(&self) -> bool {
+ io::Read::is_read_vectored(&&*self)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Read for &'a UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.0.read_vectored(bufs)
+ }
+
+ #[inline]
+ fn is_read_vectored(&self) -> bool {
+ self.0.is_read_vectored()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Write for UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ io::Write::write(&mut &*self, buf)
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ io::Write::write_vectored(&mut &*self, bufs)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ io::Write::is_write_vectored(&&*self)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ io::Write::flush(&mut &*self)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Write for &'a UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.0.write_vectored(bufs)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ self.0.is_write_vectored()
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixStream {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixStream {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+ UnixStream(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixStream {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for UnixStream {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<UnixStream> for OwnedFd {
+ #[inline]
+ fn from(unix_stream: UnixStream) -> OwnedFd {
+ unsafe { OwnedFd::from_raw_fd(unix_stream.into_raw_fd()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for UnixStream {
+ #[inline]
+ fn from(owned: OwnedFd) -> Self {
+ unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
+ }
+}
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
new file mode 100644
index 000000000..e4499f9b6
--- /dev/null
+++ b/library/std/src/os/unix/net/tests.rs
@@ -0,0 +1,753 @@
+use super::*;
+use crate::io::prelude::*;
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use crate::os::unix::io::AsRawFd;
+use crate::sys_common::io::test::tmpdir;
+use crate::thread;
+use crate::time::Duration;
+
+macro_rules! or_panic {
+ ($e:expr) => {
+ match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{e}"),
+ }
+ };
+}
+
+#[test]
+fn basic() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ let mut buf = [0; 5];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(stream.write_all(msg2));
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname());
+ or_panic!(stream.write_all(msg1));
+ let mut buf = vec![];
+ or_panic!(stream.read_to_end(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(stream);
+
+ thread.join().unwrap();
+}
+
+#[test]
+fn vectored() {
+ let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+
+ let len = or_panic!(s1.write_vectored(&[
+ IoSlice::new(b"hello"),
+ IoSlice::new(b" "),
+ IoSlice::new(b"world!")
+ ],));
+ assert_eq!(len, 12);
+
+ let mut buf1 = [0; 6];
+ let mut buf2 = [0; 7];
+ let len =
+ or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],));
+ assert_eq!(len, 12);
+ assert_eq!(&buf1, b"hello ");
+ assert_eq!(&buf2, b"world!\0");
+}
+
+#[test]
+fn pair() {
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+ let thread = thread::spawn(move || {
+ // s1 must be moved in or the test will hang!
+ let mut buf = [0; 5];
+ or_panic!(s1.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(s1.write_all(msg2));
+ });
+
+ or_panic!(s2.write_all(msg1));
+ let mut buf = vec![];
+ or_panic!(s2.read_to_end(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(s2);
+
+ thread.join().unwrap();
+}
+
+#[test]
+fn try_clone() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+ let msg1 = b"hello";
+ let msg2 = b"world";
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ or_panic!(stream.write_all(msg1));
+ or_panic!(stream.write_all(msg2));
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ let mut stream2 = or_panic!(stream.try_clone());
+
+ let mut buf = [0; 5];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(stream2.read(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+
+ thread.join().unwrap();
+}
+
+#[test]
+fn iter() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ for stream in listener.incoming().take(2) {
+ let mut stream = or_panic!(stream);
+ let mut buf = [0];
+ or_panic!(stream.read(&mut buf));
+ }
+ });
+
+ for _ in 0..2 {
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.write_all(&[0]));
+ }
+
+ thread.join().unwrap();
+}
+
+#[test]
+fn long_path() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join(
+ "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
+ sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf",
+ );
+ match UnixStream::connect(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {e}"),
+ Ok(_) => panic!("unexpected success"),
+ }
+
+ match UnixListener::bind(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {e}"),
+ Ok(_) => panic!("unexpected success"),
+ }
+
+ match UnixDatagram::bind(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {e}"),
+ Ok(_) => panic!("unexpected success"),
+ }
+}
+
+#[test]
+fn timeouts() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let stream = or_panic!(UnixStream::connect(&socket_path));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, or_panic!(stream.read_timeout()));
+
+ or_panic!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
+
+ assert_eq!(None, or_panic!(stream.write_timeout()));
+
+ or_panic!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
+
+ or_panic!(stream.set_read_timeout(None));
+ assert_eq!(None, or_panic!(stream.read_timeout()));
+
+ or_panic!(stream.set_write_timeout(None));
+ assert_eq!(None, or_panic!(stream.write_timeout()));
+}
+
+#[test]
+fn test_read_timeout() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+ let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+ assert!(
+ kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}",
+ kind
+ );
+}
+
+#[test]
+fn test_read_with_timeout() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut other_end = or_panic!(listener.accept()).0;
+ or_panic!(other_end.write_all(b"hello world"));
+
+ let mut buf = [0; 11];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+ assert!(
+ kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}",
+ kind
+ );
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_unix_stream_timeout_zero_duration() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let stream = or_panic!(UnixStream::connect(&socket_path));
+
+ let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ drop(listener);
+}
+
+#[test]
+fn test_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::bind(&path2));
+
+ let msg = b"hello world";
+ or_panic!(sock1.send_to(msg, &path2));
+ let mut buf = [0; 11];
+ or_panic!(sock2.recv_from(&mut buf));
+ assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_unnamed_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+
+ let msg = b"hello world";
+ or_panic!(sock2.send_to(msg, &path1));
+ let mut buf = [0; 11];
+ let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
+ assert_eq!(usize, 11);
+ assert!(addr.is_unnamed());
+ assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_unix_datagram_connect_to_recv_addr() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::bind(&path2));
+
+ let msg = b"hello world";
+ let sock1_addr = or_panic!(sock1.local_addr());
+ or_panic!(sock2.send_to_addr(msg, &sock1_addr));
+ let mut buf = [0; 11];
+ let (_, addr) = or_panic!(sock1.recv_from(&mut buf));
+
+ let new_msg = b"hello back";
+ let mut new_buf = [0; 10];
+ or_panic!(sock2.connect_addr(&addr));
+ or_panic!(sock2.send(new_msg)); // set by connect_addr
+ let usize = or_panic!(sock2.recv(&mut new_buf));
+ assert_eq!(usize, 10);
+ assert_eq!(new_msg, &new_buf[..]);
+}
+
+#[test]
+fn test_connect_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+ let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+ let sock = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock.connect(&path1));
+
+ // Check send()
+ let msg = b"hello there";
+ or_panic!(sock.send(msg));
+ let mut buf = [0; 11];
+ let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
+ assert_eq!(usize, 11);
+ assert!(addr.is_unnamed());
+ assert_eq!(msg, &buf[..]);
+
+ // Changing default socket works too
+ or_panic!(sock.connect(&path2));
+ or_panic!(sock.send(msg));
+ or_panic!(bsock2.recv_from(&mut buf));
+}
+
+#[test]
+fn test_unix_datagram_recv() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock2.connect(&path1));
+
+ let msg = b"hello world";
+ or_panic!(sock2.send(msg));
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.recv(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn datagram_pair() {
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let (s1, s2) = or_panic!(UnixDatagram::pair());
+ let thread = thread::spawn(move || {
+ // s1 must be moved in or the test will hang!
+ let mut buf = [0; 5];
+ or_panic!(s1.recv(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(s1.send(msg2));
+ });
+
+ or_panic!(s2.send(msg1));
+ let mut buf = [0; 6];
+ or_panic!(s2.recv(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(s2);
+
+ thread.join().unwrap();
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_unix_datagram_timeout_zero_duration() {
+ let dir = tmpdir();
+ let path = dir.path().join("sock");
+
+ let datagram = or_panic!(UnixDatagram::bind(&path));
+
+ let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+}
+
+#[test]
+fn abstract_namespace_not_allowed_connect() {
+ assert!(UnixStream::connect("\0asdf").is_err());
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_stream_connect() {
+ let msg1 = b"hello";
+ let msg2 = b"world";
+
+ let socket_addr = or_panic!(SocketAddr::from_abstract_namespace(b"namespace"));
+ let listener = or_panic!(UnixListener::bind_addr(&socket_addr));
+
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ let mut buf = [0; 5];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(stream.write_all(msg2));
+ });
+
+ let mut stream = or_panic!(UnixStream::connect_addr(&socket_addr));
+
+ let peer = or_panic!(stream.peer_addr());
+ assert_eq!(peer.as_abstract_namespace().unwrap(), b"namespace");
+
+ or_panic!(stream.write_all(msg1));
+ let mut buf = vec![];
+ or_panic!(stream.read_to_end(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(stream);
+
+ thread.join().unwrap();
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_stream_iter() {
+ let addr = or_panic!(SocketAddr::from_abstract_namespace(b"hidden"));
+ let listener = or_panic!(UnixListener::bind_addr(&addr));
+
+ let thread = thread::spawn(move || {
+ for stream in listener.incoming().take(2) {
+ let mut stream = or_panic!(stream);
+ let mut buf = [0];
+ or_panic!(stream.read(&mut buf));
+ }
+ });
+
+ for _ in 0..2 {
+ let mut stream = or_panic!(UnixStream::connect_addr(&addr));
+ or_panic!(stream.write_all(&[0]));
+ }
+
+ thread.join().unwrap();
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_datagram_bind_send_to_addr() {
+ let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns1"));
+ let sock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
+
+ let local = or_panic!(sock1.local_addr());
+ assert_eq!(local.as_abstract_namespace().unwrap(), b"ns1");
+
+ let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns2"));
+ let sock2 = or_panic!(UnixDatagram::bind_addr(&addr2));
+
+ let msg = b"hello world";
+ or_panic!(sock1.send_to_addr(msg, &addr2));
+ let mut buf = [0; 11];
+ let (len, addr) = or_panic!(sock2.recv_from(&mut buf));
+ assert_eq!(msg, &buf[..]);
+ assert_eq!(len, 11);
+ assert_eq!(addr.as_abstract_namespace().unwrap(), b"ns1");
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_datagram_connect_addr() {
+ let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns3"));
+ let bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
+
+ let sock = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock.connect_addr(&addr1));
+
+ let msg = b"hello world";
+ or_panic!(sock.send(msg));
+ let mut buf = [0; 11];
+ let (len, addr) = or_panic!(bsock1.recv_from(&mut buf));
+ assert_eq!(len, 11);
+ assert_eq!(addr.is_unnamed(), true);
+ assert_eq!(msg, &buf[..]);
+
+ let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns4"));
+ let bsock2 = or_panic!(UnixDatagram::bind_addr(&addr2));
+
+ or_panic!(sock.connect_addr(&addr2));
+ or_panic!(sock.send(msg));
+ or_panic!(bsock2.recv_from(&mut buf));
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_namespace_too_long() {
+ match SocketAddr::from_abstract_namespace(
+ b"abcdefghijklmnopqrstuvwxyzabcdefghijklmn\
+ opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi\
+ jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
+ ) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {e}"),
+ Ok(_) => panic!("unexpected success"),
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_namespace_no_pathname_and_not_unnamed() {
+ let namespace = b"local";
+ let addr = or_panic!(SocketAddr::from_abstract_namespace(&namespace[..]));
+ assert_eq!(addr.as_pathname(), None);
+ assert_eq!(addr.as_abstract_namespace(), Some(&namespace[..]));
+ assert_eq!(addr.is_unnamed(), false);
+}
+
+#[test]
+fn test_unix_stream_peek() {
+ let (txdone, rxdone) = crate::sync::mpsc::channel();
+
+ let dir = tmpdir();
+ let path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ or_panic!(stream.write_all(&[1, 3, 3, 7]));
+ or_panic!(rxdone.recv());
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&path));
+ let mut buf = [0; 10];
+ for _ in 0..2 {
+ assert_eq!(or_panic!(stream.peek(&mut buf)), 4);
+ }
+ assert_eq!(or_panic!(stream.read(&mut buf)), 4);
+
+ or_panic!(stream.set_nonblocking(true));
+ match stream.peek(&mut buf) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ Err(e) => panic!("unexpected error: {e}"),
+ }
+
+ or_panic!(txdone.send(()));
+ thread.join().unwrap();
+}
+
+#[test]
+fn test_unix_datagram_peek() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock2.connect(&path1));
+
+ let msg = b"hello world";
+ or_panic!(sock2.send(msg));
+ for _ in 0..2 {
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.peek(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+ }
+
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.recv(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_unix_datagram_peek_from() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock2.connect(&path1));
+
+ let msg = b"hello world";
+ or_panic!(sock2.send(msg));
+ for _ in 0..2 {
+ let mut buf = [0; 11];
+ let (size, _) = or_panic!(sock1.peek_from(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+ }
+
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.recv(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_send_vectored_fds_unix_stream() {
+ let (s1, s2) = or_panic!(UnixStream::pair());
+
+ let buf1 = [1; 8];
+ let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+ let mut ancillary1_buffer = [0; 128];
+ let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+ assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..]));
+
+ let usize = or_panic!(s1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
+ assert_eq!(usize, 8);
+
+ let mut buf2 = [0; 8];
+ let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+ let mut ancillary2_buffer = [0; 128];
+ let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+ let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+ assert_eq!(usize, 8);
+ assert_eq!(buf1, buf2);
+
+ let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+ assert_eq!(ancillary_data_vec.len(), 1);
+ if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
+ let fd_vec = Vec::from_iter(scm_rights);
+ assert_eq!(fd_vec.len(), 1);
+ unsafe {
+ libc::close(fd_vec[0]);
+ }
+ } else {
+ unreachable!("must be ScmRights");
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux",))]
+#[test]
+fn test_send_vectored_with_ancillary_to_unix_datagram() {
+ fn getpid() -> libc::pid_t {
+ unsafe { libc::getpid() }
+ }
+
+ fn getuid() -> libc::uid_t {
+ unsafe { libc::getuid() }
+ }
+
+ fn getgid() -> libc::gid_t {
+ unsafe { libc::getgid() }
+ }
+
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+ let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+
+ or_panic!(bsock2.set_passcred(true));
+
+ let buf1 = [1; 8];
+ let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+ let mut ancillary1_buffer = [0; 128];
+ let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+ let mut cred1 = SocketCred::new();
+ cred1.set_pid(getpid());
+ cred1.set_uid(getuid());
+ cred1.set_gid(getgid());
+ assert!(ancillary1.add_creds(&[cred1.clone()][..]));
+
+ let usize =
+ or_panic!(bsock1.send_vectored_with_ancillary_to(&bufs_send, &mut ancillary1, &path2));
+ assert_eq!(usize, 8);
+
+ let mut buf2 = [0; 8];
+ let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+ let mut ancillary2_buffer = [0; 128];
+ let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+ let (usize, truncated, _addr) =
+ or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2));
+ assert_eq!(ancillary2.truncated(), false);
+ assert_eq!(usize, 8);
+ assert_eq!(truncated, false);
+ assert_eq!(buf1, buf2);
+
+ let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+ assert_eq!(ancillary_data_vec.len(), 1);
+ if let AncillaryData::ScmCredentials(scm_credentials) =
+ ancillary_data_vec.pop().unwrap().unwrap()
+ {
+ let cred_vec = Vec::from_iter(scm_credentials);
+ assert_eq!(cred_vec.len(), 1);
+ assert_eq!(cred1.get_pid(), cred_vec[0].get_pid());
+ assert_eq!(cred1.get_uid(), cred_vec[0].get_uid());
+ assert_eq!(cred1.get_gid(), cred_vec[0].get_gid());
+ } else {
+ unreachable!("must be ScmCredentials");
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_send_vectored_with_ancillary_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+ let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+
+ let buf1 = [1; 8];
+ let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+ let mut ancillary1_buffer = [0; 128];
+ let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+ assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..]));
+
+ or_panic!(bsock1.connect(&path2));
+ let usize = or_panic!(bsock1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
+ assert_eq!(usize, 8);
+
+ let mut buf2 = [0; 8];
+ let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+ let mut ancillary2_buffer = [0; 128];
+ let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+ let (usize, truncated) =
+ or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+ assert_eq!(usize, 8);
+ assert_eq!(truncated, false);
+ assert_eq!(buf1, buf2);
+
+ let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+ assert_eq!(ancillary_data_vec.len(), 1);
+ if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
+ let fd_vec = Vec::from_iter(scm_rights);
+ assert_eq!(fd_vec.len(), 1);
+ unsafe {
+ libc::close(fd_vec[0]);
+ }
+ } else {
+ unreachable!("must be ScmRights");
+ }
+}
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
new file mode 100644
index 000000000..09b2bfe39
--- /dev/null
+++ b/library/std/src/os/unix/process.rs
@@ -0,0 +1,466 @@
+//! Unix-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::ffi::OsStr;
+use crate::io;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::process;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
+type UserId = u32;
+#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
+type GroupId = u32;
+
+#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
+type UserId = u16;
+#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
+type GroupId = u16;
+
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt: Sealed {
+ /// Sets the child process's user ID. This translates to a
+ /// `setuid` call in the child process. Failure in the `setuid`
+ /// call will cause the spawn to fail.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn uid(&mut self, id: UserId) -> &mut process::Command;
+
+ /// Similar to `uid`, but sets the group ID of the child process. This has
+ /// the same semantics as the `uid` field.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn gid(&mut self, id: GroupId) -> &mut process::Command;
+
+ /// Sets the supplementary group IDs for the calling process. Translates to
+ /// a `setgroups` call in the child process.
+ #[unstable(feature = "setgroups", issue = "90747")]
+ fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// The closure is allowed to return an I/O error whose OS error code will
+ /// be communicated back to the parent and returned as an error from when
+ /// the spawn was requested.
+ ///
+ /// Multiple closures can be registered and they will be called in order of
+ /// their registration. If a closure returns `Err` then no further closures
+ /// will be called and the spawn operation will immediately return with a
+ /// failure.
+ ///
+ /// # Notes and Safety
+ ///
+ /// This closure will be run in the context of the child process after a
+ /// `fork`. This primarily means that any modifications made to memory on
+ /// behalf of this closure will **not** be visible to the parent process.
+ /// This is often a very constrained environment where normal operations
+ /// like `malloc`, accessing environment variables through [`std::env`]
+ /// or acquiring a mutex are not guaranteed to work (due to
+ /// other threads perhaps still running when the `fork` was run).
+ ///
+ /// For further details refer to the [POSIX fork() specification]
+ /// and the equivalent documentation for any targeted
+ /// platform, especially the requirements around *async-signal-safety*.
+ ///
+ /// This also means that all resources such as file descriptors and
+ /// memory-mapped regions got duplicated. It is your responsibility to make
+ /// sure that the closure does not violate library invariants by making
+ /// invalid use of these duplicates.
+ ///
+ /// Panicking in the closure is safe only if all the format arguments for the
+ /// panic message can be safely formatted; this is because although
+ /// `Command` calls [`std::panic::always_abort`](crate::panic::always_abort)
+ /// before calling the pre_exec hook, panic will still try to format the
+ /// panic message.
+ ///
+ /// When this closure is run, aspects such as the stdio file descriptors and
+ /// working directory have successfully been changed, so output to these
+ /// locations might not appear where intended.
+ ///
+ /// [POSIX fork() specification]:
+ /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
+ /// [`std::env`]: mod@crate::env
+ #[stable(feature = "process_pre_exec", since = "1.34.0")]
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where
+ F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// This method is stable and usable, but it should be unsafe. To fix
+ /// that, it got deprecated in favor of the unsafe [`pre_exec`].
+ ///
+ /// [`pre_exec`]: CommandExt::pre_exec
+ #[stable(feature = "process_exec", since = "1.15.0")]
+ #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")]
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where
+ F: FnMut() -> io::Result<()> + Send + Sync + 'static,
+ {
+ unsafe { self.pre_exec(f) }
+ }
+
+ /// Performs all the required setup by this `Command`, followed by calling
+ /// the `execvp` syscall.
+ ///
+ /// On success this function will not return, and otherwise it will return
+ /// an error indicating why the exec (or another part of the setup of the
+ /// `Command`) failed.
+ ///
+ /// `exec` not returning has the same implications as calling
+ /// [`process::exit`] – no destructors on the current stack or any other
+ /// thread’s stack will be run. Therefore, it is recommended to only call
+ /// `exec` at a point where it is fine to not run any destructors. Note,
+ /// that the `execvp` syscall independently guarantees that all memory is
+ /// freed and all file descriptors with the `CLOEXEC` option (set by default
+ /// on all file descriptors opened by the standard library) are closed.
+ ///
+ /// This function, unlike `spawn`, will **not** `fork` the process to create
+ /// a new child. Like spawn, however, the default behavior for the stdio
+ /// descriptors will be to inherited from the current process.
+ ///
+ /// # Notes
+ ///
+ /// The process may be in a "broken state" if this function returns in
+ /// error. For example the working directory, environment variables, signal
+ /// handling settings, various user/group information, or aspects of stdio
+ /// file descriptors may have changed. If a "transactional spawn" is
+ /// required to gracefully handle errors it is recommended to use the
+ /// cross-platform `spawn` instead.
+ #[stable(feature = "process_exec2", since = "1.9.0")]
+ fn exec(&mut self) -> io::Error;
+
+ /// Set executable argument
+ ///
+ /// Set the first process argument, `argv[0]`, to something other than the
+ /// default executable path.
+ #[stable(feature = "process_set_argv0", since = "1.45.0")]
+ fn arg0<S>(&mut self, arg: S) -> &mut process::Command
+ where
+ S: AsRef<OsStr>;
+
+ /// Sets the process group ID (PGID) of the child process. Equivalent to a
+ /// `setpgid` call in the child process, but may be more efficient.
+ ///
+ /// Process groups determine which processes receive signals.
+ ///
+ /// # Examples
+ ///
+ /// Pressing Ctrl-C in a terminal will send SIGINT to all processes in
+ /// the current foreground process group. By spawning the `sleep`
+ /// subprocess in a new process group, it will not receive SIGINT from the
+ /// terminal.
+ ///
+ /// The parent process could install a signal handler and manage the
+ /// subprocess on its own terms.
+ ///
+ /// A process group ID of 0 will use the process ID as the PGID.
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ /// use std::os::unix::process::CommandExt;
+ ///
+ /// Command::new("sleep")
+ /// .arg("10")
+ /// .process_group(0)
+ /// .spawn()?
+ /// .wait()?;
+ /// #
+ /// # Ok::<_, Box<dyn std::error::Error>>(())
+ /// ```
+ #[stable(feature = "process_set_process_group", since = "1.64.0")]
+ fn process_group(&mut self, pgroup: i32) -> &mut process::Command;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+ fn uid(&mut self, id: UserId) -> &mut process::Command {
+ self.as_inner_mut().uid(id);
+ self
+ }
+
+ fn gid(&mut self, id: GroupId) -> &mut process::Command {
+ self.as_inner_mut().gid(id);
+ self
+ }
+
+ fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command {
+ self.as_inner_mut().groups(groups);
+ self
+ }
+
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where
+ F: FnMut() -> io::Result<()> + Send + Sync + 'static,
+ {
+ self.as_inner_mut().pre_exec(Box::new(f));
+ self
+ }
+
+ fn exec(&mut self) -> io::Error {
+ // NOTE: This may *not* be safe to call after `libc::fork`, because it
+ // may allocate. That may be worth fixing at some point in the future.
+ self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+ }
+
+ fn arg0<S>(&mut self, arg: S) -> &mut process::Command
+ where
+ S: AsRef<OsStr>,
+ {
+ self.as_inner_mut().set_arg_0(arg.as_ref());
+ self
+ }
+
+ fn process_group(&mut self, pgroup: i32) -> &mut process::Command {
+ self.as_inner_mut().pgroup(pgroup);
+ self
+ }
+}
+
+/// Unix-specific extensions to [`process::ExitStatus`] and
+/// [`ExitStatusError`](process::ExitStatusError).
+///
+/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
+/// passed to the `_exit` system call or returned by
+/// [`ExitStatus::code()`](crate::process::ExitStatus::code). It represents **any wait status**
+/// as returned by one of the `wait` family of system
+/// calls.
+///
+/// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also
+/// represent other kinds of process event.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt: Sealed {
+ /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status
+ /// value from `wait`
+ ///
+ /// The value should be a **wait status, not an exit status**.
+ ///
+ /// # Panics
+ ///
+ /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`.
+ ///
+ /// Making an `ExitStatus` always succeeds and never panics.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: i32) -> Self;
+
+ /// If the process was terminated by a signal, returns that signal.
+ ///
+ /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn signal(&self) -> Option<i32>;
+
+ /// If the process was terminated by a signal, says whether it dumped core.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn core_dumped(&self) -> bool;
+
+ /// If the process was stopped by a signal, returns that signal.
+ ///
+ /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from
+ /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn stopped_signal(&self) -> Option<i32>;
+
+ /// Whether the process was continued from a stopped status.
+ ///
+ /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call
+ /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn continued(&self) -> bool;
+
+ /// Returns the underlying raw `wait` status.
+ ///
+ /// The returned integer is a **wait status, not an exit status**.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn into_raw(self) -> i32;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: i32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+
+ fn signal(&self) -> Option<i32> {
+ self.as_inner().signal()
+ }
+
+ fn core_dumped(&self) -> bool {
+ self.as_inner().core_dumped()
+ }
+
+ fn stopped_signal(&self) -> Option<i32> {
+ self.as_inner().stopped_signal()
+ }
+
+ fn continued(&self) -> bool {
+ self.as_inner().continued()
+ }
+
+ fn into_raw(self) -> i32 {
+ self.as_inner().into_raw().into()
+ }
+}
+
+#[unstable(feature = "exit_status_error", issue = "84908")]
+impl ExitStatusExt for process::ExitStatusError {
+ fn from_raw(raw: i32) -> Self {
+ process::ExitStatus::from_raw(raw)
+ .exit_ok()
+ .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
+ }
+
+ fn signal(&self) -> Option<i32> {
+ self.into_status().signal()
+ }
+
+ fn core_dumped(&self) -> bool {
+ self.into_status().core_dumped()
+ }
+
+ fn stopped_signal(&self) -> Option<i32> {
+ self.into_status().stopped_signal()
+ }
+
+ fn continued(&self) -> bool {
+ self.into_status().continued()
+ }
+
+ fn into_raw(self) -> i32 {
+ self.into_status().into_raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::from_raw_fd(fd);
+ let io = sys::process::Stdio::Fd(fd);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for process::Stdio {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let io = sys::process::Stdio::Fd(fd);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStdin {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdin> for OwnedFd {
+ #[inline]
+ fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
+ child_stdin.into_inner().into_inner().into_inner()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStdout {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdout> for OwnedFd {
+ #[inline]
+ fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
+ child_stdout.into_inner().into_inner().into_inner()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStderr {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStderr> for OwnedFd {
+ #[inline]
+ fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
+ child_stderr.into_inner().into_inner().into_inner()
+ }
+}
+
+/// Returns the OS-assigned process identifier associated with this process's parent.
+#[must_use]
+#[stable(feature = "unix_ppid", since = "1.27.0")]
+pub fn parent_id() -> u32 {
+ crate::sys::os::getppid()
+}
diff --git a/library/std/src/os/unix/raw.rs b/library/std/src/os/unix/raw.rs
new file mode 100644
index 000000000..fe761627b
--- /dev/null
+++ b/library/std/src/os/unix/raw.rs
@@ -0,0 +1,33 @@
+//! Unix-specific primitives available on all unix platforms.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type uid_t = u32;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type gid_t = u32;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type pid_t = i32;
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use super::platform::raw::pthread_t;
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use super::platform::raw::{blkcnt_t, time_t};
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use super::platform::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t};
diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs
new file mode 100644
index 000000000..03dcc3a4f
--- /dev/null
+++ b/library/std/src/os/unix/thread.rs
@@ -0,0 +1,41 @@
+//! Unix-specific extensions to primitives in the [`std::thread`] module.
+//!
+//! [`std::thread`]: crate::thread
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+#[allow(deprecated)]
+use crate::os::unix::raw::pthread_t;
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread::JoinHandle;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+#[allow(deprecated)]
+pub type RawPthread = pthread_t;
+
+/// Unix-specific extensions to [`JoinHandle`].
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+pub trait JoinHandleExt {
+ /// Extracts the raw pthread_t without taking ownership
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn as_pthread_t(&self) -> RawPthread;
+
+ /// Consumes the thread, returning the raw pthread_t
+ ///
+ /// This function **transfers ownership** of the underlying pthread_t to
+ /// the caller. Callers are then the unique owners of the pthread_t and
+ /// must either detach or join the pthread_t once it's no longer needed.
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn into_pthread_t(self) -> RawPthread;
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> JoinHandleExt for JoinHandle<T> {
+ fn as_pthread_t(&self) -> RawPthread {
+ self.as_inner().id() as RawPthread
+ }
+
+ fn into_pthread_t(self) -> RawPthread {
+ self.into_inner().into_id() as RawPthread
+ }
+}
diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs
new file mode 100644
index 000000000..ae4faf27b
--- /dev/null
+++ b/library/std/src/os/unix/ucred.rs
@@ -0,0 +1,136 @@
+//! Unix peer credentials.
+
+// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
+// GitHub.
+//
+// For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
+// Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
+
+use libc::{gid_t, pid_t, uid_t};
+
+/// Credentials for a UNIX process for credentials passing.
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct UCred {
+ /// The UID part of the peer credential. This is the effective UID of the process at the domain
+ /// socket's endpoint.
+ pub uid: uid_t,
+ /// The GID part of the peer credential. This is the effective GID of the process at the domain
+ /// socket's endpoint.
+ pub gid: gid_t,
+ /// The PID part of the peer credential. This field is optional because the PID part of the
+ /// peer credentials is not supported on every platform. On platforms where the mechanism to
+ /// discover the PID exists, this field will be populated to the PID of the process at the
+ /// domain socket's endpoint. Otherwise, it will be set to None.
+ pub pid: Option<pid_t>,
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::impl_linux::peer_cred;
+
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd"
+))]
+pub use self::impl_bsd::peer_cred;
+
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+pub use self::impl_mac::peer_cred;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub mod impl_linux {
+ use super::UCred;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+ use crate::{io, mem};
+ use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let ucred_size = mem::size_of::<ucred>();
+
+ // Trivial sanity checks.
+ assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
+ assert!(ucred_size <= u32::MAX as usize);
+
+ let mut ucred_size = ucred_size as socklen_t;
+ let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
+
+ unsafe {
+ let ret = getsockopt(
+ socket.as_raw_fd(),
+ SOL_SOCKET,
+ SO_PEERCRED,
+ &mut ucred as *mut ucred as *mut c_void,
+ &mut ucred_size,
+ );
+
+ if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
+ Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+}
+
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd"
+))]
+pub mod impl_bsd {
+ use super::UCred;
+ use crate::io;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let mut cred = UCred { uid: 1, gid: 1, pid: None };
+ unsafe {
+ let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+ if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
+ }
+ }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+pub mod impl_mac {
+ use super::UCred;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+ use crate::{io, mem};
+ use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let mut cred = UCred { uid: 1, gid: 1, pid: None };
+ unsafe {
+ let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+ if ret != 0 {
+ return Err(io::Error::last_os_error());
+ }
+
+ let mut pid: pid_t = 1;
+ let mut pid_size = mem::size_of::<pid_t>() as socklen_t;
+
+ let ret = getsockopt(
+ socket.as_raw_fd(),
+ SOL_LOCAL,
+ LOCAL_PEERPID,
+ &mut pid as *mut pid_t as *mut c_void,
+ &mut pid_size,
+ );
+
+ if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() {
+ cred.pid = Some(pid);
+ Ok(cred)
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+}
diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs
new file mode 100644
index 000000000..e63a2fc24
--- /dev/null
+++ b/library/std/src/os/unix/ucred/tests.rs
@@ -0,0 +1,39 @@
+use crate::os::unix::net::UnixStream;
+use libc::{getegid, geteuid, getpid};
+
+#[test]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "openbsd"
+))]
+fn test_socket_pair() {
+ // Create two connected sockets and get their peer credentials. They should be equal.
+ let (sock_a, sock_b) = UnixStream::pair().unwrap();
+ let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+ assert_eq!(cred_a, cred_b);
+
+ // Check that the UID and GIDs match up.
+ let uid = unsafe { geteuid() };
+ let gid = unsafe { getegid() };
+ assert_eq!(cred_a.uid, uid);
+ assert_eq!(cred_a.gid, gid);
+}
+
+#[test]
+#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))]
+fn test_socket_pair_pids(arg: Type) -> RetType {
+ // Create two connected sockets and get their peer credentials.
+ let (sock_a, sock_b) = UnixStream::pair().unwrap();
+ let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+
+ // On supported platforms (see the cfg above), the credentials should always include the PID.
+ let pid = unsafe { getpid() };
+ assert_eq!(cred_a.pid, Some(pid));
+ assert_eq!(cred_b.pid, Some(pid));
+}
diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs
new file mode 100644
index 000000000..77e6238ca
--- /dev/null
+++ b/library/std/src/os/vxworks/fs.rs
@@ -0,0 +1,99 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_attrib(&self) -> u8;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ 0
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ 0
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ 0
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+ fn st_attrib(&self) -> u8 {
+ self.as_inner().as_inner().st_attrib as u8
+ }
+}
diff --git a/library/std/src/os/vxworks/mod.rs b/library/std/src/os/vxworks/mod.rs
new file mode 100644
index 000000000..0a7ac641d
--- /dev/null
+++ b/library/std/src/os/vxworks/mod.rs
@@ -0,0 +1,6 @@
+//! VxWorks-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/vxworks/raw.rs b/library/std/src/os/vxworks/raw.rs
new file mode 100644
index 000000000..cb41ddfe2
--- /dev/null
+++ b/library/std/src/os/vxworks/raw.rs
@@ -0,0 +1,10 @@
+//! VxWorks-specific raw type definitions
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::os::raw::c_ulong;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, time_t};
diff --git a/library/std/src/os/wasi/ffi.rs b/library/std/src/os/wasi/ffi.rs
new file mode 100644
index 000000000..41dd8702e
--- /dev/null
+++ b/library/std/src/os/wasi/ffi.rs
@@ -0,0 +1,11 @@
+//! WASI-specific extensions to primitives in the [`std::ffi`] module
+//!
+//! [`std::ffi`]: crate::ffi
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
new file mode 100644
index 000000000..160c8f1ec
--- /dev/null
+++ b/library/std/src/os/wasi/fs.rs
@@ -0,0 +1,558 @@
+//! WASI-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+use crate::ffi::OsStr;
+use crate::fs::{self, File, Metadata, OpenOptions};
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::path::{Path, PathBuf};
+use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+// Used for `File::read` on intra-doc links
+#[allow(unused_imports)]
+use io::{Read, Write};
+
+/// WASI-specific extensions to [`File`].
+pub trait FileExt {
+ /// Reads a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Note that similar to [`File::read`], it is not an error to return with a
+ /// short read.
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ let bufs = &mut [IoSliceMut::new(buf)];
+ self.read_vectored_at(bufs, offset)
+ }
+
+ /// Reads a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Note that similar to [`File::read_vectored`], it is not an error to
+ /// return with a short read.
+ fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
+
+ /// Reads the exact number of byte required to fill `buf` from the given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+ ///
+ /// [`read_at`]: FileExt::read_at
+ ///
+ /// # Errors
+ ///
+ /// If this function encounters an error of the kind
+ /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
+ /// will continue.
+ ///
+ /// If this function encounters an "end of file" before completely filling
+ /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
+ /// The contents of `buf` are unspecified in this case.
+ ///
+ /// If any other read error is encountered then this function immediately
+ /// returns. The contents of `buf` are unspecified in this case.
+ ///
+ /// If this function returns an error, it is unspecified how many bytes it
+ /// has read, but it will never read more than would be necessary to
+ /// completely fill the buffer.
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.read_at(buf, offset) {
+ Ok(0) => break,
+ Ok(n) => {
+ let tmp = buf;
+ buf = &mut tmp[n..];
+ offset += n as u64;
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ if !buf.is_empty() {
+ Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Writes a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are initialized with the value 0.
+ ///
+ /// Note that similar to [`File::write`], it is not an error to return a
+ /// short write.
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ let bufs = &[IoSlice::new(buf)];
+ self.write_vectored_at(bufs, offset)
+ }
+
+ /// Writes a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are initialized with the value 0.
+ ///
+ /// Note that similar to [`File::write_vectored`], it is not an error to return a
+ /// short write.
+ fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
+
+ /// Attempts to write an entire buffer starting from a given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// This method will continuously call [`write_at`] until there is no more data
+ /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
+ ///
+ /// # Errors
+ ///
+ /// This function will return the first error of
+ /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
+ ///
+ /// [`write_at`]: FileExt::write_at
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.write_at(buf, offset) {
+ Ok(0) => {
+ return Err(io::const_io_error!(
+ io::ErrorKind::WriteZero,
+ "failed to write whole buffer",
+ ));
+ }
+ Ok(n) => {
+ buf = &buf[n..];
+ offset += n as u64
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ Ok(())
+ }
+
+ /// Returns the current position within the file.
+ ///
+ /// This corresponds to the `fd_tell` syscall and is similar to
+ /// `seek` where you offset 0 bytes from the current position.
+ fn tell(&self) -> io::Result<u64>;
+
+ /// Adjust the flags associated with this file.
+ ///
+ /// This corresponds to the `fd_fdstat_set_flags` syscall.
+ fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
+
+ /// Adjust the rights associated with this file.
+ ///
+ /// This corresponds to the `fd_fdstat_set_rights` syscall.
+ fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
+
+ /// Provide file advisory information on a file descriptor.
+ ///
+ /// This corresponds to the `fd_advise` syscall.
+ fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
+
+ /// Force the allocation of space in a file.
+ ///
+ /// This corresponds to the `fd_allocate` syscall.
+ fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
+
+ /// Create a directory.
+ ///
+ /// This corresponds to the `path_create_directory` syscall.
+ fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
+
+ /// Read the contents of a symbolic link.
+ ///
+ /// This corresponds to the `path_readlink` syscall.
+ fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
+
+ /// Return the attributes of a file or directory.
+ ///
+ /// This corresponds to the `path_filestat_get` syscall.
+ fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
+
+ /// Unlink a file.
+ ///
+ /// This corresponds to the `path_unlink_file` syscall.
+ fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
+
+ /// Remove a directory.
+ ///
+ /// This corresponds to the `path_remove_directory` syscall.
+ fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
+}
+
+// FIXME: bind fd_fdstat_get - need to define a custom return type
+// FIXME: bind fd_readdir - can't return `ReadDir` since we only have entry name
+// FIXME: bind fd_filestat_set_times maybe? - on crates.io for unix
+// FIXME: bind path_filestat_set_times maybe? - on crates.io for unix
+// FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle
+// FIXME: bind random_get maybe? - on crates.io for unix
+
+impl FileExt for fs::File {
+ fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ self.as_inner().as_inner().pread(bufs, offset)
+ }
+
+ fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ self.as_inner().as_inner().pwrite(bufs, offset)
+ }
+
+ fn tell(&self) -> io::Result<u64> {
+ self.as_inner().as_inner().tell()
+ }
+
+ fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
+ self.as_inner().as_inner().set_flags(flags)
+ }
+
+ fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> {
+ self.as_inner().as_inner().set_rights(rights, inheriting)
+ }
+
+ fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
+ let advice = match advice {
+ a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL,
+ a if a == wasi::ADVICE_SEQUENTIAL.raw() => wasi::ADVICE_SEQUENTIAL,
+ a if a == wasi::ADVICE_RANDOM.raw() => wasi::ADVICE_RANDOM,
+ a if a == wasi::ADVICE_WILLNEED.raw() => wasi::ADVICE_WILLNEED,
+ a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED,
+ a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE,
+ _ => {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "invalid parameter 'advice'",
+ ));
+ }
+ };
+
+ self.as_inner().as_inner().advise(offset, len, advice)
+ }
+
+ fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
+ self.as_inner().as_inner().allocate(offset, len)
+ }
+
+ fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> {
+ self.as_inner().as_inner().create_directory(osstr2str(dir.as_ref().as_ref())?)
+ }
+
+ fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
+ self.as_inner().read_link(path.as_ref())
+ }
+
+ fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata> {
+ let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?;
+ Ok(FromInner::from_inner(m))
+ }
+
+ fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ self.as_inner().as_inner().unlink_file(osstr2str(path.as_ref().as_ref())?)
+ }
+
+ fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ self.as_inner().as_inner().remove_directory(osstr2str(path.as_ref().as_ref())?)
+ }
+}
+
+/// WASI-specific extensions to [`fs::OpenOptions`].
+pub trait OpenOptionsExt {
+ /// Pass custom `dirflags` argument to `path_open`.
+ ///
+ /// This option configures the `dirflags` argument to the
+ /// `path_open` syscall which `OpenOptions` will eventually call. The
+ /// `dirflags` argument configures how the file is looked up, currently
+ /// primarily affecting whether symlinks are followed or not.
+ ///
+ /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are
+ /// followed. You can call this method with 0 to disable following symlinks
+ fn lookup_flags(&mut self, flags: u32) -> &mut Self;
+
+ /// Indicates whether `OpenOptions` must open a directory or not.
+ ///
+ /// This method will configure whether the `__WASI_O_DIRECTORY` flag is
+ /// passed when opening a file. When passed it will require that the opened
+ /// path is a directory.
+ ///
+ /// This option is by default `false`
+ fn directory(&mut self, dir: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags`
+ /// field of `path_open`.
+ ///
+ /// This option is by default `false`
+ fn dsync(&mut self, dsync: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags`
+ /// field of `path_open`.
+ ///
+ /// This option is by default `false`
+ fn nonblock(&mut self, nonblock: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags`
+ /// field of `path_open`.
+ ///
+ /// This option is by default `false`
+ fn rsync(&mut self, rsync: bool) -> &mut Self;
+
+ /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags`
+ /// field of `path_open`.
+ ///
+ /// This option is by default `false`
+ fn sync(&mut self, sync: bool) -> &mut Self;
+
+ /// Indicates the value that should be passed in for the `fs_rights_base`
+ /// parameter of `path_open`.
+ ///
+ /// This option defaults based on the `read` and `write` configuration of
+ /// this `OpenOptions` builder. If this method is called, however, the
+ /// exact mask passed in will be used instead.
+ fn fs_rights_base(&mut self, rights: u64) -> &mut Self;
+
+ /// Indicates the value that should be passed in for the
+ /// `fs_rights_inheriting` parameter of `path_open`.
+ ///
+ /// The default for this option is the same value as what will be passed
+ /// for the `fs_rights_base` parameter but if this method is called then
+ /// the specified value will be used instead.
+ fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self;
+
+ /// Open a file or directory.
+ ///
+ /// This corresponds to the `path_open` syscall.
+ fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
+}
+
+impl OpenOptionsExt for OpenOptions {
+ fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().lookup_flags(flags);
+ self
+ }
+
+ fn directory(&mut self, dir: bool) -> &mut OpenOptions {
+ self.as_inner_mut().directory(dir);
+ self
+ }
+
+ fn dsync(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().dsync(enabled);
+ self
+ }
+
+ fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().nonblock(enabled);
+ self
+ }
+
+ fn rsync(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().rsync(enabled);
+ self
+ }
+
+ fn sync(&mut self, enabled: bool) -> &mut OpenOptions {
+ self.as_inner_mut().sync(enabled);
+ self
+ }
+
+ fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions {
+ self.as_inner_mut().fs_rights_base(rights);
+ self
+ }
+
+ fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions {
+ self.as_inner_mut().fs_rights_inheriting(rights);
+ self
+ }
+
+ fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File> {
+ let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?;
+ Ok(File::from_inner(inner))
+ }
+}
+
+/// WASI-specific extensions to [`fs::Metadata`].
+pub trait MetadataExt {
+ /// Returns the `st_dev` field of the internal `filestat_t`
+ fn dev(&self) -> u64;
+ /// Returns the `st_ino` field of the internal `filestat_t`
+ fn ino(&self) -> u64;
+ /// Returns the `st_nlink` field of the internal `filestat_t`
+ fn nlink(&self) -> u64;
+ /// Returns the `st_size` field of the internal `filestat_t`
+ fn size(&self) -> u64;
+ /// Returns the `st_atim` field of the internal `filestat_t`
+ fn atim(&self) -> u64;
+ /// Returns the `st_mtim` field of the internal `filestat_t`
+ fn mtim(&self) -> u64;
+ /// Returns the `st_ctim` field of the internal `filestat_t`
+ fn ctim(&self) -> u64;
+}
+
+impl MetadataExt for fs::Metadata {
+ fn dev(&self) -> u64 {
+ self.as_inner().as_wasi().dev
+ }
+ fn ino(&self) -> u64 {
+ self.as_inner().as_wasi().ino
+ }
+ fn nlink(&self) -> u64 {
+ self.as_inner().as_wasi().nlink
+ }
+ fn size(&self) -> u64 {
+ self.as_inner().as_wasi().size
+ }
+ fn atim(&self) -> u64 {
+ self.as_inner().as_wasi().atim
+ }
+ fn mtim(&self) -> u64 {
+ self.as_inner().as_wasi().mtim
+ }
+ fn ctim(&self) -> u64 {
+ self.as_inner().as_wasi().ctim
+ }
+}
+
+/// WASI-specific extensions for [`fs::FileType`].
+///
+/// Adds support for special WASI file types such as block/character devices,
+/// pipes, and sockets.
+pub trait FileTypeExt {
+ /// Returns `true` if this file type is a block device.
+ fn is_block_device(&self) -> bool;
+ /// Returns `true` if this file type is a character device.
+ fn is_char_device(&self) -> bool;
+ /// Returns `true` if this file type is a socket datagram.
+ fn is_socket_dgram(&self) -> bool;
+ /// Returns `true` if this file type is a socket stream.
+ fn is_socket_stream(&self) -> bool;
+ /// Returns `true` if this file type is any type of socket.
+ fn is_socket(&self) -> bool {
+ self.is_socket_stream() || self.is_socket_dgram()
+ }
+}
+
+impl FileTypeExt for fs::FileType {
+ fn is_block_device(&self) -> bool {
+ self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE
+ }
+ fn is_char_device(&self) -> bool {
+ self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE
+ }
+ fn is_socket_dgram(&self) -> bool {
+ self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM
+ }
+ fn is_socket_stream(&self) -> bool {
+ self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM
+ }
+}
+
+/// WASI-specific extension methods for [`fs::DirEntry`].
+pub trait DirEntryExt {
+ /// Returns the underlying `d_ino` field of the `dirent_t`
+ fn ino(&self) -> u64;
+}
+
+impl DirEntryExt for fs::DirEntry {
+ fn ino(&self) -> u64 {
+ self.as_inner().ino()
+ }
+}
+
+/// Create a hard link.
+///
+/// This corresponds to the `path_link` syscall.
+pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
+ old_fd: &File,
+ old_flags: u32,
+ old_path: P,
+ new_fd: &File,
+ new_path: U,
+) -> io::Result<()> {
+ old_fd.as_inner().as_inner().link(
+ old_flags,
+ osstr2str(old_path.as_ref().as_ref())?,
+ new_fd.as_inner().as_inner(),
+ osstr2str(new_path.as_ref().as_ref())?,
+ )
+}
+
+/// Rename a file or directory.
+///
+/// This corresponds to the `path_rename` syscall.
+pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
+ old_fd: &File,
+ old_path: P,
+ new_fd: &File,
+ new_path: U,
+) -> io::Result<()> {
+ old_fd.as_inner().as_inner().rename(
+ osstr2str(old_path.as_ref().as_ref())?,
+ new_fd.as_inner().as_inner(),
+ osstr2str(new_path.as_ref().as_ref())?,
+ )
+}
+
+/// Create a symbolic link.
+///
+/// This corresponds to the `path_symlink` syscall.
+pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
+ old_path: P,
+ fd: &File,
+ new_path: U,
+) -> io::Result<()> {
+ fd.as_inner()
+ .as_inner()
+ .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?)
+}
+
+/// Create a symbolic link.
+///
+/// This is a convenience API similar to `std::os::unix::fs::symlink` and
+/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
+pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
+ crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
+}
+
+fn osstr2str(f: &OsStr) -> io::Result<&str> {
+ f.to_str()
+ .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
+}
diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs
new file mode 100644
index 000000000..930aca887
--- /dev/null
+++ b/library/std/src/os/wasi/io/fd.rs
@@ -0,0 +1,9 @@
+//! Owned and borrowed file descriptors.
+
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+// Tests for this module
+#[cfg(test)]
+mod tests;
+
+pub use crate::os::fd::owned::*;
diff --git a/library/std/src/os/wasi/io/fd/tests.rs b/library/std/src/os/wasi/io/fd/tests.rs
new file mode 100644
index 000000000..418274752
--- /dev/null
+++ b/library/std/src/os/wasi/io/fd/tests.rs
@@ -0,0 +1,11 @@
+use crate::mem::size_of;
+use crate::os::wasi::io::RawFd;
+
+#[test]
+fn test_raw_fd_layout() {
+ // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
+ // and `rustc_layout_scalar_valid_range_end`, with values that depend on
+ // the bit width of `RawFd`. If this ever changes, those values will need
+ // to be updated.
+ assert_eq!(size_of::<RawFd>(), 4);
+}
diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs
new file mode 100644
index 000000000..6c884e2ea
--- /dev/null
+++ b/library/std/src/os/wasi/io/mod.rs
@@ -0,0 +1,12 @@
+//! WASI-specific extensions to general I/O primitives.
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+mod fd;
+mod raw;
+
+#[unstable(feature = "wasi_ext", issue = "71213")]
+pub use fd::*;
+#[unstable(feature = "wasi_ext", issue = "71213")]
+pub use raw::*;
diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs
new file mode 100644
index 000000000..da3b36ada
--- /dev/null
+++ b/library/std/src/os/wasi/io/raw.rs
@@ -0,0 +1,20 @@
+//! WASI-specific extensions to general I/O primitives.
+
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+// NOTE: despite the fact that this module is unstable,
+// stable Rust had the capability to access the stable
+// re-exported items from os::fd::raw through this
+// unstable module.
+// In PR #95956 the stability checker was changed to check
+// all path segments of an item rather than just the last,
+// which caused the aforementioned stable usage to regress
+// (see issue #99502).
+// As a result, the items in os::fd::raw were given the
+// rustc_allowed_through_unstable_modules attribute.
+// No regression tests were added to ensure this property,
+// as CI is not configured to test wasm32-wasi.
+// If this module is stabilized,
+// you may want to remove those attributes
+// (assuming no other unstable modules need them).
+pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs
new file mode 100644
index 000000000..bbaf328f4
--- /dev/null
+++ b/library/std/src/os/wasi/mod.rs
@@ -0,0 +1,57 @@
+//! Platform-specific extensions to `std` for the WebAssembly System Interface (WASI).
+//!
+//! Provides access to platform-level information on WASI, and exposes
+//! WASI-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings (`OsStr`,
+//! `OsString`), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::wasi::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//! let f = File::create("foo.txt")?;
+//! let fd = f.as_raw_fd();
+//!
+//! // use fd with native WASI bindings
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! [`OsStr`]: crate::ffi::OsStr
+//! [`OsString`]: crate::ffi::OsString
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
+#![doc(cfg(target_os = "wasi"))]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod net;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::FileTypeExt;
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+}
diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs
new file mode 100644
index 000000000..73c097d4a
--- /dev/null
+++ b/library/std/src/os/wasi/net/mod.rs
@@ -0,0 +1,23 @@
+//! WASI-specific networking functionality
+
+#![unstable(feature = "wasi_ext", issue = "71213")]
+
+use crate::io;
+use crate::net;
+use crate::sys_common::AsInner;
+
+/// WASI-specific extensions to [`std::net::TcpListener`].
+///
+/// [`std::net::TcpListener`]: crate::net::TcpListener
+pub trait TcpListenerExt {
+ /// Accept a socket.
+ ///
+ /// This corresponds to the `sock_accept` syscall.
+ fn sock_accept(&self, flags: u16) -> io::Result<u32>;
+}
+
+impl TcpListenerExt for net::TcpListener {
+ fn sock_accept(&self, flags: u16) -> io::Result<u32> {
+ self.as_inner().as_inner().as_inner().sock_accept(flags)
+ }
+}
diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs
new file mode 100644
index 000000000..96bab59d3
--- /dev/null
+++ b/library/std/src/os/windows/ffi.rs
@@ -0,0 +1,136 @@
+//! Windows-specific extensions to primitives in the [`std::ffi`] module.
+//!
+//! # Overview
+//!
+//! For historical reasons, the Windows API uses a form of potentially
+//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit
+//! code units in Windows strings may contain [isolated surrogate code
+//! points which are not paired together][ill-formed-utf-16]. The
+//! Unicode standard requires that surrogate code points (those in the
+//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
+//! encoding a *surrogate code unit pair* is used to encode a single
+//! character. For compatibility with code that does not enforce
+//! these pairings, Windows does not enforce them, either.
+//!
+//! While it is not always possible to convert such a string losslessly into
+//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
+//! able to round-trip such a string from and to Windows APIs
+//! losslessly. For example, some Rust code may be "bridging" some
+//! Windows APIs together, just passing `WCHAR` strings among those
+//! APIs without ever really looking into the strings.
+//!
+//! If Rust code *does* need to look into those strings, it can
+//! convert them to valid UTF-8, possibly lossily, by substituting
+//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is
+//! conventionally done in other Rust APIs that deal with string
+//! encodings.
+//!
+//! # `OsStringExt` and `OsStrExt`
+//!
+//! [`OsString`] is the Rust wrapper for owned strings in the
+//! preferred representation of the operating system. On Windows,
+//! this struct gets augmented with an implementation of the
+//! [`OsStringExt`] trait, which has an [`OsStringExt::from_wide`] method. This
+//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
+//! you get such a slice out of a `WCHAR` Windows API.
+//!
+//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
+//! preferred representation of the operating system. On Windows, the
+//! [`OsStrExt`] trait provides the [`OsStrExt::encode_wide`] method, which
+//! outputs an [`EncodeWide`] iterator. You can [`collect`] this
+//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
+//! pointer to this vector's contents and feed it to Windows APIs.
+//!
+//! These traits, along with [`OsString`] and [`OsStr`], work in
+//! conjunction so that it is possible to **round-trip** strings from
+//! Windows and back, with no loss of data, even if the strings are
+//! ill-formed UTF-16.
+//!
+//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
+//! [`collect`]: crate::iter::Iterator::collect
+//! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
+//! [`std::ffi`]: crate::ffi
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::ffi::{OsStr, OsString};
+use crate::sealed::Sealed;
+use crate::sys::os_str::Buf;
+use crate::sys_common::wtf8::Wtf8Buf;
+use crate::sys_common::{AsInner, FromInner};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::wtf8::EncodeWide;
+
+/// Windows-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt: Sealed {
+ /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
+ /// 16-bit code units.
+ ///
+ /// This is lossless: calling [`OsStrExt::encode_wide`] on the resulting string
+ /// will always return the original code units.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // UTF-16 encoding for "Unicode".
+ /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+ ///
+ /// let string = OsString::from_wide(&source[..]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_wide(wide: &[u16]) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+ fn from_wide(wide: &[u16]) -> OsString {
+ FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
+ }
+}
+
+/// Windows-specific extensions to [`OsStr`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt: Sealed {
+ /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially
+ /// ill-formed UTF-16.
+ ///
+ /// This is lossless: calling [`OsStringExt::from_wide`] and then
+ /// `encode_wide` on the result will yield the original code units.
+ /// Note that the encoding does not add a final null terminator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // UTF-16 encoding for "Unicode".
+ /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+ ///
+ /// let string = OsString::from_wide(&source[..]);
+ ///
+ /// let result: Vec<u16> = string.encode_wide().collect();
+ /// assert_eq!(&source[..], &result[..]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn encode_wide(&self) -> EncodeWide<'_>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+ #[inline]
+ fn encode_wide(&self) -> EncodeWide<'_> {
+ self.as_inner().inner.encode_wide()
+ }
+}
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
new file mode 100644
index 000000000..a091f06dd
--- /dev/null
+++ b/library/std/src/os/windows/fs.rs
@@ -0,0 +1,605 @@
+//! Windows-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs::{self, Metadata, OpenOptions};
+use crate::io;
+use crate::path::Path;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut};
+
+/// Windows-specific extensions to [`fs::File`].
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+ /// Seeks to a given position and reads a number of bytes.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the read.
+ ///
+ /// Reading beyond the end of the file will always return with a length of
+ /// 0\.
+ ///
+ /// Note that similar to `File::read`, it is not an error to return with a
+ /// short read. When returning from such a short read, the file pointer is
+ /// still updated.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs::File;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // Read 10 bytes, starting 72 bytes from the
+ /// // start of the file.
+ /// file.seek_read(&mut buffer[..], 72)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Seeks to a given position and writes a number of bytes.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the write.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are left uninitialized.
+ ///
+ /// Note that similar to `File::write`, it is not an error to return a
+ /// short write. When returning from such a short write, the file pointer
+ /// is still updated.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut buffer = File::create("foo.txt")?;
+ ///
+ /// // Write a byte string starting 72 bytes from
+ /// // the start of the file.
+ /// buffer.seek_write(b"some bytes", 72)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
+/// Windows-specific extensions to [`fs::OpenOptions`].
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+pub trait OpenOptionsExt {
+ /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
+ /// with the specified value.
+ ///
+ /// This will override the `read`, `write`, and `append` flags on the
+ /// `OpenOptions` structure. This method provides fine-grained control over
+ /// the permissions to read, write and append data, attributes (like hidden
+ /// and system), and extended attributes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // Open without read and write permission, for example if you only need
+ /// // to call `stat` on the file
+ /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn access_mode(&mut self, access: u32) -> &mut Self;
+
+ /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
+ /// the specified value.
+ ///
+ /// By default `share_mode` is set to
+ /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
+ /// other processes to read, write, and delete/rename the same file
+ /// while it is open. Removing any of the flags will prevent other
+ /// processes from performing the corresponding operation until the file
+ /// handle is closed.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// // Do not allow others to read or modify this file while we have it open
+ /// // for writing.
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .share_mode(0)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn share_mode(&mut self, val: u32) -> &mut Self;
+
+ /// Sets extra flags for the `dwFileFlags` argument to the call to
+ /// [`CreateFile2`] to the specified value (or combines it with
+ /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
+ /// for [`CreateFile`]).
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rust's options.
+ /// This option overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![allow(unexpected_cfgs)]
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
+ ///
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .create(true)
+ /// .write(true)
+ /// .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: u32) -> &mut Self;
+
+ /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
+ /// the specified value (or combines it with `custom_flags` and
+ /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
+ /// [`CreateFile`]).
+ ///
+ /// If a _new_ file is created because it does not yet exist and
+ /// `.create(true)` or `.create_new(true)` are specified, the new file is
+ /// given the attributes declared with `.attributes()`.
+ ///
+ /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
+ /// existing attributes are preserved and combined with the ones declared
+ /// with `.attributes()`.
+ ///
+ /// In all other cases the attributes get ignored.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![allow(unexpected_cfgs)]
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
+ ///
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create(true)
+ /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
+ /// .open("foo.txt");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn attributes(&mut self, val: u32) -> &mut Self;
+
+ /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
+ /// the specified value (or combines it with `custom_flags` and `attributes`
+ /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
+ ///
+ /// By default `security_qos_flags` is not set. It should be specified when
+ /// opening a named pipe, to control to which degree a server process can
+ /// act on behalf of a client process (security impersonation level).
+ ///
+ /// When `security_qos_flags` is not set, a malicious program can gain the
+ /// elevated privileges of a privileged Rust process when it allows opening
+ /// user-specified paths, by tricking it into opening a named pipe. So
+ /// arguably `security_qos_flags` should also be set when opening arbitrary
+ /// paths. However the bits can then conflict with other flags, specifically
+ /// `FILE_FLAG_OPEN_NO_RECALL`.
+ ///
+ /// For information about possible values, see [Impersonation Levels] on the
+ /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
+ /// automatically when using this method.
+
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![allow(unexpected_cfgs)]
+ /// # #[cfg(for_demonstration_only)]
+ /// extern crate winapi;
+ /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create(true)
+ ///
+ /// // Sets the flag value to `SecurityIdentification`.
+ /// .security_qos_flags(winapi::SECURITY_IDENTIFICATION)
+ ///
+ /// .open(r"\\.\pipe\MyPipe");
+ /// ```
+ ///
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+ /// [Impersonation Levels]:
+ /// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
+}
+
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
+ self.as_inner_mut().access_mode(access);
+ self
+ }
+
+ fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
+ self.as_inner_mut().share_mode(share);
+ self
+ }
+
+ fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags);
+ self
+ }
+
+ fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
+ self.as_inner_mut().attributes(attributes);
+ self
+ }
+
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().security_qos_flags(flags);
+ self
+ }
+}
+
+/// Windows-specific extensions to [`fs::Metadata`].
+///
+/// The data members that this trait exposes correspond to the members
+/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
+///
+/// [`BY_HANDLE_FILE_INFORMATION`]:
+/// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the value of the `dwFileAttributes` field of this metadata.
+ ///
+ /// This field contains the file system attribute information for a file
+ /// or directory. For possible values and their descriptions, see
+ /// [File Attribute Constants] in the Windows Dev Center.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let attributes = metadata.file_attributes();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [File Attribute Constants]:
+ /// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn file_attributes(&self) -> u32;
+
+ /// Returns the value of the `ftCreationTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// If the underlying filesystem does not support creation time, the
+ /// returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let creation_time = metadata.creation_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn creation_time(&self) -> u64;
+
+ /// Returns the value of the `ftLastAccessTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// For a file, the value specifies the last time that a file was read
+ /// from or written to. For a directory, the value specifies when
+ /// the directory was created. For both files and directories, the
+ /// specified date is correct, but the time of day is always set to
+ /// midnight.
+ ///
+ /// If the underlying filesystem does not support last access time, the
+ /// returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let last_access_time = metadata.last_access_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn last_access_time(&self) -> u64;
+
+ /// Returns the value of the `ftLastWriteTime` field of this metadata.
+ ///
+ /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+ /// which represents the number of 100-nanosecond intervals since
+ /// January 1, 1601 (UTC). The struct is automatically
+ /// converted to a `u64` value, as that is the recommended way
+ /// to use it.
+ ///
+ /// For a file, the value specifies the last time that a file was written
+ /// to. For a directory, the structure specifies when the directory was
+ /// created.
+ ///
+ /// If the underlying filesystem does not support the last write time,
+ /// the returned value is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let last_write_time = metadata.last_write_time();
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn last_write_time(&self) -> u64;
+
+ /// Returns the value of the `nFileSize{High,Low}` fields of this
+ /// metadata.
+ ///
+ /// The returned value does not have meaning for directories.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::windows::prelude::*;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let metadata = fs::metadata("foo.txt")?;
+ /// let file_size = metadata.file_size();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn file_size(&self) -> u64;
+
+ /// Returns the value of the `dwVolumeSerialNumber` field of this
+ /// metadata.
+ ///
+ /// This will return `None` if the `Metadata` instance was created from a
+ /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+ /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+ #[unstable(feature = "windows_by_handle", issue = "63010")]
+ fn volume_serial_number(&self) -> Option<u32>;
+
+ /// Returns the value of the `nNumberOfLinks` field of this
+ /// metadata.
+ ///
+ /// This will return `None` if the `Metadata` instance was created from a
+ /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+ /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+ #[unstable(feature = "windows_by_handle", issue = "63010")]
+ fn number_of_links(&self) -> Option<u32>;
+
+ /// Returns the value of the `nFileIndex{Low,High}` fields of this
+ /// metadata.
+ ///
+ /// This will return `None` if the `Metadata` instance was created from a
+ /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+ /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+ #[unstable(feature = "windows_by_handle", issue = "63010")]
+ fn file_index(&self) -> Option<u64>;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn file_attributes(&self) -> u32 {
+ self.as_inner().attrs()
+ }
+ fn creation_time(&self) -> u64 {
+ self.as_inner().created_u64()
+ }
+ fn last_access_time(&self) -> u64 {
+ self.as_inner().accessed_u64()
+ }
+ fn last_write_time(&self) -> u64 {
+ self.as_inner().modified_u64()
+ }
+ fn file_size(&self) -> u64 {
+ self.as_inner().size()
+ }
+ fn volume_serial_number(&self) -> Option<u32> {
+ self.as_inner().volume_serial_number()
+ }
+ fn number_of_links(&self) -> Option<u32> {
+ self.as_inner().number_of_links()
+ }
+ fn file_index(&self) -> Option<u64> {
+ self.as_inner().file_index()
+ }
+}
+
+/// Windows-specific extensions to [`fs::FileType`].
+///
+/// On Windows, a symbolic link knows whether it is a file or directory.
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+pub trait FileTypeExt: Sealed {
+ /// Returns `true` if this file type is a symbolic link that is also a directory.
+ #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+ fn is_symlink_dir(&self) -> bool;
+ /// Returns `true` if this file type is a symbolic link that is also a file.
+ #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+ fn is_symlink_file(&self) -> bool;
+}
+
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+impl Sealed for fs::FileType {}
+
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+impl FileTypeExt for fs::FileType {
+ fn is_symlink_dir(&self) -> bool {
+ self.as_inner().is_symlink_dir()
+ }
+ fn is_symlink_file(&self) -> bool {
+ self.as_inner().is_symlink_file()
+ }
+}
+
+/// Creates a new symlink to a non-directory file on the filesystem.
+///
+/// The `link` path will be a file symbolic link pointing to the `original`
+/// path.
+///
+/// The `original` path should not be a directory or a symlink to a directory,
+/// otherwise the symlink will be broken. Use [`symlink_dir`] for directories.
+///
+/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
+/// Note that this [may change in the future][changes].
+///
+/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
+/// [changes]: io#platform-specific-behavior
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink_file("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
+}
+
+/// Creates a new symlink to a directory on the filesystem.
+///
+/// The `link` path will be a directory symbolic link pointing to the `original`
+/// path.
+///
+/// The `original` path must be a directory or a symlink to a directory,
+/// otherwise the symlink will be broken. Use [`symlink_file`] for other files.
+///
+/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
+/// Note that this [may change in the future][changes].
+///
+/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
+/// [changes]: io#platform-specific-behavior
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink_dir("a", "b")?;
+/// Ok(())
+/// }
+/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
+}
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
new file mode 100644
index 000000000..16cc8fa27
--- /dev/null
+++ b/library/std/src/os/windows/io/handle.rs
@@ -0,0 +1,576 @@
+//! Owned and borrowed OS handles.
+
+#![stable(feature = "io_safety", since = "1.63.0")]
+
+use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
+use crate::fmt;
+use crate::fs;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::mem::forget;
+use crate::ptr;
+use crate::sys::c;
+use crate::sys::cvt;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// A borrowed handle.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the handle.
+///
+/// This uses `repr(transparent)` and has the representation of a host handle,
+/// so it can be used in FFI in places where a handle is passed as an argument,
+/// it is not captured or consumed.
+///
+/// Note that it *may* have the value `-1`, which in `BorrowedHandle` always
+/// represents a valid handle value, such as [the current process handle], and
+/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
+/// [here] for the full story.
+///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
+///
+/// This type's `.to_owned()` implementation returns another `BorrowedHandle`
+/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw
+/// handle, which is then borrowed under the same lifetime.
+///
+/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct BorrowedHandle<'handle> {
+ handle: RawHandle,
+ _phantom: PhantomData<&'handle OwnedHandle>,
+}
+
+/// An owned handle.
+///
+/// This closes the handle on drop.
+///
+/// Note that it *may* have the value `-1`, which in `OwnedHandle` always
+/// represents a valid handle value, such as [the current process handle], and
+/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
+/// [here] for the full story.
+///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
+///
+/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
+/// it must not be used with handles to open registry keys which need to be
+/// closed with [`RegCloseKey`] instead.
+///
+/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
+/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
+///
+/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct OwnedHandle {
+ handle: RawHandle,
+}
+
+/// FFI type for handles in return values or out parameters, where `NULL` is used
+/// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
+/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
+/// FFI declarations.
+///
+/// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
+/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
+/// `NULL`. This ensures that such FFI calls cannot start using the handle without
+/// checking for `NULL` first.
+///
+/// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when
+/// it holds `-1`, that value is interpreted as a valid handle value, such as
+/// [the current process handle], and not `INVALID_HANDLE_VALUE`.
+///
+/// If this holds a non-null handle, it will close the handle on drop.
+///
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug)]
+pub struct HandleOrNull(OwnedHandle);
+
+/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
+/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
+/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
+/// FFI declarations.
+///
+/// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an
+/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
+/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
+/// checking for `INVALID_HANDLE_VALUE` first.
+///
+/// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds
+/// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`.
+///
+/// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop.
+#[repr(transparent)]
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug)]
+pub struct HandleOrInvalid(OwnedHandle);
+
+// The Windows [`HANDLE`] type may be transferred across and shared between
+// thread boundaries (despite containing a `*mut void`, which in general isn't
+// `Send` or `Sync`).
+//
+// [`HANDLE`]: std::os::windows::raw::HANDLE
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for OwnedHandle {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for HandleOrNull {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for HandleOrInvalid {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Send for BorrowedHandle<'_> {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for OwnedHandle {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for HandleOrNull {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for HandleOrInvalid {}
+#[stable(feature = "io_safety", since = "1.63.0")]
+unsafe impl Sync for BorrowedHandle<'_> {}
+
+impl BorrowedHandle<'_> {
+ /// Return a `BorrowedHandle` holding the given raw handle.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `handle` must be a valid open handle, it
+ /// must remain open for the duration of the returned `BorrowedHandle`.
+ ///
+ /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
+ /// sometimes a valid handle value. See [here] for the full story.
+ ///
+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
+ /// detached from processes, or when `windows_subsystem` is used.
+ ///
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[inline]
+ #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub const unsafe fn borrow_raw(handle: RawHandle) -> Self {
+ Self { handle, _phantom: PhantomData }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl TryFrom<HandleOrNull> for OwnedHandle {
+ type Error = NullHandleError;
+
+ #[inline]
+ fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
+ let owned_handle = handle_or_null.0;
+ if owned_handle.handle.is_null() {
+ // Don't call `CloseHandle`; it'd be harmless, except that it could
+ // overwrite the `GetLastError` error.
+ forget(owned_handle);
+
+ Err(NullHandleError(()))
+ } else {
+ Ok(owned_handle)
+ }
+ }
+}
+
+impl OwnedHandle {
+ /// Creates a new `OwnedHandle` instance that shares the same underlying
+ /// object as the existing `OwnedHandle` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ self.as_handle().try_clone_to_owned()
+ }
+}
+
+impl BorrowedHandle<'_> {
+ /// Creates a new `OwnedHandle` instance that shares the same underlying
+ /// object as the existing `BorrowedHandle` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedHandle> {
+ self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
+ }
+
+ pub(crate) fn duplicate(
+ &self,
+ access: c::DWORD,
+ inherit: bool,
+ options: c::DWORD,
+ ) -> io::Result<OwnedHandle> {
+ let handle = self.as_raw_handle();
+
+ // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as
+ // in a process with a detached console. `DuplicateHandle` would fail
+ // if we passed it a null handle, but we can treat null as a valid
+ // handle which doesn't do any I/O, and allow it to be duplicated.
+ if handle.is_null() {
+ return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) };
+ }
+
+ let mut ret = ptr::null_mut();
+ cvt(unsafe {
+ let cur_proc = c::GetCurrentProcess();
+ c::DuplicateHandle(
+ cur_proc,
+ handle,
+ cur_proc,
+ &mut ret,
+ access,
+ inherit as c::BOOL,
+ options,
+ )
+ })?;
+ unsafe { Ok(OwnedHandle::from_raw_handle(ret)) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl TryFrom<HandleOrInvalid> for OwnedHandle {
+ type Error = InvalidHandleError;
+
+ #[inline]
+ fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
+ let owned_handle = handle_or_invalid.0;
+ if owned_handle.handle == c::INVALID_HANDLE_VALUE {
+ // Don't call `CloseHandle`; it'd be harmless, except that it could
+ // overwrite the `GetLastError` error.
+ forget(owned_handle);
+
+ Err(InvalidHandleError(()))
+ } else {
+ Ok(owned_handle)
+ }
+ }
+}
+
+/// This is the error type used by [`HandleOrNull`] when attempting to convert
+/// into a handle, to indicate that the value is null.
+// The empty field prevents constructing this, and allows extending it in the future.
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NullHandleError(());
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Display for NullHandleError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl crate::error::Error for NullHandleError {}
+
+/// This is the error type used by [`HandleOrInvalid`] when attempting to
+/// convert into a handle, to indicate that the value is
+/// `INVALID_HANDLE_VALUE`.
+// The empty field prevents constructing this, and allows extending it in the future.
+#[stable(feature = "io_safety", since = "1.63.0")]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InvalidHandleError(());
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Display for InvalidHandleError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE"
+ .fmt(fmt)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl crate::error::Error for InvalidHandleError {}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawHandle for BorrowedHandle<'_> {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.handle
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawHandle for OwnedHandle {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.handle
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl IntoRawHandle for OwnedHandle {
+ #[inline]
+ fn into_raw_handle(self) -> RawHandle {
+ let handle = self.handle;
+ forget(self);
+ handle
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl FromRawHandle for OwnedHandle {
+ #[inline]
+ unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ Self { handle }
+ }
+}
+
+impl HandleOrNull {
+ /// Constructs a new instance of `Self` from the given `RawHandle` returned
+ /// from a Windows API that uses null to indicate failure, such as
+ /// `CreateThread`.
+ ///
+ /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
+ /// use `INVALID_HANDLE_VALUE` to indicate failure.
+ ///
+ /// # Safety
+ ///
+ /// The passed `handle` value must either satisfy the safety requirements
+ /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all
+ /// Windows APIs use null for errors; see [here] for the full story.
+ ///
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ #[inline]
+ pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ Self(OwnedHandle::from_raw_handle(handle))
+ }
+}
+
+impl HandleOrInvalid {
+ /// Constructs a new instance of `Self` from the given `RawHandle` returned
+ /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
+ /// failure, such as `CreateFileW`.
+ ///
+ /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that
+ /// use null to indicate failure.
+ ///
+ /// # Safety
+ ///
+ /// The passed `handle` value must either satisfy the safety requirements
+ /// of [`FromRawHandle::from_raw_handle`], or be
+ /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use
+ /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story.
+ ///
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ #[inline]
+ pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ Self(OwnedHandle::from_raw_handle(handle))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl Drop for OwnedHandle {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let _ = c::CloseHandle(self.handle);
+ }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for BorrowedHandle<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for OwnedHandle {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedHandle").field("handle", &self.handle).finish()
+ }
+}
+
+/// A trait to borrow the handle from an underlying object.
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub trait AsHandle {
+ /// Borrows the handle.
+ ///
+ /// # Example
+ ///
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// # use std::io;
+ /// use std::os::windows::io::{AsHandle, BorrowedHandle};
+ ///
+ /// let mut f = File::open("foo.txt")?;
+ /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle();
+ /// # Ok::<(), io::Error>(())
+ /// ```
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ fn as_handle(&self) -> BorrowedHandle<'_>;
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsHandle> AsHandle for &T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsHandle> AsHandle for &mut T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for BorrowedHandle<'_> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ *self
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for OwnedHandle {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity
+ // invariants, and the `BorrowdHandle` is bounded by the lifetime
+ // of `&self`.
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for fs::File {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ self.as_inner().as_handle()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<fs::File> for OwnedHandle {
+ #[inline]
+ fn from(file: fs::File) -> OwnedHandle {
+ file.into_inner().into_inner().into_inner().into()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedHandle> for fs::File {
+ #[inline]
+ fn from(owned: OwnedHandle) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned)))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::io::Stdin {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<'a> AsHandle for crate::io::StdinLock<'a> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::io::Stdout {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<'a> AsHandle for crate::io::StdoutLock<'a> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::io::Stderr {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<'a> AsHandle for crate::io::StderrLock<'a> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::process::ChildStdin {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdin> for OwnedHandle {
+ #[inline]
+ fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle {
+ unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::process::ChildStdout {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdout> for OwnedHandle {
+ #[inline]
+ fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle {
+ unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for crate::process::ChildStderr {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStderr> for OwnedHandle {
+ #[inline]
+ fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
+ unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T> AsHandle for crate::thread::JoinHandle<T> {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T> From<crate::thread::JoinHandle<T>> for OwnedHandle {
+ #[inline]
+ fn from(join_handle: crate::thread::JoinHandle<T>) -> OwnedHandle {
+ join_handle.into_inner().into_handle().into_inner()
+ }
+}
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
new file mode 100644
index 000000000..e2a401fb6
--- /dev/null
+++ b/library/std/src/os/windows/io/mod.rs
@@ -0,0 +1,65 @@
+//! Windows-specific extensions to general I/O primitives.
+//!
+//! Just like raw pointers, raw Windows handles and sockets point to resources
+//! with dynamic lifetimes, and they can dangle if they outlive their resources
+//! or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing raw handles and sockets
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type | Analogous to |
+//! | ---------------------- | ------------ |
+//! | [`RawHandle`] | `*const _` |
+//! | [`RawSocket`] | `*const _` |
+//! | | |
+//! | [`BorrowedHandle<'a>`] | `&'a _` |
+//! | [`BorrowedSocket<'a>`] | `&'a _` |
+//! | | |
+//! | [`OwnedHandle`] | `Box<_>` |
+//! | [`OwnedSocket`] | `Box<_>` |
+//!
+//! Like raw pointers, `RawHandle` and `RawSocket` values are primitive values.
+//! And in new code, they should be considered unsafe to do I/O on (analogous
+//! to dereferencing them). Rust did not always provide this guidance, so
+//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and
+//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable,
+//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs
+//! that dereference `RawHandle` and `RawSocket` values, or by using to
+//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`.
+//!
+//! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a
+//! lifetime, to ensure that they don't outlive the resource they point to.
+//! These are safe to use. `BorrowedHandle` and `BorrowedSocket` values may be
+//! used in APIs which provide safe access to any system call except for
+//! `CloseHandle`, `closesocket`, or any other call that would end the
+//! dynamic lifetime of the resource without ending the lifetime of the
+//! handle or socket.
+//!
+//! `BorrowedHandle` and `BorrowedSocket` values may be used in APIs which
+//! provide safe access to `DuplicateHandle` and `WSADuplicateSocketW` and
+//! related functions, so types implementing `AsHandle`, `AsSocket`,
+//! `From<OwnedHandle>`, or `From<OwnedSocket>` should not assume they always
+//! have exclusive access to the underlying object.
+//!
+//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
+//! resource they point to, and free (close) it when they are dropped.
+//!
+//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
+//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod handle;
+mod raw;
+mod socket;
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use handle::*;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::*;
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use socket::*;
+
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
new file mode 100644
index 000000000..49e4f304f
--- /dev/null
+++ b/library/std/src/os/windows/io/raw.rs
@@ -0,0 +1,305 @@
+//! Windows-specific extensions to general I/O primitives.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::io;
+use crate::net;
+#[cfg(doc)]
+use crate::os::windows::io::{AsHandle, AsSocket};
+use crate::os::windows::io::{OwnedHandle, OwnedSocket};
+use crate::os::windows::raw;
+use crate::ptr;
+use crate::sys;
+use crate::sys::c;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw HANDLEs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawHandle = raw::HANDLE;
+
+/// Raw SOCKETs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawSocket = raw::SOCKET;
+
+/// Extracts raw handles.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawHandle {
+ /// Extracts the raw handle.
+ ///
+ /// This function is typically used to **borrow** an owned handle.
+ /// When used in this way, this method does **not** pass ownership of the
+ /// raw handle to the caller, and the handle is only guaranteed
+ /// to be valid while the original object has not yet been destroyed.
+ ///
+ /// This function may return null, such as when called on [`Stdin`],
+ /// [`Stdout`], or [`Stderr`] when the console is detached.
+ ///
+ /// However, borrowing is not strictly required. See [`AsHandle::as_handle`]
+ /// for an API which strictly borrows a handle.
+ ///
+ /// [`Stdin`]: io::Stdin
+ /// [`Stdout`]: io::Stdout
+ /// [`Stderr`]: io::Stderr
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_handle(&self) -> RawHandle;
+}
+
+/// Construct I/O objects from raw handles.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawHandle {
+ /// Constructs a new I/O object from the specified raw handle.
+ ///
+ /// This function is typically used to **consume ownership** of the handle
+ /// given, passing responsibility for closing the handle to the returned
+ /// object. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
+ ///
+ /// However, consuming ownership is not strictly required. Use a
+ /// `From<OwnedHandle>::from` implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `handle` passed in must:
+ /// - be a valid an open handle,
+ /// - be a handle for a resource that may be freed via [`CloseHandle`]
+ /// (as opposed to `RegCloseKey` or other close functions).
+ ///
+ /// Note that the handle *may* have the value `INVALID_HANDLE_VALUE` (-1),
+ /// which is sometimes a valid handle value. See [here] for the full story.
+ ///
+ /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_handle(handle: RawHandle) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `HANDLE`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawHandle {
+ /// Consumes this object, returning the raw underlying handle.
+ ///
+ /// This function is typically used to **transfer ownership** of the underlying
+ /// handle to the caller. When used in this way, callers are then the unique
+ /// owners of the handle and must close it once it's no longer needed.
+ ///
+ /// However, transferring ownership is not strictly required. Use a
+ /// `Into<OwnedHandle>::into` implementation for an API which strictly
+ /// transfers ownership.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_handle(self) -> RawHandle;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawHandle for fs::File {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().as_raw_handle() as RawHandle
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdin {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdout {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stderr {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdinLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdoutLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle })
+ }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StderrLock<'a> {
+ fn as_raw_handle(&self) -> RawHandle {
+ stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle })
+ }
+}
+
+// Translate a handle returned from `GetStdHandle` into a handle to return to
+// the user.
+fn stdio_handle(raw: RawHandle) -> RawHandle {
+ // `GetStdHandle` isn't expected to actually fail, so when it returns
+ // `INVALID_HANDLE_VALUE`, it means we were launched from a parent which
+ // didn't provide us with stdio handles, such as a parent with a detached
+ // console. In that case, return null to the user, which is consistent
+ // with what they'd get in the parent, and which avoids the problem that
+ // `INVALID_HANDLE_VALUE` aliases the current process handle.
+ if raw == c::INVALID_HANDLE_VALUE { ptr::null_mut() } else { raw }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawHandle for fs::File {
+ #[inline]
+ unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
+ let handle = handle as c::HANDLE;
+ fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner(
+ OwnedHandle::from_raw_handle(handle),
+ )))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for fs::File {
+ #[inline]
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_raw_handle() as *mut _
+ }
+}
+
+/// Extracts raw sockets.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawSocket {
+ /// Extracts the raw socket.
+ ///
+ /// This function is typically used to **borrow** an owned socket.
+ /// When used in this way, this method does **not** pass ownership of the
+ /// raw socket to the caller, and the socket is only guaranteed
+ /// to be valid while the original object has not yet been destroyed.
+ ///
+ /// However, borrowing is not strictly required. See [`AsSocket::as_socket`]
+ /// for an API which strictly borrows a socket.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_socket(&self) -> RawSocket;
+}
+
+/// Creates I/O objects from raw sockets.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawSocket {
+ /// Constructs a new I/O object from the specified raw socket.
+ ///
+ /// This function is typically used to **consume ownership** of the socket
+ /// given, passing responsibility for closing the socket to the returned
+ /// object. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
+ ///
+ /// However, consuming ownership is not strictly required. Use a
+ /// `From<OwnedSocket>::from` implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `socket` passed in must:
+ /// - be a valid an open socket,
+ /// - be a socket that may be freed via [`closesocket`].
+ ///
+ /// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_socket(sock: RawSocket) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `SOCKET`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawSocket {
+ /// Consumes this object, returning the raw underlying socket.
+ ///
+ /// This function is typically used to **transfer ownership** of the underlying
+ /// socket to the caller. When used in this way, callers are then the unique
+ /// owners of the socket and must close it once it's no longer needed.
+ ///
+ /// However, transferring ownership is not strictly required. Use a
+ /// `Into<OwnedSocket>::into` implementation for an API which strictly
+ /// transfers ownership.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_socket(self) -> RawSocket;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpStream {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.as_inner().socket().as_raw_socket()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpListener {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.as_inner().socket().as_raw_socket()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::UdpSocket {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.as_inner().socket().as_raw_socket()
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpStream {
+ #[inline]
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+ let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpListener {
+ #[inline]
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+ let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::UdpSocket {
+ #[inline]
+ unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+ let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpStream {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner().into_raw_socket()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpListener {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner().into_raw_socket()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::UdpSocket {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ self.into_inner().into_socket().into_inner().into_raw_socket()
+ }
+}
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
new file mode 100644
index 000000000..72cb3406d
--- /dev/null
+++ b/library/std/src/os/windows/io/socket.rs
@@ -0,0 +1,338 @@
+//! Owned and borrowed OS sockets.
+
+#![stable(feature = "io_safety", since = "1.63.0")]
+
+use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::mem;
+use crate::mem::forget;
+use crate::sys;
+use crate::sys::c;
+#[cfg(not(target_vendor = "uwp"))]
+use crate::sys::cvt;
+
+/// A borrowed socket.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the socket.
+///
+/// This uses `repr(transparent)` and has the representation of a host socket,
+/// so it can be used in FFI in places where a socket is passed as an argument,
+/// it is not captured or consumed, and it never has the value
+/// `INVALID_SOCKET`.
+///
+/// This type's `.to_owned()` implementation returns another `BorrowedSocket`
+/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw
+/// socket, which is then borrowed under the same lifetime.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
+#[cfg_attr(
+ target_pointer_width = "64",
+ rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
+)]
+#[rustc_nonnull_optimization_guaranteed]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct BorrowedSocket<'socket> {
+ socket: RawSocket,
+ _phantom: PhantomData<&'socket OwnedSocket>,
+}
+
+/// An owned socket.
+///
+/// This closes the socket on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host socket,
+/// so it can be used in FFI in places where a socket is passed as a consumed
+/// argument or returned as an owned value, and it never has the value
+/// `INVALID_SOCKET`.
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
+#[cfg_attr(
+ target_pointer_width = "64",
+ rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
+)]
+#[rustc_nonnull_optimization_guaranteed]
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub struct OwnedSocket {
+ socket: RawSocket,
+}
+
+impl BorrowedSocket<'_> {
+ /// Return a `BorrowedSocket` holding the given raw socket.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `raw` must remain open for the duration of
+ /// the returned `BorrowedSocket`, and it must not have the value
+ /// `INVALID_SOCKET`.
+ #[inline]
+ #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub const unsafe fn borrow_raw(socket: RawSocket) -> Self {
+ assert!(socket != c::INVALID_SOCKET as RawSocket);
+ Self { socket, _phantom: PhantomData }
+ }
+}
+
+impl OwnedSocket {
+ /// Creates a new `OwnedSocket` instance that shares the same underlying
+ /// object as the existing `OwnedSocket` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone(&self) -> io::Result<Self> {
+ self.as_socket().try_clone_to_owned()
+ }
+
+ // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-;
+ #[cfg(not(target_vendor = "uwp"))]
+ pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+ cvt(unsafe {
+ c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
+ })
+ .map(drop)
+ }
+
+ #[cfg(target_vendor = "uwp")]
+ pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP"))
+ }
+}
+
+impl BorrowedSocket<'_> {
+ /// Creates a new `OwnedSocket` instance that shares the same underlying
+ /// object as the existing `BorrowedSocket` instance.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ pub fn try_clone_to_owned(&self) -> io::Result<OwnedSocket> {
+ let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
+ let result = unsafe {
+ c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
+ };
+ sys::net::cvt(result)?;
+ let socket = unsafe {
+ c::WSASocketW(
+ info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info,
+ 0,
+ c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
+ )
+ };
+
+ if socket != c::INVALID_SOCKET {
+ unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
+ } else {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+ return Err(io::Error::from_raw_os_error(error));
+ }
+
+ let socket = unsafe {
+ c::WSASocketW(
+ info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info,
+ 0,
+ c::WSA_FLAG_OVERLAPPED,
+ )
+ };
+
+ if socket == c::INVALID_SOCKET {
+ return Err(last_error());
+ }
+
+ unsafe {
+ let socket = OwnedSocket::from_raw_socket(socket);
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
+ }
+ }
+}
+
+/// Returns the last error from the Windows socket interface.
+fn last_error() -> io::Error {
+ io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawSocket for BorrowedSocket<'_> {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.socket
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsRawSocket for OwnedSocket {
+ #[inline]
+ fn as_raw_socket(&self) -> RawSocket {
+ self.socket
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl IntoRawSocket for OwnedSocket {
+ #[inline]
+ fn into_raw_socket(self) -> RawSocket {
+ let socket = self.socket;
+ forget(self);
+ socket
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl FromRawSocket for OwnedSocket {
+ #[inline]
+ unsafe fn from_raw_socket(socket: RawSocket) -> Self {
+ debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
+ Self { socket }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl Drop for OwnedSocket {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let _ = c::closesocket(self.socket);
+ }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for BorrowedSocket<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedSocket").field("socket", &self.socket).finish()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl fmt::Debug for OwnedSocket {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedSocket").field("socket", &self.socket).finish()
+ }
+}
+
+/// A trait to borrow the socket from an underlying object.
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub trait AsSocket {
+ /// Borrows the socket.
+ #[stable(feature = "io_safety", since = "1.63.0")]
+ fn as_socket(&self) -> BorrowedSocket<'_>;
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsSocket> AsSocket for &T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsSocket> AsSocket for &mut T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for BorrowedSocket<'_> {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ *self
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for OwnedSocket {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity
+ // invariants, and the `BorrowdSocket` is bounded by the lifetime
+ // of `&self`.
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for crate::net::TcpStream {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::TcpStream> for OwnedSocket {
+ #[inline]
+ fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket {
+ unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedSocket> for crate::net::TcpStream {
+ #[inline]
+ fn from(owned: OwnedSocket) -> Self {
+ unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for crate::net::TcpListener {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::TcpListener> for OwnedSocket {
+ #[inline]
+ fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket {
+ unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedSocket> for crate::net::TcpListener {
+ #[inline]
+ fn from(owned: OwnedSocket) -> Self {
+ unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsSocket for crate::net::UdpSocket {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::net::UdpSocket> for OwnedSocket {
+ #[inline]
+ fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket {
+ unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedSocket> for crate::net::UdpSocket {
+ #[inline]
+ fn from(owned: OwnedSocket) -> Self {
+ unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
+ }
+}
diff --git a/library/std/src/os/windows/io/tests.rs b/library/std/src/os/windows/io/tests.rs
new file mode 100644
index 000000000..41734e52e
--- /dev/null
+++ b/library/std/src/os/windows/io/tests.rs
@@ -0,0 +1,21 @@
+#[test]
+fn test_niche_optimizations_socket() {
+ use crate::mem::size_of;
+ use crate::os::windows::io::{
+ BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
+ };
+
+ assert_eq!(size_of::<Option<OwnedSocket>>(), size_of::<RawSocket>());
+ assert_eq!(size_of::<Option<BorrowedSocket<'static>>>(), size_of::<RawSocket>(),);
+ unsafe {
+ #[cfg(target_pointer_width = "32")]
+ let (min, max) = (i32::MIN as u32, i32::MAX as u32);
+ #[cfg(target_pointer_width = "64")]
+ let (min, max) = (i64::MIN as u64, i64::MAX as u64);
+
+ assert_eq!(OwnedSocket::from_raw_socket(min).into_raw_socket(), min);
+ assert_eq!(OwnedSocket::from_raw_socket(max).into_raw_socket(), max);
+ assert_eq!(Some(OwnedSocket::from_raw_socket(min)).unwrap().into_raw_socket(), min);
+ assert_eq!(Some(OwnedSocket::from_raw_socket(max)).unwrap().into_raw_socket(), max);
+ }
+}
diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs
new file mode 100644
index 000000000..52eb3b7c0
--- /dev/null
+++ b/library/std/src/os/windows/mod.rs
@@ -0,0 +1,58 @@
+//! Platform-specific extensions to `std` for Windows.
+//!
+//! Provides access to platform-level information for Windows, and exposes
+//! Windows-specific idioms that would otherwise be inappropriate as part
+//! the core `std` library. These extensions allow developers to use
+//! `std` types and idioms with Windows in a way that the normal
+//! platform-agnostic idioms would not normally support.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::windows::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//! let f = File::create("foo.txt")?;
+//! let handle = f.as_raw_handle();
+//!
+//! // use handle with native windows bindings
+//!
+//! Ok(())
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(windows))]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod process;
+pub mod raw;
+pub mod thread;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)]
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ pub use super::fs::FileExt;
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{MetadataExt, OpenOptionsExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{
+ AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, FromRawHandle, FromRawSocket,
+ HandleOrInvalid, IntoRawHandle, IntoRawSocket, OwnedHandle, OwnedSocket,
+ };
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
+}
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
new file mode 100644
index 000000000..073168cf2
--- /dev/null
+++ b/library/std/src/os/windows/process.rs
@@ -0,0 +1,259 @@
+//! Windows-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
+
+#![stable(feature = "process_extensions", since = "1.2.0")]
+
+use crate::ffi::OsStr;
+use crate::os::windows::io::{
+ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
+};
+use crate::process;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawHandle for process::Stdio {
+ unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
+ let handle = sys::handle::Handle::from_raw_handle(handle as *mut _);
+ let io = sys::process::Stdio::Handle(handle);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedHandle> for process::Stdio {
+ fn from(handle: OwnedHandle) -> process::Stdio {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let io = sys::process::Stdio::Handle(handle);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::Child {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsHandle for process::Child {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ self.as_inner().handle().as_handle()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::Child {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<process::Child> for OwnedHandle {
+ fn from(child: process::Child) -> OwnedHandle {
+ child.into_inner().into_handle().into_inner()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdin {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdout {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStderr {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdin {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdout {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStderr {
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}
+
+/// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+pub trait ExitStatusExt: Sealed {
+ /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
+ /// a process.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: u32) -> Self;
+}
+
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: u32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+}
+
+/// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+pub trait CommandExt: Sealed {
+ /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
+ ///
+ /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+ ///
+ /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
+ #[stable(feature = "windows_process_extensions", since = "1.16.0")]
+ fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+
+ /// Forces all arguments to be wrapped in quote (`"`) characters.
+ ///
+ /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
+ /// executables: these programs will expand unquoted arguments containing
+ /// wildcard characters (`?` and `*`) by searching for any file paths
+ /// matching the wildcard pattern.
+ ///
+ /// Adding quotes has no effect when passing arguments to programs
+ /// that use [msvcrt][2]. This includes programs built with both
+ /// MinGW and MSVC.
+ ///
+ /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
+ /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
+ #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
+ fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
+
+ /// Append literal text to the command line without any quoting or escaping.
+ ///
+ /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow
+ /// `CommandLineToArgvW` escaping rules.
+ #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")]
+ fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command;
+
+ /// When [`process::Command`] creates pipes, request that our side is always async.
+ ///
+ /// By default [`process::Command`] may choose to use pipes where both ends
+ /// are opened for synchronous read or write operations. By using
+ /// `async_pipes(true)`, this behavior is overridden so that our side is
+ /// always async.
+ ///
+ /// This is important because if doing async I/O a pipe or a file has to be
+ /// opened for async access.
+ ///
+ /// The end of the pipe sent to the child process will always be synchronous
+ /// regardless of this option.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(windows_process_extensions_async_pipes)]
+ /// use std::os::windows::process::CommandExt;
+ /// use std::process::{Command, Stdio};
+ ///
+ /// # let program = "";
+ ///
+ /// Command::new(program)
+ /// .async_pipes(true)
+ /// .stdin(Stdio::piped())
+ /// .stdout(Stdio::piped())
+ /// .stderr(Stdio::piped());
+ /// ```
+ #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
+ fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
+}
+
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+impl CommandExt for process::Command {
+ fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
+ self.as_inner_mut().creation_flags(flags);
+ self
+ }
+
+ fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
+ self.as_inner_mut().force_quotes(enabled);
+ self
+ }
+
+ fn raw_arg<S: AsRef<OsStr>>(&mut self, raw_text: S) -> &mut process::Command {
+ self.as_inner_mut().raw_arg(raw_text.as_ref());
+ self
+ }
+
+ fn async_pipes(&mut self, always_async: bool) -> &mut process::Command {
+ // FIXME: This currently has an intentional no-op implementation.
+ // For the time being our side of the pipes will always be async.
+ // Once the ecosystem has adjusted, we may then be able to start making
+ // use of synchronous pipes within the standard library.
+ let _ = always_async;
+ self
+ }
+}
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+pub trait ChildExt: Sealed {
+ /// Extracts the main thread raw handle, without taking ownership
+ #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+ fn main_thread_handle(&self) -> BorrowedHandle<'_>;
+}
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+impl ChildExt for process::Child {
+ fn main_thread_handle(&self) -> BorrowedHandle<'_> {
+ self.handle.main_thread_handle()
+ }
+}
+
+/// Windows-specific extensions to [`process::ExitCode`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+pub trait ExitCodeExt: Sealed {
+ /// Creates a new `ExitCode` from the raw underlying `u32` return value of
+ /// a process.
+ ///
+ /// The exit code should not be 259, as this conflicts with the `STILL_ACTIVE`
+ /// macro returned from the `GetExitCodeProcess` function to signal that the
+ /// process has yet to run to completion.
+ #[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+ fn from_raw(raw: u32) -> Self;
+}
+
+#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+impl ExitCodeExt for process::ExitCode {
+ fn from_raw(raw: u32) -> Self {
+ process::ExitCode::from_inner(From::from(raw))
+ }
+}
diff --git a/library/std/src/os/windows/raw.rs b/library/std/src/os/windows/raw.rs
new file mode 100644
index 000000000..0ef3adade
--- /dev/null
+++ b/library/std/src/os/windows/raw.rs
@@ -0,0 +1,16 @@
+//! Windows-specific primitives.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+use crate::os::raw::c_void;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type HANDLE = *mut c_void;
+#[cfg(target_pointer_width = "32")]
+#[doc(cfg(all()))]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type SOCKET = u32;
+#[cfg(target_pointer_width = "64")]
+#[doc(cfg(all()))]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type SOCKET = u64;
diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs
new file mode 100644
index 000000000..d81d6d0ac
--- /dev/null
+++ b/library/std/src/os/windows/thread.rs
@@ -0,0 +1,25 @@
+//! Windows-specific extensions to primitives in the [`std::thread`] module.
+//!
+//! [`std::thread`]: crate::thread
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+use crate::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> AsRawHandle for thread::JoinHandle<T> {
+ #[inline]
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().as_raw_handle() as *mut _
+ }
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> IntoRawHandle for thread::JoinHandle<T> {
+ #[inline]
+ fn into_raw_handle(self) -> RawHandle {
+ self.into_inner().into_handle().into_raw_handle() as *mut _
+ }
+}