diff options
| author | bors <bors@rust-lang.org> | 2015-04-30 00:07:10 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-04-30 00:07:10 +0000 |
| commit | 5449f5d29e175230a1285ebe92394f50c76e1df6 (patch) | |
| tree | c89deb8cc68b46e6fc768e862c32bd3e830a31c3 /src/libstd/sys | |
| parent | 551a74dddd84cf01440ee84148ebd18bc68bd7c8 (diff) | |
| parent | 1b34c099a6a624947877315875018093587a8834 (diff) | |
| download | rust-5449f5d29e175230a1285ebe92394f50c76e1df6.tar.gz rust-5449f5d29e175230a1285ebe92394f50c76e1df6.zip | |
Auto merge of #24967 - alexcrichton:rollup, r=alexcrichton
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/unix/c.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext.rs | 337 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext/ffi.rs | 62 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext/fs.rs | 207 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext/io.rs | 108 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext/mod.rs | 53 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext/process.rs | 65 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext/raw.rs | 22 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fs2.rs | 136 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/windows/backtrace.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext.rs | 301 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/ffi.rs | 58 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/fs.rs | 150 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/io.rs | 131 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/mod.rs | 35 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/raw.rs | 21 | ||||
| -rw-r--r-- | src/libstd/sys/windows/fs2.rs | 234 | ||||
| -rw-r--r-- | src/libstd/sys/windows/handle.rs | 13 | ||||
| -rw-r--r-- | src/libstd/sys/windows/process2.rs | 278 | ||||
| -rw-r--r-- | src/libstd/sys/windows/stdio.rs | 16 |
21 files changed, 1340 insertions, 900 deletions
diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index aa4bf821207..1e68eac5a67 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -161,6 +161,8 @@ extern { pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; pub fn setgroups(ngroups: libc::c_int, ptr: *const libc::c_void) -> libc::c_int; + pub fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char) + -> *mut libc::c_char; } #[cfg(any(target_os = "macos", target_os = "ios"))] diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs deleted file mode 100644 index 66aaf26b09b..00000000000 --- a/src/libstd/sys/unix/ext.rs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Experimental extensions to `std` for Unix platforms. -//! -//! For now, this module is limited to extracting file descriptors, -//! but its functionality will grow over time. -//! -//! # Example -//! -//! ```no_run -//! use std::fs::File; -//! use std::os::unix::prelude::*; -//! -//! fn main() { -//! let f = File::create("foo.txt").unwrap(); -//! let fd = f.as_raw_fd(); -//! -//! // use fd with native unix bindings -//! } -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] - -/// Unix-specific extensions to general I/O primitives -#[stable(feature = "rust1", since = "1.0.0")] -pub mod io { - use fs; - use libc; - use net; - use sys_common::{net2, AsInner, FromInner}; - use sys; - - /// Raw file descriptors. - #[stable(feature = "rust1", since = "1.0.0")] - pub type RawFd = libc::c_int; - - /// A trait to extract the raw unix 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 `AsRawHandle` - /// and `AsRawSocket` set of traits. - #[stable(feature = "rust1", since = "1.0.0")] - 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 guarantee to be valid while - /// the original object has not yet been destroyed. - #[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. - #[unstable(feature = "from_raw_os", - reason = "recent addition to std::os::unix::io")] - pub trait FromRawFd { - /// Constructs a new instances 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; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs2::File::from_inner(fd)) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } - } - - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(net2::TcpStream::from_inner(socket)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(net2::TcpListener::from_inner(socket)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket)) - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// OsString and OsStr -//////////////////////////////////////////////////////////////////////////////// - -/// Unix-specific extension to the primitives in the `std::ffi` module -#[stable(feature = "rust1", since = "1.0.0")] -pub mod ffi { - use ffi::{OsStr, OsString}; - use mem; - use prelude::v1::*; - use sys::os_str::Buf; - use sys_common::{FromInner, IntoInner, AsInner}; - - /// Unix-specific extensions to `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStringExt { - /// Creates an `OsString` from a byte vector. - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec<u8>) -> Self; - - /// Yields the underlying byte vector of this `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec<u8>; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl OsStringExt for OsString { - fn from_vec(vec: Vec<u8>) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec<u8> { - self.into_inner().inner - } - } - - /// Unix-specific extensions to `OsStr`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the `OsStr` slice. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } - } -} - -/// Unix-specific extensions to primitives in the `std::fs` module. -#[unstable(feature = "fs_ext", - reason = "may want a more useful mode abstraction")] -pub mod fs { - use sys; - use sys_common::{FromInner, AsInner, AsInnerMut}; - use fs::{Permissions, OpenOptions}; - use path::Path; - use convert::AsRef; - use io; - - /// Unix-specific extensions to `Permissions` - pub trait PermissionsExt { - fn mode(&self) -> i32; - fn set_mode(&mut self, mode: i32); - } - - impl PermissionsExt for Permissions { - fn mode(&self) -> i32 { self.as_inner().mode() } - - fn set_mode(&mut self, mode: i32) { - *self = FromInner::from_inner(FromInner::from_inner(mode)); - } - } - - /// Unix-specific extensions to `OpenOptions` - pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of a `File::open_opts` call then this - /// specified `mode` will be used as the permission bits for the new file. - fn mode(&mut self, mode: i32) -> &mut Self; - } - - impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: i32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - } - - /// Creates a new symbolic link on the filesystem. - /// - /// The `dst` path will be a symbolic link pointing to the `src` path. - /// - /// # Note - /// - /// On Windows, you must specify whether a symbolic link points to a file - /// or directory. Use `os::windows::fs::symlink_file` to create a - /// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a - /// symbolic link to a directory. Additionally, the process must have - /// `SeCreateSymbolicLinkPrivilege` in order to be able to create a - /// symbolic link. - /// - /// # Examples - /// - /// ``` - /// #![feature(fs_ext)] - /// use std::os::unix::fs; - /// - /// # fn foo() -> std::io::Result<()> { - /// try!(fs::symlink("a.txt", "b.txt")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> - { - sys::fs2::symlink(src.as_ref(), dst.as_ref()) - } - -} - -//////////////////////////////////////////////////////////////////////////////// -// Process and Command -//////////////////////////////////////////////////////////////////////////////// - -/// Unix-specific extensions to primitives in the `std::process` module. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod process { - use prelude::v1::*; - use libc::{uid_t, gid_t}; - use process; - use sys; - use sys_common::{AsInnerMut, AsInner}; - - /// Unix-specific extensions to the `std::process::Command` builder - #[stable(feature = "rust1", since = "1.0.0")] - pub trait CommandExt { - /// 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: uid_t) -> &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: gid_t) -> &mut process::Command; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl CommandExt for process::Command { - fn uid(&mut self, id: uid_t) -> &mut process::Command { - self.as_inner_mut().uid = Some(id); - self - } - - fn gid(&mut self, id: gid_t) -> &mut process::Command { - self.as_inner_mut().gid = Some(id); - self - } - } - - /// Unix-specific extensions to `std::process::ExitStatus` - #[stable(feature = "rust1", since = "1.0.0")] - pub trait ExitStatusExt { - /// If the process was terminated by a signal, returns that signal. - #[stable(feature = "rust1", since = "1.0.0")] - fn signal(&self) -> Option<i32>; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ExitStatusExt for process::ExitStatus { - fn signal(&self) -> Option<i32> { - match *self.as_inner() { - sys::process2::ExitStatus::Signal(s) => Some(s), - _ => None - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Prelude -//////////////////////////////////////////////////////////////////////////////// - -/// 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)] - pub use super::io::{RawFd, AsRawFd}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] - pub use super::fs::{PermissionsExt, OpenOptionsExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::process::{CommandExt, ExitStatusExt}; -} diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs new file mode 100644 index 00000000000..825e74cabde --- /dev/null +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -0,0 +1,62 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extension to the primitives in the `std::ffi` module + +#![stable(feature = "rust1", since = "1.0.0")] + +use ffi::{OsStr, OsString}; +use mem; +use prelude::v1::*; +use sys::os_str::Buf; +use sys_common::{FromInner, IntoInner, AsInner}; + +/// Unix-specific extensions to `OsString`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt { + /// Creates an `OsString` from a byte vector. + #[stable(feature = "rust1", since = "1.0.0")] + fn from_vec(vec: Vec<u8>) -> Self; + + /// Yields the underlying byte vector of this `OsString`. + #[stable(feature = "rust1", since = "1.0.0")] + fn into_vec(self) -> Vec<u8>; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + fn from_vec(vec: Vec<u8>) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + fn into_vec(self) -> Vec<u8> { + self.into_inner().inner + } +} + +/// Unix-specific extensions to `OsStr`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt { + #[stable(feature = "rust1", since = "1.0.0")] + fn from_bytes(slice: &[u8]) -> &Self; + + /// Gets the underlying byte view of the `OsStr` slice. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_bytes(&self) -> &[u8]; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + fn from_bytes(slice: &[u8]) -> &OsStr { + unsafe { mem::transmute(slice) } + } + fn as_bytes(&self) -> &[u8] { + &self.as_inner().inner + } +} diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs new file mode 100644 index 00000000000..2e4ed38e50f --- /dev/null +++ b/src/libstd/sys/unix/ext/fs.rs @@ -0,0 +1,207 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extensions to primitives in the `std::fs` module. + +#![stable(feature = "rust1", since = "1.0.0")] + +use prelude::v1::*; + +use fs::{self, Permissions, OpenOptions}; +use io; +use mem; +use os::raw::c_long; +use os::unix::raw; +use path::Path; +use sys::platform; +use sys; +use sys_common::{FromInner, AsInner, AsInnerMut}; + +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_READ: raw::mode_t = 0o400; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_WRITE: raw::mode_t = 0o200; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_EXECUTE: raw::mode_t = 0o100; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_RWX: raw::mode_t = 0o700; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_READ: raw::mode_t = 0o040; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_WRITE: raw::mode_t = 0o020; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_EXECUTE: raw::mode_t = 0o010; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_RWX: raw::mode_t = 0o070; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_READ: raw::mode_t = 0o004; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_WRITE: raw::mode_t = 0o002; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_EXECUTE: raw::mode_t = 0o001; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_RWX: raw::mode_t = 0o007; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_READ: raw::mode_t = 0o444; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_WRITE: raw::mode_t = 0o222; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_EXECUTE: raw::mode_t = 0o111; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_RWX: raw::mode_t = 0o777; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const SETUID: raw::mode_t = 0o4000; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const SETGID: raw::mode_t = 0o2000; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const STICKY_BIT: raw::mode_t = 0o1000; + +/// Unix-specific extensions to `Permissions` +#[unstable(feature = "fs_ext", + reason = "may want a more useful mode abstraction")] +pub trait PermissionsExt { + fn mode(&self) -> raw::mode_t; + fn set_mode(&mut self, mode: raw::mode_t); + fn from_mode(mode: raw::mode_t) -> Self; +} + +impl PermissionsExt for Permissions { + fn mode(&self) -> raw::mode_t { self.as_inner().mode() } + + fn set_mode(&mut self, mode: raw::mode_t) { + *self = FromInner::from_inner(FromInner::from_inner(mode)); + } + + fn from_mode(mode: raw::mode_t) -> Permissions { + FromInner::from_inner(FromInner::from_inner(mode)) + } +} + +/// Unix-specific extensions to `OpenOptions` +#[unstable(feature = "fs_ext", + reason = "may want a more useful mode abstraction")] +pub trait OpenOptionsExt { + /// Sets the mode bits that a new file will be created with. + /// + /// If a new file is created as part of a `File::open_opts` call then this + /// specified `mode` will be used as the permission bits for the new file. + fn mode(&mut self, mode: raw::mode_t) -> &mut Self; +} + +impl OpenOptionsExt for OpenOptions { + fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions { + self.as_inner_mut().mode(mode); self + } +} + +#[unstable(feature = "metadata_ext", reason = "recently added API")] +pub struct Metadata(sys::fs2::FileAttr); + +#[unstable(feature = "metadata_ext", reason = "recently added API")] +pub trait MetadataExt { + fn as_raw(&self) -> &Metadata; +} + +impl MetadataExt for fs::Metadata { + fn as_raw(&self) -> &Metadata { + let inner: &sys::fs2::FileAttr = self.as_inner(); + unsafe { mem::transmute(inner) } + } +} + +impl AsInner<platform::raw::stat> for Metadata { + fn as_inner(&self) -> &platform::raw::stat { self.0.as_inner() } +} + +// Hm, why are there casts here to the returned type, shouldn't the types always +// be the same? Right you are! Turns out, however, on android at least the types +// in the raw `stat` structure are not the same as the types being returned. Who +// knew! +// +// As a result to make sure this compiles for all platforms we do the manual +// casts and rely on manual lowering to `stat` if the raw type is desired. +#[unstable(feature = "metadata_ext", reason = "recently added API")] +impl Metadata { + pub fn dev(&self) -> raw::dev_t { self.0.raw().st_dev as raw::dev_t } + pub fn ino(&self) -> raw::ino_t { self.0.raw().st_ino as raw::ino_t } + pub fn mode(&self) -> raw::mode_t { self.0.raw().st_mode as raw::mode_t } + pub fn nlink(&self) -> raw::nlink_t { self.0.raw().st_nlink as raw::nlink_t } + pub fn uid(&self) -> raw::uid_t { self.0.raw().st_uid as raw::uid_t } + pub fn gid(&self) -> raw::gid_t { self.0.raw().st_gid as raw::gid_t } + pub fn rdev(&self) -> raw::dev_t { self.0.raw().st_rdev as raw::dev_t } + pub fn size(&self) -> raw::off_t { self.0.raw().st_size as raw::off_t } + pub fn atime(&self) -> raw::time_t { self.0.raw().st_atime } + pub fn atime_nsec(&self) -> c_long { self.0.raw().st_atime } + pub fn mtime(&self) -> raw::time_t { self.0.raw().st_mtime } + pub fn mtime_nsec(&self) -> c_long { self.0.raw().st_mtime } + pub fn ctime(&self) -> raw::time_t { self.0.raw().st_ctime } + pub fn ctime_nsec(&self) -> c_long { self.0.raw().st_ctime } + + pub fn blksize(&self) -> raw::blksize_t { + self.0.raw().st_blksize as raw::blksize_t + } + pub fn blocks(&self) -> raw::blkcnt_t { + self.0.raw().st_blocks as raw::blkcnt_t + } +} + +#[unstable(feature = "dir_entry_ext", reason = "recently added API")] +pub trait DirEntryExt { + fn ino(&self) -> raw::ino_t; +} + +impl DirEntryExt for fs::DirEntry { + fn ino(&self) -> raw::ino_t { self.as_inner().ino() } +} + +/// Creates a new symbolic link on the filesystem. +/// +/// The `dst` path will be a symbolic link pointing to the `src` path. +/// +/// # Note +/// +/// On Windows, you must specify whether a symbolic link points to a file +/// or directory. Use `os::windows::fs::symlink_file` to create a +/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a +/// symbolic link to a directory. Additionally, the process must have +/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a +/// symbolic link. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::symlink("a.txt", "b.txt")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> +{ + sys::fs2::symlink(src.as_ref(), dst.as_ref()) +} + +#[unstable(feature = "dir_builder", reason = "recently added API")] +/// An extension trait for `fs::DirBuilder` for unix-specific options. +pub trait DirBuilderExt { + /// Sets the mode to create new directories with. This option defaults to + /// 0o777. + fn mode(&mut self, mode: raw::mode_t) -> &mut Self; +} + +impl DirBuilderExt for fs::DirBuilder { + fn mode(&mut self, mode: raw::mode_t) -> &mut fs::DirBuilder { + self.as_inner_mut().set_mode(mode); + self + } +} + diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs new file mode 100644 index 00000000000..8cb4b4907f6 --- /dev/null +++ b/src/libstd/sys/unix/ext/io.rs @@ -0,0 +1,108 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extensions to general I/O primitives + +#![stable(feature = "rust1", since = "1.0.0")] + +use fs; +use net; +use os::raw; +use sys; +use sys_common::{net2, AsInner, FromInner}; + +/// Raw file descriptors. +#[stable(feature = "rust1", since = "1.0.0")] +pub type RawFd = raw::c_int; + +/// A trait to extract the raw unix 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 `AsRawHandle` +/// and `AsRawSocket` set of traits. +#[stable(feature = "rust1", since = "1.0.0")] +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 guarantee to be valid while + /// the original object has not yet been destroyed. + #[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. +#[unstable(feature = "from_raw_os", + reason = "recent addition to std::os::unix::io")] +pub trait FromRawFd { + /// Constructs a new instances 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; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for fs::File { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for fs::File { + unsafe fn from_raw_fd(fd: RawFd) -> fs::File { + fs::File::from_inner(sys::fs2::File::from_inner(fd)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } +} + +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + let socket = sys::net::Socket::from_inner(fd); + net::TcpStream::from_inner(net2::TcpStream::from_inner(socket)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + let socket = sys::net::Socket::from_inner(fd); + net::TcpListener::from_inner(net2::TcpListener::from_inner(socket)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + let socket = sys::net::Socket::from_inner(fd); + net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket)) + } +} diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs new file mode 100644 index 00000000000..6fde45a7301 --- /dev/null +++ b/src/libstd/sys/unix/ext/mod.rs @@ -0,0 +1,53 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Experimental extensions to `std` for Unix platforms. +//! +//! For now, this module is limited to extracting file descriptors, +//! but its functionality will grow over time. +//! +//! # Example +//! +//! ```no_run +//! use std::fs::File; +//! use std::os::unix::prelude::*; +//! +//! fn main() { +//! let f = File::create("foo.txt").unwrap(); +//! let fd = f.as_raw_fd(); +//! +//! // use fd with native unix bindings +//! } +//! ``` + +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod io; +pub mod ffi; +pub mod fs; +pub mod process; +pub mod raw; + +/// 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)] + pub use super::io::{RawFd, AsRawFd}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt}; + #[doc(no_inline)] + pub use super::fs::{DirEntryExt}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use super::process::{CommandExt, ExitStatusExt}; +} diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs new file mode 100644 index 00000000000..8c9d0a86583 --- /dev/null +++ b/src/libstd/sys/unix/ext/process.rs @@ -0,0 +1,65 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extensions to primitives in the `std::process` module. + +#![stable(feature = "rust1", since = "1.0.0")] + +use os::unix::raw::{uid_t, gid_t}; +use prelude::v1::*; +use process; +use sys; +use sys_common::{AsInnerMut, AsInner}; + +/// Unix-specific extensions to the `std::process::Command` builder +#[stable(feature = "rust1", since = "1.0.0")] +pub trait CommandExt { + /// 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: uid_t) -> &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: gid_t) -> &mut process::Command; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl CommandExt for process::Command { + fn uid(&mut self, id: uid_t) -> &mut process::Command { + self.as_inner_mut().uid = Some(id); + self + } + + fn gid(&mut self, id: gid_t) -> &mut process::Command { + self.as_inner_mut().gid = Some(id); + self + } +} + +/// Unix-specific extensions to `std::process::ExitStatus` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait ExitStatusExt { + /// If the process was terminated by a signal, returns that signal. + #[stable(feature = "rust1", since = "1.0.0")] + fn signal(&self) -> Option<i32>; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExitStatusExt for process::ExitStatus { + fn signal(&self) -> Option<i32> { + match *self.as_inner() { + sys::process2::ExitStatus::Signal(s) => Some(s), + _ => None + } + } +} diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs new file mode 100644 index 00000000000..8fe4b90456a --- /dev/null +++ b/src/libstd/sys/unix/ext/raw.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific primitives available on all unix platforms + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub type uid_t = u32; +pub type gid_t = u32; +pub type pid_t = i32; + +#[doc(inline)] +pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t}; +#[doc(inline)] +pub use sys::platform::raw::{blkcnt_t, time_t}; diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index 8eb84b26f22..350161c751c 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -21,14 +21,15 @@ use path::{Path, PathBuf}; use ptr; use sync::Arc; use sys::fd::FileDesc; +use sys::platform::raw; use sys::{c, cvt, cvt_r}; -use sys_common::FromInner; +use sys_common::{AsInner, FromInner}; use vec::Vec; pub struct File(FileDesc); pub struct FileAttr { - stat: libc::stat, + stat: raw::stat, } pub struct ReadDir { @@ -57,13 +58,12 @@ pub struct OpenOptions { #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { mode: mode_t } +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct FileType { mode: mode_t } + +pub struct DirBuilder { mode: mode_t } + impl FileAttr { - pub fn is_dir(&self) -> bool { - (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFDIR - } - pub fn is_file(&self) -> bool { - (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFREG - } pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 } @@ -76,12 +76,35 @@ impl FileAttr { self.mktime(self.stat.st_mtime as u64, self.stat.st_mtime_nsec as u64) } + pub fn file_type(&self) -> FileType { + FileType { mode: self.stat.st_mode as mode_t } + } + + pub fn raw(&self) -> &raw::stat { &self.stat } + // times are in milliseconds (currently) fn mktime(&self, secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } } +impl AsInner<raw::stat> for FileAttr { + fn as_inner(&self) -> &raw::stat { &self.stat } +} + +#[unstable(feature = "metadata_ext", reason = "recently added API")] +pub trait MetadataExt { + fn as_raw_stat(&self) -> &raw::stat; +} + +impl MetadataExt for ::fs::Metadata { + fn as_raw_stat(&self) -> &raw::stat { &self.as_inner().stat } +} + +impl MetadataExt for ::os::unix::fs::Metadata { + fn as_raw_stat(&self) -> &raw::stat { self.as_inner() } +} + impl FilePermissions { pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 } pub fn set_readonly(&mut self, readonly: bool) { @@ -91,11 +114,19 @@ impl FilePermissions { self.mode |= 0o222; } } - pub fn mode(&self) -> i32 { self.mode as i32 } + pub fn mode(&self) -> raw::mode_t { self.mode } } -impl FromInner<i32> for FilePermissions { - fn from_inner(mode: i32) -> FilePermissions { +impl FileType { + pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) } + pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) } + pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) } + + fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } +} + +impl FromInner<raw::mode_t> for FilePermissions { + fn from_inner(mode: raw::mode_t) -> FilePermissions { FilePermissions { mode: mode as mode_t } } } @@ -147,6 +178,33 @@ impl DirEntry { self.root.join(<OsStr as OsStrExt>::from_bytes(self.name_bytes())) } + pub fn file_name(&self) -> OsString { + OsStr::from_bytes(self.name_bytes()).to_os_string() + } + + pub fn metadata(&self) -> io::Result<FileAttr> { + lstat(&self.path()) + } + + pub fn file_type(&self) -> io::Result<FileType> { + extern { + fn rust_dir_get_mode(ptr: *mut libc::dirent_t) -> c_int; + } + unsafe { + match rust_dir_get_mode(self.dirent()) { + -1 => lstat(&self.path()).map(|m| m.file_type()), + n => Ok(FileType { mode: n as mode_t }), + } + } + } + + pub fn ino(&self) -> raw::ino_t { + extern { + fn rust_dir_get_ino(ptr: *mut libc::dirent_t) -> raw::ino_t; + } + unsafe { rust_dir_get_ino(self.dirent()) } + } + fn name_bytes(&self) -> &[u8] { extern { fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char; @@ -191,7 +249,7 @@ impl OpenOptions { self.flag(libc::O_CREAT, create); } - pub fn mode(&mut self, mode: i32) { + pub fn mode(&mut self, mode: raw::mode_t) { self.mode = mode as mode_t; } @@ -228,8 +286,10 @@ impl File { pub fn into_fd(self) -> FileDesc { self.0 } pub fn file_attr(&self) -> io::Result<FileAttr> { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - try!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) })); + let mut stat: raw::stat = unsafe { mem::zeroed() }; + try!(cvt(unsafe { + libc::fstat(self.0.raw(), &mut stat as *mut _ as *mut _) + })); Ok(FileAttr { stat: stat }) } @@ -284,6 +344,22 @@ impl File { pub fn fd(&self) -> &FileDesc { &self.0 } } +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder { mode: 0o777 } + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let p = try!(cstr(p)); + try!(cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })); + Ok(()) + } + + pub fn set_mode(&mut self, mode: mode_t) { + self.mode = mode; + } +} + fn cstr(path: &Path) -> io::Result<CString> { path.as_os_str().to_cstring().ok_or( io::Error::new(io::ErrorKind::InvalidInput, "path contained a null")) @@ -343,12 +419,6 @@ impl fmt::Debug for File { } } -pub fn mkdir(p: &Path) -> io::Result<()> { - let p = try!(cstr(p)); - try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) })); - Ok(()) -} - pub fn readdir(p: &Path) -> io::Result<ReadDir> { let root = Arc::new(p.to_path_buf()); let p = try!(cstr(p)); @@ -420,15 +490,19 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result<FileAttr> { let p = try!(cstr(p)); - let mut stat: libc::stat = unsafe { mem::zeroed() }; - try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) })); + let mut stat: raw::stat = unsafe { mem::zeroed() }; + try!(cvt(unsafe { + libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) + })); Ok(FileAttr { stat: stat }) } pub fn lstat(p: &Path) -> io::Result<FileAttr> { let p = try!(cstr(p)); - let mut stat: libc::stat = unsafe { mem::zeroed() }; - try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) })); + let mut stat: raw::stat = unsafe { mem::zeroed() }; + try!(cvt(unsafe { + libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) + })); Ok(FileAttr { stat: stat }) } @@ -438,3 +512,17 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) })); Ok(()) } + +pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { + let path = try!(CString::new(p.as_os_str().as_bytes())); + let mut buf = vec![0u8; 16 * 1024]; + unsafe { + let r = c::realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _); + if r.is_null() { + return Err(io::Error::last_os_error()) + } + } + let p = buf.iter().position(|i| *i == 0).unwrap(); + buf.truncate(p); + Ok(PathBuf::from(OsString::from_vec(buf))) +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index d99753a6a4c..78b798d3bff 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -18,6 +18,16 @@ use libc; use num::One; use ops::Neg; +#[cfg(target_os = "android")] pub use os::android as platform; +#[cfg(target_os = "bitrig")] pub use os::bitrig as platform; +#[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform; +#[cfg(target_os = "freebsd")] pub use os::freebsd as platform; +#[cfg(target_os = "ios")] pub use os::ios as platform; +#[cfg(target_os = "linux")] pub use os::linux as platform; +#[cfg(target_os = "macos")] pub use os::macos as platform; +#[cfg(target_os = "nacl")] pub use os::nacl as platform; +#[cfg(target_os = "openbsd")] pub use os::openbsd as platform; + pub mod backtrace; pub mod c; pub mod condvar; diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 385834a6226..d94dfdeeea4 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -283,7 +283,6 @@ mod arch { } } -#[repr(C)] struct Cleanup { handle: libc::HANDLE, SymCleanup: SymCleanupFn, diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs deleted file mode 100644 index dd747d202a0..00000000000 --- a/src/libstd/sys/windows/ext.rs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Experimental extensions to `std` for Windows. -//! -//! For now, this module is limited to extracting handles, file -//! descriptors, and sockets, but its functionality will grow over -//! time. - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod io { - use fs; - use libc; - use net; - use sys_common::{net2, AsInner, FromInner}; - use sys; - - /// Raw HANDLEs. - #[stable(feature = "rust1", since = "1.0.0")] - pub type RawHandle = libc::HANDLE; - - /// Raw SOCKETs. - #[stable(feature = "rust1", since = "1.0.0")] - pub type RawSocket = libc::SOCKET; - - /// Extract raw handles. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait AsRawHandle { - /// Extracts the raw handle, without taking any ownership. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_handle(&self) -> RawHandle; - } - - /// Construct I/O objects from raw handles. - #[unstable(feature = "from_raw_os", - reason = "recent addition to the std::os::windows::io module")] - pub trait FromRawHandle { - /// Constructs a new I/O object from the specified raw handle. - /// - /// This function will **consume ownership** of the handle given, - /// passing responsibility for closing the handle to the returned - /// object. - /// - /// 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_handle(handle: RawHandle) -> Self; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawHandle for fs::File { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() - } - } - - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawHandle for fs::File { - unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - fs::File::from_inner(sys::fs2::File::from_inner(handle)) - } - } - - /// Extract raw sockets. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait AsRawSocket { - /// Extracts the underlying raw socket from this object. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_socket(&self) -> RawSocket; - } - - /// Create I/O objects from raw sockets. - #[unstable(feature = "from_raw_os", reason = "recent addition to module")] - pub trait FromRawSocket { - /// Creates a new I/O object from the given raw socket. - /// - /// This function will **consume ownership** of the socket provided and - /// it will be closed when the returned 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_socket(sock: RawSocket) -> Self; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for net::TcpStream { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for net::TcpListener { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for net::UdpSocket { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } - } - - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawSocket for net::TcpStream { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(sock); - net::TcpStream::from_inner(net2::TcpStream::from_inner(sock)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawSocket for net::TcpListener { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(sock); - net::TcpListener::from_inner(net2::TcpListener::from_inner(sock)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawSocket for net::UdpSocket { - unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(sock); - net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock)) - } - } -} - -/// Windows-specific extensions to the primitives in the `std::ffi` module. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod ffi { - use ffi::{OsString, OsStr}; - use sys::os_str::Buf; - use sys_common::wtf8::Wtf8Buf; - use sys_common::{FromInner, AsInner}; - - pub use sys_common::wtf8::EncodeWide; - - /// Windows-specific extensions to `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStringExt { - /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of - /// 16-bit code units. - /// - /// This is lossless: calling `.encode_wide()` on the resulting string - /// will always return the original code units. - #[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`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStrExt { - /// Re-encodes an `OsStr` as a wide character sequence, - /// i.e. potentially ill-formed UTF-16. - /// - /// This is lossless. Note that the encoding does not include a final - /// null. - #[stable(feature = "rust1", since = "1.0.0")] - fn encode_wide(&self) -> EncodeWide; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl OsStrExt for OsStr { - fn encode_wide(&self) -> EncodeWide { - self.as_inner().inner.encode_wide() - } - } -} - -/// Windows-specific extensions for the primitives in `std::fs` -#[unstable(feature = "fs_ext", reason = "may require more thought/methods")] -pub mod fs { - use fs::OpenOptions; - use sys; - use sys_common::AsInnerMut; - use path::Path; - use convert::AsRef; - use io; - - /// Windows-specific extensions to `OpenOptions` - pub trait OpenOptionsExt { - /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` - /// with the specified value. - fn desired_access(&mut self, access: i32) -> &mut Self; - - /// Overrides the `dwCreationDisposition` argument to the call to - /// `CreateFile` with the specified value. - /// - /// This will override any values of the standard `create` flags, for - /// example. - fn creation_disposition(&mut self, val: i32) -> &mut Self; - - /// Overrides the `dwFlagsAndAttributes` argument to the call to - /// `CreateFile` with the specified value. - /// - /// This will override any values of the standard flags on the - /// `OpenOptions` structure. - fn flags_and_attributes(&mut self, val: i32) -> &mut Self; - - /// Overrides the `dwShareMode` argument to the call to `CreateFile` with - /// the specified value. - /// - /// This will override any values of the standard flags on the - /// `OpenOptions` structure. - fn share_mode(&mut self, val: i32) -> &mut Self; - } - - impl OpenOptionsExt for OpenOptions { - fn desired_access(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().desired_access(access); self - } - fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().creation_disposition(access); self - } - fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().flags_and_attributes(access); self - } - fn share_mode(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().share_mode(access); self - } - } - - /// Creates a new file symbolic link on the filesystem. - /// - /// The `dst` path will be a file symbolic link pointing to the `src` - /// path. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(fs_ext)] - /// use std::os::windows::fs; - /// - /// # fn foo() -> std::io::Result<()> { - /// try!(fs::symlink_file("a.txt", "b.txt")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) - -> io::Result<()> - { - sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false) - } - - /// Creates a new directory symlink on the filesystem. - /// - /// The `dst` path will be a directory symbolic link pointing to the `src` - /// path. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(fs_ext)] - /// use std::os::windows::fs; - /// - /// # fn foo() -> std::io::Result<()> { - /// try!(fs::symlink_file("a", "b")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>> (src: P, dst: Q) - -> io::Result<()> - { - sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true) - } -} - -/// 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)] - pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] - pub use super::fs::OpenOptionsExt; -} diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs new file mode 100644 index 00000000000..3fa96f4dd13 --- /dev/null +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -0,0 +1,58 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Windows-specific extensions to the primitives in the `std::ffi` module. + +#![stable(feature = "rust1", since = "1.0.0")] + +use ffi::{OsString, OsStr}; +use sys::os_str::Buf; +use sys_common::wtf8::Wtf8Buf; +use sys_common::{FromInner, AsInner}; + +pub use sys_common::wtf8::EncodeWide; + +/// Windows-specific extensions to `OsString`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt { + /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of + /// 16-bit code units. + /// + /// This is lossless: calling `.encode_wide()` on the resulting string + /// will always return the original code units. + #[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`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt { + /// Re-encodes an `OsStr` as a wide character sequence, + /// i.e. potentially ill-formed UTF-16. + /// + /// This is lossless. Note that the encoding does not include a final + /// null. + #[stable(feature = "rust1", since = "1.0.0")] + fn encode_wide(&self) -> EncodeWide; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + fn encode_wide(&self) -> EncodeWide { + self.as_inner().inner.encode_wide() + } +} diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs new file mode 100644 index 00000000000..23c1fcf4b3c --- /dev/null +++ b/src/libstd/sys/windows/ext/fs.rs @@ -0,0 +1,150 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Windows-specific extensions for the primitives in `std::fs` + +#![stable(feature = "rust1", since = "1.0.0")] + +use prelude::v1::*; + +use fs::{OpenOptions, Metadata}; +use io; +use path::Path; +use sys; +use sys_common::{AsInnerMut, AsInner}; + +/// Windows-specific extensions to `OpenOptions` +#[unstable(feature = "fs_ext", reason = "may require more thought/methods")] +pub trait OpenOptionsExt { + /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` + /// with the specified value. + fn desired_access(&mut self, access: i32) -> &mut Self; + + /// Overrides the `dwCreationDisposition` argument to the call to + /// `CreateFile` with the specified value. + /// + /// This will override any values of the standard `create` flags, for + /// example. + fn creation_disposition(&mut self, val: i32) -> &mut Self; + + /// Overrides the `dwFlagsAndAttributes` argument to the call to + /// `CreateFile` with the specified value. + /// + /// This will override any values of the standard flags on the + /// `OpenOptions` structure. + fn flags_and_attributes(&mut self, val: i32) -> &mut Self; + + /// Overrides the `dwShareMode` argument to the call to `CreateFile` with + /// the specified value. + /// + /// This will override any values of the standard flags on the + /// `OpenOptions` structure. + fn share_mode(&mut self, val: i32) -> &mut Self; +} + +impl OpenOptionsExt for OpenOptions { + fn desired_access(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().desired_access(access); self + } + fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().creation_disposition(access); self + } + fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().flags_and_attributes(access); self + } + fn share_mode(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().share_mode(access); self + } +} + +/// Extension methods for `fs::Metadata` to access the raw fields contained +/// within. +#[unstable(feature = "metadata_ext", reason = "recently added API")] +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. + fn file_attributes(&self) -> u32; + + /// Returns the value of the `ftCreationTime` field of this metadata. + /// + /// The returned 64-bit value represents the number of 100-nanosecond + /// intervals since January 1, 1601 (UTC). + fn creation_time(&self) -> u64; + + /// Returns the value of the `ftLastAccessTime` field of this metadata. + /// + /// The returned 64-bit value represents the number of 100-nanosecond + /// intervals since January 1, 1601 (UTC). + fn last_access_time(&self) -> u64; + + /// Returns the value of the `ftLastWriteTime` field of this metadata. + /// + /// The returned 64-bit value represents the number of 100-nanosecond + /// intervals since January 1, 1601 (UTC). + 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. + fn file_size(&self) -> u64; +} + +impl MetadataExt for Metadata { + fn file_attributes(&self) -> u32 { self.as_inner().attrs() } + fn creation_time(&self) -> u64 { self.as_inner().created() } + fn last_access_time(&self) -> u64 { self.as_inner().accessed() } + fn last_write_time(&self) -> u64 { self.as_inner().modified() } + fn file_size(&self) -> u64 { self.as_inner().size() } +} + +/// Creates a new file symbolic link on the filesystem. +/// +/// The `dst` path will be a file symbolic link pointing to the `src` +/// path. +/// +/// # Examples +/// +/// ```ignore +/// use std::os::windows::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::symlink_file("a.txt", "b.txt")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) + -> io::Result<()> { + sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false) +} + +/// Creates a new directory symlink on the filesystem. +/// +/// The `dst` path will be a directory symbolic link pointing to the `src` +/// path. +/// +/// # Examples +/// +/// ```ignore +/// use std::os::windows::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::symlink_file("a", "b")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) + -> io::Result<()> { + sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true) +} diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs new file mode 100644 index 00000000000..b88a6316eee --- /dev/null +++ b/src/libstd/sys/windows/ext/io.rs @@ -0,0 +1,131 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "rust1", since = "1.0.0")] + +use fs; +use os::windows::raw; +use net; +use sys_common::{net2, AsInner, FromInner}; +use sys; + +/// 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; + +/// Extract raw handles. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawHandle { + /// Extracts the raw handle, without taking any ownership. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_handle(&self) -> RawHandle; +} + +/// Construct I/O objects from raw handles. +#[unstable(feature = "from_raw_os", + reason = "recent addition to the std::os::windows::io module")] +pub trait FromRawHandle { + /// Constructs a new I/O object from the specified raw handle. + /// + /// This function will **consume ownership** of the handle given, + /// passing responsibility for closing the handle to the returned + /// object. + /// + /// 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_handle(handle: RawHandle) -> Self; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawHandle for fs::File { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle().raw() as RawHandle + } +} + +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawHandle for fs::File { + unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { + let handle = handle as ::libc::HANDLE; + fs::File::from_inner(sys::fs2::File::from_inner(handle)) + } +} + +/// Extract raw sockets. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawSocket { + /// Extracts the underlying raw socket from this object. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_socket(&self) -> RawSocket; +} + +/// Create I/O objects from raw sockets. +#[unstable(feature = "from_raw_os", reason = "recent addition to module")] +pub trait FromRawSocket { + /// Creates a new I/O object from the given raw socket. + /// + /// This function will **consume ownership** of the socket provided and + /// it will be closed when the returned 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_socket(sock: RawSocket) -> Self; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::TcpStream { + fn as_raw_socket(&self) -> RawSocket { + *self.as_inner().socket().as_inner() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::TcpListener { + fn as_raw_socket(&self) -> RawSocket { + *self.as_inner().socket().as_inner() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::UdpSocket { + fn as_raw_socket(&self) -> RawSocket { + *self.as_inner().socket().as_inner() + } +} + +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawSocket for net::TcpStream { + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { + let sock = sys::net::Socket::from_inner(sock); + net::TcpStream::from_inner(net2::TcpStream::from_inner(sock)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawSocket for net::TcpListener { + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { + let sock = sys::net::Socket::from_inner(sock); + net::TcpListener::from_inner(net2::TcpListener::from_inner(sock)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawSocket for net::UdpSocket { + unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { + let sock = sys::net::Socket::from_inner(sock); + net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock)) + } +} diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs new file mode 100644 index 00000000000..08dfa4cc877 --- /dev/null +++ b/src/libstd/sys/windows/ext/mod.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Experimental extensions to `std` for Windows. +//! +//! For now, this module is limited to extracting handles, file +//! descriptors, and sockets, but its functionality will grow over +//! time. + +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod ffi; +pub mod fs; +pub mod io; +pub mod raw; + +/// 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)] + pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + pub use super::fs::{OpenOptionsExt, MetadataExt}; +} diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs new file mode 100644 index 00000000000..656e480ad09 --- /dev/null +++ b/src/libstd/sys/windows/ext/raw.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Windows-specific primitives + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +use os::raw; + +pub type HANDLE = *mut raw::c_void; +#[cfg(target_pointer_width = "32")] +pub type SOCKET = u32; +#[cfg(target_pointer_width = "64")] +pub type SOCKET = u64; diff --git a/src/libstd/sys/windows/fs2.rs b/src/libstd/sys/windows/fs2.rs index 5ac9a0ace58..03a56e2958a 100644 --- a/src/libstd/sys/windows/fs2.rs +++ b/src/libstd/sys/windows/fs2.rs @@ -27,7 +27,16 @@ use sys_common::FromInner; use vec::Vec; pub struct File { handle: Handle } -pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA } + +pub struct FileAttr { + data: c::WIN32_FILE_ATTRIBUTE_DATA, + is_symlink: bool, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum FileType { + Dir, File, Symlink, ReparsePoint +} pub struct ReadDir { handle: FindNextFileHandle, @@ -56,11 +65,14 @@ pub struct OpenOptions { share_mode: Option<libc::DWORD>, creation_disposition: Option<libc::DWORD>, flags_and_attributes: Option<libc::DWORD>, + security_attributes: usize, // *mut T doesn't have a Default impl } #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { attrs: libc::DWORD } +pub struct DirBuilder; + impl Iterator for ReadDir { type Item = io::Result<DirEntry>; fn next(&mut self) -> Option<io::Result<DirEntry>> { @@ -111,8 +123,31 @@ impl DirEntry { } pub fn path(&self) -> PathBuf { + self.root.join(&self.file_name()) + } + + pub fn file_name(&self) -> OsString { let filename = super::truncate_utf16_at_nul(&self.data.cFileName); - self.root.join(&<OsString as OsStringExt>::from_wide(filename)) + OsString::from_wide(filename) + } + + pub fn file_type(&self) -> io::Result<FileType> { + Ok(FileType::new(self.data.dwFileAttributes, + self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK)) + } + + pub fn metadata(&self) -> io::Result<FileAttr> { + Ok(FileAttr { + data: c::WIN32_FILE_ATTRIBUTE_DATA { + dwFileAttributes: self.data.dwFileAttributes, + ftCreationTime: self.data.ftCreationTime, + ftLastAccessTime: self.data.ftLastAccessTime, + ftLastWriteTime: self.data.ftLastWriteTime, + nFileSizeHigh: self.data.nFileSizeHigh, + nFileSizeLow: self.data.nFileSizeLow, + }, + is_symlink: self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK, + }) } } @@ -135,6 +170,9 @@ impl OpenOptions { pub fn share_mode(&mut self, val: i32) { self.share_mode = Some(val as libc::DWORD); } + pub fn security_attributes(&mut self, attrs: libc::LPSECURITY_ATTRIBUTES) { + self.security_attributes = attrs as usize; + } fn get_desired_access(&self) -> libc::DWORD { self.desired_access.unwrap_or({ @@ -180,13 +218,20 @@ impl OpenOptions { } impl File { + fn open_reparse_point(path: &Path) -> io::Result<File> { + let mut opts = OpenOptions::new(); + opts.read(true); + opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32); + File::open(path, &opts) + } + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { let path = to_utf16(path); let handle = unsafe { libc::CreateFileW(path.as_ptr(), opts.get_desired_access(), opts.get_share_mode(), - ptr::null_mut(), + opts.security_attributes as *mut _, opts.get_creation_disposition(), opts.get_flags_and_attributes(), ptr::null_mut()) @@ -224,7 +269,7 @@ impl File { let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed(); try!(cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))); - Ok(FileAttr { + let mut attr = FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA { dwFileAttributes: info.dwFileAttributes, ftCreationTime: info.ftCreationTime, @@ -232,8 +277,13 @@ impl File { ftLastWriteTime: info.ftLastWriteTime, nFileSizeHigh: info.nFileSizeHigh, nFileSizeLow: info.nFileSizeLow, - } - }) + }, + is_symlink: false, + }; + if attr.is_reparse_point() { + attr.is_symlink = self.is_symlink(); + } + Ok(attr) } } @@ -263,6 +313,43 @@ impl File { } pub fn handle(&self) -> &Handle { &self.handle } + + fn is_symlink(&self) -> bool { + self.readlink().is_ok() + } + + fn readlink(&self) -> io::Result<PathBuf> { + let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut bytes = 0; + + unsafe { + try!(cvt({ + c::DeviceIoControl(self.handle.raw(), + c::FSCTL_GET_REPARSE_POINT, + 0 as *mut _, + 0, + space.as_mut_ptr() as *mut _, + space.len() as libc::DWORD, + &mut bytes, + 0 as *mut _) + })); + let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _; + if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK { + return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) + } + let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = + &(*buf).rest as *const _ as *const _; + let path_buffer = &(*info).PathBuffer as *const _ as *const u16; + let subst_off = (*info).SubstituteNameOffset / 2; + let subst_ptr = path_buffer.offset(subst_off as isize); + let subst_len = (*info).SubstituteNameLength / 2; + let subst = slice::from_raw_parts(subst_ptr, subst_len as usize); + + Ok(PathBuf::from(OsString::from_wide(subst))) + } + } + + pub fn into_handle(self) -> Handle { self.handle } } impl FromInner<libc::HANDLE> for File { @@ -285,27 +372,30 @@ pub fn to_utf16(s: &Path) -> Vec<u16> { } impl FileAttr { - pub fn is_dir(&self) -> bool { - self.data.dwFileAttributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 - } - pub fn is_file(&self) -> bool { - !self.is_dir() - } pub fn size(&self) -> u64 { ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64) } + pub fn perm(&self) -> FilePermissions { FilePermissions { attrs: self.data.dwFileAttributes } } - pub fn accessed(&self) -> u64 { self.to_ms(&self.data.ftLastAccessTime) } - pub fn modified(&self) -> u64 { self.to_ms(&self.data.ftLastWriteTime) } + pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 } - fn to_ms(&self, ft: &libc::FILETIME) -> u64 { - // FILETIME is in 100ns intervals and there are 10000 intervals in a - // millisecond. - let bits = (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32); - bits / 10000 + pub fn file_type(&self) -> FileType { + FileType::new(self.data.dwFileAttributes, self.is_symlink) + } + + pub fn created(&self) -> u64 { self.to_u64(&self.data.ftCreationTime) } + pub fn accessed(&self) -> u64 { self.to_u64(&self.data.ftLastAccessTime) } + pub fn modified(&self) -> u64 { self.to_u64(&self.data.ftLastWriteTime) } + + fn to_u64(&self, ft: &libc::FILETIME) -> u64 { + (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32) + } + + fn is_reparse_point(&self) -> bool { + self.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 } } @@ -323,12 +413,36 @@ impl FilePermissions { } } -pub fn mkdir(p: &Path) -> io::Result<()> { - let p = to_utf16(p); - try!(cvt(unsafe { - libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) - })); - Ok(()) +impl FileType { + fn new(attrs: libc::DWORD, is_symlink: bool) -> FileType { + if attrs & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + if is_symlink { + FileType::Symlink + } else { + FileType::ReparsePoint + } + } else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 { + FileType::Dir + } else { + FileType::File + } + } + + pub fn is_dir(&self) -> bool { *self == FileType::Dir } + pub fn is_file(&self) -> bool { *self == FileType::File } + pub fn is_symlink(&self) -> bool { *self == FileType::Symlink } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { DirBuilder } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let p = to_utf16(p); + try!(cvt(unsafe { + libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) + })); + Ok(()) + } } pub fn readdir(p: &Path) -> io::Result<ReadDir> { @@ -374,40 +488,8 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let mut opts = OpenOptions::new(); - opts.read(true); - opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32); - let file = try!(File::open(p, &opts)); - - let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let mut bytes = 0; - - unsafe { - try!(cvt({ - c::DeviceIoControl(file.handle.raw(), - c::FSCTL_GET_REPARSE_POINT, - 0 as *mut _, - 0, - space.as_mut_ptr() as *mut _, - space.len() as libc::DWORD, - &mut bytes, - 0 as *mut _) - })); - let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _; - if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK { - return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) - } - let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = - &(*buf).rest as *const _ as *const _; - let path_buffer = &(*info).PathBuffer as *const _ as *const u16; - let subst_off = (*info).SubstituteNameOffset / 2; - let subst_ptr = path_buffer.offset(subst_off as isize); - let subst_len = (*info).SubstituteNameLength / 2; - let subst = slice::from_raw_parts(subst_ptr, subst_len as usize); - - Ok(PathBuf::from(OsString::from_wide(subst))) - } - + let file = try!(File::open_reparse_point(p)); + file.readlink() } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { @@ -435,12 +517,28 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result<FileAttr> { - let p = to_utf16(p); + let attr = try!(lstat(p)); + if attr.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + let opts = OpenOptions::new(); + let file = try!(File::open(p, &opts)); + file.file_attr() + } else { + Ok(attr) + } +} + +pub fn lstat(p: &Path) -> io::Result<FileAttr> { + let utf16 = to_utf16(p); unsafe { let mut attr: FileAttr = mem::zeroed(); - try!(cvt(c::GetFileAttributesExW(p.as_ptr(), + try!(cvt(c::GetFileAttributesExW(utf16.as_ptr(), c::GetFileExInfoStandard, &mut attr.data as *mut _ as *mut _))); + if attr.is_reparse_point() { + attr.is_symlink = File::open_reparse_point(p).map(|f| { + f.is_symlink() + }).unwrap_or(false); + } Ok(attr) } } @@ -465,3 +563,17 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { })); Ok(()) } + +pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { + use sys::c::compat::kernel32::GetFinalPathNameByHandleW; + + let mut opts = OpenOptions::new(); + opts.read(true); + let f = try!(File::open(p, &opts)); + super::fill_utf16_buf(|buf, sz| unsafe { + GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, + libc::VOLUME_NAME_DOS) + }, |buf| { + PathBuf::from(OsString::from_wide(buf)) + }) +} diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index c3a30aae9e0..9481e180ce5 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -12,6 +12,7 @@ use prelude::v1::*; use io::ErrorKind; use io; +use libc::funcs::extra::kernel32::{GetCurrentProcess, DuplicateHandle}; use libc::{self, HANDLE}; use mem; use ptr; @@ -65,6 +66,18 @@ impl Handle { })); Ok(amt as usize) } + + pub fn duplicate(&self, access: libc::DWORD, inherit: bool, + options: libc::DWORD) -> io::Result<Handle> { + let mut ret = 0 as libc::HANDLE; + try!(cvt(unsafe { + let cur_proc = GetCurrentProcess(); + DuplicateHandle(cur_proc, self.0, cur_proc, &mut ret, + access, inherit as libc::BOOL, + options) + })); + Ok(Handle::new(ret)) + } } impl Drop for Handle { diff --git a/src/libstd/sys/windows/process2.rs b/src/libstd/sys/windows/process2.rs index 2e5585d2f43..5aad5f668dd 100644 --- a/src/libstd/sys/windows/process2.rs +++ b/src/libstd/sys/windows/process2.rs @@ -13,17 +13,23 @@ use prelude::v1::*; use ascii::*; use collections::HashMap; use collections; +use env::split_paths; use env; use ffi::{OsString, OsStr}; use fmt; use fs; use io::{self, Error}; use libc::{self, c_void}; +use mem; use os::windows::ffi::OsStrExt; +use path::Path; use ptr; use sync::{StaticMutex, MUTEX_INIT}; +use sys::c; +use sys::fs2::{OpenOptions, File}; use sys::handle::Handle; use sys::pipe2::AnonPipe; +use sys::stdio; use sys::{self, cvt}; use sys_common::{AsInner, FromInner}; @@ -90,18 +96,12 @@ impl Command { // Processes //////////////////////////////////////////////////////////////////////////////// -// `CreateProcess` is racy! -// http://support.microsoft.com/kb/315939 -static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT; - /// A value representing a child process. /// /// The lifetime of this value is linked to the lifetime of the actual /// process - the Process destructor calls self.finish() which waits /// for the process to terminate. pub struct Process { - /// A HANDLE to the process, which will prevent the pid being - /// re-used until the handle is closed. handle: Handle, } @@ -112,32 +112,17 @@ pub enum Stdio { } impl Process { - #[allow(deprecated)] pub fn spawn(cfg: &Command, - in_fd: Stdio, - out_fd: Stdio, - err_fd: Stdio) -> io::Result<Process> + in_handle: Stdio, + out_handle: Stdio, + err_handle: Stdio) -> io::Result<Process> { - use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; - use libc::consts::os::extra::{ - TRUE, FALSE, - STARTF_USESTDHANDLES, - INVALID_HANDLE_VALUE, - DUPLICATE_SAME_ACCESS - }; - use libc::funcs::extra::kernel32::{ - GetCurrentProcess, - DuplicateHandle, - CloseHandle, - CreateProcessW - }; - - use env::split_paths; - use mem; - use iter::Iterator; - - // To have the spawning semantics of unix/windows stay the same, we need to - // read the *child's* PATH if one is provided. See #15149 for more details. + use libc::{TRUE, STARTF_USESTDHANDLES}; + use libc::{DWORD, STARTUPINFO, CreateProcessW}; + + // To have the spawning semantics of unix/windows stay the same, we need + // to read the *child's* PATH if one is provided. See #15149 for more + // details. let program = cfg.env.as_ref().and_then(|env| { for (key, v) in env { if OsStr::new("PATH") != &**key { continue } @@ -156,118 +141,51 @@ impl Process { None }); - unsafe { - let mut si = zeroed_startupinfo(); - si.cb = mem::size_of::<STARTUPINFO>() as DWORD; - si.dwFlags = STARTF_USESTDHANDLES; - - let cur_proc = GetCurrentProcess(); - - let set_fd = |fd: &Stdio, slot: &mut HANDLE, - is_stdin: bool| { - match *fd { - Stdio::Inherit => {} - - // Similarly to unix, we don't actually leave holes for the - // stdio file descriptors, but rather open up /dev/null - // equivalents. These equivalents are drawn from libuv's - // windows process spawning. - Stdio::None => { - let access = if is_stdin { - libc::FILE_GENERIC_READ - } else { - libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES - }; - let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>(); - let mut sa = libc::SECURITY_ATTRIBUTES { - nLength: size as libc::DWORD, - lpSecurityDescriptor: ptr::null_mut(), - bInheritHandle: 1, - }; - let mut filename: Vec<u16> = "NUL".utf16_units().collect(); - filename.push(0); - *slot = libc::CreateFileW(filename.as_ptr(), - access, - libc::FILE_SHARE_READ | - libc::FILE_SHARE_WRITE, - &mut sa, - libc::OPEN_EXISTING, - 0, - ptr::null_mut()); - if *slot == INVALID_HANDLE_VALUE { - return Err(Error::last_os_error()) - } - } - Stdio::Piped(ref pipe) => { - let orig = pipe.handle().raw(); - if DuplicateHandle(cur_proc, orig, cur_proc, slot, - 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { - return Err(Error::last_os_error()) - } - } - } - Ok(()) - }; - - try!(set_fd(&in_fd, &mut si.hStdInput, true)); - try!(set_fd(&out_fd, &mut si.hStdOutput, false)); - try!(set_fd(&err_fd, &mut si.hStdError, false)); + let mut si = zeroed_startupinfo(); + si.cb = mem::size_of::<STARTUPINFO>() as DWORD; + si.dwFlags = STARTF_USESTDHANDLES; - let mut cmd_str = make_command_line(program.as_ref().unwrap_or(&cfg.program), - &cfg.args); - cmd_str.push(0); // add null terminator + let stdin = try!(in_handle.to_handle(c::STD_INPUT_HANDLE)); + let stdout = try!(out_handle.to_handle(c::STD_OUTPUT_HANDLE)); + let stderr = try!(err_handle.to_handle(c::STD_ERROR_HANDLE)); - let mut pi = zeroed_process_information(); - let mut create_err = None; - - // stolen from the libuv code. - let mut flags = libc::CREATE_UNICODE_ENVIRONMENT; - if cfg.detach { - flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; - } + si.hStdInput = stdin.raw(); + si.hStdOutput = stdout.raw(); + si.hStdError = stderr.raw(); - with_envp(cfg.env.as_ref(), |envp| { - with_dirp(cfg.cwd.as_ref(), |dirp| { - let _lock = CREATE_PROCESS_LOCK.lock().unwrap(); - let created = CreateProcessW(ptr::null(), - cmd_str.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - TRUE, - flags, envp, dirp, - &mut si, &mut pi); - if created == FALSE { - create_err = Some(Error::last_os_error()); - } - }) - }); + let program = program.as_ref().unwrap_or(&cfg.program); + let mut cmd_str = make_command_line(program, &cfg.args); + cmd_str.push(0); // add null terminator - if !in_fd.inherited() { - assert!(CloseHandle(si.hStdInput) != 0); - } - if !out_fd.inherited() { - assert!(CloseHandle(si.hStdOutput) != 0); - } - if !err_fd.inherited() { - assert!(CloseHandle(si.hStdError) != 0); - } + // stolen from the libuv code. + let mut flags = libc::CREATE_UNICODE_ENVIRONMENT; + if cfg.detach { + flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; + } - match create_err { - Some(err) => return Err(err), - None => {} - } + let (envp, _data) = make_envp(cfg.env.as_ref()); + let (dirp, _data) = make_dirp(cfg.cwd.as_ref()); + let mut pi = zeroed_process_information(); + try!(unsafe { + // `CreateProcess` is racy! + // http://support.microsoft.com/kb/315939 + static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT; + let _lock = CREATE_PROCESS_LOCK.lock(); + + cvt(CreateProcessW(ptr::null(), + cmd_str.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + TRUE, flags, envp, dirp, + &mut si, &mut pi)) + }); - // We close the thread handle because we don't care about keeping the - // thread id valid, and we aren't keeping the thread handle around to be - // able to close it later. We don't close the process handle however - // because std::we want the process id to stay valid at least until the - // calling code closes the process handle. - assert!(CloseHandle(pi.hThread) != 0); + // We close the thread handle because we don't care about keeping + // the thread id valid, and we aren't keeping the thread handle + // around to be able to close it later. + drop(Handle::new(pi.hThread)); - Ok(Process { - handle: Handle::new(pi.hProcess) - }) - } + Ok(Process { handle: Handle::new(pi.hProcess) }) } pub unsafe fn kill(&self) -> io::Result<()> { @@ -276,45 +194,25 @@ impl Process { } pub fn wait(&self) -> io::Result<ExitStatus> { - use libc::consts::os::extra::{ - FALSE, - STILL_ACTIVE, - INFINITE, - WAIT_OBJECT_0, - }; - use libc::funcs::extra::kernel32::{ - GetExitCodeProcess, - WaitForSingleObject, - }; + use libc::{STILL_ACTIVE, INFINITE, WAIT_OBJECT_0}; + use libc::{GetExitCodeProcess, WaitForSingleObject}; unsafe { loop { let mut status = 0; - if GetExitCodeProcess(self.handle.raw(), &mut status) == FALSE { - let err = Err(Error::last_os_error()); - return err; - } + try!(cvt(GetExitCodeProcess(self.handle.raw(), &mut status))); if status != STILL_ACTIVE { return Ok(ExitStatus(status as i32)); } match WaitForSingleObject(self.handle.raw(), INFINITE) { WAIT_OBJECT_0 => {} - _ => { - let err = Err(Error::last_os_error()); - return err - } + _ => return Err(Error::last_os_error()), } } } } } -impl Stdio { - fn inherited(&self) -> bool { - match *self { Stdio::Inherit => true, _ => false } - } -} - #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct ExitStatus(i32); @@ -415,9 +313,8 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> Vec<u16> { } } -fn with_envp<F, T>(env: Option<&collections::HashMap<OsString, OsString>>, cb: F) -> T - where F: FnOnce(*mut c_void) -> T, -{ +fn make_envp(env: Option<&collections::HashMap<OsString, OsString>>) + -> (*mut c_void, Vec<u16>) { // On Windows we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final // \0 to terminate. @@ -432,22 +329,57 @@ fn with_envp<F, T>(env: Option<&collections::HashMap<OsString, OsString>>, cb: F blk.push(0); } blk.push(0); - cb(blk.as_mut_ptr() as *mut c_void) + (blk.as_mut_ptr() as *mut c_void, blk) } - _ => cb(ptr::null_mut()) + _ => (ptr::null_mut(), Vec::new()) } } -fn with_dirp<T, F>(d: Option<&OsString>, cb: F) -> T where - F: FnOnce(*const u16) -> T, -{ +fn make_dirp(d: Option<&OsString>) -> (*const u16, Vec<u16>) { match d { - Some(dir) => { - let mut dir_str: Vec<u16> = dir.encode_wide().collect(); - dir_str.push(0); - cb(dir_str.as_ptr()) - }, - None => cb(ptr::null()) + Some(dir) => { + let mut dir_str: Vec<u16> = dir.encode_wide().collect(); + dir_str.push(0); + (dir_str.as_ptr(), dir_str) + }, + None => (ptr::null(), Vec::new()) + } +} + +impl Stdio { + fn to_handle(&self, stdio_id: libc::DWORD) -> io::Result<Handle> { + use libc::DUPLICATE_SAME_ACCESS; + + match *self { + Stdio::Inherit => { + stdio::get(stdio_id).and_then(|io| { + io.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS) + }) + } + Stdio::Piped(ref pipe) => { + pipe.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS) + } + + // Similarly to unix, we don't actually leave holes for the + // stdio file descriptors, but rather open up /dev/null + // equivalents. These equivalents are drawn from libuv's + // windows process spawning. + Stdio::None => { + let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>(); + let mut sa = libc::SECURITY_ATTRIBUTES { + nLength: size as libc::DWORD, + lpSecurityDescriptor: ptr::null_mut(), + bInheritHandle: 1, + }; + let mut opts = OpenOptions::new(); + opts.read(stdio_id == c::STD_INPUT_HANDLE); + opts.write(stdio_id != c::STD_INPUT_HANDLE); + opts.security_attributes(&mut sa); + File::open(Path::new("NUL"), &opts).map(|file| { + file.into_handle() + }) + } + } } } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 91f6f328ff6..03547165f5d 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -21,9 +21,9 @@ use sys::c; use sys::cvt; use sys::handle::Handle; -struct NoClose(Option<Handle>); +pub struct NoClose(Option<Handle>); -enum Output { +pub enum Output { Console(NoClose), Pipe(NoClose), } @@ -35,7 +35,7 @@ pub struct Stdin { pub struct Stdout(Output); pub struct Stderr(Output); -fn get(handle: libc::DWORD) -> io::Result<Output> { +pub fn get(handle: libc::DWORD) -> io::Result<Output> { let handle = unsafe { c::GetStdHandle(handle) }; if handle == libc::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) @@ -159,6 +159,16 @@ impl Drop for NoClose { } } +impl Output { + pub fn handle(&self) -> &Handle { + let nc = match *self { + Output::Console(ref c) => c, + Output::Pipe(ref c) => c, + }; + nc.0.as_ref().unwrap() + } +} + fn invalid_encoding() -> io::Error { io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode") } |
