mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
Auto merge of #95101 - Dylan-DPC:rollup-r1f1v9t, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #92519 (Use verbatim paths for `process::Command` if necessary) - #92612 (Update stdlib for the l4re target) - #92663 (Implement `Write for Cursor<[u8; N]>`, plus `A: Allocator` cursor support) - #93263 (Consistently present absent stdio handles on Windows as NULL handles.) - #93692 (keyword_docs: document use of `in` with `pub` keyword) - #94984 (add `CStr` method that accepts any slice containing a nul-terminated string) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
3153584170
@ -328,6 +328,27 @@ impl FromVecWithNulError {
|
||||
}
|
||||
}
|
||||
|
||||
/// An error indicating that no nul byte was present.
|
||||
///
|
||||
/// A slice used to create a [`CStr`] must contain a nul byte somewhere
|
||||
/// within the slice.
|
||||
///
|
||||
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
|
||||
///
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
|
||||
pub struct FromBytesUntilNulError(());
|
||||
|
||||
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
|
||||
impl Error for FromBytesUntilNulError {}
|
||||
|
||||
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
|
||||
impl fmt::Display for FromBytesUntilNulError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "data provided does not contain a nul")
|
||||
}
|
||||
}
|
||||
|
||||
/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
|
||||
///
|
||||
/// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
|
||||
@ -1239,12 +1260,60 @@ impl CStr {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a C string wrapper from a byte slice.
|
||||
///
|
||||
/// This method will create a `CStr` from any byte slice that contains at
|
||||
/// least one nul byte. The caller does not need to know or specify where
|
||||
/// the nul byte is located.
|
||||
///
|
||||
/// If the first byte is a nul character, this method will return an
|
||||
/// empty `CStr`. If multiple nul characters are present, the `CStr` will
|
||||
/// end at the first one.
|
||||
///
|
||||
/// If the slice only has a single nul byte at the end, this method is
|
||||
/// equivalent to [`CStr::from_bytes_with_nul`].
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(cstr_from_bytes_until_nul)]
|
||||
///
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// let mut buffer = [0u8; 16];
|
||||
/// unsafe {
|
||||
/// // Here we might call an unsafe C function that writes a string
|
||||
/// // into the buffer.
|
||||
/// let buf_ptr = buffer.as_mut_ptr();
|
||||
/// buf_ptr.write_bytes(b'A', 8);
|
||||
/// }
|
||||
/// // Attempt to extract a C nul-terminated string from the buffer.
|
||||
/// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
|
||||
/// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
|
||||
/// ```
|
||||
///
|
||||
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
|
||||
pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
|
||||
let nul_pos = memchr::memchr(0, bytes);
|
||||
match nul_pos {
|
||||
Some(nul_pos) => {
|
||||
// SAFETY: We know there is a nul byte at nul_pos, so this slice
|
||||
// (ending at the nul byte) is a well-formed C string.
|
||||
let subslice = &bytes[..nul_pos + 1];
|
||||
Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
|
||||
}
|
||||
None => Err(FromBytesUntilNulError(())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a C string wrapper from a byte slice.
|
||||
///
|
||||
/// This function will cast the provided `bytes` to a `CStr`
|
||||
/// wrapper after ensuring that the byte slice is nul-terminated
|
||||
/// and does not contain any interior nul bytes.
|
||||
///
|
||||
/// If the nul byte may not be at the end,
|
||||
/// [`CStr::from_bytes_until_nul`] can be used instead.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
@ -117,6 +117,43 @@ fn from_bytes_with_nul_interior() {
|
||||
assert!(cstr.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cstr_from_bytes_until_nul() {
|
||||
// Test an empty slice. This should fail because it
|
||||
// does not contain a nul byte.
|
||||
let b = b"";
|
||||
assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
|
||||
|
||||
// Test a non-empty slice, that does not contain a nul byte.
|
||||
let b = b"hello";
|
||||
assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
|
||||
|
||||
// Test an empty nul-terminated string
|
||||
let b = b"\0";
|
||||
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
|
||||
assert_eq!(r.to_bytes(), b"");
|
||||
|
||||
// Test a slice with the nul byte in the middle
|
||||
let b = b"hello\0world!";
|
||||
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
|
||||
assert_eq!(r.to_bytes(), b"hello");
|
||||
|
||||
// Test a slice with the nul byte at the end
|
||||
let b = b"hello\0";
|
||||
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
|
||||
assert_eq!(r.to_bytes(), b"hello");
|
||||
|
||||
// Test a slice with two nul bytes at the end
|
||||
let b = b"hello\0\0";
|
||||
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
|
||||
assert_eq!(r.to_bytes(), b"hello");
|
||||
|
||||
// Test a slice containing lots of nul bytes
|
||||
let b = b"\0\0\0\0";
|
||||
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
|
||||
assert_eq!(r.to_bytes(), b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_boxed() {
|
||||
let orig: &[u8] = b"Hello, world!\0";
|
||||
|
@ -3,6 +3,7 @@ mod tests;
|
||||
|
||||
use crate::io::prelude::*;
|
||||
|
||||
use crate::alloc::Allocator;
|
||||
use crate::cmp;
|
||||
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
|
||||
|
||||
@ -398,7 +399,10 @@ fn slice_write_vectored(
|
||||
}
|
||||
|
||||
// Resizing write implementation
|
||||
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
|
||||
fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
let pos: usize = (*pos_mut).try_into().map_err(|_| {
|
||||
io::const_io_error!(
|
||||
ErrorKind::InvalidInput,
|
||||
@ -426,11 +430,14 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usi
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn vec_write_vectored(
|
||||
fn vec_write_vectored<A>(
|
||||
pos_mut: &mut u64,
|
||||
vec: &mut Vec<u8>,
|
||||
vec: &mut Vec<u8, A>,
|
||||
bufs: &[IoSlice<'_>],
|
||||
) -> io::Result<usize> {
|
||||
) -> io::Result<usize>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
let mut nwritten = 0;
|
||||
for buf in bufs {
|
||||
nwritten += vec_write(pos_mut, vec, buf)?;
|
||||
@ -462,7 +469,10 @@ impl Write for Cursor<&mut [u8]> {
|
||||
}
|
||||
|
||||
#[stable(feature = "cursor_mut_vec", since = "1.25.0")]
|
||||
impl Write for Cursor<&mut Vec<u8>> {
|
||||
impl<A> Write for Cursor<&mut Vec<u8, A>>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
vec_write(&mut self.pos, self.inner, buf)
|
||||
}
|
||||
@ -483,7 +493,10 @@ impl Write for Cursor<&mut Vec<u8>> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Write for Cursor<Vec<u8>> {
|
||||
impl<A> Write for Cursor<Vec<u8, A>>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
vec_write(&mut self.pos, &mut self.inner, buf)
|
||||
}
|
||||
@ -504,7 +517,33 @@ impl Write for Cursor<Vec<u8>> {
|
||||
}
|
||||
|
||||
#[stable(feature = "cursor_box_slice", since = "1.5.0")]
|
||||
impl Write for Cursor<Box<[u8]>> {
|
||||
impl<A> Write for Cursor<Box<[u8], A>>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
slice_write(&mut self.pos, &mut self.inner, buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
slice_write_vectored(&mut self.pos, &mut self.inner, bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cursor_array", since = "1.61.0")]
|
||||
impl<const N: usize> Write for Cursor<[u8; N]> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
slice_write(&mut self.pos, &mut self.inner, buf)
|
||||
|
@ -50,9 +50,11 @@ fn test_mem_mut_writer() {
|
||||
assert_eq!(&writer.get_ref()[..], b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_slice_writer() {
|
||||
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
|
||||
fn test_slice_writer<T>(writer: &mut Cursor<T>)
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
Cursor<T>: Write,
|
||||
{
|
||||
assert_eq!(writer.position(), 0);
|
||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
||||
assert_eq!(writer.position(), 1);
|
||||
@ -65,12 +67,14 @@ fn test_box_slice_writer() {
|
||||
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
|
||||
assert_eq!(writer.write(&[10]).unwrap(), 0);
|
||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
assert_eq!(&**writer.get_ref(), b);
|
||||
assert_eq!(writer.get_ref().as_ref(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_slice_writer_vectored() {
|
||||
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
|
||||
fn test_slice_writer_vectored<T>(writer: &mut Cursor<T>)
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
Cursor<T>: Write,
|
||||
{
|
||||
assert_eq!(writer.position(), 0);
|
||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
|
||||
assert_eq!(writer.position(), 1);
|
||||
@ -85,53 +89,45 @@ fn test_box_slice_writer_vectored() {
|
||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
|
||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
|
||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
assert_eq!(&**writer.get_ref(), b);
|
||||
assert_eq!(writer.get_ref().as_ref(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_slice_writer() {
|
||||
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
|
||||
test_slice_writer(&mut writer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_slice_writer_vectored() {
|
||||
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
|
||||
test_slice_writer_vectored(&mut writer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_writer() {
|
||||
let mut writer = Cursor::new([0u8; 9]);
|
||||
test_slice_writer(&mut writer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_writer_vectored() {
|
||||
let mut writer = Cursor::new([0u8; 9]);
|
||||
test_slice_writer_vectored(&mut writer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_buf_writer() {
|
||||
let mut buf = [0 as u8; 9];
|
||||
{
|
||||
let mut writer = Cursor::new(&mut buf[..]);
|
||||
assert_eq!(writer.position(), 0);
|
||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
||||
assert_eq!(writer.position(), 1);
|
||||
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
|
||||
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
|
||||
assert_eq!(writer.position(), 8);
|
||||
assert_eq!(writer.write(&[]).unwrap(), 0);
|
||||
assert_eq!(writer.position(), 8);
|
||||
|
||||
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
|
||||
assert_eq!(writer.write(&[10]).unwrap(), 0);
|
||||
}
|
||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
assert_eq!(buf, b);
|
||||
let mut writer = Cursor::new(&mut buf[..]);
|
||||
test_slice_writer(&mut writer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_buf_writer_vectored() {
|
||||
let mut buf = [0 as u8; 9];
|
||||
{
|
||||
let mut writer = Cursor::new(&mut buf[..]);
|
||||
assert_eq!(writer.position(), 0);
|
||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
|
||||
assert_eq!(writer.position(), 1);
|
||||
assert_eq!(
|
||||
writer
|
||||
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
|
||||
.unwrap(),
|
||||
7,
|
||||
);
|
||||
assert_eq!(writer.position(), 8);
|
||||
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
|
||||
assert_eq!(writer.position(), 8);
|
||||
|
||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
|
||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
|
||||
}
|
||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
assert_eq!(buf, b);
|
||||
let mut writer = Cursor::new(&mut buf[..]);
|
||||
test_slice_writer_vectored(&mut writer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -202,12 +202,18 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
|
||||
///
|
||||
/// [`io::stdin`]: stdin
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
@ -230,12 +236,18 @@ pub struct Stdin {
|
||||
/// This handle implements both the [`Read`] and [`BufRead`] traits, and
|
||||
/// is constructed via the [`Stdin::lock`] method.
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
@ -263,11 +275,18 @@ pub struct StdinLock<'a> {
|
||||
/// is synchronized via a mutex. If you need more explicit control over
|
||||
/// locking, see the [`Stdin::lock`] method.
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Using implicit synchronization:
|
||||
@ -490,11 +509,18 @@ impl fmt::Debug for StdinLock<'_> {
|
||||
///
|
||||
/// Created by the [`io::stdout`] method.
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
///
|
||||
/// [`lock`]: Stdout::lock
|
||||
/// [`io::stdout`]: stdout
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -510,10 +536,17 @@ pub struct Stdout {
|
||||
/// This handle implements the [`Write`] trait, and is constructed via
|
||||
/// the [`Stdout::lock`] method. See its documentation for more.
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
#[must_use = "if unused stdout will immediately unlock"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct StdoutLock<'a> {
|
||||
@ -528,11 +561,18 @@ static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = Sy
|
||||
/// is synchronized via a mutex. If you need more explicit control over
|
||||
/// locking, see the [`Stdout::lock`] method.
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Using implicit synchronization:
|
||||
@ -710,10 +750,17 @@ impl fmt::Debug for StdoutLock<'_> {
|
||||
///
|
||||
/// [`io::stderr`]: stderr
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Stderr {
|
||||
inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
|
||||
@ -724,10 +771,17 @@ pub struct Stderr {
|
||||
/// This handle implements the [`Write`] trait and is constructed via
|
||||
/// the [`Stderr::lock`] method. See its documentation for more.
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
#[must_use = "if unused stderr will immediately unlock"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct StderrLock<'a> {
|
||||
@ -738,11 +792,18 @@ pub struct StderrLock<'a> {
|
||||
///
|
||||
/// This handle is not buffered.
|
||||
///
|
||||
/// ### Note: Windows Portability Consideration
|
||||
/// ### Note: Windows Portability Considerations
|
||||
///
|
||||
/// When operating in a console, the Windows implementation of this stream does not support
|
||||
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
|
||||
/// an error.
|
||||
///
|
||||
/// In a process with a detached console, such as one using
|
||||
/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
|
||||
/// the contained handle will be null. In such cases, the standard library's `Read` and
|
||||
/// `Write` will do nothing and silently succeed. All other I/O operations, via the
|
||||
/// standard library or via raw Windows API calls, will fail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Using implicit synchronization:
|
||||
|
@ -728,6 +728,20 @@ mod impl_keyword {}
|
||||
/// [`IntoIterator`]: ../book/ch13-04-performance.html
|
||||
/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns
|
||||
/// [`for`]: keyword.for.html
|
||||
///
|
||||
/// The other use of `in` is with the keyword `pub`. It allows users to declare an item as visible
|
||||
/// only within a given scope.
|
||||
///
|
||||
/// ## Literal Example:
|
||||
///
|
||||
/// * `pub(in crate::outer_mod) fn outer_mod_visible_fn() {}` - fn is visible in `outer_mod`
|
||||
///
|
||||
/// Starting with the 2018 edition, paths for `pub(in path)` must start with `crate`, `self` or
|
||||
/// `super`. The 2015 edition may also use paths starting with `::` or modules from the crate root.
|
||||
///
|
||||
/// For more information, see the [Reference].
|
||||
///
|
||||
/// [Reference]: ../reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself
|
||||
mod in_keyword {}
|
||||
|
||||
#[doc(keyword = "let")]
|
||||
|
382
library/std/src/os/l4re/fs.rs
Normal file
382
library/std/src/os/l4re/fs.rs
Normal file
@ -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")]
|
||||
#[rustc_deprecated(since = "1.8.0", reason = "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
|
||||
}
|
||||
}
|
7
library/std/src/os/l4re/mod.rs
Normal file
7
library/std/src/os/l4re/mod.rs
Normal file
@ -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;
|
365
library/std/src/os/l4re/raw.rs
Normal file
365
library/std/src/os/l4re/raw.rs
Normal file
@ -0,0 +1,365 @@
|
||||
//! L4Re-specific raw type definitions.
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
#![rustc_deprecated(
|
||||
since = "1.8.0",
|
||||
reason = "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],
|
||||
}
|
||||
}
|
@ -81,7 +81,7 @@ pub mod unix;
|
||||
all(target_vendor = "fortanix", target_env = "sgx")
|
||||
)
|
||||
)))]
|
||||
#[cfg(any(target_os = "linux", target_os = "l4re", doc))]
|
||||
#[cfg(any(target_os = "linux", doc))]
|
||||
pub mod linux;
|
||||
|
||||
// wasi
|
||||
@ -127,6 +127,8 @@ pub mod haiku;
|
||||
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")]
|
||||
|
@ -55,7 +55,9 @@ mod platform {
|
||||
pub use crate::os::illumos::*;
|
||||
#[cfg(target_os = "ios")]
|
||||
pub use crate::os::ios::*;
|
||||
#[cfg(any(target_os = "linux", target_os = "l4re"))]
|
||||
#[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::*;
|
||||
|
@ -164,12 +164,22 @@ impl OwnedHandle {
|
||||
inherit: bool,
|
||||
options: c::DWORD,
|
||||
) -> io::Result<Self> {
|
||||
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(Self::from_raw_handle(handle)) };
|
||||
}
|
||||
|
||||
let mut ret = 0 as c::HANDLE;
|
||||
cvt(unsafe {
|
||||
let cur_proc = c::GetCurrentProcess();
|
||||
c::DuplicateHandle(
|
||||
cur_proc,
|
||||
self.as_raw_handle(),
|
||||
handle,
|
||||
cur_proc,
|
||||
&mut ret,
|
||||
access,
|
||||
|
@ -9,6 +9,7 @@ use crate::net;
|
||||
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};
|
||||
@ -96,45 +97,57 @@ impl AsRawHandle for fs::File {
|
||||
#[stable(feature = "asraw_stdio", since = "1.21.0")]
|
||||
impl AsRawHandle for io::Stdin {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as 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 {
|
||||
unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as 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 {
|
||||
unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as 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 {
|
||||
unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as 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 {
|
||||
unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as 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 {
|
||||
unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as 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]
|
||||
|
@ -13,6 +13,7 @@ pub mod net {
|
||||
use crate::fmt;
|
||||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
|
||||
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
@ -59,7 +60,7 @@ pub mod net {
|
||||
}
|
||||
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
unimpl!();
|
||||
false
|
||||
}
|
||||
|
||||
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
|
||||
@ -83,7 +84,7 @@ pub mod net {
|
||||
}
|
||||
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
unimpl!();
|
||||
false
|
||||
}
|
||||
|
||||
pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
|
||||
@ -121,23 +122,52 @@ pub mod net {
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<libc::c_int> for Socket {
|
||||
fn as_inner(&self) -> &libc::c_int {
|
||||
self.0.as_inner()
|
||||
// This is used by sys_common code to abstract over Windows and Unix.
|
||||
pub fn as_raw(&self) -> RawFd {
|
||||
self.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<libc::c_int> for Socket {
|
||||
fn from_inner(fd: libc::c_int) -> Socket {
|
||||
Socket(FileDesc::new(fd))
|
||||
impl AsInner<FileDesc> for Socket {
|
||||
fn as_inner(&self) -> &FileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<libc::c_int> for Socket {
|
||||
fn into_inner(self) -> libc::c_int {
|
||||
self.0.into_raw()
|
||||
impl FromInner<FileDesc> for Socket {
|
||||
fn from_inner(file_desc: FileDesc) -> Socket {
|
||||
Socket(file_desc)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<FileDesc> for Socket {
|
||||
fn into_inner(self) -> FileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for Socket {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Socket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Socket {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Socket {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
Self(FromRawFd::from_raw_fd(raw_fd))
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +221,7 @@ pub mod net {
|
||||
}
|
||||
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
unimpl!();
|
||||
false
|
||||
}
|
||||
|
||||
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
|
||||
@ -203,7 +233,7 @@ pub mod net {
|
||||
}
|
||||
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
unimpl!();
|
||||
false
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
@ -497,7 +527,7 @@ pub mod net {
|
||||
|
||||
impl LookupHost {
|
||||
pub fn port(&self) -> u16 {
|
||||
unimpl!();
|
||||
0 // unimplemented
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "redox",
|
||||
target_os = "l4re",
|
||||
)))] {
|
||||
use crate::sys::os::errno;
|
||||
let pfds: &mut [_] = &mut [
|
||||
|
@ -27,7 +27,10 @@ use crate::sys::weak::weak;
|
||||
use libc::RTP_ID as pid_t;
|
||||
|
||||
#[cfg(not(target_os = "vxworks"))]
|
||||
use libc::{c_int, gid_t, pid_t, uid_t};
|
||||
use libc::{c_int, pid_t};
|
||||
|
||||
#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
|
||||
use libc::{gid_t, uid_t};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Command
|
||||
|
@ -19,12 +19,12 @@ use crate::path::{Path, PathBuf};
|
||||
use crate::ptr;
|
||||
use crate::sys::c;
|
||||
use crate::sys::c::NonZeroDWORD;
|
||||
use crate::sys::cvt;
|
||||
use crate::sys::fs::{File, OpenOptions};
|
||||
use crate::sys::handle::Handle;
|
||||
use crate::sys::path;
|
||||
use crate::sys::pipe::{self, AnonPipe};
|
||||
use crate::sys::stdio;
|
||||
use crate::sys::{cvt, to_u16s};
|
||||
use crate::sys_common::mutex::StaticMutex;
|
||||
use crate::sys_common::process::{CommandEnv, CommandEnvs};
|
||||
use crate::sys_common::{AsInner, IntoInner};
|
||||
@ -269,8 +269,13 @@ impl Command {
|
||||
None
|
||||
};
|
||||
let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
|
||||
// Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
|
||||
let is_batch_file = matches!(
|
||||
program.len().checked_sub(5).and_then(|i| program.get(i..)),
|
||||
Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0])
|
||||
);
|
||||
let mut cmd_str =
|
||||
make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
|
||||
make_command_line(&program, &self.args, self.force_quotes_enabled, is_batch_file)?;
|
||||
cmd_str.push(0); // add null terminator
|
||||
|
||||
// stolen from the libuv code.
|
||||
@ -309,7 +314,6 @@ impl Command {
|
||||
si.hStdOutput = stdout.as_raw_handle();
|
||||
si.hStdError = stderr.as_raw_handle();
|
||||
|
||||
let program = to_u16s(&program)?;
|
||||
unsafe {
|
||||
cvt(c::CreateProcessW(
|
||||
program.as_ptr(),
|
||||
@ -366,7 +370,7 @@ fn resolve_exe<'a>(
|
||||
exe_path: &'a OsStr,
|
||||
parent_paths: impl FnOnce() -> Option<OsString>,
|
||||
child_paths: Option<&OsStr>,
|
||||
) -> io::Result<PathBuf> {
|
||||
) -> io::Result<Vec<u16>> {
|
||||
// Early return if there is no filename.
|
||||
if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
|
||||
return Err(io::const_io_error!(
|
||||
@ -388,19 +392,19 @@ fn resolve_exe<'a>(
|
||||
if has_exe_suffix {
|
||||
// The application name is a path to a `.exe` file.
|
||||
// Let `CreateProcessW` figure out if it exists or not.
|
||||
return Ok(exe_path.into());
|
||||
return path::maybe_verbatim(Path::new(exe_path));
|
||||
}
|
||||
let mut path = PathBuf::from(exe_path);
|
||||
|
||||
// Append `.exe` if not already there.
|
||||
path = path::append_suffix(path, EXE_SUFFIX.as_ref());
|
||||
if program_exists(&path) {
|
||||
if let Some(path) = program_exists(&path) {
|
||||
return Ok(path);
|
||||
} else {
|
||||
// It's ok to use `set_extension` here because the intent is to
|
||||
// remove the extension that was just added.
|
||||
path.set_extension("");
|
||||
return Ok(path);
|
||||
return path::maybe_verbatim(&path);
|
||||
}
|
||||
} else {
|
||||
ensure_no_nuls(exe_path)?;
|
||||
@ -415,7 +419,7 @@ fn resolve_exe<'a>(
|
||||
if !has_extension {
|
||||
path.set_extension(EXE_EXTENSION);
|
||||
}
|
||||
if program_exists(&path) { Some(path) } else { None }
|
||||
program_exists(&path)
|
||||
});
|
||||
if let Some(path) = result {
|
||||
return Ok(path);
|
||||
@ -431,10 +435,10 @@ fn search_paths<Paths, Exists>(
|
||||
parent_paths: Paths,
|
||||
child_paths: Option<&OsStr>,
|
||||
mut exists: Exists,
|
||||
) -> Option<PathBuf>
|
||||
) -> Option<Vec<u16>>
|
||||
where
|
||||
Paths: FnOnce() -> Option<OsString>,
|
||||
Exists: FnMut(PathBuf) -> Option<PathBuf>,
|
||||
Exists: FnMut(PathBuf) -> Option<Vec<u16>>,
|
||||
{
|
||||
// 1. Child paths
|
||||
// This is for consistency with Rust's historic behaviour.
|
||||
@ -486,17 +490,18 @@ where
|
||||
}
|
||||
|
||||
/// Check if a file exists without following symlinks.
|
||||
fn program_exists(path: &Path) -> bool {
|
||||
fn program_exists(path: &Path) -> Option<Vec<u16>> {
|
||||
unsafe {
|
||||
to_u16s(path)
|
||||
.map(|path| {
|
||||
// Getting attributes using `GetFileAttributesW` does not follow symlinks
|
||||
// and it will almost always be successful if the link exists.
|
||||
// There are some exceptions for special system files (e.g. the pagefile)
|
||||
// but these are not executable.
|
||||
c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES
|
||||
})
|
||||
.unwrap_or(false)
|
||||
let path = path::maybe_verbatim(path).ok()?;
|
||||
// Getting attributes using `GetFileAttributesW` does not follow symlinks
|
||||
// and it will almost always be successful if the link exists.
|
||||
// There are some exceptions for special system files (e.g. the pagefile)
|
||||
// but these are not executable.
|
||||
if c::GetFileAttributesW(path.as_ptr()) == c::INVALID_FILE_ATTRIBUTES {
|
||||
None
|
||||
} else {
|
||||
Some(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -730,7 +735,12 @@ enum Quote {
|
||||
|
||||
// Produces a wide string *without terminating null*; returns an error if
|
||||
// `prog` or any of the `args` contain a nul.
|
||||
fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
|
||||
fn make_command_line(
|
||||
prog: &[u16],
|
||||
args: &[Arg],
|
||||
force_quotes: bool,
|
||||
is_batch_file: bool,
|
||||
) -> io::Result<Vec<u16>> {
|
||||
// Encode the command and arguments in a command line string such
|
||||
// that the spawned process may recover them using CommandLineToArgvW.
|
||||
let mut cmd: Vec<u16> = Vec::new();
|
||||
@ -739,17 +749,18 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu
|
||||
// need to add an extra pair of quotes surrounding the whole command line
|
||||
// so they are properly passed on to the script.
|
||||
// See issue #91991.
|
||||
let is_batch_file = Path::new(prog)
|
||||
.extension()
|
||||
.map(|ext| ext.eq_ignore_ascii_case("cmd") || ext.eq_ignore_ascii_case("bat"))
|
||||
.unwrap_or(false);
|
||||
if is_batch_file {
|
||||
cmd.push(b'"' as u16);
|
||||
}
|
||||
|
||||
// Always quote the program name so CreateProcess doesn't interpret args as
|
||||
// part of the name if the binary wasn't found first time.
|
||||
append_arg(&mut cmd, prog, Quote::Always)?;
|
||||
// Always quote the program name so CreateProcess to avoid ambiguity when
|
||||
// the child process parses its arguments.
|
||||
// Note that quotes aren't escaped here because they can't be used in arg0.
|
||||
// But that's ok because file paths can't contain quotes.
|
||||
cmd.push(b'"' as u16);
|
||||
cmd.extend_from_slice(prog.strip_suffix(&[0]).unwrap_or(prog));
|
||||
cmd.push(b'"' as u16);
|
||||
|
||||
for arg in args {
|
||||
cmd.push(' ' as u16);
|
||||
let (arg, quote) = match arg {
|
||||
|
@ -3,11 +3,12 @@ use super::Arg;
|
||||
use crate::env;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::process::Command;
|
||||
use crate::sys::to_u16s;
|
||||
|
||||
#[test]
|
||||
fn test_raw_args() {
|
||||
let command_line = &make_command_line(
|
||||
OsStr::new("quoted exe"),
|
||||
&to_u16s("quoted exe").unwrap(),
|
||||
&[
|
||||
Arg::Regular(OsString::from("quote me")),
|
||||
Arg::Raw(OsString::from("quote me *not*")),
|
||||
@ -16,6 +17,7 @@ fn test_raw_args() {
|
||||
Arg::Regular(OsString::from("optional-quotes")),
|
||||
],
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
@ -28,9 +30,10 @@ fn test_raw_args() {
|
||||
fn test_make_command_line() {
|
||||
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
|
||||
let command_line = &make_command_line(
|
||||
OsStr::new(prog),
|
||||
&to_u16s(prog).unwrap(),
|
||||
&args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
|
||||
force_quotes,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
String::from_utf16(command_line).unwrap()
|
||||
|
Loading…
Reference in New Issue
Block a user