Browse Source
* Update for latest nightly 2018-06-09 * We now have a proper horizon os and sys modules in libstdpull/10/head
Valentin
7 years ago
committed by
FenrirWolf
244 changed files with 36777 additions and 1061 deletions
@ -0,0 +1,137 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#![deny(warnings)] |
||||||
|
|
||||||
|
extern crate build_helper; |
||||||
|
extern crate cc; |
||||||
|
|
||||||
|
use build_helper::native_lib_boilerplate; |
||||||
|
use std::env; |
||||||
|
use std::fs::File; |
||||||
|
|
||||||
|
fn main() { |
||||||
|
let target = env::var("TARGET").expect("TARGET was not set"); |
||||||
|
if cfg!(feature = "backtrace") && |
||||||
|
!target.contains("cloudabi") && |
||||||
|
!target.contains("emscripten") && |
||||||
|
!target.contains("fuchsia") && |
||||||
|
!target.contains("msvc") && |
||||||
|
!target.contains("wasm32") |
||||||
|
{ |
||||||
|
let _ = build_libbacktrace(&target); |
||||||
|
} |
||||||
|
|
||||||
|
if target.contains("linux") { |
||||||
|
if target.contains("android") { |
||||||
|
println!("cargo:rustc-link-lib=dl"); |
||||||
|
println!("cargo:rustc-link-lib=log"); |
||||||
|
println!("cargo:rustc-link-lib=gcc"); |
||||||
|
} else if !target.contains("musl") { |
||||||
|
println!("cargo:rustc-link-lib=dl"); |
||||||
|
println!("cargo:rustc-link-lib=rt"); |
||||||
|
println!("cargo:rustc-link-lib=pthread"); |
||||||
|
} |
||||||
|
} else if target.contains("freebsd") { |
||||||
|
println!("cargo:rustc-link-lib=execinfo"); |
||||||
|
println!("cargo:rustc-link-lib=pthread"); |
||||||
|
} else if target.contains("dragonfly") || target.contains("bitrig") || |
||||||
|
target.contains("netbsd") || target.contains("openbsd") { |
||||||
|
println!("cargo:rustc-link-lib=pthread"); |
||||||
|
} else if target.contains("solaris") { |
||||||
|
println!("cargo:rustc-link-lib=socket"); |
||||||
|
println!("cargo:rustc-link-lib=posix4"); |
||||||
|
println!("cargo:rustc-link-lib=pthread"); |
||||||
|
println!("cargo:rustc-link-lib=resolv"); |
||||||
|
} else if target.contains("apple-darwin") { |
||||||
|
println!("cargo:rustc-link-lib=System"); |
||||||
|
|
||||||
|
// res_init and friends require -lresolv on macOS/iOS.
|
||||||
|
// See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
|
||||||
|
println!("cargo:rustc-link-lib=resolv"); |
||||||
|
} else if target.contains("apple-ios") { |
||||||
|
println!("cargo:rustc-link-lib=System"); |
||||||
|
println!("cargo:rustc-link-lib=objc"); |
||||||
|
println!("cargo:rustc-link-lib=framework=Security"); |
||||||
|
println!("cargo:rustc-link-lib=framework=Foundation"); |
||||||
|
println!("cargo:rustc-link-lib=resolv"); |
||||||
|
} else if target.contains("windows") { |
||||||
|
println!("cargo:rustc-link-lib=advapi32"); |
||||||
|
println!("cargo:rustc-link-lib=ws2_32"); |
||||||
|
println!("cargo:rustc-link-lib=userenv"); |
||||||
|
println!("cargo:rustc-link-lib=shell32"); |
||||||
|
} else if target.contains("fuchsia") { |
||||||
|
// use system-provided libbacktrace
|
||||||
|
if cfg!(feature = "backtrace") { |
||||||
|
println!("cargo:rustc-link-lib=backtrace"); |
||||||
|
} |
||||||
|
println!("cargo:rustc-link-lib=zircon"); |
||||||
|
println!("cargo:rustc-link-lib=fdio"); |
||||||
|
} else if target.contains("cloudabi") { |
||||||
|
if cfg!(feature = "backtrace") { |
||||||
|
println!("cargo:rustc-link-lib=unwind"); |
||||||
|
} |
||||||
|
println!("cargo:rustc-link-lib=c"); |
||||||
|
println!("cargo:rustc-link-lib=compiler_rt"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn build_libbacktrace(target: &str) -> Result<(), ()> { |
||||||
|
let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?; |
||||||
|
|
||||||
|
let mut build = cc::Build::new(); |
||||||
|
build |
||||||
|
.flag("-fvisibility=hidden") |
||||||
|
.include("../libbacktrace") |
||||||
|
.include(&native.out_dir) |
||||||
|
.out_dir(&native.out_dir) |
||||||
|
.warnings(false) |
||||||
|
.file("../libbacktrace/alloc.c") |
||||||
|
.file("../libbacktrace/backtrace.c") |
||||||
|
.file("../libbacktrace/dwarf.c") |
||||||
|
.file("../libbacktrace/fileline.c") |
||||||
|
.file("../libbacktrace/posix.c") |
||||||
|
.file("../libbacktrace/read.c") |
||||||
|
.file("../libbacktrace/sort.c") |
||||||
|
.file("../libbacktrace/state.c"); |
||||||
|
|
||||||
|
if target.contains("darwin") { |
||||||
|
build.file("../libbacktrace/macho.c"); |
||||||
|
} else if target.contains("windows") { |
||||||
|
build.file("../libbacktrace/pecoff.c"); |
||||||
|
} else { |
||||||
|
build.file("../libbacktrace/elf.c"); |
||||||
|
|
||||||
|
if target.contains("64") { |
||||||
|
build.define("BACKTRACE_ELF_SIZE", "64"); |
||||||
|
} else { |
||||||
|
build.define("BACKTRACE_ELF_SIZE", "32"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
File::create(native.out_dir.join("backtrace-supported.h")).unwrap(); |
||||||
|
build.define("BACKTRACE_SUPPORTED", "1"); |
||||||
|
build.define("BACKTRACE_USES_MALLOC", "1"); |
||||||
|
build.define("BACKTRACE_SUPPORTS_THREADS", "0"); |
||||||
|
build.define("BACKTRACE_SUPPORTS_DATA", "0"); |
||||||
|
|
||||||
|
File::create(native.out_dir.join("config.h")).unwrap(); |
||||||
|
if !target.contains("apple-ios") && |
||||||
|
!target.contains("solaris") && |
||||||
|
!target.contains("redox") && |
||||||
|
!target.contains("android") { |
||||||
|
build.define("HAVE_DL_ITERATE_PHDR", "1"); |
||||||
|
} |
||||||
|
build.define("_GNU_SOURCE", "1"); |
||||||
|
build.define("_LARGE_FILES", "1"); |
||||||
|
|
||||||
|
build.compile("backtrace"); |
||||||
|
Ok(()) |
||||||
|
} |
@ -0,0 +1,393 @@ |
|||||||
|
// Copyright 2016 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 = "metadata_ext", since = "1.1.0")] |
||||||
|
|
||||||
|
use libc; |
||||||
|
|
||||||
|
use fs::Metadata; |
||||||
|
use sys_common::AsInner; |
||||||
|
|
||||||
|
#[allow(deprecated)] |
||||||
|
use os::horizon::raw; |
||||||
|
|
||||||
|
/// OS-specific extensions to [`fs::Metadata`].
|
||||||
|
///
|
||||||
|
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
|
||||||
|
#[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`]: ../../../../std/os/linux/raw/struct.stat.html
|
||||||
|
///
|
||||||
|
/// # 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 = "deprecated in favor of the accessor \ |
||||||
|
methods of this trait")] |
||||||
|
#[allow(deprecated)] |
||||||
|
fn as_raw_stat(&self) -> &raw::stat; |
||||||
|
|
||||||
|
/// Returns the device ID on which this file resides.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::io;
|
||||||
|
/// use std::os::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.
|
||||||
|
///
|
||||||
|
/// # 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, nano seconds part.
|
||||||
|
///
|
||||||
|
/// # 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.
|
||||||
|
///
|
||||||
|
/// # 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, nano seconds part.
|
||||||
|
///
|
||||||
|
/// # 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.
|
||||||
|
///
|
||||||
|
/// # 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, nano seconds part.
|
||||||
|
///
|
||||||
|
/// # 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" blocksize 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::stat |
||||||
|
as *const raw::stat) |
||||||
|
} |
||||||
|
} |
||||||
|
fn st_dev(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_dev as u64 |
||||||
|
} |
||||||
|
fn st_ino(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_ino as u64 |
||||||
|
} |
||||||
|
fn st_mode(&self) -> u32 { |
||||||
|
self.as_inner().as_inner().st_mode as u32 |
||||||
|
} |
||||||
|
fn st_nlink(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_nlink as u64 |
||||||
|
} |
||||||
|
fn st_uid(&self) -> u32 { |
||||||
|
self.as_inner().as_inner().st_uid as u32 |
||||||
|
} |
||||||
|
fn st_gid(&self) -> u32 { |
||||||
|
self.as_inner().as_inner().st_gid as u32 |
||||||
|
} |
||||||
|
fn st_rdev(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_rdev as u64 |
||||||
|
} |
||||||
|
fn st_size(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_size as u64 |
||||||
|
} |
||||||
|
fn st_atime(&self) -> i64 { |
||||||
|
self.as_inner().as_inner().st_atime as i64 |
||||||
|
} |
||||||
|
fn st_atime_nsec(&self) -> i64 { |
||||||
|
//self.as_inner().as_inner().st_atime_nsec as i64
|
||||||
|
0i64 |
||||||
|
} |
||||||
|
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
|
||||||
|
0i64 |
||||||
|
} |
||||||
|
fn st_ctime(&self) -> i64 { |
||||||
|
//self.as_inner().as_inner().st_ctime as i64
|
||||||
|
0i64 |
||||||
|
} |
||||||
|
fn st_ctime_nsec(&self) -> i64 { |
||||||
|
//self.as_inner().as_inner().st_ctime_nsec as i64
|
||||||
|
0i64 |
||||||
|
} |
||||||
|
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 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Linux-specific definitions
|
||||||
|
|
||||||
|
#![stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
|
||||||
|
pub mod raw; |
||||||
|
pub mod fs; |
@ -0,0 +1,275 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Linux-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)] |
||||||
|
#![allow(missing_debug_implementations)] |
||||||
|
|
||||||
|
use 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::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; |
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86",
|
||||||
|
target_arch = "le32", |
||||||
|
target_arch = "powerpc", |
||||||
|
target_arch = "arm", |
||||||
|
target_arch = "asmjs", |
||||||
|
target_arch = "wasm32"))] |
||||||
|
mod arch { |
||||||
|
use 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 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(any(target_arch = "mips64",
|
||||||
|
target_arch = "s390x", |
||||||
|
target_arch = "sparc64"))] |
||||||
|
mod arch { |
||||||
|
pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")] |
||||||
|
mod arch { |
||||||
|
use os::raw::{c_long, c_int}; |
||||||
|
|
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; |
||||||
|
|
||||||
|
#[repr(C)] |
||||||
|
#[derive(Clone)] |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub struct stat { |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_dev: u64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_ino: u64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_mode: u32, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_nlink: u32, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_uid: u32, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_gid: u32, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_rdev: u64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub __pad1: u64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_size: i64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_blksize: i32, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub __pad2: c_int, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_blocks: i64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_atime: i64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_atime_nsec: c_long, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_mtime: i64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_mtime_nsec: c_long, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_ctime: i64, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub st_ctime_nsec: c_long, |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub __unused: [c_int; 2], |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))] |
||||||
|
mod arch { |
||||||
|
use os::raw::{c_long, c_int}; |
||||||
|
|
||||||
|
#[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], |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions
|
||||||
|
// are met:
|
||||||
|
// 1. Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
// SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Appease Rust's tidy.
|
||||||
|
// ignore-license
|
||||||
|
|
||||||
|
#[cfg(feature = "bitflags")] |
||||||
|
#[macro_use] |
||||||
|
extern crate bitflags; |
||||||
|
|
||||||
|
// Minimal implementation of bitflags! in case we can't depend on the bitflags
|
||||||
|
// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't
|
||||||
|
// actually truncate.
|
||||||
|
#[cfg(not(feature = "bitflags"))] |
||||||
|
macro_rules! bitflags { |
||||||
|
( |
||||||
|
$(#[$attr:meta])* |
||||||
|
pub struct $name:ident: $type:ty { |
||||||
|
$($(#[$const_attr:meta])* const $const:ident = $val:expr;)* |
||||||
|
} |
||||||
|
) => { |
||||||
|
$(#[$attr])* |
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] |
||||||
|
pub struct $name { bits: $type } |
||||||
|
impl $name { |
||||||
|
$($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)* |
||||||
|
pub fn bits(&self) -> $type { self.bits } |
||||||
|
pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
#[allow(warnings)] |
||||||
|
mod cloudabi; |
||||||
|
pub use self::cloudabi::*; |
@ -0,0 +1,17 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
pub use sys::cloudabi::shims::args::*; |
||||||
|
|
||||||
|
#[allow(dead_code)] |
||||||
|
pub fn init(_: isize, _: *const *const u8) {} |
||||||
|
|
||||||
|
#[allow(dead_code)] |
||||||
|
pub fn cleanup() {} |
@ -0,0 +1,122 @@ |
|||||||
|
// Copyright 2014-2018 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.
|
||||||
|
|
||||||
|
use error::Error; |
||||||
|
use ffi::CStr; |
||||||
|
use intrinsics; |
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use sys_common::backtrace::Frame; |
||||||
|
use unwind as uw; |
||||||
|
|
||||||
|
pub struct BacktraceContext; |
||||||
|
|
||||||
|
struct Context<'a> { |
||||||
|
idx: usize, |
||||||
|
frames: &'a mut [Frame], |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
struct UnwindError(uw::_Unwind_Reason_Code); |
||||||
|
|
||||||
|
impl Error for UnwindError { |
||||||
|
fn description(&self) -> &'static str { |
||||||
|
"unexpected return value while unwinding" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl ::fmt::Display for UnwindError { |
||||||
|
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { |
||||||
|
write!(f, "{}: {:?}", self.description(), self.0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline(never)] // if we know this is a function call, we can skip it when
|
||||||
|
// tracing
|
||||||
|
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { |
||||||
|
let mut cx = Context { idx: 0, frames }; |
||||||
|
let result_unwind = |
||||||
|
unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) }; |
||||||
|
// See libunwind:src/unwind/Backtrace.c for the return values.
|
||||||
|
// No, there is no doc.
|
||||||
|
match result_unwind { |
||||||
|
// These return codes seem to be benign and need to be ignored for backtraces
|
||||||
|
// to show up properly on all tested platforms.
|
||||||
|
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { |
||||||
|
Ok((cx.idx, BacktraceContext)) |
||||||
|
} |
||||||
|
_ => Err(io::Error::new( |
||||||
|
io::ErrorKind::Other, |
||||||
|
UnwindError(result_unwind), |
||||||
|
)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" fn trace_fn( |
||||||
|
ctx: *mut uw::_Unwind_Context, |
||||||
|
arg: *mut libc::c_void, |
||||||
|
) -> uw::_Unwind_Reason_Code { |
||||||
|
let cx = unsafe { &mut *(arg as *mut Context) }; |
||||||
|
let mut ip_before_insn = 0; |
||||||
|
let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; |
||||||
|
if !ip.is_null() && ip_before_insn == 0 { |
||||||
|
// this is a non-signaling frame, so `ip` refers to the address
|
||||||
|
// after the calling instruction. account for that.
|
||||||
|
ip = (ip as usize - 1) as *mut _; |
||||||
|
} |
||||||
|
|
||||||
|
let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; |
||||||
|
if cx.idx < cx.frames.len() { |
||||||
|
cx.frames[cx.idx] = Frame { |
||||||
|
symbol_addr: symaddr as *mut u8, |
||||||
|
exact_position: ip as *mut u8, |
||||||
|
inline_context: 0, |
||||||
|
}; |
||||||
|
cx.idx += 1; |
||||||
|
} |
||||||
|
|
||||||
|
uw::_URC_NO_REASON |
||||||
|
} |
||||||
|
|
||||||
|
pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool> |
||||||
|
where |
||||||
|
F: FnMut(&[u8], u32) -> io::Result<()>, |
||||||
|
{ |
||||||
|
// No way to obtain this information on CloudABI.
|
||||||
|
Ok(false) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn resolve_symname<F>(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()> |
||||||
|
where |
||||||
|
F: FnOnce(Option<&str>) -> io::Result<()>, |
||||||
|
{ |
||||||
|
unsafe { |
||||||
|
let mut info: Dl_info = intrinsics::init(); |
||||||
|
let symname = |
||||||
|
if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() { |
||||||
|
None |
||||||
|
} else { |
||||||
|
CStr::from_ptr(info.dli_sname).to_str().ok() |
||||||
|
}; |
||||||
|
callback(symname) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[repr(C)] |
||||||
|
struct Dl_info { |
||||||
|
dli_fname: *const libc::c_char, |
||||||
|
dli_fbase: *mut libc::c_void, |
||||||
|
dli_sname: *const libc::c_char, |
||||||
|
dli_saddr: *mut libc::c_void, |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" { |
||||||
|
fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; |
||||||
|
} |
@ -0,0 +1,169 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use cell::UnsafeCell; |
||||||
|
use mem; |
||||||
|
use sync::atomic::{AtomicU32, Ordering}; |
||||||
|
use sys::cloudabi::abi; |
||||||
|
use sys::mutex::{self, Mutex}; |
||||||
|
use sys::time::dur2intervals; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
extern "C" { |
||||||
|
#[thread_local] |
||||||
|
static __pthread_thread_id: abi::tid; |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Condvar { |
||||||
|
condvar: UnsafeCell<AtomicU32>, |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Send for Condvar {} |
||||||
|
unsafe impl Sync for Condvar {} |
||||||
|
|
||||||
|
impl Condvar { |
||||||
|
pub const fn new() -> Condvar { |
||||||
|
Condvar { |
||||||
|
condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn init(&mut self) {} |
||||||
|
|
||||||
|
pub unsafe fn notify_one(&self) { |
||||||
|
let condvar = self.condvar.get(); |
||||||
|
if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { |
||||||
|
let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1); |
||||||
|
assert_eq!( |
||||||
|
ret, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to signal on condition variable" |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn notify_all(&self) { |
||||||
|
let condvar = self.condvar.get(); |
||||||
|
if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { |
||||||
|
let ret = abi::condvar_signal( |
||||||
|
condvar as *mut abi::condvar, |
||||||
|
abi::scope::PRIVATE, |
||||||
|
abi::nthreads::max_value(), |
||||||
|
); |
||||||
|
assert_eq!( |
||||||
|
ret, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to broadcast on condition variable" |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn wait(&self, mutex: &Mutex) { |
||||||
|
let mutex = mutex::raw(mutex); |
||||||
|
assert_eq!( |
||||||
|
(*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
"This lock is not write-locked by this thread" |
||||||
|
); |
||||||
|
|
||||||
|
// Call into the kernel to wait on the condition variable.
|
||||||
|
let condvar = self.condvar.get(); |
||||||
|
let subscription = abi::subscription { |
||||||
|
type_: abi::eventtype::CONDVAR, |
||||||
|
union: abi::subscription_union { |
||||||
|
condvar: abi::subscription_condvar { |
||||||
|
condvar: condvar as *mut abi::condvar, |
||||||
|
condvar_scope: abi::scope::PRIVATE, |
||||||
|
lock: mutex as *mut abi::lock, |
||||||
|
lock_scope: abi::scope::PRIVATE, |
||||||
|
}, |
||||||
|
}, |
||||||
|
..mem::zeroed() |
||||||
|
}; |
||||||
|
let mut event: abi::event = mem::uninitialized(); |
||||||
|
let mut nevents: usize = mem::uninitialized(); |
||||||
|
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); |
||||||
|
assert_eq!( |
||||||
|
ret, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to wait on condition variable" |
||||||
|
); |
||||||
|
assert_eq!( |
||||||
|
event.error, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to wait on condition variable" |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { |
||||||
|
let mutex = mutex::raw(mutex); |
||||||
|
assert_eq!( |
||||||
|
(*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
"This lock is not write-locked by this thread" |
||||||
|
); |
||||||
|
|
||||||
|
// Call into the kernel to wait on the condition variable.
|
||||||
|
let condvar = self.condvar.get(); |
||||||
|
let subscriptions = [ |
||||||
|
abi::subscription { |
||||||
|
type_: abi::eventtype::CONDVAR, |
||||||
|
union: abi::subscription_union { |
||||||
|
condvar: abi::subscription_condvar { |
||||||
|
condvar: condvar as *mut abi::condvar, |
||||||
|
condvar_scope: abi::scope::PRIVATE, |
||||||
|
lock: mutex as *mut abi::lock, |
||||||
|
lock_scope: abi::scope::PRIVATE, |
||||||
|
}, |
||||||
|
}, |
||||||
|
..mem::zeroed() |
||||||
|
}, |
||||||
|
abi::subscription { |
||||||
|
type_: abi::eventtype::CLOCK, |
||||||
|
union: abi::subscription_union { |
||||||
|
clock: abi::subscription_clock { |
||||||
|
clock_id: abi::clockid::MONOTONIC, |
||||||
|
timeout: dur2intervals(&dur), |
||||||
|
..mem::zeroed() |
||||||
|
}, |
||||||
|
}, |
||||||
|
..mem::zeroed() |
||||||
|
}, |
||||||
|
]; |
||||||
|
let mut events: [abi::event; 2] = mem::uninitialized(); |
||||||
|
let mut nevents: usize = mem::uninitialized(); |
||||||
|
let ret = abi::poll(subscriptions.as_ptr(), events.as_mut_ptr(), 2, &mut nevents); |
||||||
|
assert_eq!( |
||||||
|
ret, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to wait on condition variable" |
||||||
|
); |
||||||
|
for i in 0..nevents { |
||||||
|
assert_eq!( |
||||||
|
events[i].error, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to wait on condition variable" |
||||||
|
); |
||||||
|
if events[i].type_ == abi::eventtype::CONDVAR { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
false |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
let condvar = self.condvar.get(); |
||||||
|
assert_eq!( |
||||||
|
(*condvar).load(Ordering::Relaxed), |
||||||
|
abi::CONDVAR_HAS_NO_WAITERS.0, |
||||||
|
"Attempted to destroy a condition variable with blocked threads" |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use mem; |
||||||
|
|
||||||
|
pub mod args; |
||||||
|
#[cfg(feature = "backtrace")] |
||||||
|
pub mod backtrace; |
||||||
|
#[path = "../unix/cmath.rs"] |
||||||
|
pub mod cmath; |
||||||
|
pub mod condvar; |
||||||
|
#[path = "../unix/memchr.rs"] |
||||||
|
pub mod memchr; |
||||||
|
pub mod mutex; |
||||||
|
pub mod os; |
||||||
|
#[path = "../unix/os_str.rs"] |
||||||
|
pub mod os_str; |
||||||
|
pub mod rwlock; |
||||||
|
pub mod stack_overflow; |
||||||
|
pub mod stdio; |
||||||
|
pub mod thread; |
||||||
|
#[path = "../unix/thread_local.rs"] |
||||||
|
pub mod thread_local; |
||||||
|
pub mod time; |
||||||
|
|
||||||
|
mod abi; |
||||||
|
|
||||||
|
mod shims; |
||||||
|
pub use self::shims::*; |
||||||
|
|
||||||
|
#[allow(dead_code)] |
||||||
|
pub fn init() {} |
||||||
|
|
||||||
|
pub fn decode_error_kind(errno: i32) -> io::ErrorKind { |
||||||
|
match errno { |
||||||
|
x if x == abi::errno::ACCES as i32 => io::ErrorKind::PermissionDenied, |
||||||
|
x if x == abi::errno::ADDRINUSE as i32 => io::ErrorKind::AddrInUse, |
||||||
|
x if x == abi::errno::ADDRNOTAVAIL as i32 => io::ErrorKind::AddrNotAvailable, |
||||||
|
x if x == abi::errno::AGAIN as i32 => io::ErrorKind::WouldBlock, |
||||||
|
x if x == abi::errno::CONNABORTED as i32 => io::ErrorKind::ConnectionAborted, |
||||||
|
x if x == abi::errno::CONNREFUSED as i32 => io::ErrorKind::ConnectionRefused, |
||||||
|
x if x == abi::errno::CONNRESET as i32 => io::ErrorKind::ConnectionReset, |
||||||
|
x if x == abi::errno::EXIST as i32 => io::ErrorKind::AlreadyExists, |
||||||
|
x if x == abi::errno::INTR as i32 => io::ErrorKind::Interrupted, |
||||||
|
x if x == abi::errno::INVAL as i32 => io::ErrorKind::InvalidInput, |
||||||
|
x if x == abi::errno::NOENT as i32 => io::ErrorKind::NotFound, |
||||||
|
x if x == abi::errno::NOTCONN as i32 => io::ErrorKind::NotConnected, |
||||||
|
x if x == abi::errno::PERM as i32 => io::ErrorKind::PermissionDenied, |
||||||
|
x if x == abi::errno::PIPE as i32 => io::ErrorKind::BrokenPipe, |
||||||
|
x if x == abi::errno::TIMEDOUT as i32 => io::ErrorKind::TimedOut, |
||||||
|
_ => io::ErrorKind::Other, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn abort_internal() -> ! { |
||||||
|
::core::intrinsics::abort(); |
||||||
|
} |
||||||
|
|
||||||
|
pub use libc::strlen; |
||||||
|
|
||||||
|
pub fn hashmap_random_keys() -> (u64, u64) { |
||||||
|
unsafe { |
||||||
|
let mut v = mem::uninitialized(); |
||||||
|
libc::arc4random_buf(&mut v as *mut _ as *mut libc::c_void, mem::size_of_val(&v)); |
||||||
|
v |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,158 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use cell::UnsafeCell; |
||||||
|
use mem; |
||||||
|
use sync::atomic::{AtomicU32, Ordering}; |
||||||
|
use sys::cloudabi::abi; |
||||||
|
use sys::rwlock::{self, RWLock}; |
||||||
|
|
||||||
|
extern "C" { |
||||||
|
#[thread_local] |
||||||
|
static __pthread_thread_id: abi::tid; |
||||||
|
} |
||||||
|
|
||||||
|
// Implement Mutex using an RWLock. This doesn't introduce any
|
||||||
|
// performance overhead in this environment, as the operations would be
|
||||||
|
// implemented identically.
|
||||||
|
pub struct Mutex(RWLock); |
||||||
|
|
||||||
|
pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 { |
||||||
|
rwlock::raw(&m.0) |
||||||
|
} |
||||||
|
|
||||||
|
impl Mutex { |
||||||
|
pub const fn new() -> Mutex { |
||||||
|
Mutex(RWLock::new()) |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn init(&mut self) { |
||||||
|
// This function should normally reinitialize the mutex after
|
||||||
|
// moving it to a different memory address. This implementation
|
||||||
|
// does not require adjustments after moving.
|
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn try_lock(&self) -> bool { |
||||||
|
self.0.try_write() |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn lock(&self) { |
||||||
|
self.0.write() |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn unlock(&self) { |
||||||
|
self.0.write_unlock() |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
self.0.destroy() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct ReentrantMutex { |
||||||
|
lock: UnsafeCell<AtomicU32>, |
||||||
|
recursion: UnsafeCell<u32>, |
||||||
|
} |
||||||
|
|
||||||
|
impl ReentrantMutex { |
||||||
|
pub unsafe fn uninitialized() -> ReentrantMutex { |
||||||
|
mem::uninitialized() |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn init(&mut self) { |
||||||
|
self.lock = UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)); |
||||||
|
self.recursion = UnsafeCell::new(0); |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn try_lock(&self) -> bool { |
||||||
|
// Attempt to acquire the lock.
|
||||||
|
let lock = self.lock.get(); |
||||||
|
let recursion = self.recursion.get(); |
||||||
|
if let Err(old) = (*lock).compare_exchange( |
||||||
|
abi::LOCK_UNLOCKED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
Ordering::Acquire, |
||||||
|
Ordering::Relaxed, |
||||||
|
) { |
||||||
|
// If we fail to acquire the lock, it may be the case
|
||||||
|
// that we've already acquired it and may need to recurse.
|
||||||
|
if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 { |
||||||
|
*recursion += 1; |
||||||
|
true |
||||||
|
} else { |
||||||
|
false |
||||||
|
} |
||||||
|
} else { |
||||||
|
// Success.
|
||||||
|
assert_eq!(*recursion, 0, "Mutex has invalid recursion count"); |
||||||
|
true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn lock(&self) { |
||||||
|
if !self.try_lock() { |
||||||
|
// Call into the kernel to acquire a write lock.
|
||||||
|
let lock = self.lock.get(); |
||||||
|
let subscription = abi::subscription { |
||||||
|
type_: abi::eventtype::LOCK_WRLOCK, |
||||||
|
union: abi::subscription_union { |
||||||
|
lock: abi::subscription_lock { |
||||||
|
lock: lock as *mut abi::lock, |
||||||
|
lock_scope: abi::scope::PRIVATE, |
||||||
|
}, |
||||||
|
}, |
||||||
|
..mem::zeroed() |
||||||
|
}; |
||||||
|
let mut event: abi::event = mem::uninitialized(); |
||||||
|
let mut nevents: usize = mem::uninitialized(); |
||||||
|
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex"); |
||||||
|
assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn unlock(&self) { |
||||||
|
let lock = self.lock.get(); |
||||||
|
let recursion = self.recursion.get(); |
||||||
|
assert_eq!( |
||||||
|
(*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
"This mutex is locked by a different thread" |
||||||
|
); |
||||||
|
|
||||||
|
if *recursion > 0 { |
||||||
|
*recursion -= 1; |
||||||
|
} else if !(*lock) |
||||||
|
.compare_exchange( |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
abi::LOCK_UNLOCKED.0, |
||||||
|
Ordering::Release, |
||||||
|
Ordering::Relaxed, |
||||||
|
) |
||||||
|
.is_ok() |
||||||
|
{ |
||||||
|
// Lock is managed by kernelspace. Call into the kernel
|
||||||
|
// to unblock waiting threads.
|
||||||
|
let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
let lock = self.lock.get(); |
||||||
|
let recursion = self.recursion.get(); |
||||||
|
assert_eq!( |
||||||
|
(*lock).load(Ordering::Relaxed), |
||||||
|
abi::LOCK_UNLOCKED.0, |
||||||
|
"Attempted to destroy locked mutex" |
||||||
|
); |
||||||
|
assert_eq!(*recursion, 0, "Recursion counter invalid"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use ffi::CStr; |
||||||
|
use libc::{self, c_int}; |
||||||
|
use str; |
||||||
|
|
||||||
|
pub use sys::cloudabi::shims::os::*; |
||||||
|
|
||||||
|
pub fn errno() -> i32 { |
||||||
|
extern "C" { |
||||||
|
#[thread_local] |
||||||
|
static errno: c_int; |
||||||
|
} |
||||||
|
|
||||||
|
unsafe { errno as i32 } |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets a detailed string description for the given error number.
|
||||||
|
pub fn error_string(errno: i32) -> String { |
||||||
|
// cloudlibc's strerror() is guaranteed to be thread-safe. There is
|
||||||
|
// thus no need to use strerror_r().
|
||||||
|
str::from_utf8(unsafe { CStr::from_ptr(libc::strerror(errno)) }.to_bytes()) |
||||||
|
.unwrap() |
||||||
|
.to_owned() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn exit(code: i32) -> ! { |
||||||
|
unsafe { libc::exit(code as c_int) } |
||||||
|
} |
@ -0,0 +1,237 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use cell::UnsafeCell; |
||||||
|
use mem; |
||||||
|
use sync::atomic::{AtomicU32, Ordering}; |
||||||
|
use sys::cloudabi::abi; |
||||||
|
|
||||||
|
extern "C" { |
||||||
|
#[thread_local] |
||||||
|
static __pthread_thread_id: abi::tid; |
||||||
|
} |
||||||
|
|
||||||
|
#[thread_local] |
||||||
|
static mut RDLOCKS_ACQUIRED: u32 = 0; |
||||||
|
|
||||||
|
pub struct RWLock { |
||||||
|
lock: UnsafeCell<AtomicU32>, |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 { |
||||||
|
r.lock.get() |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Send for RWLock {} |
||||||
|
unsafe impl Sync for RWLock {} |
||||||
|
|
||||||
|
impl RWLock { |
||||||
|
pub const fn new() -> RWLock { |
||||||
|
RWLock { |
||||||
|
lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn try_read(&self) -> bool { |
||||||
|
let lock = self.lock.get(); |
||||||
|
let mut old = abi::LOCK_UNLOCKED.0; |
||||||
|
while let Err(cur) = |
||||||
|
(*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) |
||||||
|
{ |
||||||
|
if (cur & abi::LOCK_WRLOCKED.0) != 0 { |
||||||
|
// Another thread already has a write lock.
|
||||||
|
assert_ne!( |
||||||
|
old & !abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
"Attempted to acquire a read lock while holding a write lock" |
||||||
|
); |
||||||
|
return false; |
||||||
|
} else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 { |
||||||
|
// Lock has threads waiting for the lock. Only acquire
|
||||||
|
// the lock if we have already acquired read locks. In
|
||||||
|
// that case, it is justified to acquire this lock to
|
||||||
|
// prevent a deadlock.
|
||||||
|
return false; |
||||||
|
} |
||||||
|
old = cur; |
||||||
|
} |
||||||
|
|
||||||
|
RDLOCKS_ACQUIRED += 1; |
||||||
|
true |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn read(&self) { |
||||||
|
if !self.try_read() { |
||||||
|
// Call into the kernel to acquire a read lock.
|
||||||
|
let lock = self.lock.get(); |
||||||
|
let subscription = abi::subscription { |
||||||
|
type_: abi::eventtype::LOCK_RDLOCK, |
||||||
|
union: abi::subscription_union { |
||||||
|
lock: abi::subscription_lock { |
||||||
|
lock: lock as *mut abi::lock, |
||||||
|
lock_scope: abi::scope::PRIVATE, |
||||||
|
}, |
||||||
|
}, |
||||||
|
..mem::zeroed() |
||||||
|
}; |
||||||
|
let mut event: abi::event = mem::uninitialized(); |
||||||
|
let mut nevents: usize = mem::uninitialized(); |
||||||
|
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock"); |
||||||
|
assert_eq!( |
||||||
|
event.error, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to acquire read lock" |
||||||
|
); |
||||||
|
|
||||||
|
RDLOCKS_ACQUIRED += 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn read_unlock(&self) { |
||||||
|
// Perform a read unlock. We can do this in userspace, except when
|
||||||
|
// other threads are blocked and we are performing the last unlock.
|
||||||
|
// In that case, call into the kernel.
|
||||||
|
//
|
||||||
|
// Other threads may attempt to increment the read lock count,
|
||||||
|
// meaning that the call into the kernel could be spurious. To
|
||||||
|
// prevent this from happening, upgrade to a write lock first. This
|
||||||
|
// allows us to call into the kernel, having the guarantee that the
|
||||||
|
// lock value will not change in the meantime.
|
||||||
|
assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count"); |
||||||
|
let mut old = 1; |
||||||
|
loop { |
||||||
|
let lock = self.lock.get(); |
||||||
|
if old == 1 | abi::LOCK_KERNEL_MANAGED.0 { |
||||||
|
// Last read lock while threads are waiting. Attempt to upgrade
|
||||||
|
// to a write lock before calling into the kernel to unlock.
|
||||||
|
if let Err(cur) = (*lock).compare_exchange_weak( |
||||||
|
old, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
Ordering::Acquire, |
||||||
|
Ordering::Relaxed, |
||||||
|
) { |
||||||
|
old = cur; |
||||||
|
} else { |
||||||
|
// Call into the kernel to unlock.
|
||||||
|
let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// No threads waiting or not the last read lock. Just decrement
|
||||||
|
// the read lock count.
|
||||||
|
assert_ne!( |
||||||
|
old & !abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
0, |
||||||
|
"This rwlock is not locked" |
||||||
|
); |
||||||
|
assert_eq!( |
||||||
|
old & abi::LOCK_WRLOCKED.0, |
||||||
|
0, |
||||||
|
"Attempted to read-unlock a write-locked rwlock" |
||||||
|
); |
||||||
|
if let Err(cur) = (*lock).compare_exchange_weak( |
||||||
|
old, |
||||||
|
old - 1, |
||||||
|
Ordering::Acquire, |
||||||
|
Ordering::Relaxed, |
||||||
|
) { |
||||||
|
old = cur; |
||||||
|
} else { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
RDLOCKS_ACQUIRED -= 1; |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn try_write(&self) -> bool { |
||||||
|
// Attempt to acquire the lock.
|
||||||
|
let lock = self.lock.get(); |
||||||
|
if let Err(old) = (*lock).compare_exchange( |
||||||
|
abi::LOCK_UNLOCKED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
Ordering::Acquire, |
||||||
|
Ordering::Relaxed, |
||||||
|
) { |
||||||
|
// Failure. Crash upon recursive acquisition.
|
||||||
|
assert_ne!( |
||||||
|
old & !abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
"Attempted to recursive write-lock a rwlock", |
||||||
|
); |
||||||
|
false |
||||||
|
} else { |
||||||
|
// Success.
|
||||||
|
true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn write(&self) { |
||||||
|
if !self.try_write() { |
||||||
|
// Call into the kernel to acquire a write lock.
|
||||||
|
let lock = self.lock.get(); |
||||||
|
let subscription = abi::subscription { |
||||||
|
type_: abi::eventtype::LOCK_WRLOCK, |
||||||
|
union: abi::subscription_union { |
||||||
|
lock: abi::subscription_lock { |
||||||
|
lock: lock as *mut abi::lock, |
||||||
|
lock_scope: abi::scope::PRIVATE, |
||||||
|
}, |
||||||
|
}, |
||||||
|
..mem::zeroed() |
||||||
|
}; |
||||||
|
let mut event: abi::event = mem::uninitialized(); |
||||||
|
let mut nevents: usize = mem::uninitialized(); |
||||||
|
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock"); |
||||||
|
assert_eq!( |
||||||
|
event.error, |
||||||
|
abi::errno::SUCCESS, |
||||||
|
"Failed to acquire write lock" |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn write_unlock(&self) { |
||||||
|
let lock = self.lock.get(); |
||||||
|
assert_eq!( |
||||||
|
(*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
"This rwlock is not write-locked by this thread" |
||||||
|
); |
||||||
|
|
||||||
|
if !(*lock) |
||||||
|
.compare_exchange( |
||||||
|
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, |
||||||
|
abi::LOCK_UNLOCKED.0, |
||||||
|
Ordering::Release, |
||||||
|
Ordering::Relaxed, |
||||||
|
) |
||||||
|
.is_ok() |
||||||
|
{ |
||||||
|
// Lock is managed by kernelspace. Call into the kernel
|
||||||
|
// to unblock waiting threads.
|
||||||
|
let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
let lock = self.lock.get(); |
||||||
|
assert_eq!( |
||||||
|
(*lock).load(Ordering::Relaxed), |
||||||
|
abi::LOCK_UNLOCKED.0, |
||||||
|
"Attempted to destroy locked rwlock" |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use ffi::OsString; |
||||||
|
|
||||||
|
pub struct Args(()); |
||||||
|
|
||||||
|
impl Args { |
||||||
|
pub fn inner_debug(&self) -> &[OsString] { |
||||||
|
&[] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Iterator for Args { |
||||||
|
type Item = OsString; |
||||||
|
fn next(&mut self) -> Option<OsString> { |
||||||
|
None |
||||||
|
} |
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) { |
||||||
|
(0, Some(0)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl ExactSizeIterator for Args { |
||||||
|
fn len(&self) -> usize { |
||||||
|
0 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DoubleEndedIterator for Args { |
||||||
|
fn next_back(&mut self) -> Option<OsString> { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn args() -> Args { |
||||||
|
Args(()) |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "cloudabi"; |
||||||
|
pub const OS: &'static str = "cloudabi"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
@ -0,0 +1,302 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use ffi::OsString; |
||||||
|
use fmt; |
||||||
|
use hash::{Hash, Hasher}; |
||||||
|
use io::{self, SeekFrom}; |
||||||
|
use path::{Path, PathBuf}; |
||||||
|
use sys::time::SystemTime; |
||||||
|
use sys::{unsupported, Void}; |
||||||
|
|
||||||
|
pub struct File(Void); |
||||||
|
|
||||||
|
pub struct FileAttr(Void); |
||||||
|
|
||||||
|
pub struct ReadDir(Void); |
||||||
|
|
||||||
|
pub struct DirEntry(Void); |
||||||
|
|
||||||
|
#[derive(Clone, Debug)] |
||||||
|
pub struct OpenOptions {} |
||||||
|
|
||||||
|
pub struct FilePermissions(Void); |
||||||
|
|
||||||
|
pub struct FileType(Void); |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct DirBuilder {} |
||||||
|
|
||||||
|
impl FileAttr { |
||||||
|
pub fn size(&self) -> u64 { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn perm(&self) -> FilePermissions { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn file_type(&self) -> FileType { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn modified(&self) -> io::Result<SystemTime> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn accessed(&self) -> io::Result<SystemTime> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn created(&self) -> io::Result<SystemTime> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Clone for FileAttr { |
||||||
|
fn clone(&self) -> FileAttr { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl FilePermissions { |
||||||
|
pub fn readonly(&self) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_readonly(&mut self, _readonly: bool) { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Clone for FilePermissions { |
||||||
|
fn clone(&self) -> FilePermissions { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl PartialEq for FilePermissions { |
||||||
|
fn eq(&self, _other: &FilePermissions) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Eq for FilePermissions {} |
||||||
|
|
||||||
|
impl fmt::Debug for FilePermissions { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl FileType { |
||||||
|
pub fn is_dir(&self) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn is_file(&self) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn is_symlink(&self) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Clone for FileType { |
||||||
|
fn clone(&self) -> FileType { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Copy for FileType {} |
||||||
|
|
||||||
|
impl PartialEq for FileType { |
||||||
|
fn eq(&self, _other: &FileType) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Eq for FileType {} |
||||||
|
|
||||||
|
impl Hash for FileType { |
||||||
|
fn hash<H: Hasher>(&self, _h: &mut H) { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for FileType { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for ReadDir { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Iterator for ReadDir { |
||||||
|
type Item = io::Result<DirEntry>; |
||||||
|
|
||||||
|
fn next(&mut self) -> Option<io::Result<DirEntry>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DirEntry { |
||||||
|
pub fn path(&self) -> PathBuf { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn file_name(&self) -> OsString { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn metadata(&self) -> io::Result<FileAttr> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn file_type(&self) -> io::Result<FileType> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl OpenOptions { |
||||||
|
pub fn new() -> OpenOptions { |
||||||
|
OpenOptions {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&mut self, _read: bool) {} |
||||||
|
pub fn write(&mut self, _write: bool) {} |
||||||
|
pub fn append(&mut self, _append: bool) {} |
||||||
|
pub fn truncate(&mut self, _truncate: bool) {} |
||||||
|
pub fn create(&mut self, _create: bool) {} |
||||||
|
pub fn create_new(&mut self, _create_new: bool) {} |
||||||
|
} |
||||||
|
|
||||||
|
impl File { |
||||||
|
pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn file_attr(&self) -> io::Result<FileAttr> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn fsync(&self) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn datasync(&self) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn truncate(&self, _size: u64) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<File> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn diverge(&self) -> ! { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DirBuilder { |
||||||
|
pub fn new() -> DirBuilder { |
||||||
|
DirBuilder {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn mkdir(&self, _p: &Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for File { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn readdir(_p: &Path) -> io::Result<ReadDir> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn unlink(_p: &Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { |
||||||
|
match perm.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn rmdir(_p: &Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn remove_dir_all(_path: &Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn readlink(_p: &Path) -> io::Result<PathBuf> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn stat(_p: &Path) -> io::Result<FileAttr> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn lstat(_p: &Path) -> io::Result<FileAttr> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> { |
||||||
|
unsupported() |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use io; |
||||||
|
|
||||||
|
pub mod args; |
||||||
|
pub mod env; |
||||||
|
pub mod fs; |
||||||
|
pub mod net; |
||||||
|
#[path = "../../unix/path.rs"] |
||||||
|
pub mod path; |
||||||
|
pub mod pipe; |
||||||
|
pub mod process; |
||||||
|
pub mod os; |
||||||
|
|
||||||
|
// This enum is used as the storage for a bunch of types which can't actually exist.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] |
||||||
|
pub enum Void {} |
||||||
|
|
||||||
|
pub fn unsupported<T>() -> io::Result<T> { |
||||||
|
Err(io::Error::new( |
||||||
|
io::ErrorKind::Other, |
||||||
|
"This function is not available on CloudABI.", |
||||||
|
)) |
||||||
|
} |
@ -0,0 +1,296 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use fmt; |
||||||
|
use io; |
||||||
|
use net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; |
||||||
|
use time::Duration; |
||||||
|
use sys::{unsupported, Void}; |
||||||
|
|
||||||
|
pub extern crate libc as netc; |
||||||
|
|
||||||
|
pub struct TcpStream(Void); |
||||||
|
|
||||||
|
impl TcpStream { |
||||||
|
pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, _: &[u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<TcpStream> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nodelay(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn nodelay(&self) -> io::Result<bool> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_ttl(&self, _: u32) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn ttl(&self) -> io::Result<u32> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for TcpStream { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct TcpListener(Void); |
||||||
|
|
||||||
|
impl TcpListener { |
||||||
|
pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<TcpListener> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_ttl(&self, _: u32) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn ttl(&self) -> io::Result<u32> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_only_v6(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn only_v6(&self) -> io::Result<bool> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for TcpListener { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct UdpSocket(Void); |
||||||
|
|
||||||
|
impl UdpSocket { |
||||||
|
pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<UdpSocket> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_broadcast(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn broadcast(&self) -> io::Result<bool> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn multicast_loop_v4(&self) -> io::Result<bool> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn multicast_ttl_v4(&self) -> io::Result<u32> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn multicast_loop_v6(&self) -> io::Result<bool> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_ttl(&self, _: u32) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn ttl(&self) -> io::Result<u32> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn send(&self, _: &[u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn connect(&self, _: &SocketAddr) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for UdpSocket { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct LookupHost(Void); |
||||||
|
|
||||||
|
impl Iterator for LookupHost { |
||||||
|
type Item = SocketAddr; |
||||||
|
fn next(&mut self) -> Option<SocketAddr> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn lookup_host(_: &str) -> io::Result<LookupHost> { |
||||||
|
unsupported() |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use error::Error as StdError; |
||||||
|
use ffi::{OsStr, OsString}; |
||||||
|
use fmt; |
||||||
|
use io; |
||||||
|
use iter; |
||||||
|
use path::{self, PathBuf}; |
||||||
|
use sys::{unsupported, Void}; |
||||||
|
|
||||||
|
pub fn getcwd() -> io::Result<PathBuf> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn chdir(_: &path::Path) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub type Env = iter::Empty<(OsString, OsString)>; |
||||||
|
|
||||||
|
pub fn env() -> Env { |
||||||
|
iter::empty() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> { |
||||||
|
Ok(None) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn unsetenv(_: &OsStr) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub struct SplitPaths<'a>(&'a Void); |
||||||
|
|
||||||
|
pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { |
||||||
|
panic!("unsupported") |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> Iterator for SplitPaths<'a> { |
||||||
|
type Item = PathBuf; |
||||||
|
fn next(&mut self) -> Option<PathBuf> { |
||||||
|
match *self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct JoinPathsError; |
||||||
|
|
||||||
|
pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError> |
||||||
|
where |
||||||
|
I: Iterator<Item = T>, |
||||||
|
T: AsRef<OsStr>, |
||||||
|
{ |
||||||
|
Err(JoinPathsError) |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Display for JoinPathsError { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
"not supported on CloudABI yet".fmt(f) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl StdError for JoinPathsError { |
||||||
|
fn description(&self) -> &str { |
||||||
|
"not supported on CloudABI yet" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn home_dir() -> Option<PathBuf> { |
||||||
|
None |
||||||
|
} |
||||||
|
|
||||||
|
pub fn temp_dir() -> PathBuf { |
||||||
|
PathBuf::from("/tmp") |
||||||
|
} |
||||||
|
|
||||||
|
pub fn current_exe() -> io::Result<PathBuf> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn getpid() -> u32 { |
||||||
|
1 |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use sys::Void; |
||||||
|
|
||||||
|
pub struct AnonPipe(Void); |
||||||
|
|
||||||
|
impl AnonPipe { |
||||||
|
pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn diverge(&self) -> ! { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> { |
||||||
|
match p1.0 {} |
||||||
|
} |
@ -0,0 +1,159 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use ffi::OsStr; |
||||||
|
use fmt; |
||||||
|
use io; |
||||||
|
use sys::fs::File; |
||||||
|
use sys::pipe::AnonPipe; |
||||||
|
use sys::{unsupported, Void}; |
||||||
|
use sys_common::process::{CommandEnv, DefaultEnvKey}; |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Command
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
pub struct Command { |
||||||
|
env: CommandEnv<DefaultEnvKey>, |
||||||
|
} |
||||||
|
|
||||||
|
// passed back to std::process with the pipes connected to the child, if any
|
||||||
|
// were requested
|
||||||
|
pub struct StdioPipes { |
||||||
|
pub stdin: Option<AnonPipe>, |
||||||
|
pub stdout: Option<AnonPipe>, |
||||||
|
pub stderr: Option<AnonPipe>, |
||||||
|
} |
||||||
|
|
||||||
|
pub enum Stdio { |
||||||
|
Inherit, |
||||||
|
Null, |
||||||
|
MakePipe, |
||||||
|
} |
||||||
|
|
||||||
|
impl Command { |
||||||
|
pub fn new(_program: &OsStr) -> Command { |
||||||
|
Command { |
||||||
|
env: Default::default(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn arg(&mut self, _arg: &OsStr) {} |
||||||
|
|
||||||
|
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { |
||||||
|
&mut self.env |
||||||
|
} |
||||||
|
|
||||||
|
pub fn cwd(&mut self, _dir: &OsStr) {} |
||||||
|
|
||||||
|
pub fn stdin(&mut self, _stdin: Stdio) {} |
||||||
|
|
||||||
|
pub fn stdout(&mut self, _stdout: Stdio) {} |
||||||
|
|
||||||
|
pub fn stderr(&mut self, _stderr: Stdio) {} |
||||||
|
|
||||||
|
pub fn spawn( |
||||||
|
&mut self, |
||||||
|
_default: Stdio, |
||||||
|
_needs_stdin: bool, |
||||||
|
) -> io::Result<(Process, StdioPipes)> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl From<AnonPipe> for Stdio { |
||||||
|
fn from(pipe: AnonPipe) -> Stdio { |
||||||
|
pipe.diverge() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl From<File> for Stdio { |
||||||
|
fn from(file: File) -> Stdio { |
||||||
|
file.diverge() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for Command { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct ExitStatus(Void); |
||||||
|
|
||||||
|
impl ExitStatus { |
||||||
|
pub fn success(&self) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn code(&self) -> Option<i32> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Clone for ExitStatus { |
||||||
|
fn clone(&self) -> ExitStatus { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Copy for ExitStatus {} |
||||||
|
|
||||||
|
impl PartialEq for ExitStatus { |
||||||
|
fn eq(&self, _other: &ExitStatus) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Eq for ExitStatus {} |
||||||
|
|
||||||
|
impl fmt::Debug for ExitStatus { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Display for ExitStatus { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)] |
||||||
|
pub struct ExitCode(bool); |
||||||
|
|
||||||
|
impl ExitCode { |
||||||
|
pub const SUCCESS: ExitCode = ExitCode(false); |
||||||
|
pub const FAILURE: ExitCode = ExitCode(true); |
||||||
|
|
||||||
|
pub fn as_i32(&self) -> i32 { |
||||||
|
self.0 as i32 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Process(Void); |
||||||
|
|
||||||
|
impl Process { |
||||||
|
pub fn id(&self) -> u32 { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn kill(&mut self) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn wait(&mut self) -> io::Result<ExitStatus> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
#![cfg_attr(test, allow(dead_code))] |
||||||
|
|
||||||
|
pub struct Handler; |
||||||
|
|
||||||
|
impl Handler { |
||||||
|
pub unsafe fn new() -> Handler { |
||||||
|
Handler |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn init() {} |
||||||
|
|
||||||
|
pub unsafe fn cleanup() {} |
@ -0,0 +1,83 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use sys::cloudabi::abi; |
||||||
|
|
||||||
|
pub struct Stdin(()); |
||||||
|
pub struct Stdout(()); |
||||||
|
pub struct Stderr(()); |
||||||
|
|
||||||
|
impl Stdin { |
||||||
|
pub fn new() -> io::Result<Stdin> { |
||||||
|
Ok(Stdin(())) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
Ok(0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stdout { |
||||||
|
pub fn new() -> io::Result<Stdout> { |
||||||
|
Ok(Stdout(())) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, _: &[u8]) -> io::Result<usize> { |
||||||
|
Err(io::Error::new( |
||||||
|
io::ErrorKind::BrokenPipe, |
||||||
|
"Stdout is not connected to any output in this environment", |
||||||
|
)) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stderr { |
||||||
|
pub fn new() -> io::Result<Stderr> { |
||||||
|
Ok(Stderr(())) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, _: &[u8]) -> io::Result<usize> { |
||||||
|
Err(io::Error::new( |
||||||
|
io::ErrorKind::BrokenPipe, |
||||||
|
"Stderr is not connected to any output in this environment", |
||||||
|
)) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// FIXME: right now this raw stderr handle is used in a few places because
|
||||||
|
// std::io::stderr_raw isn't exposed, but once that's exposed this impl
|
||||||
|
// should go away
|
||||||
|
impl io::Write for Stderr { |
||||||
|
fn write(&mut self, data: &[u8]) -> io::Result<usize> { |
||||||
|
Stderr::write(self, data) |
||||||
|
} |
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
Stderr::flush(self) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn is_ebadf(err: &io::Error) -> bool { |
||||||
|
err.raw_os_error() == Some(abi::errno::BADF as i32) |
||||||
|
} |
||||||
|
|
||||||
|
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; |
||||||
|
|
||||||
|
pub fn stderr_prints_nothing() -> bool { |
||||||
|
false |
||||||
|
} |
@ -0,0 +1,126 @@ |
|||||||
|
// Copyright 2014-2018 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.
|
||||||
|
|
||||||
|
use boxed::FnBox; |
||||||
|
use cmp; |
||||||
|
use ffi::CStr; |
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use mem; |
||||||
|
use ptr; |
||||||
|
use sys::cloudabi::abi; |
||||||
|
use sys::time::dur2intervals; |
||||||
|
use sys_common::thread::*; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; |
||||||
|
|
||||||
|
pub struct Thread { |
||||||
|
id: libc::pthread_t, |
||||||
|
} |
||||||
|
|
||||||
|
// CloudABI has pthread_t as a pointer in which case we still want
|
||||||
|
// a thread to be Send/Sync
|
||||||
|
unsafe impl Send for Thread {} |
||||||
|
unsafe impl Sync for Thread {} |
||||||
|
|
||||||
|
impl Thread { |
||||||
|
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> { |
||||||
|
let p = box p; |
||||||
|
let mut native: libc::pthread_t = mem::zeroed(); |
||||||
|
let mut attr: libc::pthread_attr_t = mem::zeroed(); |
||||||
|
assert_eq!(libc::pthread_attr_init(&mut attr), 0); |
||||||
|
|
||||||
|
let stack_size = cmp::max(stack, min_stack_size(&attr)); |
||||||
|
assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); |
||||||
|
|
||||||
|
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _); |
||||||
|
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); |
||||||
|
|
||||||
|
return if ret != 0 { |
||||||
|
Err(io::Error::from_raw_os_error(ret)) |
||||||
|
} else { |
||||||
|
mem::forget(p); // ownership passed to pthread_create
|
||||||
|
Ok(Thread { id: native }) |
||||||
|
}; |
||||||
|
|
||||||
|
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { |
||||||
|
unsafe { |
||||||
|
start_thread(main as *mut u8); |
||||||
|
} |
||||||
|
ptr::null_mut() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn yield_now() { |
||||||
|
let ret = unsafe { abi::thread_yield() }; |
||||||
|
debug_assert_eq!(ret, abi::errno::SUCCESS); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_name(_name: &CStr) { |
||||||
|
// CloudABI has no way to set a thread name.
|
||||||
|
} |
||||||
|
|
||||||
|
pub fn sleep(dur: Duration) { |
||||||
|
unsafe { |
||||||
|
let subscription = abi::subscription { |
||||||
|
type_: abi::eventtype::CLOCK, |
||||||
|
union: abi::subscription_union { |
||||||
|
clock: abi::subscription_clock { |
||||||
|
clock_id: abi::clockid::MONOTONIC, |
||||||
|
timeout: dur2intervals(&dur), |
||||||
|
..mem::zeroed() |
||||||
|
}, |
||||||
|
}, |
||||||
|
..mem::zeroed() |
||||||
|
}; |
||||||
|
let mut event: abi::event = mem::uninitialized(); |
||||||
|
let mut nevents: usize = mem::uninitialized(); |
||||||
|
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS); |
||||||
|
assert_eq!(event.error, abi::errno::SUCCESS); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn join(self) { |
||||||
|
unsafe { |
||||||
|
let ret = libc::pthread_join(self.id, ptr::null_mut()); |
||||||
|
mem::forget(self); |
||||||
|
assert!( |
||||||
|
ret == 0, |
||||||
|
"failed to join thread: {}", |
||||||
|
io::Error::from_raw_os_error(ret) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for Thread { |
||||||
|
fn drop(&mut self) { |
||||||
|
let ret = unsafe { libc::pthread_detach(self.id) }; |
||||||
|
debug_assert_eq!(ret, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg_attr(test, allow(dead_code))] |
||||||
|
pub mod guard { |
||||||
|
pub type Guard = !; |
||||||
|
pub unsafe fn current() -> Option<Guard> { |
||||||
|
None |
||||||
|
} |
||||||
|
pub unsafe fn init() -> Option<Guard> { |
||||||
|
None |
||||||
|
} |
||||||
|
pub unsafe fn deinit() {} |
||||||
|
} |
||||||
|
|
||||||
|
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { |
||||||
|
libc::PTHREAD_STACK_MIN |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
use mem; |
||||||
|
use sys::cloudabi::abi; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
const NSEC_PER_SEC: abi::timestamp = 1_000_000_000; |
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] |
||||||
|
pub struct Instant { |
||||||
|
t: abi::timestamp, |
||||||
|
} |
||||||
|
|
||||||
|
pub fn dur2intervals(dur: &Duration) -> abi::timestamp { |
||||||
|
dur.as_secs() |
||||||
|
.checked_mul(NSEC_PER_SEC) |
||||||
|
.and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp)) |
||||||
|
.expect("overflow converting duration to nanoseconds") |
||||||
|
} |
||||||
|
|
||||||
|
impl Instant { |
||||||
|
pub fn now() -> Instant { |
||||||
|
unsafe { |
||||||
|
let mut t = mem::uninitialized(); |
||||||
|
let ret = abi::clock_time_get(abi::clockid::MONOTONIC, 0, &mut t); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS); |
||||||
|
Instant { t: t } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_instant(&self, other: &Instant) -> Duration { |
||||||
|
let diff = self.t |
||||||
|
.checked_sub(other.t) |
||||||
|
.expect("second instant is later than self"); |
||||||
|
Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn add_duration(&self, other: &Duration) -> Instant { |
||||||
|
Instant { |
||||||
|
t: self.t |
||||||
|
.checked_add(dur2intervals(other)) |
||||||
|
.expect("overflow when adding duration to instant"), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_duration(&self, other: &Duration) -> Instant { |
||||||
|
Instant { |
||||||
|
t: self.t |
||||||
|
.checked_sub(dur2intervals(other)) |
||||||
|
.expect("overflow when subtracting duration from instant"), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] |
||||||
|
pub struct SystemTime { |
||||||
|
t: abi::timestamp, |
||||||
|
} |
||||||
|
|
||||||
|
impl SystemTime { |
||||||
|
pub fn now() -> SystemTime { |
||||||
|
unsafe { |
||||||
|
let mut t = mem::uninitialized(); |
||||||
|
let ret = abi::clock_time_get(abi::clockid::REALTIME, 0, &mut t); |
||||||
|
assert_eq!(ret, abi::errno::SUCCESS); |
||||||
|
SystemTime { t: t } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { |
||||||
|
if self.t >= other.t { |
||||||
|
let diff = self.t - other.t; |
||||||
|
Ok(Duration::new( |
||||||
|
diff / NSEC_PER_SEC, |
||||||
|
(diff % NSEC_PER_SEC) as u32, |
||||||
|
)) |
||||||
|
} else { |
||||||
|
let diff = other.t - self.t; |
||||||
|
Err(Duration::new( |
||||||
|
diff / NSEC_PER_SEC, |
||||||
|
(diff % NSEC_PER_SEC) as u32, |
||||||
|
)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn add_duration(&self, other: &Duration) -> SystemTime { |
||||||
|
SystemTime { |
||||||
|
t: self.t |
||||||
|
.checked_add(dur2intervals(other)) |
||||||
|
.expect("overflow when adding duration to instant"), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_duration(&self, other: &Duration) -> SystemTime { |
||||||
|
SystemTime { |
||||||
|
t: self.t |
||||||
|
.checked_sub(dur2intervals(other)) |
||||||
|
.expect("overflow when subtracting duration from instant"), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub const UNIX_EPOCH: SystemTime = SystemTime { t: 0 }; |
@ -0,0 +1,170 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
//! Android ABI-compatibility module
|
||||||
|
//!
|
||||||
|
//! The ABI of Android has changed quite a bit over time, and libstd attempts to
|
||||||
|
//! be both forwards and backwards compatible as much as possible. We want to
|
||||||
|
//! always work with the most recent version of Android, but we also want to
|
||||||
|
//! work with older versions of Android for whenever projects need to.
|
||||||
|
//!
|
||||||
|
//! Our current minimum supported Android version is `android-9`, e.g. Android
|
||||||
|
//! with API level 9. We then in theory want to work on that and all future
|
||||||
|
//! versions of Android!
|
||||||
|
//!
|
||||||
|
//! Some of the detection here is done at runtime via `dlopen` and
|
||||||
|
//! introspection. Other times no detection is performed at all and we just
|
||||||
|
//! provide a fallback implementation as some versions of Android we support
|
||||||
|
//! don't have the function.
|
||||||
|
//!
|
||||||
|
//! You'll find more details below about why each compatibility shim is needed.
|
||||||
|
|
||||||
|
#![cfg(target_os = "android")] |
||||||
|
|
||||||
|
use libc::{c_int, c_void, sighandler_t, size_t, ssize_t}; |
||||||
|
use libc::{ftruncate, pread, pwrite}; |
||||||
|
|
||||||
|
use io; |
||||||
|
use super::{cvt, cvt_r}; |
||||||
|
|
||||||
|
// The `log2` and `log2f` functions apparently appeared in android-18, or at
|
||||||
|
// least you can see they're not present in the android-17 header [1] and they
|
||||||
|
// are present in android-18 [2].
|
||||||
|
//
|
||||||
|
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
|
||||||
|
// /android-17/arch-arm/usr/include/math.h
|
||||||
|
// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
|
||||||
|
// /android-18/arch-arm/usr/include/math.h
|
||||||
|
//
|
||||||
|
// Note that these shims are likely less precise than directly calling `log2`,
|
||||||
|
// but hopefully that should be enough for now...
|
||||||
|
//
|
||||||
|
// Note that mathematically, for any arbitrary `y`:
|
||||||
|
//
|
||||||
|
// log_2(x) = log_y(x) / log_y(2)
|
||||||
|
// = log_y(x) / (1 / log_2(y))
|
||||||
|
// = log_y(x) * log_2(y)
|
||||||
|
//
|
||||||
|
// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
|
||||||
|
// and get:
|
||||||
|
//
|
||||||
|
// log_2(x) = ln(x) * log_2(e)
|
||||||
|
|
||||||
|
#[cfg(not(test))] |
||||||
|
pub fn log2f32(f: f32) -> f32 { |
||||||
|
f.ln() * ::f32::consts::LOG2_E |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(test))] |
||||||
|
pub fn log2f64(f: f64) -> f64 { |
||||||
|
f.ln() * ::f64::consts::LOG2_E |
||||||
|
} |
||||||
|
|
||||||
|
// Back in the day [1] the `signal` function was just an inline wrapper
|
||||||
|
// around `bsd_signal`, but starting in API level android-20 the `signal`
|
||||||
|
// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
|
||||||
|
// removed [3].
|
||||||
|
//
|
||||||
|
// Basically this means that if we want to be binary compatible with multiple
|
||||||
|
// Android releases (oldest being 9 and newest being 21) then we need to check
|
||||||
|
// for both symbols and not actually link against either.
|
||||||
|
//
|
||||||
|
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
|
||||||
|
// /android-18/arch-arm/usr/include/signal.h
|
||||||
|
// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
|
||||||
|
// /platforms/android-20/arch-arm
|
||||||
|
// /usr/include/signal.h
|
||||||
|
// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
|
||||||
|
// /android-21/arch-arm/usr/include/signal.h
|
||||||
|
pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t { |
||||||
|
weak!(fn signal(c_int, sighandler_t) -> sighandler_t); |
||||||
|
weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t); |
||||||
|
|
||||||
|
let f = signal.get().or_else(|| bsd_signal.get()); |
||||||
|
let f = f.expect("neither `signal` nor `bsd_signal` symbols found"); |
||||||
|
f(signum, handler) |
||||||
|
} |
||||||
|
|
||||||
|
// The `ftruncate64` symbol apparently appeared in android-12, so we do some
|
||||||
|
// dynamic detection to see if we can figure out whether `ftruncate64` exists.
|
||||||
|
//
|
||||||
|
// If it doesn't we just fall back to `ftruncate`, generating an error for
|
||||||
|
// too-large values.
|
||||||
|
#[cfg(target_pointer_width = "32")] |
||||||
|
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { |
||||||
|
weak!(fn ftruncate64(c_int, i64) -> c_int); |
||||||
|
|
||||||
|
unsafe { |
||||||
|
match ftruncate64.get() { |
||||||
|
Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()), |
||||||
|
None => { |
||||||
|
if size > i32::max_value() as u64 { |
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidInput, |
||||||
|
"cannot truncate >2GB")) |
||||||
|
} else { |
||||||
|
cvt_r(|| ftruncate(fd, size as i32)).map(|_| ()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")] |
||||||
|
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { |
||||||
|
unsafe { |
||||||
|
cvt_r(|| ftruncate(fd, size as i64)).map(|_| ()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")] |
||||||
|
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) |
||||||
|
-> io::Result<ssize_t> |
||||||
|
{ |
||||||
|
use convert::TryInto; |
||||||
|
weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t); |
||||||
|
pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { |
||||||
|
if let Ok(o) = offset.try_into() { |
||||||
|
cvt(pread(fd, buf, count, o)) |
||||||
|
} else { |
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidInput, |
||||||
|
"cannot pread >2GB")) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")] |
||||||
|
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) |
||||||
|
-> io::Result<ssize_t> |
||||||
|
{ |
||||||
|
use convert::TryInto; |
||||||
|
weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t); |
||||||
|
pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { |
||||||
|
if let Ok(o) = offset.try_into() { |
||||||
|
cvt(pwrite(fd, buf, count, o)) |
||||||
|
} else { |
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidInput, |
||||||
|
"cannot pwrite >2GB")) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")] |
||||||
|
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) |
||||||
|
-> io::Result<ssize_t> |
||||||
|
{ |
||||||
|
cvt(pread(fd, buf, count, offset)) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")] |
||||||
|
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) |
||||||
|
-> io::Result<ssize_t> |
||||||
|
{ |
||||||
|
cvt(pwrite(fd, buf, count, offset)) |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use ffi::OsString; |
||||||
|
use marker::PhantomData; |
||||||
|
use vec; |
||||||
|
|
||||||
|
pub unsafe fn init(_argc: isize, _argv: *const *const u8) { |
||||||
|
// Currently null because we haven't implemented args yet
|
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn cleanup() { |
||||||
|
} |
||||||
|
|
||||||
|
pub fn args() -> Args { |
||||||
|
return Args { |
||||||
|
iter: Vec::new().into_iter(), |
||||||
|
_dont_send_or_sync_me: PhantomData, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Args { |
||||||
|
iter: vec::IntoIter<OsString>, |
||||||
|
_dont_send_or_sync_me: PhantomData<*mut ()>, |
||||||
|
} |
||||||
|
|
||||||
|
impl Args { |
||||||
|
pub fn inner_debug(&self) -> &[OsString] { |
||||||
|
self.iter.as_slice() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Iterator for Args { |
||||||
|
type Item = OsString; |
||||||
|
fn next(&mut self) -> Option<OsString> { |
||||||
|
self.iter.next() |
||||||
|
} |
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) { |
||||||
|
self.iter.size_hint() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl ExactSizeIterator for Args { |
||||||
|
fn len(&self) -> usize { |
||||||
|
self.iter.len() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DoubleEndedIterator for Args { |
||||||
|
fn next_back(&mut self) -> Option<OsString> { |
||||||
|
self.iter.next_back() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/// Backtrace support built on libgcc with some extra OS-specific support
|
||||||
|
///
|
||||||
|
/// Some methods of getting a backtrace:
|
||||||
|
///
|
||||||
|
/// * The backtrace() functions on unix. It turns out this doesn't work very
|
||||||
|
/// well for green threads on macOS, and the address to symbol portion of it
|
||||||
|
/// suffers problems that are described below.
|
||||||
|
///
|
||||||
|
/// * Using libunwind. This is more difficult than it sounds because libunwind
|
||||||
|
/// isn't installed everywhere by default. It's also a bit of a hefty library,
|
||||||
|
/// so possibly not the best option. When testing, libunwind was excellent at
|
||||||
|
/// getting both accurate backtraces and accurate symbols across platforms.
|
||||||
|
/// This route was not chosen in favor of the next option, however.
|
||||||
|
///
|
||||||
|
/// * We're already using libgcc_s for exceptions in rust (triggering thread
|
||||||
|
/// unwinding and running destructors on the stack), and it turns out that it
|
||||||
|
/// conveniently comes with a function that also gives us a backtrace. All of
|
||||||
|
/// these functions look like _Unwind_*, but it's not quite the full
|
||||||
|
/// repertoire of the libunwind API. Due to it already being in use, this was
|
||||||
|
/// the chosen route of getting a backtrace.
|
||||||
|
///
|
||||||
|
/// After choosing libgcc_s for backtraces, the sad part is that it will only
|
||||||
|
/// give us a stack trace of instruction pointers. Thankfully these instruction
|
||||||
|
/// pointers are accurate (they work for green and native threads), but it's
|
||||||
|
/// then up to us again to figure out how to translate these addresses to
|
||||||
|
/// symbols. As with before, we have a few options. Before, that, a little bit
|
||||||
|
/// of an interlude about symbols. This is my very limited knowledge about
|
||||||
|
/// symbol tables, and this information is likely slightly wrong, but the
|
||||||
|
/// general idea should be correct.
|
||||||
|
///
|
||||||
|
/// When talking about symbols, it's helpful to know a few things about where
|
||||||
|
/// symbols are located. Some symbols are located in the dynamic symbol table
|
||||||
|
/// of the executable which in theory means that they're available for dynamic
|
||||||
|
/// linking and lookup. Other symbols end up only in the local symbol table of
|
||||||
|
/// the file. This loosely corresponds to pub and priv functions in Rust.
|
||||||
|
///
|
||||||
|
/// Armed with this knowledge, we know that our solution for address to symbol
|
||||||
|
/// translation will need to consult both the local and dynamic symbol tables.
|
||||||
|
/// With that in mind, here's our options of translating an address to
|
||||||
|
/// a symbol.
|
||||||
|
///
|
||||||
|
/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
|
||||||
|
/// behind the scenes to translate, and this is why backtrace() was not used.
|
||||||
|
/// Conveniently, this method works fantastically on macOS. It appears dladdr()
|
||||||
|
/// uses magic to consult the local symbol table, or we're putting everything
|
||||||
|
/// in the dynamic symbol table anyway. Regardless, for macOS, this is the
|
||||||
|
/// method used for translation. It's provided by the system and easy to do.o
|
||||||
|
///
|
||||||
|
/// Sadly, all other systems have a dladdr() implementation that does not
|
||||||
|
/// consult the local symbol table. This means that most functions are blank
|
||||||
|
/// because they don't have symbols. This means that we need another solution.
|
||||||
|
///
|
||||||
|
/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
|
||||||
|
/// libgcc_s version of the libunwind api), but involves taking a dependency
|
||||||
|
/// to libunwind. We may pursue this route in the future if we bundle
|
||||||
|
/// libunwind, but libunwind was unwieldy enough that it was not chosen at
|
||||||
|
/// this time to provide this functionality.
|
||||||
|
///
|
||||||
|
/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
|
||||||
|
/// semi-reasonable solution. The stdlib already knows how to spawn processes,
|
||||||
|
/// so in theory it could invoke readelf, parse the output, and consult the
|
||||||
|
/// local/dynamic symbol tables from there. This ended up not getting chosen
|
||||||
|
/// due to the craziness of the idea plus the advent of the next option.
|
||||||
|
///
|
||||||
|
/// * Use `libbacktrace`. It turns out that this is a small library bundled in
|
||||||
|
/// the gcc repository which provides backtrace and symbol translation
|
||||||
|
/// functionality. All we really need from it is the backtrace functionality,
|
||||||
|
/// and we only really need this on everything that's not macOS, so this is the
|
||||||
|
/// chosen route for now.
|
||||||
|
///
|
||||||
|
/// In summary, the current situation uses libgcc_s to get a trace of stack
|
||||||
|
/// pointers, and we use dladdr() or libbacktrace to translate these addresses
|
||||||
|
/// to symbols. This is a bit of a hokey implementation as-is, but it works for
|
||||||
|
/// all unix platforms we support right now, so it at least gets the job done.
|
||||||
|
|
||||||
|
pub use self::tracing::unwind_backtrace; |
||||||
|
pub use self::printing::{foreach_symbol_fileline, resolve_symname}; |
||||||
|
|
||||||
|
// tracing impls:
|
||||||
|
mod tracing; |
||||||
|
// symbol resolvers:
|
||||||
|
mod printing; |
||||||
|
|
||||||
|
#[cfg(not(target_os = "emscripten"))] |
||||||
|
pub mod gnu { |
||||||
|
use io; |
||||||
|
use fs; |
||||||
|
use libc::c_char; |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "ios")))] |
||||||
|
pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> { |
||||||
|
Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "ios"))] |
||||||
|
pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> { |
||||||
|
use env; |
||||||
|
use os::unix::ffi::OsStrExt; |
||||||
|
|
||||||
|
let filename = env::current_exe()?; |
||||||
|
let file = fs::File::open(&filename)?; |
||||||
|
let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() |
||||||
|
.map(|&x| x as c_char).collect(); |
||||||
|
filename_cstr.push(0); // Null terminate
|
||||||
|
Ok((filename_cstr, file)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct BacktraceContext; |
@ -0,0 +1,45 @@ |
|||||||
|
// Copyright 2014-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.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use intrinsics; |
||||||
|
use ffi::CStr; |
||||||
|
use libc; |
||||||
|
use sys::backtrace::BacktraceContext; |
||||||
|
use sys_common::backtrace::Frame; |
||||||
|
|
||||||
|
pub fn resolve_symname<F>(frame: Frame, |
||||||
|
callback: F, |
||||||
|
_: &BacktraceContext) -> io::Result<()> |
||||||
|
where F: FnOnce(Option<&str>) -> io::Result<()> |
||||||
|
{ |
||||||
|
unsafe { |
||||||
|
let mut info: Dl_info = intrinsics::init(); |
||||||
|
let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || |
||||||
|
info.dli_sname.is_null() { |
||||||
|
None |
||||||
|
} else { |
||||||
|
CStr::from_ptr(info.dli_sname).to_str().ok() |
||||||
|
}; |
||||||
|
callback(symname) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[repr(C)] |
||||||
|
struct Dl_info { |
||||||
|
dli_fname: *const libc::c_char, |
||||||
|
dli_fbase: *mut libc::c_void, |
||||||
|
dli_sname: *const libc::c_char, |
||||||
|
dli_saddr: *mut libc::c_void, |
||||||
|
} |
||||||
|
|
||||||
|
extern { |
||||||
|
fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
// Copyright 2014-2017 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.
|
||||||
|
|
||||||
|
mod dladdr; |
||||||
|
|
||||||
|
use sys::backtrace::BacktraceContext; |
||||||
|
use sys_common::backtrace::Frame; |
||||||
|
use io; |
||||||
|
|
||||||
|
#[cfg(target_os = "emscripten")] |
||||||
|
pub use self::dladdr::resolve_symname; |
||||||
|
|
||||||
|
#[cfg(target_os = "emscripten")] |
||||||
|
pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool> |
||||||
|
where |
||||||
|
F: FnMut(&[u8], u32) -> io::Result<()> |
||||||
|
{ |
||||||
|
Ok(false) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(target_os = "emscripten"))] |
||||||
|
pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline; |
||||||
|
|
||||||
|
#[cfg(not(target_os = "emscripten"))] |
||||||
|
pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> |
||||||
|
where |
||||||
|
F: FnOnce(Option<&str>) -> io::Result<()> |
||||||
|
{ |
||||||
|
::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { |
||||||
|
if symname.is_some() { |
||||||
|
callback(symname) |
||||||
|
} else { |
||||||
|
dladdr::resolve_symname(frame, callback, bc) |
||||||
|
} |
||||||
|
}, bc) |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
// Copyright 2014-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.
|
||||||
|
|
||||||
|
/// As always - iOS on arm uses SjLj exceptions and
|
||||||
|
/// _Unwind_Backtrace is even not available there. Still,
|
||||||
|
/// backtraces could be extracted using a backtrace function,
|
||||||
|
/// which thanks god is public
|
||||||
|
///
|
||||||
|
/// As mentioned in a huge comment block in `super::super`, backtrace
|
||||||
|
/// doesn't play well with green threads, so while it is extremely nice and
|
||||||
|
/// simple to use it should be used only on iOS devices as the only viable
|
||||||
|
/// option.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use sys::backtrace::BacktraceContext; |
||||||
|
use sys_common::backtrace::Frame; |
||||||
|
|
||||||
|
#[inline(never)] // if we know this is a function call, we can skip it when
|
||||||
|
// tracing
|
||||||
|
pub fn unwind_backtrace(frames: &mut [Frame]) |
||||||
|
-> io::Result<(usize, BacktraceContext)> |
||||||
|
{ |
||||||
|
const FRAME_LEN: usize = 100; |
||||||
|
assert!(FRAME_LEN >= frames.len()); |
||||||
|
let mut raw_frames = [::ptr::null_mut(); FRAME_LEN]; |
||||||
|
let nb_frames = unsafe { |
||||||
|
backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) |
||||||
|
} as usize; |
||||||
|
for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { |
||||||
|
*to = Frame { |
||||||
|
exact_position: *from as *mut u8, |
||||||
|
symbol_addr: *from as *mut u8, |
||||||
|
inline_context: 0, |
||||||
|
}; |
||||||
|
} |
||||||
|
Ok((nb_frames as usize, BacktraceContext)) |
||||||
|
} |
||||||
|
|
||||||
|
extern { |
||||||
|
fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
// Copyright 2014-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.
|
||||||
|
|
||||||
|
use error::Error; |
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use sys::backtrace::BacktraceContext; |
||||||
|
use sys_common::backtrace::Frame; |
||||||
|
|
||||||
|
use unwind as uw; |
||||||
|
|
||||||
|
struct Context<'a> { |
||||||
|
idx: usize, |
||||||
|
frames: &'a mut [Frame], |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
struct UnwindError(uw::_Unwind_Reason_Code); |
||||||
|
|
||||||
|
impl Error for UnwindError { |
||||||
|
fn description(&self) -> &'static str { |
||||||
|
"unexpected return value while unwinding" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl ::fmt::Display for UnwindError { |
||||||
|
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { |
||||||
|
write!(f, "{}: {:?}", self.description(), self.0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline(never)] // if we know this is a function call, we can skip it when
|
||||||
|
// tracing
|
||||||
|
pub fn unwind_backtrace(frames: &mut [Frame]) |
||||||
|
-> io::Result<(usize, BacktraceContext)> |
||||||
|
{ |
||||||
|
let mut cx = Context { |
||||||
|
idx: 0, |
||||||
|
frames, |
||||||
|
}; |
||||||
|
let result_unwind = unsafe { |
||||||
|
uw::_Unwind_Backtrace(trace_fn, |
||||||
|
&mut cx as *mut Context |
||||||
|
as *mut libc::c_void) |
||||||
|
}; |
||||||
|
// See libunwind:src/unwind/Backtrace.c for the return values.
|
||||||
|
// No, there is no doc.
|
||||||
|
match result_unwind { |
||||||
|
// These return codes seem to be benign and need to be ignored for backtraces
|
||||||
|
// to show up properly on all tested platforms.
|
||||||
|
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { |
||||||
|
Ok((cx.idx, BacktraceContext)) |
||||||
|
} |
||||||
|
_ => { |
||||||
|
Err(io::Error::new(io::ErrorKind::Other, |
||||||
|
UnwindError(result_unwind))) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
extern fn trace_fn(ctx: *mut uw::_Unwind_Context, |
||||||
|
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { |
||||||
|
let cx = unsafe { &mut *(arg as *mut Context) }; |
||||||
|
let mut ip_before_insn = 0; |
||||||
|
let mut ip = unsafe { |
||||||
|
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void |
||||||
|
}; |
||||||
|
if !ip.is_null() && ip_before_insn == 0 { |
||||||
|
// this is a non-signaling frame, so `ip` refers to the address
|
||||||
|
// after the calling instruction. account for that.
|
||||||
|
ip = (ip as usize - 1) as *mut _; |
||||||
|
} |
||||||
|
|
||||||
|
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
|
||||||
|
// it appears to work fine without it, so we only use
|
||||||
|
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
|
||||||
|
// slightly more accurate stack trace in the process.
|
||||||
|
//
|
||||||
|
// This is often because panic involves the last instruction of a
|
||||||
|
// function being "call std::rt::begin_unwind", with no ret
|
||||||
|
// instructions after it. This means that the return instruction
|
||||||
|
// pointer points *outside* of the calling function, and by
|
||||||
|
// unwinding it we go back to the original function.
|
||||||
|
let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { |
||||||
|
ip |
||||||
|
} else { |
||||||
|
unsafe { uw::_Unwind_FindEnclosingFunction(ip) } |
||||||
|
}; |
||||||
|
|
||||||
|
if cx.idx < cx.frames.len() { |
||||||
|
cx.frames[cx.idx] = Frame { |
||||||
|
symbol_addr: symaddr as *mut u8, |
||||||
|
exact_position: ip as *mut u8, |
||||||
|
inline_context: 0, |
||||||
|
}; |
||||||
|
cx.idx += 1; |
||||||
|
} |
||||||
|
|
||||||
|
uw::_URC_NO_REASON |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
pub use self::imp::*; |
||||||
|
|
||||||
|
#[cfg(not(all(target_os = "ios", target_arch = "arm")))] |
||||||
|
#[path = "gcc_s.rs"] |
||||||
|
mod imp; |
||||||
|
#[cfg(all(target_os = "ios", target_arch = "arm"))] |
||||||
|
#[path = "backtrace_fn.rs"] |
||||||
|
mod imp; |
@ -0,0 +1,43 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
#![cfg(not(test))] |
||||||
|
|
||||||
|
use libc::{c_float, c_double}; |
||||||
|
|
||||||
|
#[link_name = "m"] |
||||||
|
extern { |
||||||
|
pub fn acos(n: c_double) -> c_double; |
||||||
|
pub fn acosf(n: c_float) -> c_float; |
||||||
|
pub fn asin(n: c_double) -> c_double; |
||||||
|
pub fn asinf(n: c_float) -> c_float; |
||||||
|
pub fn atan(n: c_double) -> c_double; |
||||||
|
pub fn atan2(a: c_double, b: c_double) -> c_double; |
||||||
|
pub fn atan2f(a: c_float, b: c_float) -> c_float; |
||||||
|
pub fn atanf(n: c_float) -> c_float; |
||||||
|
pub fn cbrt(n: c_double) -> c_double; |
||||||
|
pub fn cbrtf(n: c_float) -> c_float; |
||||||
|
pub fn cosh(n: c_double) -> c_double; |
||||||
|
pub fn coshf(n: c_float) -> c_float; |
||||||
|
pub fn expm1(n: c_double) -> c_double; |
||||||
|
pub fn expm1f(n: c_float) -> c_float; |
||||||
|
pub fn fdim(a: c_double, b: c_double) -> c_double; |
||||||
|
pub fn fdimf(a: c_float, b: c_float) -> c_float; |
||||||
|
pub fn hypot(x: c_double, y: c_double) -> c_double; |
||||||
|
pub fn hypotf(x: c_float, y: c_float) -> c_float; |
||||||
|
pub fn log1p(n: c_double) -> c_double; |
||||||
|
pub fn log1pf(n: c_float) -> c_float; |
||||||
|
pub fn sinh(n: c_double) -> c_double; |
||||||
|
pub fn sinhf(n: c_float) -> c_float; |
||||||
|
pub fn tan(n: c_double) -> c_double; |
||||||
|
pub fn tanf(n: c_float) -> c_float; |
||||||
|
pub fn tanh(n: c_double) -> c_double; |
||||||
|
pub fn tanhf(n: c_float) -> c_float; |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// *Implementation adapted from `/sys/redox/condvar.rs`
|
||||||
|
|
||||||
|
use cell::UnsafeCell; |
||||||
|
use intrinsics::atomic_cxchg; |
||||||
|
use ptr; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
use sys::mutex::{self, Mutex}; |
||||||
|
|
||||||
|
pub struct Condvar { |
||||||
|
lock: UnsafeCell<*mut ::libctru::LightLock>, |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Send for Condvar {} |
||||||
|
unsafe impl Sync for Condvar {} |
||||||
|
|
||||||
|
impl Condvar { |
||||||
|
pub const fn new() -> Condvar { |
||||||
|
Condvar { |
||||||
|
lock: UnsafeCell::new(ptr::null_mut()), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn init(&self) { |
||||||
|
*self.lock.get() = ptr::null_mut(); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn notify_one(&self) { |
||||||
|
unsafe { |
||||||
|
let arbiter = ::libctru::__sync_get_arbiter(); |
||||||
|
|
||||||
|
::libctru::svcArbitrateAddress(arbiter, |
||||||
|
*self.lock.get() as u32, |
||||||
|
::libctru::ARBITRATION_SIGNAL, |
||||||
|
1, |
||||||
|
0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn notify_all(&self) { |
||||||
|
unsafe { |
||||||
|
let lock = self.lock.get(); |
||||||
|
|
||||||
|
if *lock == ptr::null_mut() { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
let arbiter = ::libctru::__sync_get_arbiter(); |
||||||
|
|
||||||
|
::libctru::svcArbitrateAddress(arbiter, |
||||||
|
*self.lock.get() as u32, |
||||||
|
::libctru::ARBITRATION_SIGNAL, |
||||||
|
-1, |
||||||
|
0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn wait(&self, mutex: &Mutex) { |
||||||
|
unsafe { |
||||||
|
let lock = self.lock.get(); |
||||||
|
|
||||||
|
if *lock != mutex::raw(mutex) as *mut i32 { |
||||||
|
if *lock != ptr::null_mut() { |
||||||
|
panic!("Condvar used with more than one Mutex"); |
||||||
|
} |
||||||
|
|
||||||
|
atomic_cxchg(lock as *mut usize, 0, mutex::raw(mutex) as usize); |
||||||
|
} |
||||||
|
|
||||||
|
mutex.unlock(); |
||||||
|
|
||||||
|
let arbiter = ::libctru::__sync_get_arbiter(); |
||||||
|
|
||||||
|
::libctru::svcArbitrateAddress(arbiter, |
||||||
|
*self.lock.get() as u32, |
||||||
|
::libctru::ARBITRATION_WAIT_IF_LESS_THAN, |
||||||
|
2, |
||||||
|
0); |
||||||
|
|
||||||
|
mutex.lock(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { |
||||||
|
use time::Instant; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let lock = self.lock.get(); |
||||||
|
|
||||||
|
if *lock != mutex::raw(mutex) as *mut i32 { |
||||||
|
if *lock != ptr::null_mut() { |
||||||
|
panic!("Condvar used with more than one Mutex"); |
||||||
|
} |
||||||
|
|
||||||
|
atomic_cxchg(lock as *mut usize, 0, mutex::raw(mutex) as usize); |
||||||
|
} |
||||||
|
|
||||||
|
let now = Instant::now(); |
||||||
|
|
||||||
|
let nanos = dur.as_secs() |
||||||
|
.saturating_mul(1_000_000_000) |
||||||
|
.saturating_add(dur.subsec_nanos() as u64); |
||||||
|
|
||||||
|
mutex.unlock(); |
||||||
|
|
||||||
|
let arbiter = ::libctru::__sync_get_arbiter(); |
||||||
|
|
||||||
|
::libctru::svcArbitrateAddress(arbiter, |
||||||
|
*self.lock.get() as u32, |
||||||
|
::libctru::ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, |
||||||
|
2, |
||||||
|
nanos as i64); |
||||||
|
|
||||||
|
mutex.lock(); |
||||||
|
|
||||||
|
now.elapsed() < dur |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
*self.lock.get() = ptr::null_mut(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,185 @@ |
|||||||
|
// Copyright 2012-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.
|
||||||
|
|
||||||
|
#[cfg(target_os = "horizon")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "nintendo"; |
||||||
|
pub const OS: &'static str = "horizon"; |
||||||
|
pub const DLL_PREFIX: &'static str = ""; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".cro"; |
||||||
|
pub const DLL_EXTENSION: &'static str = ".cro"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ".3dsx"; |
||||||
|
pub const EXE_EXTENSION: &'static str = "3dsx"; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "linux"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "macos")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "macos"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".dylib"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "dylib"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "ios")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "ios"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".dylib"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "dylib"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "freebsd")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "freebsd"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "dragonfly")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "dragonfly"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "bitrig")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "bitrig"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "netbsd")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "netbsd"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "openbsd")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "openbsd"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "android")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "android"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "solaris")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "solaris"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "haiku")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "haiku"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "emscripten"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ".js"; |
||||||
|
pub const EXE_EXTENSION: &'static str = "js"; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "emscripten"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ".js"; |
||||||
|
pub const EXE_EXTENSION: &'static str = "js"; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "fuchsia")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "fuchsia"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "l4re")] |
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "unix"; |
||||||
|
pub const OS: &'static str = "l4re"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
// 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 sys::os_str::Buf; |
||||||
|
use sys_common::{FromInner, IntoInner, AsInner}; |
||||||
|
|
||||||
|
/// Unix-specific extensions to [`OsString`].
|
||||||
|
///
|
||||||
|
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub trait OsStringExt { |
||||||
|
/// Creates an [`OsString`] from a byte vector.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::ffi::OsString;
|
||||||
|
/// use std::os::unix::ffi::OsStringExt;
|
||||||
|
///
|
||||||
|
/// let bytes = b"foo".to_vec();
|
||||||
|
/// let os_string = OsString::from_vec(bytes);
|
||||||
|
/// assert_eq!(os_string.to_str(), Some("foo"));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`OsString`]: ../../../ffi/struct.OsString.html
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
fn from_vec(vec: Vec<u8>) -> Self; |
||||||
|
|
||||||
|
/// Yields the underlying byte vector of this [`OsString`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::ffi::OsString;
|
||||||
|
/// use std::os::unix::ffi::OsStringExt;
|
||||||
|
///
|
||||||
|
/// let mut os_string = OsString::new();
|
||||||
|
/// os_string.push("foo");
|
||||||
|
/// let bytes = os_string.into_vec();
|
||||||
|
/// assert_eq!(bytes, b"foo");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`OsString`]: ../../../ffi/struct.OsString.html
|
||||||
|
#[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`].
|
||||||
|
///
|
||||||
|
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub trait OsStrExt { |
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
/// Creates an [`OsStr`] from a byte slice.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::ffi::OsStr;
|
||||||
|
/// use std::os::unix::ffi::OsStrExt;
|
||||||
|
///
|
||||||
|
/// let bytes = b"foo";
|
||||||
|
/// let os_str = OsStr::from_bytes(bytes);
|
||||||
|
/// assert_eq!(os_str.to_str(), Some("foo"));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`OsStr`]: ../../../ffi/struct.OsStr.html
|
||||||
|
fn from_bytes(slice: &[u8]) -> &Self; |
||||||
|
|
||||||
|
/// Gets the underlying byte view of the [`OsStr`] slice.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::ffi::OsStr;
|
||||||
|
/// use std::os::unix::ffi::OsStrExt;
|
||||||
|
///
|
||||||
|
/// let mut os_str = OsStr::new("foo");
|
||||||
|
/// let bytes = os_str.as_bytes();
|
||||||
|
/// assert_eq!(bytes, b"foo");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`OsStr`]: ../../../ffi/struct.OsStr.html
|
||||||
|
#[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 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,736 @@ |
|||||||
|
// 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 fs::{self, Permissions, OpenOptions}; |
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use path::Path; |
||||||
|
use sys; |
||||||
|
use sys_common::{FromInner, AsInner, AsInnerMut}; |
||||||
|
use sys::platform::fs::MetadataExt as UnixMetadataExt; |
||||||
|
|
||||||
|
/// Unix-specific extensions to [`File`].
|
||||||
|
///
|
||||||
|
/// [`File`]: ../../../../std/fs/struct.File.html
|
||||||
|
#[stable(feature = "file_offset", since = "1.15.0")] |
||||||
|
pub trait FileExt { |
||||||
|
/// Reads a number of bytes starting from a given offset.
|
||||||
|
///
|
||||||
|
/// Returns the number of bytes read.
|
||||||
|
///
|
||||||
|
/// The offset is relative to the start of the file and thus independent
|
||||||
|
/// from the current cursor.
|
||||||
|
///
|
||||||
|
/// The current file cursor is not affected by this function.
|
||||||
|
///
|
||||||
|
/// Note that similar to [`File::read`], it is not an error to return with a
|
||||||
|
/// short read.
|
||||||
|
///
|
||||||
|
/// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::io;
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::os::unix::prelude::FileExt;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let mut buf = [0u8; 8];
|
||||||
|
/// let file = File::open("foo.txt")?;
|
||||||
|
///
|
||||||
|
/// // We now read 8 bytes from the offset 10.
|
||||||
|
/// let num_bytes_read = file.read_at(&mut buf, 10)?;
|
||||||
|
/// println!("read {} bytes: {:?}", num_bytes_read, buf);
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "file_offset", since = "1.15.0")] |
||||||
|
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; |
||||||
|
|
||||||
|
/// Writes a number of bytes starting from a given offset.
|
||||||
|
///
|
||||||
|
/// Returns the number of bytes written.
|
||||||
|
///
|
||||||
|
/// The offset is relative to the start of the file and thus independent
|
||||||
|
/// from the current cursor.
|
||||||
|
///
|
||||||
|
/// The current file cursor is not affected by this function.
|
||||||
|
///
|
||||||
|
/// When writing beyond the end of the file, the file is appropriately
|
||||||
|
/// extended and the intermediate bytes are initialized with the value 0.
|
||||||
|
///
|
||||||
|
/// Note that similar to [`File::write`], it is not an error to return a
|
||||||
|
/// short write.
|
||||||
|
///
|
||||||
|
/// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::io;
|
||||||
|
/// use std::os::unix::prelude::FileExt;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let file = File::open("foo.txt")?;
|
||||||
|
///
|
||||||
|
/// // We now write at the offset 10.
|
||||||
|
/// file.write_at(b"sushi", 10)?;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "file_offset", since = "1.15.0")] |
||||||
|
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "file_offset", since = "1.15.0")] |
||||||
|
impl FileExt for fs::File { |
||||||
|
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { |
||||||
|
self.as_inner().read_at(buf, offset) |
||||||
|
} |
||||||
|
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { |
||||||
|
self.as_inner().write_at(buf, offset) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Unix-specific extensions to [`fs::Permissions`].
|
||||||
|
///
|
||||||
|
/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
pub trait PermissionsExt { |
||||||
|
/// Returns the underlying raw `st_mode` bits that contain the standard
|
||||||
|
/// Unix permissions for this file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::os::unix::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// fn main() -> std::io::Result<()> {
|
||||||
|
/// let f = File::create("foo.txt")?;
|
||||||
|
/// let metadata = f.metadata()?;
|
||||||
|
/// let permissions = metadata.permissions();
|
||||||
|
///
|
||||||
|
/// println!("permissions: {}", permissions.mode());
|
||||||
|
/// Ok(()) }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn mode(&self) -> u32; |
||||||
|
|
||||||
|
/// Sets the underlying raw bits for this set of permissions.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::os::unix::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// fn main() -> std::io::Result<()> {
|
||||||
|
/// let f = File::create("foo.txt")?;
|
||||||
|
/// let metadata = f.metadata()?;
|
||||||
|
/// let mut permissions = metadata.permissions();
|
||||||
|
///
|
||||||
|
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
|
||||||
|
/// assert_eq!(permissions.mode(), 0o644);
|
||||||
|
/// Ok(()) }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn set_mode(&mut self, mode: u32); |
||||||
|
|
||||||
|
/// Creates a new instance of `Permissions` from the given set of Unix
|
||||||
|
/// permission bits.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::fs::Permissions;
|
||||||
|
/// use std::os::unix::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// // Read/write for owner and read for others.
|
||||||
|
/// let permissions = Permissions::from_mode(0o644);
|
||||||
|
/// assert_eq!(permissions.mode(), 0o644);
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn from_mode(mode: u32) -> Self; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
impl PermissionsExt for Permissions { |
||||||
|
fn mode(&self) -> u32 { |
||||||
|
self.as_inner().mode() |
||||||
|
} |
||||||
|
|
||||||
|
fn set_mode(&mut self, mode: u32) { |
||||||
|
*self = Permissions::from_inner(FromInner::from_inner(mode)); |
||||||
|
} |
||||||
|
|
||||||
|
fn from_mode(mode: u32) -> Permissions { |
||||||
|
Permissions::from_inner(FromInner::from_inner(mode)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Unix-specific extensions to [`fs::OpenOptions`].
|
||||||
|
///
|
||||||
|
/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
pub trait OpenOptionsExt { |
||||||
|
/// Sets the mode bits that a new file will be created with.
|
||||||
|
///
|
||||||
|
/// If a new file is created as part of a `File::open_opts` call then this
|
||||||
|
/// specified `mode` will be used as the permission bits for the new file.
|
||||||
|
/// If no `mode` is set, the default of `0o666` will be used.
|
||||||
|
/// The operating system masks out bits with the systems `umask`, to produce
|
||||||
|
/// the final permissions.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// # fn main() {
|
||||||
|
/// let mut options = OpenOptions::new();
|
||||||
|
/// options.mode(0o644); // Give read/write for owner and read for others.
|
||||||
|
/// let file = options.open("foo.txt");
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn mode(&mut self, mode: u32) -> &mut Self; |
||||||
|
|
||||||
|
/// Pass custom flags to the `flags` argument of `open`.
|
||||||
|
///
|
||||||
|
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
|
||||||
|
/// ensure they do not interfere with the access mode set by Rusts options.
|
||||||
|
///
|
||||||
|
/// Custom flags can only set flags, not remove flags set by Rusts options.
|
||||||
|
/// This options overwrites any previously set custom flags.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # #![feature(libc)]
|
||||||
|
/// extern crate libc;
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// # fn main() {
|
||||||
|
/// let mut options = OpenOptions::new();
|
||||||
|
/// options.write(true);
|
||||||
|
/// if cfg!(unix) {
|
||||||
|
/// options.custom_flags(libc::O_NOFOLLOW);
|
||||||
|
/// }
|
||||||
|
/// let file = options.open("foo.txt");
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "open_options_ext", since = "1.10.0")] |
||||||
|
fn custom_flags(&mut self, flags: i32) -> &mut Self; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
impl OpenOptionsExt for OpenOptions { |
||||||
|
fn mode(&mut self, mode: u32) -> &mut OpenOptions { |
||||||
|
self.as_inner_mut().mode(mode); self |
||||||
|
} |
||||||
|
|
||||||
|
fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { |
||||||
|
self.as_inner_mut().custom_flags(flags); self |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Unix-specific extensions to [`fs::Metadata`].
|
||||||
|
///
|
||||||
|
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
pub trait MetadataExt { |
||||||
|
/// Returns the ID of the device containing the file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::io;
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let dev_id = meta.dev();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn dev(&self) -> u64; |
||||||
|
/// Returns the inode number.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let inode = meta.ino();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn ino(&self) -> u64; |
||||||
|
/// Returns the rights applied to this file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let mode = meta.mode();
|
||||||
|
/// let user_has_write_access = mode & 0o200;
|
||||||
|
/// let user_has_read_write_access = mode & 0o600;
|
||||||
|
/// let group_has_read_access = mode & 0o040;
|
||||||
|
/// let others_have_exec_access = mode & 0o001;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn mode(&self) -> u32; |
||||||
|
/// Returns the number of hard links pointing to this file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let nb_hard_links = meta.nlink();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn nlink(&self) -> u64; |
||||||
|
/// Returns the user ID of the owner of this file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let user_id = meta.uid();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn uid(&self) -> u32; |
||||||
|
/// Returns the group ID of the owner of this file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let group_id = meta.gid();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn gid(&self) -> u32; |
||||||
|
/// Returns the device ID of this file (if it is a special one).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let device_id = meta.rdev();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn rdev(&self) -> u64; |
||||||
|
/// Returns the total size of this file in bytes.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let file_size = meta.size();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn size(&self) -> u64; |
||||||
|
/// Returns the time of the last access to the file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let last_access_time = meta.atime();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn atime(&self) -> i64; |
||||||
|
/// Returns the time of the last access to the file in nanoseconds.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let nano_last_access_time = meta.atime_nsec();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn atime_nsec(&self) -> i64; |
||||||
|
/// Returns the time of the last modification of the file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let last_modification_time = meta.mtime();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn mtime(&self) -> i64; |
||||||
|
/// Returns the time of the last modification of the file in nanoseconds.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let nano_last_modification_time = meta.mtime_nsec();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn mtime_nsec(&self) -> i64; |
||||||
|
/// Returns the time of the last status change of the file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let last_status_change_time = meta.ctime();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn ctime(&self) -> i64; |
||||||
|
/// Returns the time of the last status change of the file in nanoseconds.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let nano_last_status_change_time = meta.ctime_nsec();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn ctime_nsec(&self) -> i64; |
||||||
|
/// Returns the blocksize for filesystem I/O.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let blocksize = meta.blksize();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn blksize(&self) -> u64; |
||||||
|
/// Returns the number of blocks allocated to the file, in 512-byte units.
|
||||||
|
///
|
||||||
|
/// Please note that this may be smaller than `st_size / 512` when the file has holes.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::MetadataExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("some_file")?;
|
||||||
|
/// let blocks = meta.blocks();
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn blocks(&self) -> u64; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
impl MetadataExt for fs::Metadata { |
||||||
|
fn dev(&self) -> u64 { self.st_dev() } |
||||||
|
fn ino(&self) -> u64 { self.st_ino() } |
||||||
|
fn mode(&self) -> u32 { self.st_mode() } |
||||||
|
fn nlink(&self) -> u64 { self.st_nlink() } |
||||||
|
fn uid(&self) -> u32 { self.st_uid() } |
||||||
|
fn gid(&self) -> u32 { self.st_gid() } |
||||||
|
fn rdev(&self) -> u64 { self.st_rdev() } |
||||||
|
fn size(&self) -> u64 { self.st_size() } |
||||||
|
fn atime(&self) -> i64 { self.st_atime() } |
||||||
|
fn atime_nsec(&self) -> i64 { self.st_atime_nsec() } |
||||||
|
fn mtime(&self) -> i64 { self.st_mtime() } |
||||||
|
fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() } |
||||||
|
fn ctime(&self) -> i64 { self.st_ctime() } |
||||||
|
fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() } |
||||||
|
fn blksize(&self) -> u64 { self.st_blksize() } |
||||||
|
fn blocks(&self) -> u64 { self.st_blocks() } |
||||||
|
} |
||||||
|
|
||||||
|
/// Unix-specific extensions for [`FileType`].
|
||||||
|
///
|
||||||
|
/// Adds support for special Unix file types such as block/character devices,
|
||||||
|
/// pipes, and sockets.
|
||||||
|
///
|
||||||
|
/// [`FileType`]: ../../../../std/fs/struct.FileType.html
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
pub trait FileTypeExt { |
||||||
|
/// Returns whether this file type is a block device.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::FileTypeExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("block_device_file")?;
|
||||||
|
/// let file_type = meta.file_type();
|
||||||
|
/// assert!(file_type.is_block_device());
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_block_device(&self) -> bool; |
||||||
|
/// Returns whether this file type is a char device.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::FileTypeExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("char_device_file")?;
|
||||||
|
/// let file_type = meta.file_type();
|
||||||
|
/// assert!(file_type.is_char_device());
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_char_device(&self) -> bool; |
||||||
|
/// Returns whether this file type is a fifo.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::FileTypeExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("fifo_file")?;
|
||||||
|
/// let file_type = meta.file_type();
|
||||||
|
/// assert!(file_type.is_fifo());
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_fifo(&self) -> bool; |
||||||
|
/// Returns whether this file type is a socket.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::FileTypeExt;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// fn main() -> io::Result<()> {
|
||||||
|
/// let meta = fs::metadata("unix.socket")?;
|
||||||
|
/// let file_type = meta.file_type();
|
||||||
|
/// assert!(file_type.is_socket());
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_socket(&self) -> bool; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
impl FileTypeExt for fs::FileType { |
||||||
|
fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) } |
||||||
|
fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) } |
||||||
|
fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) } |
||||||
|
fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } |
||||||
|
} |
||||||
|
|
||||||
|
/// Unix-specific extension methods for [`fs::DirEntry`].
|
||||||
|
///
|
||||||
|
/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
|
||||||
|
#[stable(feature = "dir_entry_ext", since = "1.1.0")] |
||||||
|
pub trait DirEntryExt { |
||||||
|
/// Returns the underlying `d_ino` field in the contained `dirent`
|
||||||
|
/// structure.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::os::unix::fs::DirEntryExt;
|
||||||
|
///
|
||||||
|
/// if let Ok(entries) = fs::read_dir(".") {
|
||||||
|
/// for entry in entries {
|
||||||
|
/// if let Ok(entry) = entry {
|
||||||
|
/// // Here, `entry` is a `DirEntry`.
|
||||||
|
/// println!("{:?}: {}", entry.file_name(), entry.ino());
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "dir_entry_ext", since = "1.1.0")] |
||||||
|
fn ino(&self) -> u64; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "dir_entry_ext", since = "1.1.0")] |
||||||
|
impl DirEntryExt for fs::DirEntry { |
||||||
|
fn ino(&self) -> u64 { 0u64 } |
||||||
|
} |
||||||
|
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::os::unix::fs;
|
||||||
|
///
|
||||||
|
/// fn main() -> std::io::Result<()> {
|
||||||
|
/// fs::symlink("a.txt", "b.txt")?;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "symlink", since = "1.1.0")] |
||||||
|
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> |
||||||
|
{ |
||||||
|
sys::fs::symlink(src.as_ref(), dst.as_ref()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Unix-specific extensions to [`fs::DirBuilder`].
|
||||||
|
///
|
||||||
|
/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
|
||||||
|
#[stable(feature = "dir_builder", since = "1.6.0")] |
||||||
|
pub trait DirBuilderExt { |
||||||
|
/// Sets the mode to create new directories with. This option defaults to
|
||||||
|
/// 0o777.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::DirBuilder;
|
||||||
|
/// use std::os::unix::fs::DirBuilderExt;
|
||||||
|
///
|
||||||
|
/// let mut builder = DirBuilder::new();
|
||||||
|
/// builder.mode(0o755);
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "dir_builder", since = "1.6.0")] |
||||||
|
fn mode(&mut self, mode: u32) -> &mut Self; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "dir_builder", since = "1.6.0")] |
||||||
|
impl DirBuilderExt for fs::DirBuilder { |
||||||
|
fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { |
||||||
|
self.as_inner_mut().set_mode(mode); |
||||||
|
self |
||||||
|
} |
||||||
|
} |
@ -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 os::raw; |
||||||
|
use sys; |
||||||
|
use io; |
||||||
|
use sys_common::{AsInner, FromInner, IntoInner}; |
||||||
|
use libc; |
||||||
|
|
||||||
|
/// 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 guaranteed 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.
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
pub trait FromRawFd { |
||||||
|
/// Constructs a new instance of `Self` from the given raw file
|
||||||
|
/// descriptor.
|
||||||
|
///
|
||||||
|
/// This function **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.
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> Self; |
||||||
|
} |
||||||
|
|
||||||
|
/// A trait to express the ability to consume an object and acquire ownership of
|
||||||
|
/// its raw file descriptor.
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
pub trait IntoRawFd { |
||||||
|
/// Consumes this object, returning the raw underlying file descriptor.
|
||||||
|
///
|
||||||
|
/// This function **transfers ownership** of the underlying file descriptor
|
||||||
|
/// to the caller. Callers are then the unique owners of the file descriptor
|
||||||
|
/// and must close the descriptor once it's no longer needed.
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
fn into_raw_fd(self) -> RawFd; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl AsRawFd for fs::File { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
impl FromRawFd for fs::File { |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> fs::File { |
||||||
|
fs::File::from_inner(sys::fs::File::from_inner(fd)) |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for fs::File { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "asraw_stdio", since = "1.21.0")] |
||||||
|
impl AsRawFd for io::Stdin { |
||||||
|
fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO } |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "asraw_stdio", since = "1.21.0")] |
||||||
|
impl AsRawFd for io::Stdout { |
||||||
|
fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO } |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "asraw_stdio", since = "1.21.0")] |
||||||
|
impl AsRawFd for io::Stderr { |
||||||
|
fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
// 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.
|
||||||
|
//!
|
||||||
|
//! Provides access to platform-level information on Unix platforms, and
|
||||||
|
//! exposes Unix-specific functions that would otherwise be inappropriate as
|
||||||
|
//! part of the core `std` library.
|
||||||
|
//!
|
||||||
|
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
|
||||||
|
//! `OsString`), allows to set permissions more granularly, extract low-level
|
||||||
|
//! file descriptors from files and sockets, and has platform-specific helpers
|
||||||
|
//! for spawning processes.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! use std::fs::File;
|
||||||
|
//! use std::os::unix::prelude::*;
|
||||||
|
//!
|
||||||
|
//! fn main() {
|
||||||
|
//! 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")] |
||||||
|
#![doc(cfg(unix))] |
||||||
|
|
||||||
|
pub mod io; |
||||||
|
pub mod ffi; |
||||||
|
pub mod fs; |
||||||
|
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)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::ffi::{OsStrExt, OsStringExt}; |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt}; |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::fs::DirEntryExt; |
||||||
|
#[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")] |
||||||
|
pub use super::fs::FileExt; |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
// 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
|
||||||
|
|
||||||
|
#![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)] |
||||||
|
|
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32; |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32; |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32; |
||||||
|
|
||||||
|
#[doc(inline)] |
||||||
|
#[stable(feature = "pthread_t", since = "1.8.0")] |
||||||
|
pub use sys::platform::raw::pthread_t; |
||||||
|
#[doc(inline)] |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t}; |
||||||
|
#[doc(inline)] |
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")] |
||||||
|
pub use sys::platform::raw::{blkcnt_t, time_t}; |
@ -0,0 +1,77 @@ |
|||||||
|
// Copyright 2014-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.
|
||||||
|
|
||||||
|
#![cfg(target_thread_local)] |
||||||
|
#![unstable(feature = "thread_local_internals", issue = "0")] |
||||||
|
|
||||||
|
// Since what appears to be glibc 2.18 this symbol has been shipped which
|
||||||
|
// GCC and clang both use to invoke destructors in thread_local globals, so
|
||||||
|
// let's do the same!
|
||||||
|
//
|
||||||
|
// Note, however, that we run on lots older linuxes, as well as cross
|
||||||
|
// compiling from a newer linux to an older linux, so we also have a
|
||||||
|
// fallback implementation to use as well.
|
||||||
|
//
|
||||||
|
// Due to rust-lang/rust#18804, make sure this is not generic!
|
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { |
||||||
|
use libc; |
||||||
|
use mem; |
||||||
|
use sys_common::thread_local::register_dtor_fallback; |
||||||
|
|
||||||
|
extern { |
||||||
|
#[linkage = "extern_weak"] |
||||||
|
static __dso_handle: *mut u8; |
||||||
|
#[linkage = "extern_weak"] |
||||||
|
static __cxa_thread_atexit_impl: *const libc::c_void; |
||||||
|
} |
||||||
|
if !__cxa_thread_atexit_impl.is_null() { |
||||||
|
type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), |
||||||
|
arg: *mut u8, |
||||||
|
dso_handle: *mut u8) -> libc::c_int; |
||||||
|
mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) |
||||||
|
(dtor, t, &__dso_handle as *const _ as *mut _); |
||||||
|
return |
||||||
|
} |
||||||
|
register_dtor_fallback(t, dtor); |
||||||
|
} |
||||||
|
|
||||||
|
// macOS's analog of the above linux function is this _tlv_atexit function.
|
||||||
|
// The disassembly of thread_local globals in C++ (at least produced by
|
||||||
|
// clang) will have this show up in the output.
|
||||||
|
#[cfg(target_os = "macos")] |
||||||
|
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { |
||||||
|
extern { |
||||||
|
fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), |
||||||
|
arg: *mut u8); |
||||||
|
} |
||||||
|
_tlv_atexit(dtor, t); |
||||||
|
} |
||||||
|
|
||||||
|
// Just use the thread_local fallback implementation, at least until there's
|
||||||
|
// a more direct implementation.
|
||||||
|
#[cfg(target_os = "fuchsia")] |
||||||
|
pub use sys_common::thread_local::register_dtor_fallback as register_dtor; |
||||||
|
|
||||||
|
pub fn requires_move_before_drop() -> bool { |
||||||
|
// The macOS implementation of TLS apparently had an odd aspect to it
|
||||||
|
// where the pointer we have may be overwritten while this destructor
|
||||||
|
// is running. Specifically if a TLS destructor re-accesses TLS it may
|
||||||
|
// trigger a re-initialization of all TLS variables, paving over at
|
||||||
|
// least some destroyed ones with initial values.
|
||||||
|
//
|
||||||
|
// This means that if we drop a TLS value in place on macOS that we could
|
||||||
|
// revert the value to its original state halfway through the
|
||||||
|
// destructor, which would be bad!
|
||||||
|
//
|
||||||
|
// Hence, we use `ptr::read` on macOS (to move to a "safe" location)
|
||||||
|
// instead of drop_in_place.
|
||||||
|
cfg!(target_os = "macos") |
||||||
|
} |
@ -0,0 +1,265 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#![unstable(reason = "not public", issue = "0", feature = "fd")] |
||||||
|
|
||||||
|
use cmp; |
||||||
|
use io::{self, Read}; |
||||||
|
use libc::{self, c_int, c_void, ssize_t}; |
||||||
|
use mem; |
||||||
|
use sync::atomic::{AtomicBool, Ordering}; |
||||||
|
use sys::cvt; |
||||||
|
use sys_common::AsInner; |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct FileDesc { |
||||||
|
fd: c_int, |
||||||
|
} |
||||||
|
|
||||||
|
fn max_len() -> usize { |
||||||
|
// The maximum read limit on most posix-like systems is `SSIZE_MAX`,
|
||||||
|
// with the man page quoting that if the count of bytes to read is
|
||||||
|
// greater than `SSIZE_MAX` the result is "unspecified".
|
||||||
|
//
|
||||||
|
// On macOS, however, apparently the 64-bit libc is either buggy or
|
||||||
|
// intentionally showing odd behavior by rejecting any read with a size
|
||||||
|
// larger than or equal to INT_MAX. To handle both of these the read
|
||||||
|
// size is capped on both platforms.
|
||||||
|
if cfg!(target_os = "macos") { |
||||||
|
<c_int>::max_value() as usize - 1 |
||||||
|
} else { |
||||||
|
<ssize_t>::max_value() as usize |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl FileDesc { |
||||||
|
pub fn new(fd: c_int) -> FileDesc { |
||||||
|
FileDesc { fd: fd } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn raw(&self) -> c_int { self.fd } |
||||||
|
|
||||||
|
/// Extracts the actual filedescriptor without closing it.
|
||||||
|
pub fn into_raw(self) -> c_int { |
||||||
|
let fd = self.fd; |
||||||
|
mem::forget(self); |
||||||
|
fd |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
let ret = cvt(unsafe { |
||||||
|
libc::read(self.fd, |
||||||
|
buf.as_mut_ptr() as *mut c_void, |
||||||
|
cmp::min(buf.len(), max_len())) |
||||||
|
})?; |
||||||
|
Ok(ret as usize) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { |
||||||
|
let mut me = self; |
||||||
|
(&mut me).read_to_end(buf) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { |
||||||
|
#[cfg(target_os = "android")] |
||||||
|
use super::android::cvt_pread64; |
||||||
|
|
||||||
|
#[cfg(target_os = "emscripten")] |
||||||
|
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) |
||||||
|
-> io::Result<isize> |
||||||
|
{ |
||||||
|
use convert::TryInto; |
||||||
|
use libc::pread64; |
||||||
|
// pread64 on emscripten actually takes a 32 bit offset
|
||||||
|
if let Ok(o) = offset.try_into() { |
||||||
|
cvt(pread64(fd, buf, count, o)) |
||||||
|
} else { |
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidInput, |
||||||
|
"cannot pread >2GB")) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "emscripten")))] |
||||||
|
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) |
||||||
|
-> io::Result<isize> |
||||||
|
{ |
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
use libc::pread64; |
||||||
|
#[cfg(not(target_os = "linux"))] |
||||||
|
use libc::pread as pread64; |
||||||
|
cvt(pread64(fd, buf, count, offset)) |
||||||
|
} |
||||||
|
|
||||||
|
unsafe { |
||||||
|
cvt_pread64(self.fd, |
||||||
|
buf.as_mut_ptr() as *mut c_void, |
||||||
|
cmp::min(buf.len(), max_len()), |
||||||
|
offset as i64) |
||||||
|
.map(|n| n as usize) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
let ret = cvt(unsafe { |
||||||
|
libc::write(self.fd, |
||||||
|
buf.as_ptr() as *const c_void, |
||||||
|
cmp::min(buf.len(), max_len())) |
||||||
|
})?; |
||||||
|
Ok(ret as usize) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { |
||||||
|
#[cfg(target_os = "android")] |
||||||
|
use super::android::cvt_pwrite64; |
||||||
|
|
||||||
|
#[cfg(target_os = "emscripten")] |
||||||
|
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) |
||||||
|
-> io::Result<isize> |
||||||
|
{ |
||||||
|
use convert::TryInto; |
||||||
|
use libc::pwrite64; |
||||||
|
// pwrite64 on emscripten actually takes a 32 bit offset
|
||||||
|
if let Ok(o) = offset.try_into() { |
||||||
|
cvt(pwrite64(fd, buf, count, o)) |
||||||
|
} else { |
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidInput, |
||||||
|
"cannot pwrite >2GB")) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "emscripten")))] |
||||||
|
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) |
||||||
|
-> io::Result<isize> |
||||||
|
{ |
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
use libc::pwrite64; |
||||||
|
#[cfg(not(target_os = "linux"))] |
||||||
|
use libc::pwrite as pwrite64; |
||||||
|
cvt(pwrite64(fd, buf, count, offset)) |
||||||
|
} |
||||||
|
|
||||||
|
unsafe { |
||||||
|
cvt_pwrite64(self.fd, |
||||||
|
buf.as_ptr() as *const c_void, |
||||||
|
cmp::min(buf.len(), max_len()), |
||||||
|
offset as i64) |
||||||
|
.map(|n| n as usize) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// We don't have fork/exec on the 3DS, so this shouldn't need to do anything
|
||||||
|
#[cfg(target_os = "horizon")] |
||||||
|
pub fn set_cloexec(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
pub fn get_cloexec(&self) -> io::Result<bool> { |
||||||
|
unsafe { |
||||||
|
Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
||||||
|
unsafe { |
||||||
|
let v = nonblocking as c_int; |
||||||
|
cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))] |
||||||
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
||||||
|
unsafe { |
||||||
|
let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; |
||||||
|
let new = if nonblocking { |
||||||
|
previous | libc::O_NONBLOCK |
||||||
|
} else { |
||||||
|
previous & !libc::O_NONBLOCK |
||||||
|
}; |
||||||
|
if new != previous { |
||||||
|
cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<FileDesc> { |
||||||
|
// We want to atomically duplicate this file descriptor and set the
|
||||||
|
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
|
||||||
|
// flag, however, isn't supported on older Linux kernels (earlier than
|
||||||
|
// 2.6.24).
|
||||||
|
//
|
||||||
|
// To detect this and ensure that CLOEXEC is still set, we
|
||||||
|
// follow a strategy similar to musl [1] where if passing
|
||||||
|
// F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
|
||||||
|
// supported (the third parameter, 0, is always valid), so we stop
|
||||||
|
// trying that.
|
||||||
|
//
|
||||||
|
// Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
|
||||||
|
// resolve so we at least compile this.
|
||||||
|
//
|
||||||
|
// [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
|
||||||
|
#[cfg(any(target_os = "android", target_os = "haiku"))] |
||||||
|
use libc::F_DUPFD as F_DUPFD_CLOEXEC; |
||||||
|
#[cfg(not(any(target_os = "android", target_os="haiku")))] |
||||||
|
use libc::F_DUPFD_CLOEXEC; |
||||||
|
|
||||||
|
let make_filedesc = |fd| { |
||||||
|
let fd = FileDesc::new(fd); |
||||||
|
fd.set_cloexec()?; |
||||||
|
Ok(fd) |
||||||
|
}; |
||||||
|
static TRY_CLOEXEC: AtomicBool = |
||||||
|
AtomicBool::new(!cfg!(target_os = "android")); |
||||||
|
let fd = self.raw(); |
||||||
|
if TRY_CLOEXEC.load(Ordering::Relaxed) { |
||||||
|
match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) { |
||||||
|
// We *still* call the `set_cloexec` method as apparently some
|
||||||
|
// linux kernel at some point stopped setting CLOEXEC even
|
||||||
|
// though it reported doing so on F_DUPFD_CLOEXEC.
|
||||||
|
Ok(fd) => { |
||||||
|
return Ok(if cfg!(target_os = "linux") { |
||||||
|
make_filedesc(fd)? |
||||||
|
} else { |
||||||
|
FileDesc::new(fd) |
||||||
|
}) |
||||||
|
} |
||||||
|
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { |
||||||
|
TRY_CLOEXEC.store(false, Ordering::Relaxed); |
||||||
|
} |
||||||
|
Err(e) => return Err(e), |
||||||
|
} |
||||||
|
} |
||||||
|
cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> Read for &'a FileDesc { |
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
(**self).read(buf) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl AsInner<c_int> for FileDesc { |
||||||
|
fn as_inner(&self) -> &c_int { &self.fd } |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for FileDesc { |
||||||
|
fn drop(&mut self) { |
||||||
|
// Note that errors are ignored when closing a file descriptor. The
|
||||||
|
// reason for this is that if an error occurs we don't actually know if
|
||||||
|
// the file descriptor was closed or not, and if we retried (for
|
||||||
|
// something like EINTR), we might close another valid file descriptor
|
||||||
|
// (opened after we closed ours.
|
||||||
|
let _ = unsafe { libc::close(self.fd) }; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,928 @@ |
|||||||
|
// Copyright 2013-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.
|
||||||
|
|
||||||
|
use os::unix::prelude::*; |
||||||
|
|
||||||
|
use ffi::{CString, CStr, OsString, OsStr}; |
||||||
|
use fmt; |
||||||
|
use io::{self, Error, ErrorKind, SeekFrom}; |
||||||
|
use libc::{self, c_int, mode_t}; |
||||||
|
use mem; |
||||||
|
use path::{Path, PathBuf}; |
||||||
|
use ptr; |
||||||
|
use sync::Arc; |
||||||
|
use sys::fd::FileDesc; |
||||||
|
use sys::time::SystemTime; |
||||||
|
use sys::{cvt, cvt_r}; |
||||||
|
use sys_common::{AsInner, FromInner}; |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] |
||||||
|
use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; |
||||||
|
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] |
||||||
|
use libc::{fstatat, dirfd}; |
||||||
|
#[cfg(target_os = "android")] |
||||||
|
use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64, |
||||||
|
dirent as dirent64, open as open64}; |
||||||
|
#[cfg(not(any(target_os = "linux",
|
||||||
|
target_os = "emscripten", |
||||||
|
target_os = "l4re", |
||||||
|
target_os = "android")))] |
||||||
|
use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t, |
||||||
|
ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64}; |
||||||
|
#[cfg(not(any(target_os = "linux",
|
||||||
|
target_os = "emscripten", |
||||||
|
target_os = "solaris", |
||||||
|
target_os = "l4re", |
||||||
|
target_os = "fuchsia")))] |
||||||
|
use libc::{readdir_r as readdir64_r}; |
||||||
|
|
||||||
|
pub struct File(FileDesc); |
||||||
|
|
||||||
|
#[derive(Clone)] |
||||||
|
pub struct FileAttr { |
||||||
|
stat: stat64, |
||||||
|
} |
||||||
|
|
||||||
|
// all DirEntry's will have a reference to this struct
|
||||||
|
struct InnerReadDir { |
||||||
|
dirp: Dir, |
||||||
|
root: PathBuf, |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone)] |
||||||
|
pub struct ReadDir(Arc<InnerReadDir>); |
||||||
|
|
||||||
|
struct Dir(*mut libc::DIR); |
||||||
|
|
||||||
|
unsafe impl Send for Dir {} |
||||||
|
unsafe impl Sync for Dir {} |
||||||
|
|
||||||
|
pub struct DirEntry { |
||||||
|
entry: dirent64, |
||||||
|
dir: ReadDir, |
||||||
|
// We need to store an owned copy of the entry name
|
||||||
|
// on Solaris and Fuchsia because a) it uses a zero-length
|
||||||
|
// array to store the name, b) its lifetime between readdir
|
||||||
|
// calls is not guaranteed.
|
||||||
|
#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] |
||||||
|
name: Box<[u8]> |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, Debug)] |
||||||
|
pub struct OpenOptions { |
||||||
|
// generic
|
||||||
|
read: bool, |
||||||
|
write: bool, |
||||||
|
append: bool, |
||||||
|
truncate: bool, |
||||||
|
create: bool, |
||||||
|
create_new: bool, |
||||||
|
// system-specific
|
||||||
|
custom_flags: i32, |
||||||
|
mode: mode_t, |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)] |
||||||
|
pub struct FilePermissions { mode: mode_t } |
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |
||||||
|
pub struct FileType { mode: mode_t } |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct DirBuilder { mode: mode_t } |
||||||
|
|
||||||
|
impl FileAttr { |
||||||
|
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) } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn file_type(&self) -> FileType { |
||||||
|
FileType { mode: self.stat.st_mode as mode_t } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "netbsd")] |
||||||
|
impl FileAttr { |
||||||
|
pub fn modified(&self) -> io::Result<SystemTime> { |
||||||
|
Ok(SystemTime::from(libc::timespec { |
||||||
|
tv_sec: self.stat.st_mtime as libc::time_t, |
||||||
|
tv_nsec: self.stat.st_mtimensec as libc::c_long, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn accessed(&self) -> io::Result<SystemTime> { |
||||||
|
Ok(SystemTime::from(libc::timespec { |
||||||
|
tv_sec: self.stat.st_atime as libc::time_t, |
||||||
|
tv_nsec: self.stat.st_atimensec as libc::c_long, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn created(&self) -> io::Result<SystemTime> { |
||||||
|
Ok(SystemTime::from(libc::timespec { |
||||||
|
tv_sec: self.stat.st_birthtime as libc::time_t, |
||||||
|
tv_nsec: self.stat.st_birthtimensec as libc::c_long, |
||||||
|
})) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(target_os = "netbsd"))] |
||||||
|
impl FileAttr { |
||||||
|
pub fn modified(&self) -> io::Result<SystemTime> { |
||||||
|
Ok(SystemTime::from(libc::timespec { |
||||||
|
tv_sec: self.stat.st_mtime as libc::time_t, |
||||||
|
tv_nsec: 0 as _, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn accessed(&self) -> io::Result<SystemTime> { |
||||||
|
Ok(SystemTime::from(libc::timespec { |
||||||
|
tv_sec: self.stat.st_atime as libc::time_t, |
||||||
|
tv_nsec: 0 as _, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "bitrig",
|
||||||
|
target_os = "freebsd", |
||||||
|
target_os = "openbsd", |
||||||
|
target_os = "macos", |
||||||
|
target_os = "ios"))] |
||||||
|
pub fn created(&self) -> io::Result<SystemTime> { |
||||||
|
Ok(SystemTime::from(libc::timespec { |
||||||
|
tv_sec: self.stat.st_birthtime as libc::time_t, |
||||||
|
tv_nsec: self.stat.st_birthtime_nsec as libc::c_long, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "bitrig",
|
||||||
|
target_os = "freebsd", |
||||||
|
target_os = "openbsd", |
||||||
|
target_os = "macos", |
||||||
|
target_os = "ios")))] |
||||||
|
pub fn created(&self) -> io::Result<SystemTime> { |
||||||
|
Err(io::Error::new(io::ErrorKind::Other, |
||||||
|
"creation time is not available on this platform \ |
||||||
|
currently")) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl AsInner<stat64> for FileAttr { |
||||||
|
fn as_inner(&self) -> &stat64 { &self.stat } |
||||||
|
} |
||||||
|
|
||||||
|
impl FilePermissions { |
||||||
|
pub fn readonly(&self) -> bool { |
||||||
|
// check if any class (owner, group, others) has write permission
|
||||||
|
self.mode & 0o222 == 0 |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_readonly(&mut self, readonly: bool) { |
||||||
|
if readonly { |
||||||
|
// remove write permission for all classes; equivalent to `chmod a-w <file>`
|
||||||
|
self.mode &= !0o222; |
||||||
|
} else { |
||||||
|
// add write permission for all classes; equivalent to `chmod a+w <file>`
|
||||||
|
self.mode |= 0o222; |
||||||
|
} |
||||||
|
} |
||||||
|
pub fn mode(&self) -> u32 { self.mode as u32 } |
||||||
|
} |
||||||
|
|
||||||
|
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) } |
||||||
|
|
||||||
|
pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } |
||||||
|
} |
||||||
|
|
||||||
|
impl FromInner<u32> for FilePermissions { |
||||||
|
fn from_inner(mode: u32) -> FilePermissions { |
||||||
|
FilePermissions { mode: mode as mode_t } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for ReadDir { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
|
||||||
|
// Thus the result will be e g 'ReadDir("/home")'
|
||||||
|
fmt::Debug::fmt(&*self.0.root, f) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Iterator for ReadDir { |
||||||
|
type Item = io::Result<DirEntry>; |
||||||
|
|
||||||
|
#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] |
||||||
|
fn next(&mut self) -> Option<io::Result<DirEntry>> { |
||||||
|
unsafe { |
||||||
|
loop { |
||||||
|
// Although readdir_r(3) would be a correct function to use here because
|
||||||
|
// of the thread safety, on Illumos and Fuchsia the readdir(3C) function
|
||||||
|
// is safe to use in threaded applications and it is generally preferred
|
||||||
|
// over the readdir_r(3C) function.
|
||||||
|
super::os::set_errno(0); |
||||||
|
let entry_ptr = libc::readdir(self.0.dirp.0); |
||||||
|
if entry_ptr.is_null() { |
||||||
|
// NULL can mean either the end is reached or an error occurred.
|
||||||
|
// So we had to clear errno beforehand to check for an error now.
|
||||||
|
return match super::os::errno() { |
||||||
|
0 => None, |
||||||
|
e => Some(Err(Error::from_raw_os_error(e))), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let name = (*entry_ptr).d_name.as_ptr() as *const u8; |
||||||
|
let namelen = libc::strlen(name) as usize; |
||||||
|
|
||||||
|
let ret = DirEntry { |
||||||
|
entry: *entry_ptr, |
||||||
|
name: ::slice::from_raw_parts(name as *const u8, |
||||||
|
namelen as usize).to_owned().into_boxed_slice(), |
||||||
|
dir: self.clone() |
||||||
|
}; |
||||||
|
if ret.name_bytes() != b"." && ret.name_bytes() != b".." { |
||||||
|
return Some(Ok(ret)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))] |
||||||
|
fn next(&mut self) -> Option<io::Result<DirEntry>> { |
||||||
|
unsafe { |
||||||
|
let mut ret = DirEntry { |
||||||
|
entry: mem::zeroed(), |
||||||
|
dir: self.clone(), |
||||||
|
}; |
||||||
|
let mut entry_ptr = ptr::null_mut(); |
||||||
|
loop { |
||||||
|
if readdir64_r(self.0.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { |
||||||
|
return Some(Err(Error::last_os_error())) |
||||||
|
} |
||||||
|
if entry_ptr.is_null() { |
||||||
|
return None |
||||||
|
} |
||||||
|
if ret.name_bytes() != b"." && ret.name_bytes() != b".." { |
||||||
|
return Some(Ok(ret)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for Dir { |
||||||
|
fn drop(&mut self) { |
||||||
|
let r = unsafe { libc::closedir(self.0) }; |
||||||
|
debug_assert_eq!(r, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DirEntry { |
||||||
|
pub fn path(&self) -> PathBuf { |
||||||
|
self.dir.0.root.join(OsStr::from_bytes(self.name_bytes())) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn file_name(&self) -> OsString { |
||||||
|
OsStr::from_bytes(self.name_bytes()).to_os_string() |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] |
||||||
|
pub fn metadata(&self) -> io::Result<FileAttr> { |
||||||
|
let fd = cvt(unsafe {dirfd(self.dir.0.dirp.0)})?; |
||||||
|
let mut stat: stat64 = unsafe { mem::zeroed() }; |
||||||
|
cvt(unsafe { |
||||||
|
fstatat(fd, |
||||||
|
self.entry.d_name.as_ptr() as *const u8, |
||||||
|
&mut stat as *mut _ as *mut _, |
||||||
|
libc::AT_SYMLINK_NOFOLLOW) |
||||||
|
})?; |
||||||
|
Ok(FileAttr { stat: stat }) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] |
||||||
|
pub fn metadata(&self) -> io::Result<FileAttr> { |
||||||
|
lstat(&self.path()) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "solaris", target_os = "haiku"))] |
||||||
|
pub fn file_type(&self) -> io::Result<FileType> { |
||||||
|
lstat(&self.path()).map(|m| m.file_type()) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "solaris", target_os = "haiku")))] |
||||||
|
pub fn file_type(&self) -> io::Result<FileType> { |
||||||
|
match self.entry.d_type { |
||||||
|
libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), |
||||||
|
libc::DT_FIFO => Ok(FileType { mode: libc::S_IFIFO }), |
||||||
|
libc::DT_LNK => Ok(FileType { mode: libc::S_IFLNK }), |
||||||
|
libc::DT_REG => Ok(FileType { mode: libc::S_IFREG }), |
||||||
|
libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }), |
||||||
|
libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }), |
||||||
|
libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }), |
||||||
|
_ => lstat(&self.path()).map(|m| m.file_type()), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos",
|
||||||
|
target_os = "ios", |
||||||
|
target_os = "linux", |
||||||
|
target_os = "emscripten", |
||||||
|
target_os = "android", |
||||||
|
target_os = "solaris", |
||||||
|
target_os = "haiku", |
||||||
|
target_os = "l4re", |
||||||
|
target_os = "fuchsia"))] |
||||||
|
pub fn ino(&self) -> u64 { |
||||||
|
self.entry.d_ino as u64 |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "freebsd",
|
||||||
|
target_os = "openbsd", |
||||||
|
target_os = "bitrig", |
||||||
|
target_os = "netbsd", |
||||||
|
target_os = "dragonfly"))] |
||||||
|
pub fn ino(&self) -> u64 { |
||||||
|
self.entry.d_fileno as u64 |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos",
|
||||||
|
target_os = "ios", |
||||||
|
target_os = "netbsd", |
||||||
|
target_os = "openbsd", |
||||||
|
target_os = "freebsd", |
||||||
|
target_os = "dragonfly", |
||||||
|
target_os = "bitrig"))] |
||||||
|
fn name_bytes(&self) -> &[u8] { |
||||||
|
unsafe { |
||||||
|
::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8 as *const u8, |
||||||
|
self.entry.d_namlen as usize) |
||||||
|
} |
||||||
|
} |
||||||
|
#[cfg(any(target_os = "android",
|
||||||
|
target_os = "linux", |
||||||
|
target_os = "emscripten", |
||||||
|
target_os = "l4re", |
||||||
|
target_os = "haiku", |
||||||
|
target_os = "horizon"))] |
||||||
|
fn name_bytes(&self) -> &[u8] { |
||||||
|
unsafe { |
||||||
|
CStr::from_ptr(self.entry.d_name.as_ptr() as *const i8).to_bytes() |
||||||
|
} |
||||||
|
} |
||||||
|
#[cfg(any(target_os = "solaris",
|
||||||
|
target_os = "fuchsia"))] |
||||||
|
fn name_bytes(&self) -> &[u8] { |
||||||
|
&*self.name |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl OpenOptions { |
||||||
|
pub fn new() -> OpenOptions { |
||||||
|
OpenOptions { |
||||||
|
// generic
|
||||||
|
read: false, |
||||||
|
write: false, |
||||||
|
append: false, |
||||||
|
truncate: false, |
||||||
|
create: false, |
||||||
|
create_new: false, |
||||||
|
// system-specific
|
||||||
|
custom_flags: 0, |
||||||
|
mode: 0o666, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&mut self, read: bool) { self.read = read; } |
||||||
|
pub fn write(&mut self, write: bool) { self.write = write; } |
||||||
|
pub fn append(&mut self, append: bool) { self.append = append; } |
||||||
|
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } |
||||||
|
pub fn create(&mut self, create: bool) { self.create = create; } |
||||||
|
pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; } |
||||||
|
|
||||||
|
pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; } |
||||||
|
pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; } |
||||||
|
|
||||||
|
fn get_access_mode(&self) -> io::Result<c_int> { |
||||||
|
match (self.read, self.write, self.append) { |
||||||
|
(true, false, false) => Ok(libc::O_RDONLY), |
||||||
|
(false, true, false) => Ok(libc::O_WRONLY), |
||||||
|
(true, true, false) => Ok(libc::O_RDWR), |
||||||
|
(false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), |
||||||
|
(true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), |
||||||
|
(false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn get_creation_mode(&self) -> io::Result<c_int> { |
||||||
|
match (self.write, self.append) { |
||||||
|
(true, false) => {} |
||||||
|
(false, false) => |
||||||
|
if self.truncate || self.create || self.create_new { |
||||||
|
return Err(Error::from_raw_os_error(libc::EINVAL)); |
||||||
|
}, |
||||||
|
(_, true) => |
||||||
|
if self.truncate && !self.create_new { |
||||||
|
return Err(Error::from_raw_os_error(libc::EINVAL)); |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
Ok(match (self.create, self.truncate, self.create_new) { |
||||||
|
(false, false, false) => 0, |
||||||
|
(true, false, false) => libc::O_CREAT, |
||||||
|
(false, true, false) => libc::O_TRUNC, |
||||||
|
(true, true, false) => libc::O_CREAT | libc::O_TRUNC, |
||||||
|
(_, _, true) => libc::O_CREAT | libc::O_EXCL, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl File { |
||||||
|
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { |
||||||
|
let path = cstr(path)?; |
||||||
|
File::open_c(&path, opts) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> { |
||||||
|
let flags = libc::O_CLOEXEC | |
||||||
|
opts.get_access_mode()? | |
||||||
|
opts.get_creation_mode()? | |
||||||
|
(opts.custom_flags as c_int & !libc::O_ACCMODE); |
||||||
|
let fd = cvt_r(|| unsafe { |
||||||
|
open64(path.as_ptr() as *const u8, flags, opts.mode as c_int) |
||||||
|
})?; |
||||||
|
let fd = FileDesc::new(fd); |
||||||
|
|
||||||
|
// Currently the standard library supports Linux 2.6.18 which did not
|
||||||
|
// have the O_CLOEXEC flag (passed above). If we're running on an older
|
||||||
|
// Linux kernel then the flag is just ignored by the OS. After we open
|
||||||
|
// the first file, we check whether it has CLOEXEC set. If it doesn't,
|
||||||
|
// we will explicitly ask for a CLOEXEC fd for every further file we
|
||||||
|
// open, if it does, we will skip that step.
|
||||||
|
//
|
||||||
|
// The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
|
||||||
|
// that we support, so we only do this on Linux currently.
|
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> { |
||||||
|
use sync::atomic::{AtomicUsize, Ordering}; |
||||||
|
|
||||||
|
const OPEN_CLOEXEC_UNKNOWN: usize = 0; |
||||||
|
const OPEN_CLOEXEC_SUPPORTED: usize = 1; |
||||||
|
const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2; |
||||||
|
static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN); |
||||||
|
|
||||||
|
let need_to_set; |
||||||
|
match OPEN_CLOEXEC.load(Ordering::Relaxed) { |
||||||
|
OPEN_CLOEXEC_UNKNOWN => { |
||||||
|
need_to_set = !fd.get_cloexec()?; |
||||||
|
OPEN_CLOEXEC.store(if need_to_set { |
||||||
|
OPEN_CLOEXEC_NOTSUPPORTED |
||||||
|
} else { |
||||||
|
OPEN_CLOEXEC_SUPPORTED |
||||||
|
}, Ordering::Relaxed); |
||||||
|
}, |
||||||
|
OPEN_CLOEXEC_SUPPORTED => need_to_set = false, |
||||||
|
OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true, |
||||||
|
_ => unreachable!(), |
||||||
|
} |
||||||
|
if need_to_set { |
||||||
|
fd.set_cloexec()?; |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))] |
||||||
|
fn ensure_cloexec(_: &FileDesc) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
ensure_cloexec(&fd)?; |
||||||
|
Ok(File(fd)) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn file_attr(&self) -> io::Result<FileAttr> { |
||||||
|
let mut stat: stat64 = unsafe { mem::zeroed() }; |
||||||
|
cvt(unsafe { |
||||||
|
fstat64(self.0.raw(), &mut stat) |
||||||
|
})?; |
||||||
|
Ok(FileAttr { stat: stat }) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn fsync(&self) -> io::Result<()> { |
||||||
|
cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn datasync(&self) -> io::Result<()> { |
||||||
|
cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; |
||||||
|
return Ok(()); |
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "ios"))] |
||||||
|
unsafe fn os_datasync(fd: c_int) -> c_int { |
||||||
|
libc::fcntl(fd, libc::F_FULLFSYNC) |
||||||
|
} |
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) } |
||||||
|
#[cfg(not(any(target_os = "macos",
|
||||||
|
target_os = "ios", |
||||||
|
target_os = "linux")))] |
||||||
|
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn truncate(&self, size: u64) -> io::Result<()> { |
||||||
|
#[cfg(target_os = "android")] |
||||||
|
return ::sys::android::ftruncate64(self.0.raw(), size); |
||||||
|
|
||||||
|
#[cfg(not(target_os = "android"))] |
||||||
|
return cvt_r(|| unsafe { |
||||||
|
ftruncate64(self.0.raw(), size as off64_t) |
||||||
|
}).map(|_| ()); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
self.0.read(buf) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { |
||||||
|
self.0.read_at(buf, offset) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
self.0.write(buf) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { |
||||||
|
self.0.write_at(buf, offset) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { Ok(()) } |
||||||
|
|
||||||
|
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { |
||||||
|
let (whence, pos) = match pos { |
||||||
|
// Casting to `i64` is fine, too large values will end up as
|
||||||
|
// negative which will cause an error in `lseek64`.
|
||||||
|
SeekFrom::Start(off) => (libc::SEEK_SET, off as i64), |
||||||
|
SeekFrom::End(off) => (libc::SEEK_END, off), |
||||||
|
SeekFrom::Current(off) => (libc::SEEK_CUR, off), |
||||||
|
}; |
||||||
|
#[cfg(target_os = "emscripten")] |
||||||
|
let pos = pos as i32; |
||||||
|
let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?; |
||||||
|
Ok(n as u64) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<File> { |
||||||
|
self.0.duplicate().map(File) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn fd(&self) -> &FileDesc { &self.0 } |
||||||
|
|
||||||
|
pub fn into_fd(self) -> FileDesc { self.0 } |
||||||
|
|
||||||
|
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { |
||||||
|
cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DirBuilder { |
||||||
|
pub fn new() -> DirBuilder { |
||||||
|
DirBuilder { mode: 0o777 } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn mkdir(&self, p: &Path) -> io::Result<()> { |
||||||
|
let p = cstr(p)?; |
||||||
|
cvt(unsafe { libc::mkdir(p.as_ptr() as *const u8, self.mode) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_mode(&mut self, mode: u32) { |
||||||
|
self.mode = mode as mode_t; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn cstr(path: &Path) -> io::Result<CString> { |
||||||
|
Ok(CString::new(path.as_os_str().as_bytes())?) |
||||||
|
} |
||||||
|
|
||||||
|
impl FromInner<c_int> for File { |
||||||
|
fn from_inner(fd: c_int) -> File { |
||||||
|
File(FileDesc::new(fd)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for File { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
fn get_path(fd: c_int) -> Option<PathBuf> { |
||||||
|
let mut p = PathBuf::from("/proc/self/fd"); |
||||||
|
p.push(&fd.to_string()); |
||||||
|
readlink(&p).ok() |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "macos")] |
||||||
|
fn get_path(fd: c_int) -> Option<PathBuf> { |
||||||
|
// FIXME: The use of PATH_MAX is generally not encouraged, but it
|
||||||
|
// is inevitable in this case because macOS defines `fcntl` with
|
||||||
|
// `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
|
||||||
|
// alternatives. If a better method is invented, it should be used
|
||||||
|
// instead.
|
||||||
|
let mut buf = vec![0;libc::PATH_MAX as usize]; |
||||||
|
let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr() as *const u8) }; |
||||||
|
if n == -1 { |
||||||
|
return None; |
||||||
|
} |
||||||
|
let l = buf.iter().position(|&c| c == 0).unwrap(); |
||||||
|
buf.truncate(l as usize); |
||||||
|
buf.shrink_to_fit(); |
||||||
|
Some(PathBuf::from(OsString::from_vec(buf))) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos")))] |
||||||
|
fn get_path(_fd: c_int) -> Option<PathBuf> { |
||||||
|
// FIXME(#24570): implement this for other Unix platforms
|
||||||
|
None |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))] |
||||||
|
fn get_mode(fd: c_int) -> Option<(bool, bool)> { |
||||||
|
let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; |
||||||
|
if mode == -1 { |
||||||
|
return None; |
||||||
|
} |
||||||
|
match mode & libc::O_ACCMODE { |
||||||
|
libc::O_RDONLY => Some((true, false)), |
||||||
|
libc::O_RDWR => Some((true, true)), |
||||||
|
libc::O_WRONLY => Some((false, true)), |
||||||
|
_ => None |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos")))] |
||||||
|
fn get_mode(_fd: c_int) -> Option<(bool, bool)> { |
||||||
|
// FIXME(#24570): implement this for other Unix platforms
|
||||||
|
None |
||||||
|
} |
||||||
|
|
||||||
|
let fd = self.0.raw(); |
||||||
|
let mut b = f.debug_struct("File"); |
||||||
|
b.field("fd", &fd); |
||||||
|
if let Some(path) = get_path(fd) { |
||||||
|
b.field("path", &path); |
||||||
|
} |
||||||
|
if let Some((read, write)) = get_mode(fd) { |
||||||
|
b.field("read", &read).field("write", &write); |
||||||
|
} |
||||||
|
b.finish() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn readdir(p: &Path) -> io::Result<ReadDir> { |
||||||
|
let root = p.to_path_buf(); |
||||||
|
let p = cstr(p)?; |
||||||
|
unsafe { |
||||||
|
let ptr = libc::opendir(p.as_ptr() as *const u8); |
||||||
|
if ptr.is_null() { |
||||||
|
Err(Error::last_os_error()) |
||||||
|
} else { |
||||||
|
let inner = InnerReadDir { dirp: Dir(ptr), root }; |
||||||
|
Ok(ReadDir(Arc::new(inner))) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn unlink(p: &Path) -> io::Result<()> { |
||||||
|
let p = cstr(p)?; |
||||||
|
cvt(unsafe { libc::unlink(p.as_ptr() as *const u8) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn rename(old: &Path, new: &Path) -> io::Result<()> { |
||||||
|
let old = cstr(old)?; |
||||||
|
let new = cstr(new)?; |
||||||
|
cvt(unsafe { libc::rename(old.as_ptr() as *const u8, new.as_ptr() as *const u8) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { |
||||||
|
let p = cstr(p)?; |
||||||
|
cvt_r(|| unsafe { libc::chmod(p.as_ptr() as *const u8, perm.mode) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn rmdir(p: &Path) -> io::Result<()> { |
||||||
|
let p = cstr(p)?; |
||||||
|
cvt(unsafe { libc::rmdir(p.as_ptr() as *const u8) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn remove_dir_all(path: &Path) -> io::Result<()> { |
||||||
|
let filetype = lstat(path)?.file_type(); |
||||||
|
if filetype.is_symlink() { |
||||||
|
unlink(path) |
||||||
|
} else { |
||||||
|
remove_dir_all_recursive(path) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { |
||||||
|
for child in readdir(path)? { |
||||||
|
let child = child?; |
||||||
|
if child.file_type()?.is_dir() { |
||||||
|
remove_dir_all_recursive(&child.path())?; |
||||||
|
} else { |
||||||
|
unlink(&child.path())?; |
||||||
|
} |
||||||
|
} |
||||||
|
rmdir(path) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn readlink(p: &Path) -> io::Result<PathBuf> { |
||||||
|
let c_path = cstr(p)?; |
||||||
|
let p = c_path.as_ptr() as *const u8; |
||||||
|
|
||||||
|
let mut buf = Vec::with_capacity(256); |
||||||
|
|
||||||
|
loop { |
||||||
|
let buf_read = cvt(unsafe { |
||||||
|
libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) |
||||||
|
})? as usize; |
||||||
|
|
||||||
|
unsafe { buf.set_len(buf_read); } |
||||||
|
|
||||||
|
if buf_read != buf.capacity() { |
||||||
|
buf.shrink_to_fit(); |
||||||
|
|
||||||
|
return Ok(PathBuf::from(OsString::from_vec(buf))); |
||||||
|
} |
||||||
|
|
||||||
|
// Trigger the internal buffer resizing logic of `Vec` by requiring
|
||||||
|
// more space than the current capacity. The length is guaranteed to be
|
||||||
|
// the same as the capacity due to the if statement above.
|
||||||
|
buf.reserve(1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { |
||||||
|
let src = cstr(src)?; |
||||||
|
let dst = cstr(dst)?; |
||||||
|
cvt(unsafe { libc::symlink(src.as_ptr() as *const u8, dst.as_ptr() as *const u8) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn link(src: &Path, dst: &Path) -> io::Result<()> { |
||||||
|
let src = cstr(src)?; |
||||||
|
let dst = cstr(dst)?; |
||||||
|
cvt(unsafe { libc::link(src.as_ptr() as *const u8, dst.as_ptr() as *const u8) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn stat(p: &Path) -> io::Result<FileAttr> { |
||||||
|
let p = cstr(p)?; |
||||||
|
let mut stat: stat64 = unsafe { mem::zeroed() }; |
||||||
|
cvt(unsafe { |
||||||
|
stat64(p.as_ptr() as *const u8, &mut stat as *mut _ as *mut _) |
||||||
|
})?; |
||||||
|
Ok(FileAttr { stat: stat }) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn lstat(p: &Path) -> io::Result<FileAttr> { |
||||||
|
let p = cstr(p)?; |
||||||
|
let mut stat: stat64 = unsafe { mem::zeroed() }; |
||||||
|
cvt(unsafe { |
||||||
|
lstat64(p.as_ptr() as *const u8, &mut stat as *mut _ as *mut _) |
||||||
|
})?; |
||||||
|
Ok(FileAttr { stat: stat }) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { |
||||||
|
let path = CString::new(p.as_os_str().as_bytes())?; |
||||||
|
let buf; |
||||||
|
unsafe { |
||||||
|
let r = libc::realpath(path.as_ptr() as *const u8, ptr::null_mut()); |
||||||
|
if r.is_null() { |
||||||
|
return Err(io::Error::last_os_error()) |
||||||
|
} |
||||||
|
buf = CStr::from_ptr(r as *const i8).to_bytes().to_vec(); |
||||||
|
libc::free(r as *mut _); |
||||||
|
} |
||||||
|
Ok(PathBuf::from(OsString::from_vec(buf))) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "android")))] |
||||||
|
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { |
||||||
|
use fs::File; |
||||||
|
if !from.is_file() { |
||||||
|
return Err(Error::new(ErrorKind::InvalidInput, |
||||||
|
"the source path is not an existing regular file")) |
||||||
|
} |
||||||
|
|
||||||
|
let mut reader = File::open(from)?; |
||||||
|
let mut writer = File::create(to)?; |
||||||
|
let perm = reader.metadata()?.permissions(); |
||||||
|
|
||||||
|
let ret = io::copy(&mut reader, &mut writer)?; |
||||||
|
writer.set_permissions(perm)?; |
||||||
|
Ok(ret) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))] |
||||||
|
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { |
||||||
|
use cmp; |
||||||
|
use fs::File; |
||||||
|
use sync::atomic::{AtomicBool, Ordering}; |
||||||
|
|
||||||
|
// Kernel prior to 4.5 don't have copy_file_range
|
||||||
|
// We store the availability in a global to avoid unneccessary syscalls
|
||||||
|
static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); |
||||||
|
|
||||||
|
unsafe fn copy_file_range( |
||||||
|
fd_in: libc::c_int, |
||||||
|
off_in: *mut libc::loff_t, |
||||||
|
fd_out: libc::c_int, |
||||||
|
off_out: *mut libc::loff_t, |
||||||
|
len: libc::size_t, |
||||||
|
flags: libc::c_uint, |
||||||
|
) -> libc::c_long { |
||||||
|
libc::syscall( |
||||||
|
libc::SYS_copy_file_range, |
||||||
|
fd_in, |
||||||
|
off_in, |
||||||
|
fd_out, |
||||||
|
off_out, |
||||||
|
len, |
||||||
|
flags, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
if !from.is_file() { |
||||||
|
return Err(Error::new(ErrorKind::InvalidInput, |
||||||
|
"the source path is not an existing regular file")) |
||||||
|
} |
||||||
|
|
||||||
|
let mut reader = File::open(from)?; |
||||||
|
let mut writer = File::create(to)?; |
||||||
|
let (perm, len) = { |
||||||
|
let metadata = reader.metadata()?; |
||||||
|
(metadata.permissions(), metadata.size()) |
||||||
|
}; |
||||||
|
|
||||||
|
let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); |
||||||
|
let mut written = 0u64; |
||||||
|
while written < len { |
||||||
|
let copy_result = if has_copy_file_range { |
||||||
|
let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; |
||||||
|
let copy_result = unsafe { |
||||||
|
// We actually don't have to adjust the offsets,
|
||||||
|
// because copy_file_range adjusts the file offset automatically
|
||||||
|
cvt(copy_file_range(reader.as_raw_fd(), |
||||||
|
ptr::null_mut(), |
||||||
|
writer.as_raw_fd(), |
||||||
|
ptr::null_mut(), |
||||||
|
bytes_to_copy, |
||||||
|
0) |
||||||
|
) |
||||||
|
}; |
||||||
|
if let Err(ref copy_err) = copy_result { |
||||||
|
match copy_err.raw_os_error() { |
||||||
|
Some(libc::ENOSYS) | Some(libc::EPERM) => { |
||||||
|
HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); |
||||||
|
} |
||||||
|
_ => {} |
||||||
|
} |
||||||
|
} |
||||||
|
copy_result |
||||||
|
} else { |
||||||
|
Err(io::Error::from_raw_os_error(libc::ENOSYS)) |
||||||
|
}; |
||||||
|
match copy_result { |
||||||
|
Ok(ret) => written += ret as u64, |
||||||
|
Err(err) => { |
||||||
|
match err.raw_os_error() { |
||||||
|
Some(os_err) if os_err == libc::ENOSYS |
||||||
|
|| os_err == libc::EXDEV |
||||||
|
|| os_err == libc::EPERM => { |
||||||
|
// Try fallback io::copy if either:
|
||||||
|
// - Kernel version is < 4.5 (ENOSYS)
|
||||||
|
// - Files are mounted on different fs (EXDEV)
|
||||||
|
// - copy_file_range is disallowed, for example by seccomp (EPERM)
|
||||||
|
assert_eq!(written, 0); |
||||||
|
let ret = io::copy(&mut reader, &mut writer)?; |
||||||
|
writer.set_permissions(perm)?; |
||||||
|
return Ok(ret) |
||||||
|
}, |
||||||
|
_ => return Err(err), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
writer.set_permissions(perm)?; |
||||||
|
Ok(written) |
||||||
|
} |
@ -0,0 +1,441 @@ |
|||||||
|
// Copyright 2016-2017 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.
|
||||||
|
|
||||||
|
macro_rules! unimpl { |
||||||
|
() => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));) |
||||||
|
} |
||||||
|
|
||||||
|
pub mod net { |
||||||
|
#![allow(warnings)] |
||||||
|
use fmt; |
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; |
||||||
|
use sys_common::{AsInner, FromInner, IntoInner}; |
||||||
|
use sys::fd::FileDesc; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
|
||||||
|
pub extern crate libc as netc; |
||||||
|
|
||||||
|
pub struct Socket(FileDesc); |
||||||
|
impl Socket { |
||||||
|
pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t) |
||||||
|
-> io::Result<Socket> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<Socket> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, _: &[u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nodelay(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn nodelay(&self) -> io::Result<bool> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
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() } |
||||||
|
} |
||||||
|
|
||||||
|
impl FromInner<libc::c_int> for Socket { |
||||||
|
fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) } |
||||||
|
} |
||||||
|
|
||||||
|
impl IntoInner<libc::c_int> for Socket { |
||||||
|
fn into_inner(self) -> libc::c_int { self.0.into_raw() } |
||||||
|
} |
||||||
|
|
||||||
|
pub struct TcpStream { |
||||||
|
inner: Socket, |
||||||
|
} |
||||||
|
|
||||||
|
impl TcpStream { |
||||||
|
pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn socket(&self) -> &Socket { &self.inner } |
||||||
|
|
||||||
|
pub fn into_socket(self) -> Socket { self.inner } |
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, _: &[u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<TcpStream> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nodelay(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn nodelay(&self) -> io::Result<bool> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_ttl(&self, _: u32) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn ttl(&self) -> io::Result<u32> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl FromInner<Socket> for TcpStream { |
||||||
|
fn from_inner(socket: Socket) -> TcpStream { |
||||||
|
TcpStream { inner: socket } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for TcpStream { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
write!(f, "No networking support available on L4Re") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct TcpListener { |
||||||
|
inner: Socket, |
||||||
|
} |
||||||
|
|
||||||
|
impl TcpListener { |
||||||
|
pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn socket(&self) -> &Socket { &self.inner } |
||||||
|
|
||||||
|
pub fn into_socket(self) -> Socket { self.inner } |
||||||
|
|
||||||
|
pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<TcpListener> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_ttl(&self, _: u32) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn ttl(&self) -> io::Result<u32> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_only_v6(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn only_v6(&self) -> io::Result<bool> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl FromInner<Socket> for TcpListener { |
||||||
|
fn from_inner(socket: Socket) -> TcpListener { |
||||||
|
TcpListener { inner: socket } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for TcpListener { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
write!(f, "No networking support available on L4Re.") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct UdpSocket { |
||||||
|
inner: Socket, |
||||||
|
} |
||||||
|
|
||||||
|
impl UdpSocket { |
||||||
|
pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn socket(&self) -> &Socket { &self.inner } |
||||||
|
|
||||||
|
pub fn into_socket(self) -> Socket { self.inner } |
||||||
|
|
||||||
|
pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<UdpSocket> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_broadcast(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn broadcast(&self) -> io::Result<bool> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn multicast_loop_v4(&self) -> io::Result<bool> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn multicast_ttl_v4(&self) -> io::Result<u32> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn multicast_loop_v6(&self) -> io::Result<bool> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) |
||||||
|
-> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) |
||||||
|
-> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) |
||||||
|
-> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) |
||||||
|
-> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_ttl(&self, _: u32) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn ttl(&self) -> io::Result<u32> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn send(&self, _: &[u8]) -> io::Result<usize> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn connect(&self, _: &SocketAddr) -> io::Result<()> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl FromInner<Socket> for UdpSocket { |
||||||
|
fn from_inner(socket: Socket) -> UdpSocket { |
||||||
|
UdpSocket { inner: socket } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for UdpSocket { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
write!(f, "No networking support on L4Re available.") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct LookupHost { |
||||||
|
original: *mut libc::addrinfo, |
||||||
|
cur: *mut libc::addrinfo, |
||||||
|
} |
||||||
|
|
||||||
|
impl Iterator for LookupHost { |
||||||
|
type Item = SocketAddr; |
||||||
|
fn next(&mut self) -> Option<SocketAddr> { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Sync for LookupHost {} |
||||||
|
unsafe impl Send for LookupHost {} |
||||||
|
|
||||||
|
pub fn lookup_host(_: &str) -> io::Result<LookupHost> { |
||||||
|
unimpl!(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,57 @@ |
|||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Original implementation taken from rust-memchr
|
||||||
|
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
||||||
|
|
||||||
|
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { |
||||||
|
use libc; |
||||||
|
|
||||||
|
let p = unsafe { |
||||||
|
libc::memchr( |
||||||
|
haystack.as_ptr() as *const libc::c_void, |
||||||
|
needle as libc::c_int, |
||||||
|
haystack.len()) |
||||||
|
}; |
||||||
|
if p.is_null() { |
||||||
|
None |
||||||
|
} else { |
||||||
|
Some(p as usize - (haystack.as_ptr() as usize)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> { |
||||||
|
|
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> { |
||||||
|
use libc; |
||||||
|
|
||||||
|
// GNU's memrchr() will - unlike memchr() - error if haystack is empty.
|
||||||
|
if haystack.is_empty() {return None} |
||||||
|
let p = unsafe { |
||||||
|
libc::memrchr( |
||||||
|
haystack.as_ptr() as *const libc::c_void, |
||||||
|
needle as libc::c_int, |
||||||
|
haystack.len()) |
||||||
|
}; |
||||||
|
if p.is_null() { |
||||||
|
None |
||||||
|
} else { |
||||||
|
Some(p as usize - (haystack.as_ptr() as usize)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))] |
||||||
|
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> { |
||||||
|
::core::slice::memchr::memrchr(needle, haystack) |
||||||
|
} |
||||||
|
|
||||||
|
memrchr_specific(needle, haystack) |
||||||
|
} |
@ -0,0 +1,179 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#![allow(missing_docs, bad_style)] |
||||||
|
|
||||||
|
use io::{self, ErrorKind}; |
||||||
|
use libc; |
||||||
|
|
||||||
|
#[cfg(any(dox, target_os = "linux"))] pub use os::linux as platform; |
||||||
|
|
||||||
|
#[cfg(all(not(dox), target_os = "android"))] pub use os::android as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "bitrig"))] pub use os::bitrig as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "dragonfly"))] pub use os::dragonfly as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "freebsd"))] pub use os::freebsd as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "haiku"))] pub use os::haiku as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "ios"))] pub use os::ios as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "macos"))] pub use os::macos as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "netbsd"))] pub use os::netbsd as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "openbsd"))] pub use os::openbsd as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "solaris"))] pub use os::solaris as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform; |
||||||
|
#[cfg(all(not(dox), target_os = "horizon"))] pub use os::horizon as platform; |
||||||
|
|
||||||
|
pub use self::rand::hashmap_random_keys; |
||||||
|
pub use libc::strlen; |
||||||
|
|
||||||
|
#[macro_use] |
||||||
|
pub mod weak; |
||||||
|
|
||||||
|
pub mod args; |
||||||
|
pub mod android; |
||||||
|
#[cfg(feature = "backtrace")] |
||||||
|
pub mod backtrace; |
||||||
|
pub mod cmath; |
||||||
|
pub mod condvar; |
||||||
|
pub mod env; |
||||||
|
pub mod ext; |
||||||
|
pub mod fast_thread_local; |
||||||
|
pub mod fd; |
||||||
|
pub mod fs; |
||||||
|
pub mod memchr; |
||||||
|
pub mod mutex; |
||||||
|
#[cfg(not(target_os = "l4re"))] |
||||||
|
pub mod net; |
||||||
|
#[cfg(target_os = "l4re")] |
||||||
|
mod l4re; |
||||||
|
#[cfg(target_os = "l4re")] |
||||||
|
pub use self::l4re::net; |
||||||
|
pub mod os; |
||||||
|
pub mod os_str; |
||||||
|
pub mod path; |
||||||
|
pub mod pipe; |
||||||
|
pub mod process; |
||||||
|
pub mod rand; |
||||||
|
pub mod rwlock; |
||||||
|
pub mod stack_overflow; |
||||||
|
pub mod thread; |
||||||
|
pub mod thread_local; |
||||||
|
pub mod time; |
||||||
|
pub mod stdio; |
||||||
|
|
||||||
|
#[cfg(not(test))] |
||||||
|
pub fn init() { |
||||||
|
// By default, some platforms will send a *signal* when an EPIPE error
|
||||||
|
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
|
||||||
|
// handler, causing it to kill the program, which isn't exactly what we
|
||||||
|
// want!
|
||||||
|
//
|
||||||
|
// Hence, we set SIGPIPE to ignore when the program starts up in order
|
||||||
|
// to prevent this problem.
|
||||||
|
unsafe { |
||||||
|
reset_sigpipe(); |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] |
||||||
|
unsafe fn reset_sigpipe() { |
||||||
|
assert!(signal(0 as _, libc::SIG_IGN) != libc::SIG_ERR); |
||||||
|
} |
||||||
|
#[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] |
||||||
|
unsafe fn reset_sigpipe() {} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "android")] |
||||||
|
pub use sys::android::signal; |
||||||
|
#[cfg(not(target_os = "android"))] |
||||||
|
pub use libc::signal; |
||||||
|
|
||||||
|
pub fn unsupported<T>() -> io::Result<T> { |
||||||
|
Err(unsupported_err()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn unsupported_err() -> io::Error { |
||||||
|
io::Error::new(io::ErrorKind::Other, |
||||||
|
"operation not supported on 3DS yet") |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Copy,Clone)] |
||||||
|
pub enum Void {} |
||||||
|
|
||||||
|
pub fn decode_error_kind(errno: i32) -> ErrorKind { |
||||||
|
match errno as libc::c_int { |
||||||
|
libc::ECONNREFUSED => ErrorKind::ConnectionRefused, |
||||||
|
libc::ECONNRESET => ErrorKind::ConnectionReset, |
||||||
|
libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, |
||||||
|
libc::EPIPE => ErrorKind::BrokenPipe, |
||||||
|
libc::ENOTCONN => ErrorKind::NotConnected, |
||||||
|
libc::ECONNABORTED => ErrorKind::ConnectionAborted, |
||||||
|
libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, |
||||||
|
libc::EADDRINUSE => ErrorKind::AddrInUse, |
||||||
|
libc::ENOENT => ErrorKind::NotFound, |
||||||
|
libc::EINTR => ErrorKind::Interrupted, |
||||||
|
libc::EINVAL => ErrorKind::InvalidInput, |
||||||
|
libc::ETIMEDOUT => ErrorKind::TimedOut, |
||||||
|
libc::EEXIST => ErrorKind::AlreadyExists, |
||||||
|
|
||||||
|
// These two constants can have the same value on some systems,
|
||||||
|
// but different values on others, so we can't use a match
|
||||||
|
// clause
|
||||||
|
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => |
||||||
|
ErrorKind::WouldBlock, |
||||||
|
|
||||||
|
_ => ErrorKind::Other, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[doc(hidden)] |
||||||
|
pub trait IsMinusOne { |
||||||
|
fn is_minus_one(&self) -> bool; |
||||||
|
} |
||||||
|
|
||||||
|
macro_rules! impl_is_minus_one { |
||||||
|
($($t:ident)*) => ($(impl IsMinusOne for $t { |
||||||
|
fn is_minus_one(&self) -> bool { |
||||||
|
*self == -1 |
||||||
|
} |
||||||
|
})*) |
||||||
|
} |
||||||
|
|
||||||
|
impl_is_minus_one! { i8 i16 i32 i64 isize } |
||||||
|
|
||||||
|
pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { |
||||||
|
if t.is_minus_one() { |
||||||
|
Err(io::Error::last_os_error()) |
||||||
|
} else { |
||||||
|
Ok(t) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> |
||||||
|
where T: IsMinusOne, |
||||||
|
F: FnMut() -> T |
||||||
|
{ |
||||||
|
loop { |
||||||
|
match cvt(f()) { |
||||||
|
Err(ref e) if e.kind() == ErrorKind::Interrupted => {} |
||||||
|
other => return other, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// On Unix-like platforms, libc::abort will unregister signal handlers
|
||||||
|
// including the SIGABRT handler, preventing the abort from being blocked, and
|
||||||
|
// fclose streams, with the side effect of flushing them so libc bufferred
|
||||||
|
// output will be printed. Additionally the shell will generally print a more
|
||||||
|
// understandable error message like "Abort trap" rather than "Illegal
|
||||||
|
// instruction" that intrinsics::abort would cause, as intrinsics::abort is
|
||||||
|
// implemented as an illegal instruction.
|
||||||
|
pub unsafe fn abort_internal() -> ! { |
||||||
|
::libc::abort() |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use cell::UnsafeCell; |
||||||
|
use mem; |
||||||
|
|
||||||
|
pub struct Mutex { |
||||||
|
inner: UnsafeCell<::libctru::LightLock>, |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock { |
||||||
|
m.inner.get() |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Send for Mutex {} |
||||||
|
unsafe impl Sync for Mutex {} |
||||||
|
|
||||||
|
impl Mutex { |
||||||
|
pub const fn new() -> Mutex { |
||||||
|
Mutex { inner: UnsafeCell::new(0) } |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn init(&mut self) { |
||||||
|
::libctru::LightLock_Init(self.inner.get()); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn lock(&self) { |
||||||
|
::libctru::LightLock_Lock(self.inner.get()); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn unlock(&self) { |
||||||
|
::libctru::LightLock_Unlock(self.inner.get()); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn try_lock(&self) -> bool { |
||||||
|
match ::libctru::LightLock_TryLock(self.inner.get()) { |
||||||
|
0 => false, |
||||||
|
_ => true, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct ReentrantMutex { inner: UnsafeCell<::libctru::RecursiveLock> } |
||||||
|
|
||||||
|
unsafe impl Send for ReentrantMutex {} |
||||||
|
unsafe impl Sync for ReentrantMutex {} |
||||||
|
|
||||||
|
impl ReentrantMutex { |
||||||
|
pub unsafe fn uninitialized() -> ReentrantMutex { |
||||||
|
ReentrantMutex { inner: mem::uninitialized() } |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn init(&mut self) { |
||||||
|
::libctru::RecursiveLock_Init(self.inner.get()); |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn lock(&self) { |
||||||
|
::libctru::RecursiveLock_Lock(self.inner.get()); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn try_lock(&self) -> bool { |
||||||
|
match ::libctru::RecursiveLock_TryLock(self.inner.get()) { |
||||||
|
0 => false, |
||||||
|
_ => true, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn unlock(&self) { |
||||||
|
::libctru::RecursiveLock_Unlock(self.inner.get()); |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) {} |
||||||
|
} |
@ -0,0 +1,428 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#![allow(dead_code)] |
||||||
|
|
||||||
|
use ffi::CStr; |
||||||
|
use io; |
||||||
|
use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK}; |
||||||
|
use mem; |
||||||
|
use net::{SocketAddr, Shutdown}; |
||||||
|
use str; |
||||||
|
use sys::fd::FileDesc; |
||||||
|
use sys_common::{AsInner, FromInner, IntoInner}; |
||||||
|
use sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; |
||||||
|
use time::{Duration, Instant}; |
||||||
|
use cmp; |
||||||
|
|
||||||
|
pub use sys::{cvt, cvt_r}; |
||||||
|
pub extern crate libc as netc; |
||||||
|
|
||||||
|
pub type wrlen_t = size_t; |
||||||
|
|
||||||
|
// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on
|
||||||
|
// Linux currently (e.g. support doesn't exist on other platforms). In order to
|
||||||
|
// get name resolution to work and things to compile we just define a dummy
|
||||||
|
// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't
|
||||||
|
// actually ever used (the blocks below are wrapped in `if cfg!` as well.
|
||||||
|
#[cfg(target_os = "linux")] |
||||||
|
use libc::SOCK_CLOEXEC; |
||||||
|
#[cfg(not(target_os = "linux"))] |
||||||
|
const SOCK_CLOEXEC: c_int = 0; |
||||||
|
|
||||||
|
// Another conditional contant for name resolution: Macos et iOS use
|
||||||
|
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
|
||||||
|
// Other platforms do otherwise.
|
||||||
|
#[cfg(target_vendor = "apple")] |
||||||
|
use libc::SO_NOSIGPIPE; |
||||||
|
#[cfg(not(target_vendor = "apple"))] |
||||||
|
const SO_NOSIGPIPE: c_int = 0; |
||||||
|
|
||||||
|
const EAI_SYSTEM: c_int = 0; |
||||||
|
|
||||||
|
pub struct Socket(FileDesc); |
||||||
|
|
||||||
|
pub fn init() {} |
||||||
|
|
||||||
|
pub fn cvt_gai(err: c_int) -> io::Result<()> { |
||||||
|
if err == 0 { |
||||||
|
return Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
// We may need to trigger a glibc workaround. See on_resolver_failure() for details.
|
||||||
|
on_resolver_failure(); |
||||||
|
|
||||||
|
if err == EAI_SYSTEM { |
||||||
|
return Err(io::Error::last_os_error()) |
||||||
|
} |
||||||
|
|
||||||
|
let detail = unsafe { |
||||||
|
str::from_utf8(CStr::from_ptr(libc::gai_strerror(err) as *const i8).to_bytes()).unwrap() |
||||||
|
.to_owned() |
||||||
|
}; |
||||||
|
Err(io::Error::new(io::ErrorKind::Other, |
||||||
|
&format!("failed to lookup address information: {}", |
||||||
|
detail)[..])) |
||||||
|
} |
||||||
|
|
||||||
|
impl Socket { |
||||||
|
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { |
||||||
|
let fam = match *addr { |
||||||
|
SocketAddr::V4(..) => libc::AF_INET, |
||||||
|
SocketAddr::V6(..) => libc::AF_INET6, |
||||||
|
}; |
||||||
|
Socket::new_raw(fam, ty) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> { |
||||||
|
unsafe { |
||||||
|
// On linux we first attempt to pass the SOCK_CLOEXEC flag to
|
||||||
|
// atomically create the socket and set it as CLOEXEC. Support for
|
||||||
|
// this option, however, was added in 2.6.27, and we still support
|
||||||
|
// 2.6.18 as a kernel, so if the returned error is EINVAL we
|
||||||
|
// fallthrough to the fallback.
|
||||||
|
if cfg!(target_os = "linux") { |
||||||
|
match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) { |
||||||
|
Ok(fd) => return Ok(Socket(FileDesc::new(fd))), |
||||||
|
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} |
||||||
|
Err(e) => return Err(e), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let fd = cvt(libc::socket(fam, ty, 0))?; |
||||||
|
let fd = FileDesc::new(fd); |
||||||
|
fd.set_cloexec()?; |
||||||
|
let socket = Socket(fd); |
||||||
|
if cfg!(target_vendor = "apple") { |
||||||
|
setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?; |
||||||
|
} |
||||||
|
Ok(socket) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { |
||||||
|
unsafe { |
||||||
|
let mut fds = [0, 0]; |
||||||
|
|
||||||
|
// Like above, see if we can set cloexec atomically
|
||||||
|
if cfg!(target_os = "linux") { |
||||||
|
match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { |
||||||
|
Ok(_) => { |
||||||
|
return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))); |
||||||
|
} |
||||||
|
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}, |
||||||
|
Err(e) => return Err(e), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; |
||||||
|
let a = FileDesc::new(fds[0]); |
||||||
|
let b = FileDesc::new(fds[1]); |
||||||
|
a.set_cloexec()?; |
||||||
|
b.set_cloexec()?; |
||||||
|
Ok((Socket(a), Socket(b))) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { |
||||||
|
self.set_nonblocking(true)?; |
||||||
|
let r = unsafe { |
||||||
|
let (addrp, len) = addr.into_inner(); |
||||||
|
cvt(libc::connect(self.0.raw(), addrp, len)) |
||||||
|
}; |
||||||
|
self.set_nonblocking(false)?; |
||||||
|
|
||||||
|
match r { |
||||||
|
Ok(_) => return Ok(()), |
||||||
|
// there's no ErrorKind for EINPROGRESS :(
|
||||||
|
Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} |
||||||
|
Err(e) => return Err(e), |
||||||
|
} |
||||||
|
|
||||||
|
let mut pollfd = libc::pollfd { |
||||||
|
fd: self.0.raw(), |
||||||
|
events: libc::POLLOUT, |
||||||
|
revents: 0, |
||||||
|
}; |
||||||
|
|
||||||
|
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { |
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidInput, |
||||||
|
"cannot set a 0 duration timeout")); |
||||||
|
} |
||||||
|
|
||||||
|
let start = Instant::now(); |
||||||
|
|
||||||
|
loop { |
||||||
|
let elapsed = start.elapsed(); |
||||||
|
if elapsed >= timeout { |
||||||
|
return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")); |
||||||
|
} |
||||||
|
|
||||||
|
let timeout = timeout - elapsed; |
||||||
|
let mut timeout = timeout.as_secs() |
||||||
|
.saturating_mul(1_000) |
||||||
|
.saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); |
||||||
|
if timeout == 0 { |
||||||
|
timeout = 1; |
||||||
|
} |
||||||
|
|
||||||
|
let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; |
||||||
|
|
||||||
|
match unsafe { libc::poll(&mut pollfd, 1, timeout) } { |
||||||
|
-1 => { |
||||||
|
let err = io::Error::last_os_error(); |
||||||
|
if err.kind() != io::ErrorKind::Interrupted { |
||||||
|
return Err(err); |
||||||
|
} |
||||||
|
} |
||||||
|
0 => {} |
||||||
|
_ => { |
||||||
|
// linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
|
||||||
|
// for POLLHUP rather than read readiness
|
||||||
|
if pollfd.revents & libc::POLLHUP != 0 { |
||||||
|
let e = self.take_error()? |
||||||
|
.unwrap_or_else(|| { |
||||||
|
io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") |
||||||
|
}); |
||||||
|
return Err(e); |
||||||
|
} |
||||||
|
|
||||||
|
return Ok(()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) |
||||||
|
-> io::Result<Socket> { |
||||||
|
// Unfortunately the only known way right now to accept a socket and
|
||||||
|
// atomically set the CLOEXEC flag is to use the `accept4` syscall on
|
||||||
|
// Linux. This was added in 2.6.28, however, and because we support
|
||||||
|
// 2.6.18 we must detect this support dynamically.
|
||||||
|
if cfg!(target_os = "linux") { |
||||||
|
weak! { |
||||||
|
fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int |
||||||
|
} |
||||||
|
if let Some(accept) = accept4.get() { |
||||||
|
let res = cvt_r(|| unsafe { |
||||||
|
accept(self.0.raw(), storage, len, SOCK_CLOEXEC) |
||||||
|
}); |
||||||
|
match res { |
||||||
|
Ok(fd) => return Ok(Socket(FileDesc::new(fd))), |
||||||
|
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} |
||||||
|
Err(e) => return Err(e), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let fd = cvt_r(|| unsafe { |
||||||
|
libc::accept(self.0.raw(), storage, len) |
||||||
|
})?; |
||||||
|
let fd = FileDesc::new(fd); |
||||||
|
fd.set_cloexec()?; |
||||||
|
Ok(Socket(fd)) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<Socket> { |
||||||
|
self.0.duplicate().map(Socket) |
||||||
|
} |
||||||
|
|
||||||
|
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { |
||||||
|
let ret = cvt(unsafe { |
||||||
|
libc::recv(self.0.raw(), |
||||||
|
buf.as_mut_ptr() as *mut c_void, |
||||||
|
buf.len(), |
||||||
|
flags) |
||||||
|
})?; |
||||||
|
Ok(ret as usize) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
self.recv_with_flags(buf, 0) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
self.recv_with_flags(buf, MSG_PEEK) |
||||||
|
} |
||||||
|
|
||||||
|
fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int) |
||||||
|
-> io::Result<(usize, SocketAddr)> { |
||||||
|
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; |
||||||
|
let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; |
||||||
|
|
||||||
|
let n = cvt(unsafe { |
||||||
|
libc::recvfrom(self.0.raw(), |
||||||
|
buf.as_mut_ptr() as *mut c_void, |
||||||
|
buf.len(), |
||||||
|
flags, |
||||||
|
&mut storage as *mut _ as *mut _, |
||||||
|
&mut addrlen) |
||||||
|
})?; |
||||||
|
Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
self.recv_from_with_flags(buf, 0) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
||||||
|
self.recv_from_with_flags(buf, MSG_PEEK) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
self.0.write(buf) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> { |
||||||
|
let timeout = match dur { |
||||||
|
Some(dur) => { |
||||||
|
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { |
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidInput, |
||||||
|
"cannot set a 0 duration timeout")); |
||||||
|
} |
||||||
|
|
||||||
|
let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { |
||||||
|
libc::time_t::max_value() |
||||||
|
} else { |
||||||
|
dur.as_secs() as libc::time_t |
||||||
|
}; |
||||||
|
let mut timeout = libc::timeval { |
||||||
|
tv_sec: secs, |
||||||
|
tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, |
||||||
|
}; |
||||||
|
if timeout.tv_sec == 0 && timeout.tv_usec == 0 { |
||||||
|
timeout.tv_usec = 1; |
||||||
|
} |
||||||
|
timeout |
||||||
|
} |
||||||
|
None => { |
||||||
|
libc::timeval { |
||||||
|
tv_sec: 0, |
||||||
|
tv_usec: 0, |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
setsockopt(self, libc::SOL_SOCKET, kind, timeout) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> { |
||||||
|
let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; |
||||||
|
if raw.tv_sec == 0 && raw.tv_usec == 0 { |
||||||
|
Ok(None) |
||||||
|
} else { |
||||||
|
let sec = raw.tv_sec as u64; |
||||||
|
let nsec = (raw.tv_usec as u32) * 1000; |
||||||
|
Ok(Some(Duration::new(sec, nsec))) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
||||||
|
let how = match how { |
||||||
|
Shutdown::Write => libc::SHUT_WR, |
||||||
|
Shutdown::Read => libc::SHUT_RD, |
||||||
|
Shutdown::Both => libc::SHUT_RDWR, |
||||||
|
}; |
||||||
|
cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { |
||||||
|
setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn nodelay(&self) -> io::Result<bool> { |
||||||
|
let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; |
||||||
|
Ok(raw != 0) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
||||||
|
let mut nonblocking = nonblocking as libc::c_int; |
||||||
|
cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO as u32, &mut nonblocking) }).map(|_| ()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
||||||
|
let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; |
||||||
|
if raw == 0 { |
||||||
|
Ok(None) |
||||||
|
} else { |
||||||
|
Ok(Some(io::Error::from_raw_os_error(raw as i32))) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl AsInner<c_int> for Socket { |
||||||
|
fn as_inner(&self) -> &c_int { self.0.as_inner() } |
||||||
|
} |
||||||
|
|
||||||
|
impl FromInner<c_int> for Socket { |
||||||
|
fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) } |
||||||
|
} |
||||||
|
|
||||||
|
impl IntoInner<c_int> for Socket { |
||||||
|
fn into_inner(self) -> c_int { self.0.into_raw() } |
||||||
|
} |
||||||
|
|
||||||
|
// In versions of glibc prior to 2.26, there's a bug where the DNS resolver
|
||||||
|
// will cache the contents of /etc/resolv.conf, so changes to that file on disk
|
||||||
|
// can be ignored by a long-running program. That can break DNS lookups on e.g.
|
||||||
|
// laptops where the network comes and goes. See
|
||||||
|
// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some
|
||||||
|
// distros including Debian have patched glibc to fix this for a long time.
|
||||||
|
//
|
||||||
|
// A workaround for this bug is to call the res_init libc function, to clear
|
||||||
|
// the cached configs. Unfortunately, while we believe glibc's implementation
|
||||||
|
// of res_init is thread-safe, we know that other implementations are not
|
||||||
|
// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
|
||||||
|
// try to synchronize its res_init calls with a Mutex, but that wouldn't
|
||||||
|
// protect programs that call into libc in other ways. So instead of calling
|
||||||
|
// res_init unconditionally, we call it only when we detect we're linking
|
||||||
|
// against glibc version < 2.26. (That is, when we both know its needed and
|
||||||
|
// believe it's thread-safe).
|
||||||
|
#[cfg(target_env = "gnu")] |
||||||
|
fn on_resolver_failure() { |
||||||
|
use sys; |
||||||
|
|
||||||
|
// If the version fails to parse, we treat it the same as "not glibc".
|
||||||
|
if let Some(version) = sys::os::glibc_version() { |
||||||
|
if version < (2, 26) { |
||||||
|
unsafe { libc::res_init() }; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(target_env = "gnu"))] |
||||||
|
fn on_resolver_failure() {} |
||||||
|
|
||||||
|
#[cfg(all(test, taget_env = "gnu"))] |
||||||
|
mod test { |
||||||
|
use super::*; |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn test_res_init() { |
||||||
|
// This mostly just tests that the weak linkage doesn't panic wildly...
|
||||||
|
res_init_if_glibc_before_2_26().unwrap(); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn test_parse_glibc_version() { |
||||||
|
let cases = [ |
||||||
|
("0.0", Some((0, 0))), |
||||||
|
("01.+2", Some((1, 2))), |
||||||
|
("3.4.5.six", Some((3, 4))), |
||||||
|
("1", None), |
||||||
|
("1.-2", None), |
||||||
|
("1.foo", None), |
||||||
|
("foo.1", None), |
||||||
|
]; |
||||||
|
for &(version_str, parsed) in cases.iter() { |
||||||
|
assert_eq!(parsed, parse_glibc_version(version_str)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,191 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use error::Error as StdError; |
||||||
|
use ffi::{CString, CStr, OsString, OsStr}; |
||||||
|
use fmt; |
||||||
|
use io; |
||||||
|
use iter; |
||||||
|
use libc::{self, c_int, c_char}; |
||||||
|
use path::{self, PathBuf}; |
||||||
|
use slice; |
||||||
|
use str; |
||||||
|
use sys::{unsupported, Void}; |
||||||
|
use sys::horizon::ext::ffi::{OsStrExt, OsStringExt}; |
||||||
|
|
||||||
|
const TMPBUF_SZ: usize = 128; |
||||||
|
|
||||||
|
extern "C" { |
||||||
|
fn __errno() -> *mut c_int; |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns the platform-specific value of errno
|
||||||
|
pub fn errno() -> i32 { |
||||||
|
unsafe { |
||||||
|
(*__errno()) as i32 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets a detailed string description for the given error number.
|
||||||
|
pub fn error_string(errno: i32) -> String { |
||||||
|
extern { |
||||||
|
#[cfg_attr(any(target_os = "linux", target_env = "newlib"),
|
||||||
|
link_name = "__xpg_strerror_r")] |
||||||
|
fn strerror_r(errnum: c_int, buf: *mut c_char, |
||||||
|
buflen: libc::size_t) -> c_int; |
||||||
|
} |
||||||
|
|
||||||
|
let mut buf = [0 as c_char; TMPBUF_SZ]; |
||||||
|
|
||||||
|
let p = buf.as_mut_ptr(); |
||||||
|
unsafe { |
||||||
|
if strerror_r(errno as c_int, p, buf.len()) < 0 { |
||||||
|
panic!("strerror_r failure"); |
||||||
|
} |
||||||
|
|
||||||
|
let p = p as *const _; |
||||||
|
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn getcwd() -> io::Result<PathBuf> { |
||||||
|
let mut buf = Vec::with_capacity(512); |
||||||
|
loop { |
||||||
|
unsafe { |
||||||
|
let ptr = buf.as_mut_ptr() as *mut libc::c_char; |
||||||
|
if !libc::getcwd(ptr, buf.capacity()).is_null() { |
||||||
|
let len = CStr::from_ptr(buf.as_ptr() as *const i8).to_bytes().len(); |
||||||
|
buf.set_len(len); |
||||||
|
buf.shrink_to_fit(); |
||||||
|
return Ok(PathBuf::from(OsString::from_vec(buf))); |
||||||
|
} else { |
||||||
|
let error = io::Error::last_os_error(); |
||||||
|
if error.raw_os_error() != Some(libc::ERANGE) { |
||||||
|
return Err(error); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Trigger the internal buffer resizing logic of `Vec` by requiring
|
||||||
|
// more space than the current capacity.
|
||||||
|
let cap = buf.capacity(); |
||||||
|
buf.set_len(cap); |
||||||
|
buf.reserve(1); |
||||||
|
} |
||||||
|
}
|
||||||
|
} |
||||||
|
|
||||||
|
pub fn chdir(p: &path::Path) -> io::Result<()> { |
||||||
|
let p: &OsStr = p.as_ref(); |
||||||
|
let p = CString::new(p.as_bytes())?; |
||||||
|
unsafe { |
||||||
|
match libc::chdir(p.as_ptr() as *const u8) == (0 as c_int) { |
||||||
|
true => Ok(()), |
||||||
|
false => Err(io::Error::last_os_error()), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct SplitPaths<'a> { |
||||||
|
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, |
||||||
|
fn(&'a [u8]) -> PathBuf>, |
||||||
|
} |
||||||
|
|
||||||
|
pub fn split_paths(unparsed: &OsStr) -> SplitPaths { |
||||||
|
fn bytes_to_path(b: &[u8]) -> PathBuf { |
||||||
|
PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) |
||||||
|
} |
||||||
|
fn is_colon(b: &u8) -> bool { *b == b':' } |
||||||
|
let unparsed = unparsed.as_bytes(); |
||||||
|
SplitPaths { |
||||||
|
iter: unparsed.split(is_colon as fn(&u8) -> bool) |
||||||
|
.map(bytes_to_path as fn(&[u8]) -> PathBuf) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> Iterator for SplitPaths<'a> { |
||||||
|
type Item = PathBuf; |
||||||
|
fn next(&mut self) -> Option<PathBuf> { self.iter.next() } |
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct JoinPathsError; |
||||||
|
|
||||||
|
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> |
||||||
|
where I: Iterator<Item=T>, T: AsRef<OsStr> |
||||||
|
{ |
||||||
|
let mut joined = Vec::new(); |
||||||
|
let sep = b':'; |
||||||
|
|
||||||
|
for (i, path) in paths.enumerate() { |
||||||
|
let path = path.as_ref().as_bytes(); |
||||||
|
if i > 0 { joined.push(sep) } |
||||||
|
if path.contains(&sep) { |
||||||
|
return Err(JoinPathsError) |
||||||
|
} |
||||||
|
joined.extend_from_slice(path); |
||||||
|
} |
||||||
|
Ok(OsStringExt::from_vec(joined)) |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Display for JoinPathsError { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
"path segment contains separator `:`".fmt(f) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl StdError for JoinPathsError { |
||||||
|
fn description(&self) -> &str { "failed to join paths" } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn current_exe() -> io::Result<PathBuf> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Env(Void); |
||||||
|
|
||||||
|
impl Iterator for Env { |
||||||
|
type Item = (OsString, OsString); |
||||||
|
fn next(&mut self) -> Option<(OsString, OsString)> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn env() -> Env { |
||||||
|
panic!("not supported on 3DS yet") |
||||||
|
} |
||||||
|
|
||||||
|
pub fn getenv(_k: &OsStr) -> io::Result<Option<OsString>> { |
||||||
|
return Ok(None) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn unsetenv(_n: &OsStr) -> io::Result<()> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn temp_dir() -> PathBuf { |
||||||
|
PathBuf::from("/tmp") |
||||||
|
} |
||||||
|
|
||||||
|
pub fn home_dir() -> Option<PathBuf> { |
||||||
|
None |
||||||
|
} |
||||||
|
|
||||||
|
pub fn exit(code: i32) -> ! { |
||||||
|
unsafe { libc::exit(code as c_int) } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn getpid() -> u32 { |
||||||
|
panic!("no pids on 3DS") |
||||||
|
}
|
@ -0,0 +1,189 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/// The underlying OsString/OsStr implementation on Unix systems: just
|
||||||
|
/// a `Vec<u8>`/`[u8]`.
|
||||||
|
|
||||||
|
use borrow::Cow; |
||||||
|
use fmt; |
||||||
|
use str; |
||||||
|
use mem; |
||||||
|
use rc::Rc; |
||||||
|
use sync::Arc; |
||||||
|
use sys_common::{AsInner, IntoInner}; |
||||||
|
use sys_common::bytestring::debug_fmt_bytestring; |
||||||
|
use core::str::lossy::Utf8Lossy; |
||||||
|
|
||||||
|
#[derive(Clone, Hash)] |
||||||
|
pub struct Buf { |
||||||
|
pub inner: Vec<u8> |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Slice { |
||||||
|
pub inner: [u8] |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for Slice { |
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
debug_fmt_bytestring(&self.inner, formatter) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Display for Slice { |
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for Buf { |
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
fmt::Debug::fmt(self.as_slice(), formatter) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Display for Buf { |
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
fmt::Display::fmt(self.as_slice(), formatter) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl IntoInner<Vec<u8>> for Buf { |
||||||
|
fn into_inner(self) -> Vec<u8> { |
||||||
|
self.inner |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl AsInner<[u8]> for Buf { |
||||||
|
fn as_inner(&self) -> &[u8] { |
||||||
|
&self.inner |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
impl Buf { |
||||||
|
pub fn from_string(s: String) -> Buf { |
||||||
|
Buf { inner: s.into_bytes() } |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn with_capacity(capacity: usize) -> Buf { |
||||||
|
Buf { |
||||||
|
inner: Vec::with_capacity(capacity) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn clear(&mut self) { |
||||||
|
self.inner.clear() |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn capacity(&self) -> usize { |
||||||
|
self.inner.capacity() |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn reserve(&mut self, additional: usize) { |
||||||
|
self.inner.reserve(additional) |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn reserve_exact(&mut self, additional: usize) { |
||||||
|
self.inner.reserve_exact(additional) |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn shrink_to_fit(&mut self) { |
||||||
|
self.inner.shrink_to_fit() |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn shrink_to(&mut self, min_capacity: usize) { |
||||||
|
self.inner.shrink_to(min_capacity) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &Slice { |
||||||
|
unsafe { mem::transmute(&*self.inner) } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn into_string(self) -> Result<String, Buf> { |
||||||
|
String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn push_slice(&mut self, s: &Slice) { |
||||||
|
self.inner.extend_from_slice(&s.inner) |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn into_box(self) -> Box<Slice> { |
||||||
|
unsafe { mem::transmute(self.inner.into_boxed_slice()) } |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn from_box(boxed: Box<Slice>) -> Buf { |
||||||
|
let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; |
||||||
|
Buf { inner: inner.into_vec() } |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn into_arc(&self) -> Arc<Slice> { |
||||||
|
self.as_slice().into_arc() |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn into_rc(&self) -> Rc<Slice> { |
||||||
|
self.as_slice().into_rc() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Slice { |
||||||
|
fn from_u8_slice(s: &[u8]) -> &Slice { |
||||||
|
unsafe { mem::transmute(s) } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn from_str(s: &str) -> &Slice { |
||||||
|
Slice::from_u8_slice(s.as_bytes()) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn to_str(&self) -> Option<&str> { |
||||||
|
str::from_utf8(&self.inner).ok() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn to_string_lossy(&self) -> Cow<str> { |
||||||
|
String::from_utf8_lossy(&self.inner) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn to_owned(&self) -> Buf { |
||||||
|
Buf { inner: self.inner.to_vec() } |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn into_box(&self) -> Box<Slice> { |
||||||
|
let boxed: Box<[u8]> = self.inner.into(); |
||||||
|
unsafe { mem::transmute(boxed) } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn empty_box() -> Box<Slice> { |
||||||
|
let boxed: Box<[u8]> = Default::default(); |
||||||
|
unsafe { mem::transmute(boxed) } |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn into_arc(&self) -> Arc<Slice> { |
||||||
|
let arc: Arc<[u8]> = Arc::from(&self.inner); |
||||||
|
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn into_rc(&self) -> Rc<Slice> { |
||||||
|
let rc: Rc<[u8]> = Rc::from(&self.inner); |
||||||
|
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
use path::Prefix; |
||||||
|
use ffi::OsStr; |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn is_sep_byte(b: u8) -> bool { |
||||||
|
b == b'/' |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn is_verbatim_sep(b: u8) -> bool { |
||||||
|
b == b'/' |
||||||
|
} |
||||||
|
|
||||||
|
pub fn parse_prefix(_: &OsStr) -> Option<Prefix> { |
||||||
|
None |
||||||
|
} |
||||||
|
|
||||||
|
pub const MAIN_SEP_STR: &'static str = "/"; |
||||||
|
pub const MAIN_SEP: char = '/'; |
@ -0,0 +1,137 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#![allow(dead_code)] |
||||||
|
|
||||||
|
use io; |
||||||
|
use libc::{self, c_int}; |
||||||
|
use mem; |
||||||
|
use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; |
||||||
|
use sys::fd::FileDesc; |
||||||
|
use sys::{cvt, cvt_r}; |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Anonymous pipes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
pub struct AnonPipe(FileDesc); |
||||||
|
|
||||||
|
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { |
||||||
|
weak! { fn pipe2(*mut c_int, c_int) -> c_int } |
||||||
|
static INVALID: AtomicBool = ATOMIC_BOOL_INIT; |
||||||
|
|
||||||
|
let mut fds = [0; 2]; |
||||||
|
|
||||||
|
// Unfortunately the only known way right now to create atomically set the
|
||||||
|
// CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
|
||||||
|
// 2.6.27, however, and because we support 2.6.18 we must detect this
|
||||||
|
// support dynamically.
|
||||||
|
if cfg!(any(target_os = "dragonfly", |
||||||
|
target_os = "freebsd", |
||||||
|
target_os = "linux", |
||||||
|
target_os = "netbsd", |
||||||
|
target_os = "openbsd")) && |
||||||
|
!INVALID.load(Ordering::SeqCst) |
||||||
|
{ |
||||||
|
|
||||||
|
if let Some(pipe) = pipe2.get() { |
||||||
|
// Note that despite calling a glibc function here we may still
|
||||||
|
// get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
|
||||||
|
// emulate on older kernels, so if you happen to be running on
|
||||||
|
// an older kernel you may see `pipe2` as a symbol but still not
|
||||||
|
// see the syscall.
|
||||||
|
match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { |
||||||
|
Ok(_) => { |
||||||
|
return Ok((AnonPipe(FileDesc::new(fds[0])), |
||||||
|
AnonPipe(FileDesc::new(fds[1])))); |
||||||
|
} |
||||||
|
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { |
||||||
|
INVALID.store(true, Ordering::SeqCst); |
||||||
|
} |
||||||
|
Err(e) => return Err(e), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; |
||||||
|
|
||||||
|
let fd0 = FileDesc::new(fds[0]); |
||||||
|
let fd1 = FileDesc::new(fds[1]); |
||||||
|
fd0.set_cloexec()?; |
||||||
|
fd1.set_cloexec()?; |
||||||
|
Ok((AnonPipe(fd0), AnonPipe(fd1))) |
||||||
|
} |
||||||
|
|
||||||
|
impl AnonPipe { |
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
self.0.read(buf) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
self.0.write(buf) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn fd(&self) -> &FileDesc { &self.0 } |
||||||
|
pub fn into_fd(self) -> FileDesc { self.0 } |
||||||
|
|
||||||
|
pub fn diverge(&self) -> ! { |
||||||
|
panic!() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read2(p1: AnonPipe, |
||||||
|
v1: &mut Vec<u8>, |
||||||
|
p2: AnonPipe, |
||||||
|
v2: &mut Vec<u8>) -> io::Result<()> { |
||||||
|
|
||||||
|
// Set both pipes into nonblocking mode as we're gonna be reading from both
|
||||||
|
// in the `select` loop below, and we wouldn't want one to block the other!
|
||||||
|
let p1 = p1.into_fd(); |
||||||
|
let p2 = p2.into_fd(); |
||||||
|
p1.set_nonblocking(true)?; |
||||||
|
p2.set_nonblocking(true)?; |
||||||
|
|
||||||
|
let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; |
||||||
|
fds[0].fd = p1.raw(); |
||||||
|
fds[0].events = libc::POLLIN; |
||||||
|
fds[1].fd = p2.raw(); |
||||||
|
fds[1].events = libc::POLLIN; |
||||||
|
loop { |
||||||
|
// wait for either pipe to become readable using `poll`
|
||||||
|
cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; |
||||||
|
|
||||||
|
if fds[0].revents != 0 && read(&p1, v1)? { |
||||||
|
p2.set_nonblocking(false)?; |
||||||
|
return p2.read_to_end(v2).map(|_| ()); |
||||||
|
} |
||||||
|
if fds[1].revents != 0 && read(&p2, v2)? { |
||||||
|
p1.set_nonblocking(false)?; |
||||||
|
return p1.read_to_end(v1).map(|_| ()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Read as much as we can from each pipe, ignoring EWOULDBLOCK or
|
||||||
|
// EAGAIN. If we hit EOF, then this will happen because the underlying
|
||||||
|
// reader will return Ok(0), in which case we'll see `Ok` ourselves. In
|
||||||
|
// this case we flip the other fd back into blocking mode and read
|
||||||
|
// whatever's leftover on that file descriptor.
|
||||||
|
fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> { |
||||||
|
match fd.read_to_end(dst) { |
||||||
|
Ok(_) => Ok(true), |
||||||
|
Err(e) => { |
||||||
|
if e.raw_os_error() == Some(libc::EWOULDBLOCK) || |
||||||
|
e.raw_os_error() == Some(libc::EAGAIN) { |
||||||
|
Ok(false) |
||||||
|
} else { |
||||||
|
Err(e) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,151 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use ffi::OsStr; |
||||||
|
use fmt; |
||||||
|
use io; |
||||||
|
use sys::fs::File; |
||||||
|
use sys::pipe::AnonPipe; |
||||||
|
use sys::{unsupported, Void}; |
||||||
|
use sys_common::process::{CommandEnv, DefaultEnvKey}; |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Command
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
pub struct Command { |
||||||
|
env: CommandEnv<DefaultEnvKey> |
||||||
|
} |
||||||
|
|
||||||
|
// passed back to std::process with the pipes connected to the child, if any
|
||||||
|
// were requested
|
||||||
|
pub struct StdioPipes { |
||||||
|
pub stdin: Option<AnonPipe>, |
||||||
|
pub stdout: Option<AnonPipe>, |
||||||
|
pub stderr: Option<AnonPipe>, |
||||||
|
} |
||||||
|
|
||||||
|
pub enum Stdio { |
||||||
|
Inherit, |
||||||
|
Null, |
||||||
|
MakePipe, |
||||||
|
} |
||||||
|
|
||||||
|
impl Command { |
||||||
|
pub fn new(_program: &OsStr) -> Command { |
||||||
|
Command { |
||||||
|
env: Default::default() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn arg(&mut self, _arg: &OsStr) { |
||||||
|
} |
||||||
|
|
||||||
|
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { |
||||||
|
&mut self.env |
||||||
|
} |
||||||
|
|
||||||
|
pub fn cwd(&mut self, _dir: &OsStr) { |
||||||
|
} |
||||||
|
|
||||||
|
pub fn stdin(&mut self, _stdin: Stdio) { |
||||||
|
} |
||||||
|
|
||||||
|
pub fn stdout(&mut self, _stdout: Stdio) { |
||||||
|
} |
||||||
|
|
||||||
|
pub fn stderr(&mut self, _stderr: Stdio) { |
||||||
|
} |
||||||
|
|
||||||
|
pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool) |
||||||
|
-> io::Result<(Process, StdioPipes)> { |
||||||
|
unsupported() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl From<AnonPipe> for Stdio { |
||||||
|
fn from(pipe: AnonPipe) -> Stdio { |
||||||
|
pipe.diverge() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl From<File> for Stdio { |
||||||
|
fn from(_file: File) -> Stdio { |
||||||
|
//file.diverge()
|
||||||
|
unimplemented!() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for Command { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct ExitStatus(Void); |
||||||
|
|
||||||
|
impl ExitStatus { |
||||||
|
pub fn success(&self) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn code(&self) -> Option<i32> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Clone for ExitStatus { |
||||||
|
fn clone(&self) -> ExitStatus { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Copy for ExitStatus {} |
||||||
|
|
||||||
|
impl PartialEq for ExitStatus { |
||||||
|
fn eq(&self, _other: &ExitStatus) -> bool { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Eq for ExitStatus { |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for ExitStatus { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Display for ExitStatus { |
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Process(Void); |
||||||
|
|
||||||
|
impl Process { |
||||||
|
pub fn id(&self) -> u32 { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn kill(&mut self) -> io::Result<()> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn wait(&mut self) -> io::Result<ExitStatus> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { |
||||||
|
match self.0 {} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,241 @@ |
|||||||
|
// Copyright 2013-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.
|
||||||
|
|
||||||
|
use mem; |
||||||
|
use slice; |
||||||
|
|
||||||
|
pub fn hashmap_random_keys() -> (u64, u64) { |
||||||
|
let mut v = (0, 0); |
||||||
|
unsafe { |
||||||
|
let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, |
||||||
|
mem::size_of_val(&v)); |
||||||
|
imp::fill_bytes(view); |
||||||
|
} |
||||||
|
return v |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "horizon")] |
||||||
|
mod imp { |
||||||
|
use libctru; |
||||||
|
|
||||||
|
pub fn fill_bytes(v: &mut [u8]) { |
||||||
|
unsafe { |
||||||
|
// Initializing and de-initializing the sslC subsystem every time
|
||||||
|
// we initialize a hashmap is pretty dumb, but I can't think of a
|
||||||
|
// better method at the moment.
|
||||||
|
//
|
||||||
|
// lazy_static won't work because
|
||||||
|
// destructors (for closing the subsystem on exit) won't run.
|
||||||
|
//
|
||||||
|
// Perhaps overriding __appInit() and __appExit() will work,
|
||||||
|
// but that's an experiment for another time.
|
||||||
|
libctru::sslcInit(0); |
||||||
|
libctru::sslcGenerateRandomData(v.as_ptr() as _, v.len() as u32); |
||||||
|
libctru::sslcExit(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(all(unix,
|
||||||
|
not(target_os = "ios"), |
||||||
|
not(target_os = "openbsd"), |
||||||
|
not(target_os = "freebsd"), |
||||||
|
not(target_os = "fuchsia"), |
||||||
|
not(target_os = "horizon") |
||||||
|
))] |
||||||
|
mod imp { |
||||||
|
use fs::File; |
||||||
|
use io::Read; |
||||||
|
use libc; |
||||||
|
use sys::os::errno; |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))] |
||||||
|
fn getrandom(buf: &mut [u8]) -> libc::c_long { |
||||||
|
unsafe { |
||||||
|
libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "android")))] |
||||||
|
fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } |
||||||
|
|
||||||
|
fn getrandom_fill_bytes(v: &mut [u8]) -> bool { |
||||||
|
let mut read = 0; |
||||||
|
while read < v.len() { |
||||||
|
let result = getrandom(&mut v[read..]); |
||||||
|
if result == -1 { |
||||||
|
let err = errno() as libc::c_int; |
||||||
|
if err == libc::EINTR { |
||||||
|
continue; |
||||||
|
} else if err == libc::EAGAIN { |
||||||
|
return false |
||||||
|
} else { |
||||||
|
panic!("unexpected getrandom error: {}", err); |
||||||
|
} |
||||||
|
} else { |
||||||
|
read += result as usize; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))] |
||||||
|
fn is_getrandom_available() -> bool { |
||||||
|
use io; |
||||||
|
use sync::atomic::{AtomicBool, Ordering}; |
||||||
|
use sync::Once; |
||||||
|
|
||||||
|
static CHECKER: Once = Once::new(); |
||||||
|
static AVAILABLE: AtomicBool = AtomicBool::new(false); |
||||||
|
|
||||||
|
CHECKER.call_once(|| { |
||||||
|
let mut buf: [u8; 0] = []; |
||||||
|
let result = getrandom(&mut buf); |
||||||
|
let available = if result == -1 { |
||||||
|
let err = io::Error::last_os_error().raw_os_error(); |
||||||
|
err != Some(libc::ENOSYS) |
||||||
|
} else { |
||||||
|
true |
||||||
|
}; |
||||||
|
AVAILABLE.store(available, Ordering::Relaxed); |
||||||
|
}); |
||||||
|
|
||||||
|
AVAILABLE.load(Ordering::Relaxed) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "android")))] |
||||||
|
fn is_getrandom_available() -> bool { false } |
||||||
|
|
||||||
|
pub fn fill_bytes(v: &mut [u8]) { |
||||||
|
// getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
|
||||||
|
// meaning it would have blocked because the non-blocking pool (urandom)
|
||||||
|
// has not initialized in the kernel yet due to a lack of entropy the
|
||||||
|
// fallback we do here is to avoid blocking applications which could
|
||||||
|
// depend on this call without ever knowing they do and don't have a
|
||||||
|
// work around. The PRNG of /dev/urandom will still be used but not
|
||||||
|
// over a completely full entropy pool
|
||||||
|
if is_getrandom_available() && getrandom_fill_bytes(v) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
let mut file = File::open("/dev/urandom") |
||||||
|
.expect("failed to open /dev/urandom"); |
||||||
|
file.read_exact(v).expect("failed to read /dev/urandom"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "openbsd")] |
||||||
|
mod imp { |
||||||
|
use libc; |
||||||
|
use sys::os::errno; |
||||||
|
|
||||||
|
pub fn fill_bytes(v: &mut [u8]) { |
||||||
|
// getentropy(2) permits a maximum buffer size of 256 bytes
|
||||||
|
for s in v.chunks_mut(256) { |
||||||
|
let ret = unsafe { |
||||||
|
libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) |
||||||
|
}; |
||||||
|
if ret == -1 { |
||||||
|
panic!("unexpected getentropy error: {}", errno()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "ios")] |
||||||
|
mod imp { |
||||||
|
use io; |
||||||
|
use libc::{c_int, size_t}; |
||||||
|
use ptr; |
||||||
|
|
||||||
|
enum SecRandom {} |
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)] |
||||||
|
const kSecRandomDefault: *const SecRandom = ptr::null(); |
||||||
|
|
||||||
|
extern { |
||||||
|
fn SecRandomCopyBytes(rnd: *const SecRandom, |
||||||
|
count: size_t, |
||||||
|
bytes: *mut u8) -> c_int; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn fill_bytes(v: &mut [u8]) { |
||||||
|
let ret = unsafe { |
||||||
|
SecRandomCopyBytes(kSecRandomDefault, |
||||||
|
v.len(), |
||||||
|
v.as_mut_ptr()) |
||||||
|
}; |
||||||
|
if ret == -1 { |
||||||
|
panic!("couldn't generate random bytes: {}", |
||||||
|
io::Error::last_os_error()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "freebsd")] |
||||||
|
mod imp { |
||||||
|
use libc; |
||||||
|
use ptr; |
||||||
|
|
||||||
|
pub fn fill_bytes(v: &mut [u8]) { |
||||||
|
let mib = [libc::CTL_KERN, libc::KERN_ARND]; |
||||||
|
// kern.arandom permits a maximum buffer size of 256 bytes
|
||||||
|
for s in v.chunks_mut(256) { |
||||||
|
let mut s_len = s.len(); |
||||||
|
let ret = unsafe { |
||||||
|
libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, |
||||||
|
s.as_mut_ptr() as *mut _, &mut s_len, |
||||||
|
ptr::null(), 0) |
||||||
|
}; |
||||||
|
if ret == -1 || s_len != s.len() { |
||||||
|
panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", |
||||||
|
ret, s.len(), s_len); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "fuchsia")] |
||||||
|
mod imp { |
||||||
|
#[link(name = "zircon")] |
||||||
|
extern { |
||||||
|
fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; |
||||||
|
} |
||||||
|
|
||||||
|
fn getrandom(buf: &mut [u8]) -> Result<usize, i32> { |
||||||
|
unsafe { |
||||||
|
let mut actual = 0; |
||||||
|
let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); |
||||||
|
if status == 0 { |
||||||
|
Ok(actual) |
||||||
|
} else { |
||||||
|
Err(status) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn fill_bytes(v: &mut [u8]) { |
||||||
|
let mut buf = v; |
||||||
|
while !buf.is_empty() { |
||||||
|
let ret = getrandom(buf); |
||||||
|
match ret { |
||||||
|
Err(err) => { |
||||||
|
panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})", |
||||||
|
err, buf.len()) |
||||||
|
} |
||||||
|
Ok(actual) => { |
||||||
|
let move_buf = buf; |
||||||
|
buf = &mut move_buf[(actual as usize)..]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
use cell::UnsafeCell; |
||||||
|
use super::mutex::Mutex; |
||||||
|
use super::condvar::Condvar; |
||||||
|
|
||||||
|
// A simple read-preferring RWLock implementation that I found on wikipedia <.<
|
||||||
|
pub struct RWLock { |
||||||
|
mutex: Mutex, |
||||||
|
cvar: Condvar, |
||||||
|
reader_count: UnsafeCell<u32>,
|
||||||
|
writer_active: UnsafeCell<bool>, |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Send for RWLock {} |
||||||
|
unsafe impl Sync for RWLock {} |
||||||
|
|
||||||
|
impl RWLock { |
||||||
|
pub const fn new() -> RWLock { |
||||||
|
RWLock { |
||||||
|
mutex: Mutex::new(), |
||||||
|
cvar: Condvar::new(), |
||||||
|
reader_count: UnsafeCell::new(0), |
||||||
|
writer_active: UnsafeCell::new(false), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn read(&self) { |
||||||
|
self.mutex.lock(); |
||||||
|
|
||||||
|
while *self.writer_active.get() { |
||||||
|
self.cvar.wait(&self.mutex); |
||||||
|
} |
||||||
|
|
||||||
|
assert!(*self.reader_count.get() != u32::max_value()); |
||||||
|
*self.reader_count.get() += 1; |
||||||
|
|
||||||
|
self.mutex.unlock(); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn try_read(&self) -> bool { |
||||||
|
if !self.mutex.try_lock() { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
while *self.writer_active.get() { |
||||||
|
self.cvar.wait(&self.mutex); |
||||||
|
} |
||||||
|
|
||||||
|
assert!(*self.reader_count.get() != u32::max_value()); |
||||||
|
*self.reader_count.get() += 1; |
||||||
|
|
||||||
|
self.mutex.unlock(); |
||||||
|
true |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn write(&self) { |
||||||
|
self.mutex.lock(); |
||||||
|
|
||||||
|
while *self.writer_active.get() || *self.reader_count.get() > 0 { |
||||||
|
self.cvar.wait(&self.mutex); |
||||||
|
} |
||||||
|
|
||||||
|
*self.writer_active.get() = true; |
||||||
|
|
||||||
|
self.mutex.unlock(); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn try_write(&self) -> bool { |
||||||
|
if !self.mutex.try_lock() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
while *self.writer_active.get() || *self.reader_count.get() > 0 { |
||||||
|
self.cvar.wait(&self.mutex); |
||||||
|
} |
||||||
|
|
||||||
|
*self.writer_active.get() = true; |
||||||
|
|
||||||
|
self.mutex.unlock(); |
||||||
|
true |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn read_unlock(&self) { |
||||||
|
self.mutex.lock(); |
||||||
|
|
||||||
|
*self.reader_count.get() -= 1; |
||||||
|
|
||||||
|
if *self.reader_count.get() == 0 { |
||||||
|
self.cvar.notify_one() |
||||||
|
} |
||||||
|
|
||||||
|
self.mutex.unlock(); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn write_unlock(&self) { |
||||||
|
self.mutex.lock(); |
||||||
|
|
||||||
|
*self.writer_active.get() = false; |
||||||
|
|
||||||
|
self.cvar.notify_all(); |
||||||
|
|
||||||
|
self.mutex.unlock(); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
self.mutex.destroy(); |
||||||
|
self.cvar.destroy(); |
||||||
|
*self.reader_count.get() = 0; |
||||||
|
*self.writer_active.get() = false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,220 @@ |
|||||||
|
// Copyright 2014-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.
|
||||||
|
|
||||||
|
#![cfg_attr(test, allow(dead_code))] |
||||||
|
|
||||||
|
use libc; |
||||||
|
use self::imp::{make_handler, drop_handler}; |
||||||
|
|
||||||
|
pub use self::imp::cleanup; |
||||||
|
pub use self::imp::init; |
||||||
|
|
||||||
|
pub struct Handler { |
||||||
|
_data: *mut libc::c_void |
||||||
|
} |
||||||
|
|
||||||
|
impl Handler { |
||||||
|
pub unsafe fn new() -> Handler { |
||||||
|
make_handler() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for Handler { |
||||||
|
fn drop(&mut self) { |
||||||
|
unsafe { |
||||||
|
drop_handler(self); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux",
|
||||||
|
target_os = "macos", |
||||||
|
target_os = "bitrig", |
||||||
|
target_os = "dragonfly", |
||||||
|
target_os = "freebsd", |
||||||
|
target_os = "solaris", |
||||||
|
all(target_os = "netbsd", not(target_vendor = "rumprun")), |
||||||
|
target_os = "openbsd"))] |
||||||
|
mod imp { |
||||||
|
use super::Handler; |
||||||
|
use mem; |
||||||
|
use ptr; |
||||||
|
use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; |
||||||
|
use libc::{sigaction, SIGBUS, SIG_DFL, |
||||||
|
SA_SIGINFO, SA_ONSTACK, sighandler_t}; |
||||||
|
use libc; |
||||||
|
use libc::{mmap, munmap}; |
||||||
|
use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON}; |
||||||
|
use libc::MAP_FAILED; |
||||||
|
|
||||||
|
use sys_common::thread_info; |
||||||
|
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))] |
||||||
|
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { |
||||||
|
#[repr(C)] |
||||||
|
struct siginfo_t { |
||||||
|
a: [libc::c_int; 3], // si_signo, si_errno, si_code
|
||||||
|
si_addr: *mut libc::c_void, |
||||||
|
} |
||||||
|
|
||||||
|
(*(info as *const siginfo_t)).si_addr as usize |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "android")))] |
||||||
|
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { |
||||||
|
(*info).si_addr as usize |
||||||
|
} |
||||||
|
|
||||||
|
// Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
|
||||||
|
// (unmapped pages) at the end of every thread's stack, so if a thread ends
|
||||||
|
// up running into the guard page it'll trigger this handler. We want to
|
||||||
|
// detect these cases and print out a helpful error saying that the stack
|
||||||
|
// has overflowed. All other signals, however, should go back to what they
|
||||||
|
// were originally supposed to do.
|
||||||
|
//
|
||||||
|
// This handler currently exists purely to print an informative message
|
||||||
|
// whenever a thread overflows its stack. We then abort to exit and
|
||||||
|
// indicate a crash, but to avoid a misleading SIGSEGV that might lead
|
||||||
|
// users to believe that unsafe code has accessed an invalid pointer; the
|
||||||
|
// SIGSEGV encountered when overflowing the stack is expected and
|
||||||
|
// well-defined.
|
||||||
|
//
|
||||||
|
// If this is not a stack overflow, the handler un-registers itself and
|
||||||
|
// then returns (to allow the original signal to be delivered again).
|
||||||
|
// Returning from this kind of signal handler is technically not defined
|
||||||
|
// to work when reading the POSIX spec strictly, but in practice it turns
|
||||||
|
// out many large systems and all implementations allow returning from a
|
||||||
|
// signal handler to work. For a more detailed explanation see the
|
||||||
|
// comments on #26458.
|
||||||
|
unsafe extern fn signal_handler(signum: libc::c_int, |
||||||
|
info: *mut libc::siginfo_t, |
||||||
|
_data: *mut libc::c_void) { |
||||||
|
use sys_common::util::report_overflow; |
||||||
|
|
||||||
|
let guard = thread_info::stack_guard().unwrap_or(0..0); |
||||||
|
let addr = siginfo_si_addr(info); |
||||||
|
|
||||||
|
// If the faulting address is within the guard page, then we print a
|
||||||
|
// message saying so and abort.
|
||||||
|
if guard.start <= addr && addr < guard.end { |
||||||
|
report_overflow(); |
||||||
|
rtabort!("stack overflow"); |
||||||
|
} else { |
||||||
|
// Unregister ourselves by reverting back to the default behavior.
|
||||||
|
let mut action: sigaction = mem::zeroed(); |
||||||
|
action.sa_sigaction = SIG_DFL; |
||||||
|
sigaction(signum, &action, ptr::null_mut()); |
||||||
|
|
||||||
|
// See comment above for why this function returns.
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); |
||||||
|
|
||||||
|
pub unsafe fn init() { |
||||||
|
let mut action: sigaction = mem::zeroed(); |
||||||
|
action.sa_flags = SA_SIGINFO | SA_ONSTACK; |
||||||
|
action.sa_sigaction = signal_handler as sighandler_t; |
||||||
|
sigaction(SIGSEGV, &action, ptr::null_mut()); |
||||||
|
sigaction(SIGBUS, &action, ptr::null_mut()); |
||||||
|
|
||||||
|
let handler = make_handler(); |
||||||
|
MAIN_ALTSTACK = handler._data; |
||||||
|
mem::forget(handler); |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn cleanup() { |
||||||
|
Handler { _data: MAIN_ALTSTACK }; |
||||||
|
} |
||||||
|
|
||||||
|
unsafe fn get_stackp() -> *mut libc::c_void { |
||||||
|
let stackp = mmap(ptr::null_mut(), |
||||||
|
SIGSTKSZ, |
||||||
|
PROT_READ | PROT_WRITE, |
||||||
|
MAP_PRIVATE | MAP_ANON, |
||||||
|
-1, |
||||||
|
0); |
||||||
|
if stackp == MAP_FAILED { |
||||||
|
panic!("failed to allocate an alternative stack"); |
||||||
|
} |
||||||
|
stackp |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux",
|
||||||
|
target_os = "macos", |
||||||
|
target_os = "bitrig", |
||||||
|
target_os = "netbsd", |
||||||
|
target_os = "openbsd", |
||||||
|
target_os = "solaris"))] |
||||||
|
unsafe fn get_stack() -> libc::stack_t { |
||||||
|
libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(target_os = "freebsd",
|
||||||
|
target_os = "dragonfly"))] |
||||||
|
unsafe fn get_stack() -> libc::stack_t { |
||||||
|
libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ } |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn make_handler() -> Handler { |
||||||
|
let mut stack = mem::zeroed(); |
||||||
|
sigaltstack(ptr::null(), &mut stack); |
||||||
|
// Configure alternate signal stack, if one is not already set.
|
||||||
|
if stack.ss_flags & SS_DISABLE != 0 { |
||||||
|
stack = get_stack(); |
||||||
|
sigaltstack(&stack, ptr::null_mut()); |
||||||
|
Handler { _data: stack.ss_sp as *mut libc::c_void } |
||||||
|
} else { |
||||||
|
Handler { _data: ptr::null_mut() } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn drop_handler(handler: &mut Handler) { |
||||||
|
if !handler._data.is_null() { |
||||||
|
let stack = libc::stack_t { |
||||||
|
ss_sp: ptr::null_mut(), |
||||||
|
ss_flags: SS_DISABLE, |
||||||
|
// Workaround for bug in macOS implementation of sigaltstack
|
||||||
|
// UNIX2003 which returns ENOMEM when disabling a stack while
|
||||||
|
// passing ss_size smaller than MINSIGSTKSZ. According to POSIX
|
||||||
|
// both ss_sp and ss_size should be ignored in this case.
|
||||||
|
ss_size: SIGSTKSZ, |
||||||
|
}; |
||||||
|
sigaltstack(&stack, ptr::null_mut()); |
||||||
|
munmap(handler._data, SIGSTKSZ); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux",
|
||||||
|
target_os = "macos", |
||||||
|
target_os = "bitrig", |
||||||
|
target_os = "dragonfly", |
||||||
|
target_os = "freebsd", |
||||||
|
target_os = "solaris", |
||||||
|
all(target_os = "netbsd", not(target_vendor = "rumprun")), |
||||||
|
target_os = "openbsd")))] |
||||||
|
mod imp { |
||||||
|
use ptr; |
||||||
|
|
||||||
|
pub unsafe fn init() { |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn cleanup() { |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn make_handler() -> super::Handler { |
||||||
|
super::Handler { _data: ptr::null_mut() } |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn drop_handler(_handler: &mut super::Handler) { |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use sys::fd::FileDesc; |
||||||
|
|
||||||
|
pub struct Stdin(()); |
||||||
|
pub struct Stdout(()); |
||||||
|
pub struct Stderr(()); |
||||||
|
|
||||||
|
impl Stdin { |
||||||
|
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) } |
||||||
|
|
||||||
|
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDIN_FILENO); |
||||||
|
let ret = fd.read(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stdout { |
||||||
|
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) } |
||||||
|
|
||||||
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDOUT_FILENO); |
||||||
|
let ret = fd.write(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stderr { |
||||||
|
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) } |
||||||
|
|
||||||
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDERR_FILENO); |
||||||
|
let ret = fd.write(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// FIXME: right now this raw stderr handle is used in a few places because
|
||||||
|
// std::io::stderr_raw isn't exposed, but once that's exposed this impl
|
||||||
|
// should go away
|
||||||
|
impl io::Write for Stderr { |
||||||
|
fn write(&mut self, data: &[u8]) -> io::Result<usize> { |
||||||
|
Stderr::write(self, data) |
||||||
|
} |
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
Stderr::flush(self) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn is_ebadf(err: &io::Error) -> bool { |
||||||
|
err.raw_os_error() == Some(libc::EBADF as i32) |
||||||
|
} |
||||||
|
|
||||||
|
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; |
||||||
|
|
||||||
|
pub fn stderr_prints_nothing() -> bool { |
||||||
|
false |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
use alloc_crate::boxed::FnBox; |
||||||
|
use libc; |
||||||
|
use cmp; |
||||||
|
use ffi::CStr; |
||||||
|
use io; |
||||||
|
use mem; |
||||||
|
use ptr; |
||||||
|
use sys_common::thread::start_thread; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
use libctru::Thread as ThreadHandle; |
||||||
|
|
||||||
|
pub struct Thread { |
||||||
|
handle: ThreadHandle, |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Send for Thread {} |
||||||
|
unsafe impl Sync for Thread {} |
||||||
|
|
||||||
|
pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; |
||||||
|
|
||||||
|
|
||||||
|
impl Thread { |
||||||
|
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> { |
||||||
|
let p = box p; |
||||||
|
let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE); |
||||||
|
|
||||||
|
let mut priority = 0; |
||||||
|
::libctru::svcGetThreadPriority(&mut priority, 0xFFFF8000); |
||||||
|
|
||||||
|
let handle = ::libctru::threadCreate(Some(thread_func), &*p as *const _ as *mut _, |
||||||
|
stack_size, priority, -2, false); |
||||||
|
|
||||||
|
return if handle == ptr::null_mut() { |
||||||
|
Err(io::Error::from_raw_os_error(libc::EAGAIN)) |
||||||
|
} else { |
||||||
|
mem::forget(p); // ownership passed to the new thread
|
||||||
|
Ok(Thread { handle: handle }) |
||||||
|
}; |
||||||
|
|
||||||
|
extern "C" fn thread_func(start: *mut libc::c_void) { |
||||||
|
unsafe { start_thread(start as *mut u8) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn yield_now() { |
||||||
|
unsafe { |
||||||
|
::libctru::svcSleepThread(0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_name(_name: &CStr) { |
||||||
|
// threads aren't named in libctru
|
||||||
|
} |
||||||
|
|
||||||
|
pub fn sleep(dur: Duration) { |
||||||
|
unsafe { |
||||||
|
let nanos = dur.as_secs() |
||||||
|
.saturating_mul(1_000_000_000) |
||||||
|
.saturating_add(dur.subsec_nanos() as u64); |
||||||
|
::libctru::svcSleepThread(nanos as i64) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn join(self) { |
||||||
|
unsafe { |
||||||
|
let ret = ::libctru::threadJoin(self.handle, u64::max_value()); |
||||||
|
::libctru::threadFree(self.handle); |
||||||
|
mem::forget(self); |
||||||
|
debug_assert_eq!(ret, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn id(&self) -> ThreadHandle { |
||||||
|
self.handle |
||||||
|
} |
||||||
|
|
||||||
|
#[allow(dead_code)] |
||||||
|
pub fn into_id(self) -> ThreadHandle { |
||||||
|
let handle = self.handle; |
||||||
|
mem::forget(self); |
||||||
|
handle |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for Thread { |
||||||
|
fn drop(&mut self) { |
||||||
|
unsafe { ::libctru::threadDetach(self.handle) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub mod guard { |
||||||
|
pub unsafe fn current() -> Option<usize> { None } |
||||||
|
pub unsafe fn init() -> Option<usize> { None } |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
#![allow(dead_code)] // not used on all platforms
|
||||||
|
|
||||||
|
use collections::BTreeMap; |
||||||
|
use ptr; |
||||||
|
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; |
||||||
|
|
||||||
|
pub type Key = usize; |
||||||
|
|
||||||
|
type Dtor = unsafe extern fn(*mut u8); |
||||||
|
|
||||||
|
static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT; |
||||||
|
|
||||||
|
static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut(); |
||||||
|
|
||||||
|
#[thread_local] |
||||||
|
static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut(); |
||||||
|
|
||||||
|
unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> { |
||||||
|
if KEYS == ptr::null_mut() { |
||||||
|
KEYS = Box::into_raw(Box::new(BTreeMap::new())); |
||||||
|
} |
||||||
|
&mut *KEYS |
||||||
|
} |
||||||
|
|
||||||
|
unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> { |
||||||
|
if LOCALS == ptr::null_mut() { |
||||||
|
LOCALS = Box::into_raw(Box::new(BTreeMap::new())); |
||||||
|
} |
||||||
|
&mut *LOCALS |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn create(dtor: Option<Dtor>) -> Key { |
||||||
|
let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); |
||||||
|
keys().insert(key, dtor); |
||||||
|
key |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn get(key: Key) -> *mut u8 { |
||||||
|
if let Some(&entry) = locals().get(&key) { |
||||||
|
entry |
||||||
|
} else { |
||||||
|
ptr::null_mut() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn set(key: Key, value: *mut u8) { |
||||||
|
locals().insert(key, value); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn destroy(key: Key) { |
||||||
|
keys().remove(&key); |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn requires_synchronized_create() -> bool { |
||||||
|
false |
||||||
|
} |
@ -0,0 +1,285 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
use cmp::Ordering; |
||||||
|
use libc; |
||||||
|
use time::Duration; |
||||||
|
use core::hash::{Hash, Hasher}; |
||||||
|
|
||||||
|
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; |
||||||
|
|
||||||
|
const NSEC_PER_SEC: u64 = 1_000_000_000; |
||||||
|
|
||||||
|
#[derive(Copy, Clone)] |
||||||
|
struct Timespec { |
||||||
|
t: libc::timespec, |
||||||
|
} |
||||||
|
|
||||||
|
impl Timespec { |
||||||
|
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { |
||||||
|
if self >= other { |
||||||
|
Ok(if self.t.tv_nsec >= other.t.tv_nsec { |
||||||
|
Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, |
||||||
|
(self.t.tv_nsec - other.t.tv_nsec) as u32) |
||||||
|
} else { |
||||||
|
Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, |
||||||
|
self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - |
||||||
|
other.t.tv_nsec as u32) |
||||||
|
}) |
||||||
|
} else { |
||||||
|
match other.sub_timespec(self) { |
||||||
|
Ok(d) => Err(d), |
||||||
|
Err(d) => Ok(d), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn add_duration(&self, other: &Duration) -> Timespec { |
||||||
|
let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); |
||||||
|
let mut secs = secs.expect("overflow when adding duration to time"); |
||||||
|
|
||||||
|
// Nano calculations can't overflow because nanos are <1B which fit
|
||||||
|
// in a u32.
|
||||||
|
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; |
||||||
|
if nsec >= NSEC_PER_SEC as u32 { |
||||||
|
nsec -= NSEC_PER_SEC as u32; |
||||||
|
secs = secs.checked_add(1).expect("overflow when adding \ |
||||||
|
duration to time"); |
||||||
|
} |
||||||
|
Timespec { |
||||||
|
t: libc::timespec { |
||||||
|
tv_sec: secs as libc::time_t, |
||||||
|
tv_nsec: nsec as libc::c_long, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn sub_duration(&self, other: &Duration) -> Timespec { |
||||||
|
let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); |
||||||
|
let mut secs = secs.expect("overflow when subtracting duration \ |
||||||
|
from time"); |
||||||
|
|
||||||
|
// Similar to above, nanos can't overflow.
|
||||||
|
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; |
||||||
|
if nsec < 0 { |
||||||
|
nsec += NSEC_PER_SEC as i32; |
||||||
|
secs = secs.checked_sub(1).expect("overflow when subtracting \ |
||||||
|
duration from time"); |
||||||
|
} |
||||||
|
Timespec { |
||||||
|
t: libc::timespec { |
||||||
|
tv_sec: secs as libc::time_t, |
||||||
|
tv_nsec: nsec as libc::c_long, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl PartialEq for Timespec { |
||||||
|
fn eq(&self, other: &Timespec) -> bool { |
||||||
|
self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Eq for Timespec {} |
||||||
|
|
||||||
|
impl PartialOrd for Timespec { |
||||||
|
fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> { |
||||||
|
Some(self.cmp(other)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Ord for Timespec { |
||||||
|
fn cmp(&self, other: &Timespec) -> Ordering { |
||||||
|
let me = (self.t.tv_sec, self.t.tv_nsec); |
||||||
|
let other = (other.t.tv_sec, other.t.tv_nsec); |
||||||
|
me.cmp(&other) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Hash for Timespec { |
||||||
|
fn hash<H : Hasher>(&self, state: &mut H) { |
||||||
|
self.t.tv_sec.hash(state); |
||||||
|
self.t.tv_nsec.hash(state); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
mod inner { |
||||||
|
use fmt; |
||||||
|
use libc; |
||||||
|
use sync::Once; |
||||||
|
use sys::cvt; |
||||||
|
use sys_common::mul_div_u64; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
use super::NSEC_PER_SEC; |
||||||
|
use super::Timespec; |
||||||
|
|
||||||
|
use libctru; |
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] |
||||||
|
pub struct Instant { |
||||||
|
t: u64 |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
||||||
|
pub struct SystemTime { |
||||||
|
t: Timespec, |
||||||
|
} |
||||||
|
|
||||||
|
pub const UNIX_EPOCH: SystemTime = SystemTime { |
||||||
|
t: Timespec { |
||||||
|
t: libc::timespec { |
||||||
|
tv_sec: 0, |
||||||
|
tv_nsec: 0, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
impl Instant { |
||||||
|
pub fn now() -> Instant { |
||||||
|
Instant { t: ctr_absolute_time() } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_instant(&self, other: &Instant) -> Duration { |
||||||
|
let info = info(); |
||||||
|
let diff = self.t.checked_sub(other.t) |
||||||
|
.expect("second instant is later than self"); |
||||||
|
let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64); |
||||||
|
Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn add_duration(&self, other: &Duration) -> Instant { |
||||||
|
Instant { |
||||||
|
t: self.t.checked_add(dur2intervals(other)) |
||||||
|
.expect("overflow when adding duration to instant"), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_duration(&self, other: &Duration) -> Instant { |
||||||
|
Instant { |
||||||
|
t: self.t.checked_sub(dur2intervals(other)) |
||||||
|
.expect("overflow when adding duration to instant"), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// The initial system tick after which all Instants occur
|
||||||
|
static mut TICK: u64 = 0; |
||||||
|
|
||||||
|
// A source of monotonic time based on ticks of the 3DS CPU. Returns the
|
||||||
|
// number of system ticks elapsed since an arbitrary point in the past
|
||||||
|
fn ctr_absolute_time() -> u64 { |
||||||
|
let first_tick = get_first_tick(); |
||||||
|
let current_tick = get_system_tick(); |
||||||
|
current_tick - first_tick |
||||||
|
} |
||||||
|
|
||||||
|
// The first time this function is called, it generates and returns the
|
||||||
|
// initial system tick used to create Instants
|
||||||
|
//
|
||||||
|
// subsequent calls to this function return the previously generated
|
||||||
|
// tick value
|
||||||
|
fn get_first_tick() -> u64 { |
||||||
|
static ONCE: Once = Once::new(); |
||||||
|
unsafe {
|
||||||
|
ONCE.call_once(|| { |
||||||
|
TICK = get_system_tick(); |
||||||
|
}); |
||||||
|
TICK |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Gets the current system tick
|
||||||
|
#[inline] |
||||||
|
fn get_system_tick() -> u64 { |
||||||
|
unsafe { libctru::svcGetSystemTick() } |
||||||
|
} |
||||||
|
|
||||||
|
// A struct representing the clock speed of the 3DS
|
||||||
|
struct CtrClockInfo { |
||||||
|
numer: u32, |
||||||
|
denom: u32, |
||||||
|
} |
||||||
|
|
||||||
|
// Initializes the CtrClockInfo struct
|
||||||
|
//
|
||||||
|
// Note that svcGetSystemTick always runs at 268MHz (268,111,856Hz), even
|
||||||
|
// on a New 3DS running in 804MHz mode
|
||||||
|
//
|
||||||
|
// See https://www.3dbrew.org/wiki/Hardware#Common_hardware
|
||||||
|
fn info() -> &'static CtrClockInfo { |
||||||
|
static INFO: CtrClockInfo = CtrClockInfo { |
||||||
|
numer: 1_000_000_000, |
||||||
|
denom: 268_111_856, |
||||||
|
}; |
||||||
|
&INFO |
||||||
|
} |
||||||
|
|
||||||
|
fn dur2intervals(dur: &Duration) -> u64 { |
||||||
|
let info = info(); |
||||||
|
let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| { |
||||||
|
nanos.checked_add(dur.subsec_nanos() as u64) |
||||||
|
}).expect("overflow converting duration to nanoseconds"); |
||||||
|
mul_div_u64(nanos, info.denom as u64, info.numer as u64) |
||||||
|
} |
||||||
|
|
||||||
|
impl SystemTime { |
||||||
|
pub fn now() -> SystemTime { |
||||||
|
use ptr; |
||||||
|
|
||||||
|
let mut s = libc::timeval { |
||||||
|
tv_sec: 0, |
||||||
|
tv_usec: 0, |
||||||
|
}; |
||||||
|
cvt(unsafe { |
||||||
|
libc::gettimeofday(&mut s, ptr::null_mut()) |
||||||
|
}).unwrap(); |
||||||
|
return SystemTime::from(s) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_time(&self, other: &SystemTime) |
||||||
|
-> Result<Duration, Duration> { |
||||||
|
self.t.sub_timespec(&other.t) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn add_duration(&self, other: &Duration) -> SystemTime { |
||||||
|
SystemTime { t: self.t.add_duration(other) } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn sub_duration(&self, other: &Duration) -> SystemTime { |
||||||
|
SystemTime { t: self.t.sub_duration(other) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl From<libc::timeval> for SystemTime { |
||||||
|
fn from(t: libc::timeval) -> SystemTime { |
||||||
|
SystemTime::from(libc::timespec { |
||||||
|
tv_sec: t.tv_sec, |
||||||
|
tv_nsec: (t.tv_usec * 1000) as libc::c_long, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl From<libc::timespec> for SystemTime { |
||||||
|
fn from(t: libc::timespec) -> SystemTime { |
||||||
|
SystemTime { t: Timespec { t: t } } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl fmt::Debug for SystemTime { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
f.debug_struct("SystemTime") |
||||||
|
.field("tv_sec", &self.t.t.tv_sec) |
||||||
|
.field("tv_nsec", &self.t.t.tv_nsec) |
||||||
|
.finish() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
//! Support for "weak linkage" to symbols on Unix
|
||||||
|
//!
|
||||||
|
//! Some I/O operations we do in libstd require newer versions of OSes but we
|
||||||
|
//! need to maintain binary compatibility with older releases for now. In order
|
||||||
|
//! to use the new functionality when available we use this module for
|
||||||
|
//! detection.
|
||||||
|
//!
|
||||||
|
//! One option to use here is weak linkage, but that is unfortunately only
|
||||||
|
//! really workable on Linux. Hence, use dlsym to get the symbol value at
|
||||||
|
//! runtime. This is also done for compatibility with older versions of glibc,
|
||||||
|
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
|
||||||
|
//! we've been dynamically linked to the library the symbol comes from, but that
|
||||||
|
//! is currently always the case for things like libpthread/libc.
|
||||||
|
//!
|
||||||
|
//! A long time ago this used weak linkage for the __pthread_get_minstack
|
||||||
|
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
|
||||||
|
//! dependency on libc6 (#23628).
|
||||||
|
|
||||||
|
use libc; |
||||||
|
|
||||||
|
use ffi::CString; |
||||||
|
use marker; |
||||||
|
use mem; |
||||||
|
use sync::atomic::{AtomicUsize, Ordering}; |
||||||
|
|
||||||
|
macro_rules! weak { |
||||||
|
(fn $name:ident($($t:ty),*) -> $ret:ty) => ( |
||||||
|
static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> = |
||||||
|
::sys::weak::Weak::new(stringify!($name)); |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Weak<F> { |
||||||
|
name: &'static str, |
||||||
|
addr: AtomicUsize, |
||||||
|
_marker: marker::PhantomData<F>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<F> Weak<F> { |
||||||
|
pub const fn new(name: &'static str) -> Weak<F> { |
||||||
|
Weak { |
||||||
|
name, |
||||||
|
addr: AtomicUsize::new(1), |
||||||
|
_marker: marker::PhantomData, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get(&self) -> Option<&F> { |
||||||
|
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); |
||||||
|
unsafe { |
||||||
|
if self.addr.load(Ordering::SeqCst) == 1 { |
||||||
|
self.addr.store(fetch(self.name), Ordering::SeqCst); |
||||||
|
} |
||||||
|
if self.addr.load(Ordering::SeqCst) == 0 { |
||||||
|
None |
||||||
|
} else { |
||||||
|
mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
unsafe fn fetch(name: &str) -> usize { |
||||||
|
let name = match CString::new(name) { |
||||||
|
Ok(cstr) => cstr, |
||||||
|
Err(..) => return 0, |
||||||
|
}; |
||||||
|
libc::dlsym(0 as _, name.as_ptr() as *const u8) as usize |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
//! Global initialization and retrieval of command line arguments.
|
||||||
|
//!
|
||||||
|
//! On some platforms these are stored during runtime startup,
|
||||||
|
//! and on some they are retrieved from the system on demand.
|
||||||
|
|
||||||
|
#![allow(dead_code)] // runtime init functions not used during testing
|
||||||
|
|
||||||
|
use ffi::OsString; |
||||||
|
use marker::PhantomData; |
||||||
|
use vec; |
||||||
|
|
||||||
|
/// One-time global initialization.
|
||||||
|
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } |
||||||
|
|
||||||
|
/// One-time global cleanup.
|
||||||
|
pub unsafe fn cleanup() { imp::cleanup() } |
||||||
|
|
||||||
|
/// Returns the command line arguments
|
||||||
|
pub fn args() -> Args { |
||||||
|
imp::args() |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Args { |
||||||
|
iter: vec::IntoIter<OsString>, |
||||||
|
_dont_send_or_sync_me: PhantomData<*mut ()>, |
||||||
|
} |
||||||
|
|
||||||
|
impl Args { |
||||||
|
pub fn inner_debug(&self) -> &[OsString] { |
||||||
|
self.iter.as_slice() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Iterator for Args { |
||||||
|
type Item = OsString; |
||||||
|
fn next(&mut self) -> Option<OsString> { self.iter.next() } |
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } |
||||||
|
} |
||||||
|
|
||||||
|
impl ExactSizeIterator for Args { |
||||||
|
fn len(&self) -> usize { self.iter.len() } |
||||||
|
} |
||||||
|
|
||||||
|
impl DoubleEndedIterator for Args { |
||||||
|
fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() } |
||||||
|
} |
||||||
|
|
||||||
|
mod imp { |
||||||
|
use os::unix::prelude::*; |
||||||
|
use mem; |
||||||
|
use ffi::{CStr, OsString}; |
||||||
|
use marker::PhantomData; |
||||||
|
use libc; |
||||||
|
use super::Args; |
||||||
|
|
||||||
|
use sys_common::mutex::Mutex; |
||||||
|
|
||||||
|
static mut GLOBAL_ARGS_PTR: usize = 0; |
||||||
|
static LOCK: Mutex = Mutex::new(); |
||||||
|
|
||||||
|
pub unsafe fn init(argc: isize, argv: *const *const u8) { |
||||||
|
let args = (0..argc).map(|i| { |
||||||
|
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() |
||||||
|
}).collect(); |
||||||
|
|
||||||
|
LOCK.lock(); |
||||||
|
let ptr = get_global_ptr(); |
||||||
|
assert!((*ptr).is_none()); |
||||||
|
(*ptr) = Some(box args); |
||||||
|
LOCK.unlock(); |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn cleanup() { |
||||||
|
LOCK.lock(); |
||||||
|
*get_global_ptr() = None; |
||||||
|
LOCK.unlock(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn args() -> Args { |
||||||
|
let bytes = clone().unwrap_or(Vec::new()); |
||||||
|
let v: Vec<OsString> = bytes.into_iter().map(|v| { |
||||||
|
OsStringExt::from_vec(v) |
||||||
|
}).collect(); |
||||||
|
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } |
||||||
|
} |
||||||
|
|
||||||
|
fn clone() -> Option<Vec<Vec<u8>>> { |
||||||
|
unsafe { |
||||||
|
LOCK.lock(); |
||||||
|
let ptr = get_global_ptr(); |
||||||
|
let ret = (*ptr).as_ref().map(|s| (**s).clone()); |
||||||
|
LOCK.unlock(); |
||||||
|
return ret |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> { |
||||||
|
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/// See sys/unix/backtrace/mod.rs for an explanation of the method used here.
|
||||||
|
|
||||||
|
pub use self::tracing::unwind_backtrace; |
||||||
|
pub use self::printing::{foreach_symbol_fileline, resolve_symname}; |
||||||
|
|
||||||
|
// tracing impls:
|
||||||
|
mod tracing; |
||||||
|
// symbol resolvers:
|
||||||
|
mod printing; |
||||||
|
|
||||||
|
pub mod gnu { |
||||||
|
use io; |
||||||
|
use fs; |
||||||
|
use libc::c_char; |
||||||
|
use vec::Vec; |
||||||
|
use ffi::OsStr; |
||||||
|
use os::unix::ffi::OsStrExt; |
||||||
|
use io::Read; |
||||||
|
|
||||||
|
pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> { |
||||||
|
let mut exefile = fs::File::open("sys:exe")?; |
||||||
|
let mut exename = Vec::new(); |
||||||
|
exefile.read_to_end(&mut exename)?; |
||||||
|
if exename.last() == Some(&b'\n') { |
||||||
|
exename.pop(); |
||||||
|
} |
||||||
|
let file = fs::File::open(OsStr::from_bytes(&exename))?; |
||||||
|
Ok((exename.into_iter().map(|c| c as c_char).collect(), file)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct BacktraceContext; |
@ -0,0 +1,11 @@ |
|||||||
|
// Copyright 2014-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.
|
||||||
|
|
||||||
|
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; |
@ -0,0 +1,107 @@ |
|||||||
|
// Copyright 2014-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.
|
||||||
|
|
||||||
|
use error::Error; |
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use sys::backtrace::BacktraceContext; |
||||||
|
use sys_common::backtrace::Frame; |
||||||
|
|
||||||
|
use unwind as uw; |
||||||
|
|
||||||
|
struct Context<'a> { |
||||||
|
idx: usize, |
||||||
|
frames: &'a mut [Frame], |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
struct UnwindError(uw::_Unwind_Reason_Code); |
||||||
|
|
||||||
|
impl Error for UnwindError { |
||||||
|
fn description(&self) -> &'static str { |
||||||
|
"unexpected return value while unwinding" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl ::fmt::Display for UnwindError { |
||||||
|
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { |
||||||
|
write!(f, "{}: {:?}", self.description(), self.0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline(never)] // if we know this is a function call, we can skip it when
|
||||||
|
// tracing
|
||||||
|
pub fn unwind_backtrace(frames: &mut [Frame]) |
||||||
|
-> io::Result<(usize, BacktraceContext)> |
||||||
|
{ |
||||||
|
let mut cx = Context { |
||||||
|
idx: 0, |
||||||
|
frames: frames, |
||||||
|
}; |
||||||
|
let result_unwind = unsafe { |
||||||
|
uw::_Unwind_Backtrace(trace_fn, |
||||||
|
&mut cx as *mut Context |
||||||
|
as *mut libc::c_void) |
||||||
|
}; |
||||||
|
// See libunwind:src/unwind/Backtrace.c for the return values.
|
||||||
|
// No, there is no doc.
|
||||||
|
match result_unwind { |
||||||
|
// These return codes seem to be benign and need to be ignored for backtraces
|
||||||
|
// to show up properly on all tested platforms.
|
||||||
|
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { |
||||||
|
Ok((cx.idx, BacktraceContext)) |
||||||
|
} |
||||||
|
_ => { |
||||||
|
Err(io::Error::new(io::ErrorKind::Other, |
||||||
|
UnwindError(result_unwind))) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
extern fn trace_fn(ctx: *mut uw::_Unwind_Context, |
||||||
|
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { |
||||||
|
let cx = unsafe { &mut *(arg as *mut Context) }; |
||||||
|
let mut ip_before_insn = 0; |
||||||
|
let mut ip = unsafe { |
||||||
|
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void |
||||||
|
}; |
||||||
|
if !ip.is_null() && ip_before_insn == 0 { |
||||||
|
// this is a non-signaling frame, so `ip` refers to the address
|
||||||
|
// after the calling instruction. account for that.
|
||||||
|
ip = (ip as usize - 1) as *mut _; |
||||||
|
} |
||||||
|
|
||||||
|
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
|
||||||
|
// it appears to work fine without it, so we only use
|
||||||
|
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
|
||||||
|
// slightly more accurate stack trace in the process.
|
||||||
|
//
|
||||||
|
// This is often because panic involves the last instruction of a
|
||||||
|
// function being "call std::rt::begin_unwind", with no ret
|
||||||
|
// instructions after it. This means that the return instruction
|
||||||
|
// pointer points *outside* of the calling function, and by
|
||||||
|
// unwinding it we go back to the original function.
|
||||||
|
let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { |
||||||
|
ip |
||||||
|
} else { |
||||||
|
unsafe { uw::_Unwind_FindEnclosingFunction(ip) } |
||||||
|
}; |
||||||
|
|
||||||
|
if cx.idx < cx.frames.len() { |
||||||
|
cx.frames[cx.idx] = Frame { |
||||||
|
symbol_addr: symaddr as *mut u8, |
||||||
|
exact_position: ip as *mut u8, |
||||||
|
inline_context: 0, |
||||||
|
}; |
||||||
|
cx.idx += 1; |
||||||
|
} |
||||||
|
|
||||||
|
uw::_URC_NO_REASON |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
#![cfg(not(test))] |
||||||
|
|
||||||
|
use libc::{c_float, c_double}; |
||||||
|
|
||||||
|
#[link_name = "m"] |
||||||
|
extern { |
||||||
|
pub fn acos(n: c_double) -> c_double; |
||||||
|
pub fn acosf(n: c_float) -> c_float; |
||||||
|
pub fn asin(n: c_double) -> c_double; |
||||||
|
pub fn asinf(n: c_float) -> c_float; |
||||||
|
pub fn atan(n: c_double) -> c_double; |
||||||
|
pub fn atan2(a: c_double, b: c_double) -> c_double; |
||||||
|
pub fn atan2f(a: c_float, b: c_float) -> c_float; |
||||||
|
pub fn atanf(n: c_float) -> c_float; |
||||||
|
pub fn cbrt(n: c_double) -> c_double; |
||||||
|
pub fn cbrtf(n: c_float) -> c_float; |
||||||
|
pub fn cosh(n: c_double) -> c_double; |
||||||
|
pub fn coshf(n: c_float) -> c_float; |
||||||
|
pub fn expm1(n: c_double) -> c_double; |
||||||
|
pub fn expm1f(n: c_float) -> c_float; |
||||||
|
pub fn fdim(a: c_double, b: c_double) -> c_double; |
||||||
|
pub fn fdimf(a: c_float, b: c_float) -> c_float; |
||||||
|
pub fn hypot(x: c_double, y: c_double) -> c_double; |
||||||
|
pub fn hypotf(x: c_float, y: c_float) -> c_float; |
||||||
|
pub fn log1p(n: c_double) -> c_double; |
||||||
|
pub fn log1pf(n: c_float) -> c_float; |
||||||
|
pub fn sinh(n: c_double) -> c_double; |
||||||
|
pub fn sinhf(n: c_float) -> c_float; |
||||||
|
pub fn tan(n: c_double) -> c_double; |
||||||
|
pub fn tanf(n: c_float) -> c_float; |
||||||
|
pub fn tanh(n: c_double) -> c_double; |
||||||
|
pub fn tanhf(n: c_float) -> c_float; |
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
use cell::UnsafeCell; |
||||||
|
use intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg}; |
||||||
|
use ptr; |
||||||
|
use time::Duration; |
||||||
|
|
||||||
|
use sys::mutex::{mutex_unlock, Mutex}; |
||||||
|
use sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; |
||||||
|
|
||||||
|
pub struct Condvar { |
||||||
|
lock: UnsafeCell<*mut i32>, |
||||||
|
seq: UnsafeCell<i32> |
||||||
|
} |
||||||
|
|
||||||
|
impl Condvar { |
||||||
|
pub const fn new() -> Condvar { |
||||||
|
Condvar { |
||||||
|
lock: UnsafeCell::new(ptr::null_mut()), |
||||||
|
seq: UnsafeCell::new(0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn init(&self) { |
||||||
|
*self.lock.get() = ptr::null_mut(); |
||||||
|
*self.seq.get() = 0; |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn notify_one(&self) { |
||||||
|
unsafe { |
||||||
|
let seq = self.seq.get(); |
||||||
|
|
||||||
|
atomic_xadd(seq, 1); |
||||||
|
|
||||||
|
let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn notify_all(&self) { |
||||||
|
unsafe { |
||||||
|
let lock = self.lock.get(); |
||||||
|
let seq = self.seq.get(); |
||||||
|
|
||||||
|
if *lock == ptr::null_mut() { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
atomic_xadd(seq, 1); |
||||||
|
|
||||||
|
let _ = futex(seq, FUTEX_REQUEUE, 1, ::usize::MAX, *lock); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool { |
||||||
|
let lock = self.lock.get(); |
||||||
|
let seq = self.seq.get(); |
||||||
|
|
||||||
|
if *lock != mutex.lock.get() { |
||||||
|
if *lock != ptr::null_mut() { |
||||||
|
panic!("Condvar used with more than one Mutex"); |
||||||
|
} |
||||||
|
|
||||||
|
atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); |
||||||
|
} |
||||||
|
|
||||||
|
mutex_unlock(*lock); |
||||||
|
|
||||||
|
let seq_before = atomic_load(seq); |
||||||
|
|
||||||
|
let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut()); |
||||||
|
|
||||||
|
let seq_after = atomic_load(seq); |
||||||
|
|
||||||
|
while atomic_xchg(*lock, 2) != 0 { |
||||||
|
let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut()); |
||||||
|
} |
||||||
|
|
||||||
|
seq_before != seq_after |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn wait(&self, mutex: &Mutex) { |
||||||
|
unsafe { |
||||||
|
assert!(self.wait_inner(mutex, ptr::null())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { |
||||||
|
unsafe { |
||||||
|
let timeout = TimeSpec { |
||||||
|
tv_sec: dur.as_secs() as i64, |
||||||
|
tv_nsec: dur.subsec_nanos() as i32 |
||||||
|
}; |
||||||
|
|
||||||
|
self.wait_inner(mutex, &timeout as *const TimeSpec) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn destroy(&self) { |
||||||
|
*self.lock.get() = ptr::null_mut(); |
||||||
|
*self.seq.get() = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl Send for Condvar {} |
||||||
|
|
||||||
|
unsafe impl Sync for Condvar {} |
@ -0,0 +1,19 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
pub mod os { |
||||||
|
pub const FAMILY: &'static str = "redox"; |
||||||
|
pub const OS: &'static str = "redox"; |
||||||
|
pub const DLL_PREFIX: &'static str = "lib"; |
||||||
|
pub const DLL_SUFFIX: &'static str = ".so"; |
||||||
|
pub const DLL_EXTENSION: &'static str = "so"; |
||||||
|
pub const EXE_SUFFIX: &'static str = ""; |
||||||
|
pub const EXE_EXTENSION: &'static str = ""; |
||||||
|
} |
@ -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.
|
||||||
|
|
||||||
|
//! Redox-specific extension to the primitives in the `std::ffi` module.
|
||||||
|
|
||||||
|
#![stable(feature = "rust1", since = "1.0.0")] |
||||||
|
|
||||||
|
use ffi::{OsStr, OsString}; |
||||||
|
use mem; |
||||||
|
use sys::os_str::Buf; |
||||||
|
use sys_common::{FromInner, IntoInner, AsInner}; |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`OsString`].
|
||||||
|
///
|
||||||
|
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
|
||||||
|
#[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 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`OsStr`].
|
||||||
|
///
|
||||||
|
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
|
||||||
|
#[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 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,349 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
//! Redox-specific extensions to primitives in the `std::fs` module.
|
||||||
|
|
||||||
|
#![stable(feature = "rust1", since = "1.0.0")] |
||||||
|
|
||||||
|
use fs::{self, Permissions, OpenOptions}; |
||||||
|
use io; |
||||||
|
use path::Path; |
||||||
|
use sys; |
||||||
|
use sys_common::{FromInner, AsInner, AsInnerMut}; |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`fs::Permissions`].
|
||||||
|
///
|
||||||
|
/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
pub trait PermissionsExt { |
||||||
|
/// Returns the underlying raw `mode_t` bits that are the standard Redox
|
||||||
|
/// permissions for this file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::os::redox::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// fn main() -> std::io::Result<()> {
|
||||||
|
/// let f = File::create("foo.txt")?;
|
||||||
|
/// let metadata = f.metadata()?;
|
||||||
|
/// let permissions = metadata.permissions();
|
||||||
|
///
|
||||||
|
/// println!("permissions: {}", permissions.mode());
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn mode(&self) -> u32; |
||||||
|
|
||||||
|
/// Sets the underlying raw bits for this set of permissions.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::os::redox::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// fn main() -> std::io::Result<()> {
|
||||||
|
/// let f = File::create("foo.txt")?;
|
||||||
|
/// let metadata = f.metadata()?;
|
||||||
|
/// let mut permissions = metadata.permissions();
|
||||||
|
///
|
||||||
|
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
|
||||||
|
/// assert_eq!(permissions.mode(), 0o644);
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn set_mode(&mut self, mode: u32); |
||||||
|
|
||||||
|
/// Creates a new instance of `Permissions` from the given set of Redox
|
||||||
|
/// permission bits.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::fs::Permissions;
|
||||||
|
/// use std::os::redox::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// // Read/write for owner and read for others.
|
||||||
|
/// let permissions = Permissions::from_mode(0o644);
|
||||||
|
/// assert_eq!(permissions.mode(), 0o644);
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn from_mode(mode: u32) -> Self; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
impl PermissionsExt for Permissions { |
||||||
|
fn mode(&self) -> u32 { |
||||||
|
self.as_inner().mode() |
||||||
|
} |
||||||
|
|
||||||
|
fn set_mode(&mut self, mode: u32) { |
||||||
|
*self = Permissions::from_inner(FromInner::from_inner(mode)); |
||||||
|
} |
||||||
|
|
||||||
|
fn from_mode(mode: u32) -> Permissions { |
||||||
|
Permissions::from_inner(FromInner::from_inner(mode)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`fs::OpenOptions`].
|
||||||
|
///
|
||||||
|
/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
pub trait OpenOptionsExt { |
||||||
|
/// Sets the mode bits that a new file will be created with.
|
||||||
|
///
|
||||||
|
/// If a new file is created as part of a `File::open_opts` call then this
|
||||||
|
/// specified `mode` will be used as the permission bits for the new file.
|
||||||
|
/// If no `mode` is set, the default of `0o666` will be used.
|
||||||
|
/// The operating system masks out bits with the systems `umask`, to produce
|
||||||
|
/// the final permissions.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # #![feature(libc)]
|
||||||
|
/// extern crate libc;
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::redox::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// # fn main() {
|
||||||
|
/// let mut options = OpenOptions::new();
|
||||||
|
/// options.mode(0o644); // Give read/write for owner and read for others.
|
||||||
|
/// let file = options.open("foo.txt");
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
fn mode(&mut self, mode: u32) -> &mut Self; |
||||||
|
|
||||||
|
/// Pass custom flags to the `flags` argument of `open`.
|
||||||
|
///
|
||||||
|
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
|
||||||
|
/// ensure they do not interfere with the access mode set by Rusts options.
|
||||||
|
///
|
||||||
|
/// Custom flags can only set flags, not remove flags set by Rusts options.
|
||||||
|
/// This options overwrites any previously set custom flags.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # #![feature(libc)]
|
||||||
|
/// extern crate libc;
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::redox::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// # fn main() {
|
||||||
|
/// let mut options = OpenOptions::new();
|
||||||
|
/// options.write(true);
|
||||||
|
/// if cfg!(target_os = "redox") {
|
||||||
|
/// options.custom_flags(libc::O_NOFOLLOW);
|
||||||
|
/// }
|
||||||
|
/// let file = options.open("foo.txt");
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "open_options_ext", since = "1.10.0")] |
||||||
|
fn custom_flags(&mut self, flags: i32) -> &mut Self; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")] |
||||||
|
impl OpenOptionsExt for OpenOptions { |
||||||
|
fn mode(&mut self, mode: u32) -> &mut OpenOptions { |
||||||
|
self.as_inner_mut().mode(mode); self |
||||||
|
} |
||||||
|
|
||||||
|
fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { |
||||||
|
self.as_inner_mut().custom_flags(flags); self |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`fs::Metadata`].
|
||||||
|
///
|
||||||
|
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
pub trait MetadataExt { |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn dev(&self) -> u64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn ino(&self) -> u64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn mode(&self) -> u32; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn nlink(&self) -> u64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn uid(&self) -> u32; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn gid(&self) -> u32; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn size(&self) -> u64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn atime(&self) -> i64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn atime_nsec(&self) -> i64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn mtime(&self) -> i64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn mtime_nsec(&self) -> i64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn ctime(&self) -> i64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn ctime_nsec(&self) -> i64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn blksize(&self) -> u64; |
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
fn blocks(&self) -> u64; |
||||||
|
} |
||||||
|
|
||||||
|
// 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.
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")] |
||||||
|
impl MetadataExt for fs::Metadata { |
||||||
|
fn dev(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_dev as u64 |
||||||
|
} |
||||||
|
fn ino(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_ino as u64 |
||||||
|
} |
||||||
|
fn mode(&self) -> u32 { |
||||||
|
self.as_inner().as_inner().st_mode as u32 |
||||||
|
} |
||||||
|
fn nlink(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_nlink as u64 |
||||||
|
} |
||||||
|
fn uid(&self) -> u32 { |
||||||
|
self.as_inner().as_inner().st_uid as u32 |
||||||
|
} |
||||||
|
fn gid(&self) -> u32 { |
||||||
|
self.as_inner().as_inner().st_gid as u32 |
||||||
|
} |
||||||
|
fn size(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_size as u64 |
||||||
|
} |
||||||
|
fn atime(&self) -> i64 { |
||||||
|
self.as_inner().as_inner().st_atime as i64 |
||||||
|
} |
||||||
|
fn atime_nsec(&self) -> i64 { |
||||||
|
self.as_inner().as_inner().st_atime_nsec as i64 |
||||||
|
} |
||||||
|
fn mtime(&self) -> i64 { |
||||||
|
self.as_inner().as_inner().st_mtime as i64 |
||||||
|
} |
||||||
|
fn mtime_nsec(&self) -> i64 { |
||||||
|
self.as_inner().as_inner().st_mtime_nsec as i64 |
||||||
|
} |
||||||
|
fn ctime(&self) -> i64 { |
||||||
|
self.as_inner().as_inner().st_ctime as i64 |
||||||
|
} |
||||||
|
fn ctime_nsec(&self) -> i64 { |
||||||
|
self.as_inner().as_inner().st_ctime_nsec as i64 |
||||||
|
} |
||||||
|
fn blksize(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_blksize as u64 |
||||||
|
} |
||||||
|
fn blocks(&self) -> u64 { |
||||||
|
self.as_inner().as_inner().st_blocks as u64 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Redox-specific extensions for [`FileType`].
|
||||||
|
///
|
||||||
|
/// Adds support for special Unix file types such as block/character devices,
|
||||||
|
/// pipes, and sockets.
|
||||||
|
///
|
||||||
|
/// [`FileType`]: ../../../../std/fs/struct.FileType.html
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
pub trait FileTypeExt { |
||||||
|
/// Returns whether this file type is a block device.
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_block_device(&self) -> bool; |
||||||
|
/// Returns whether this file type is a char device.
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_char_device(&self) -> bool; |
||||||
|
/// Returns whether this file type is a fifo.
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_fifo(&self) -> bool; |
||||||
|
/// Returns whether this file type is a socket.
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
fn is_socket(&self) -> bool; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "file_type_ext", since = "1.5.0")] |
||||||
|
impl FileTypeExt for fs::FileType { |
||||||
|
fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ } |
||||||
|
fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ } |
||||||
|
fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ } |
||||||
|
fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ } |
||||||
|
} |
||||||
|
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::os::redox::fs;
|
||||||
|
///
|
||||||
|
/// fn main() -> std::io::Result<()> {
|
||||||
|
/// fs::symlink("a.txt", "b.txt")?;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "symlink", since = "1.1.0")] |
||||||
|
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> |
||||||
|
{ |
||||||
|
sys::fs::symlink(src.as_ref(), dst.as_ref()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`fs::DirBuilder`].
|
||||||
|
///
|
||||||
|
/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
|
||||||
|
#[stable(feature = "dir_builder", since = "1.6.0")] |
||||||
|
pub trait DirBuilderExt { |
||||||
|
/// Sets the mode to create new directories with. This option defaults to
|
||||||
|
/// 0o777.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::fs::DirBuilder;
|
||||||
|
/// use std::os::redox::fs::DirBuilderExt;
|
||||||
|
///
|
||||||
|
/// let mut builder = DirBuilder::new();
|
||||||
|
/// builder.mode(0o755);
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "dir_builder", since = "1.6.0")] |
||||||
|
fn mode(&mut self, mode: u32) -> &mut Self; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "dir_builder", since = "1.6.0")] |
||||||
|
impl DirBuilderExt for fs::DirBuilder { |
||||||
|
fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { |
||||||
|
self.as_inner_mut().set_mode(mode); |
||||||
|
self |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,167 @@ |
|||||||
|
// Copyright 2016 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 sys; |
||||||
|
use io; |
||||||
|
use sys_common::{self, AsInner, FromInner, IntoInner}; |
||||||
|
|
||||||
|
/// Raw file descriptors.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub type RawFd = usize; |
||||||
|
|
||||||
|
/// 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 guaranteed 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.
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
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.
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> Self; |
||||||
|
} |
||||||
|
|
||||||
|
/// A trait to express the ability to consume an object and acquire ownership of
|
||||||
|
/// its raw file descriptor.
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
pub trait IntoRawFd { |
||||||
|
/// Consumes this object, returning the raw underlying file descriptor.
|
||||||
|
///
|
||||||
|
/// This function **transfers ownership** of the underlying file descriptor
|
||||||
|
/// to the caller. Callers are then the unique owners of the file descriptor
|
||||||
|
/// and must close the descriptor once it's no longer needed.
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
fn into_raw_fd(self) -> RawFd; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl AsRawFd for fs::File { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
impl FromRawFd for fs::File { |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> fs::File { |
||||||
|
fs::File::from_inner(sys::fs::File::from_inner(fd)) |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for fs::File { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl AsRawFd for net::TcpStream { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl AsRawFd for net::TcpListener { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl AsRawFd for net::UdpSocket { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "asraw_stdio", since = "1.21.0")] |
||||||
|
impl AsRawFd for io::Stdin { |
||||||
|
fn as_raw_fd(&self) -> RawFd { 0 } |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "asraw_stdio", since = "1.21.0")] |
||||||
|
impl AsRawFd for io::Stdout { |
||||||
|
fn as_raw_fd(&self) -> RawFd { 1 } |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "asraw_stdio", since = "1.21.0")] |
||||||
|
impl AsRawFd for io::Stderr { |
||||||
|
fn as_raw_fd(&self) -> RawFd { 2 } |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
impl FromRawFd for net::TcpStream { |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { |
||||||
|
let file = sys::fs::File::from_inner(fd); |
||||||
|
net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file)) |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
impl FromRawFd for net::TcpListener { |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { |
||||||
|
let file = sys::fs::File::from_inner(fd); |
||||||
|
net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file)) |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")] |
||||||
|
impl FromRawFd for net::UdpSocket { |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { |
||||||
|
let file = sys::fs::File::from_inner(fd); |
||||||
|
net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for net::TcpStream { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for net::TcpListener { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for net::UdpSocket { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! ```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")] |
||||||
|
#![doc(cfg(target_os = "redox"))] |
||||||
|
|
||||||
|
pub mod ffi; |
||||||
|
pub mod fs; |
||||||
|
pub mod io; |
||||||
|
pub mod process; |
||||||
|
pub mod thread; |
||||||
|
|
||||||
|
/// A prelude for conveniently writing platform-specific code.
|
||||||
|
///
|
||||||
|
/// Includes all extension traits, and some important type definitions.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub mod prelude { |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::ffi::{OsStrExt, OsStringExt}; |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt}; |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::thread::JoinHandleExt; |
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub use super::process::{CommandExt, ExitStatusExt}; |
||||||
|
} |
@ -0,0 +1,187 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
//! Redox-specific extensions to primitives in the `std::process` module.
|
||||||
|
|
||||||
|
#![stable(feature = "rust1", since = "1.0.0")] |
||||||
|
|
||||||
|
use io; |
||||||
|
use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; |
||||||
|
use process; |
||||||
|
use sys; |
||||||
|
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; |
||||||
|
|
||||||
|
/// Redox-specific extensions to the [`process::Command`] builder,
|
||||||
|
///
|
||||||
|
/// [`process::Command`]: ../../../../std/process/struct.Command.html
|
||||||
|
#[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: u32) -> &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: u32) -> &mut process::Command; |
||||||
|
|
||||||
|
/// Schedules a closure to be run just before the `exec` function is
|
||||||
|
/// invoked.
|
||||||
|
///
|
||||||
|
/// The closure is allowed to return an I/O error whose OS error code will
|
||||||
|
/// be communicated back to the parent and returned as an error from when
|
||||||
|
/// the spawn was requested.
|
||||||
|
///
|
||||||
|
/// Multiple closures can be registered and they will be called in order of
|
||||||
|
/// their registration. If a closure returns `Err` then no further closures
|
||||||
|
/// will be called and the spawn operation will immediately return with a
|
||||||
|
/// failure.
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// This closure will be run in the context of the child process after a
|
||||||
|
/// `fork`. This primarily means that any modifications made to memory on
|
||||||
|
/// behalf of this closure will **not** be visible to the parent process.
|
||||||
|
/// This is often a very constrained environment where normal operations
|
||||||
|
/// like `malloc` or acquiring a mutex are not guaranteed to work (due to
|
||||||
|
/// other threads perhaps still running when the `fork` was run).
|
||||||
|
///
|
||||||
|
/// When this closure is run, aspects such as the stdio file descriptors and
|
||||||
|
/// working directory have successfully been changed, so output to these
|
||||||
|
/// locations may not appear where intended.
|
||||||
|
#[stable(feature = "process_exec", since = "1.15.0")] |
||||||
|
fn before_exec<F>(&mut self, f: F) -> &mut process::Command |
||||||
|
where F: FnMut() -> io::Result<()> + Send + Sync + 'static; |
||||||
|
|
||||||
|
/// Performs all the required setup by this `Command`, followed by calling
|
||||||
|
/// the `execvp` syscall.
|
||||||
|
///
|
||||||
|
/// On success this function will not return, and otherwise it will return
|
||||||
|
/// an error indicating why the exec (or another part of the setup of the
|
||||||
|
/// `Command`) failed.
|
||||||
|
///
|
||||||
|
/// This function, unlike `spawn`, will **not** `fork` the process to create
|
||||||
|
/// a new child. Like spawn, however, the default behavior for the stdio
|
||||||
|
/// descriptors will be to inherited from the current process.
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// The process may be in a "broken state" if this function returns in
|
||||||
|
/// error. For example the working directory, environment variables, signal
|
||||||
|
/// handling settings, various user/group information, or aspects of stdio
|
||||||
|
/// file descriptors may have changed. If a "transactional spawn" is
|
||||||
|
/// required to gracefully handle errors it is recommended to use the
|
||||||
|
/// cross-platform `spawn` instead.
|
||||||
|
#[stable(feature = "process_exec2", since = "1.9.0")] |
||||||
|
fn exec(&mut self) -> io::Error; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl CommandExt for process::Command { |
||||||
|
fn uid(&mut self, id: u32) -> &mut process::Command { |
||||||
|
self.as_inner_mut().uid(id); |
||||||
|
self |
||||||
|
} |
||||||
|
|
||||||
|
fn gid(&mut self, id: u32) -> &mut process::Command { |
||||||
|
self.as_inner_mut().gid(id); |
||||||
|
self |
||||||
|
} |
||||||
|
|
||||||
|
fn before_exec<F>(&mut self, f: F) -> &mut process::Command |
||||||
|
where F: FnMut() -> io::Result<()> + Send + Sync + 'static |
||||||
|
{ |
||||||
|
self.as_inner_mut().before_exec(Box::new(f)); |
||||||
|
self |
||||||
|
} |
||||||
|
|
||||||
|
fn exec(&mut self) -> io::Error { |
||||||
|
self.as_inner_mut().exec(sys::process::Stdio::Inherit) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`process::ExitStatus`].
|
||||||
|
///
|
||||||
|
/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub trait ExitStatusExt { |
||||||
|
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
|
||||||
|
/// a process.
|
||||||
|
#[stable(feature = "exit_status_from", since = "1.12.0")] |
||||||
|
fn from_raw(raw: i32) -> Self; |
||||||
|
|
||||||
|
/// If the process was terminated by a signal, returns that signal.
|
||||||
|
#[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 from_raw(raw: i32) -> Self { |
||||||
|
process::ExitStatus::from_inner(From::from(raw)) |
||||||
|
} |
||||||
|
|
||||||
|
fn signal(&self) -> Option<i32> { |
||||||
|
self.as_inner().signal() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "process_extensions", since = "1.2.0")] |
||||||
|
impl FromRawFd for process::Stdio { |
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { |
||||||
|
let fd = sys::fd::FileDesc::new(fd); |
||||||
|
let io = sys::process::Stdio::Fd(fd); |
||||||
|
process::Stdio::from_inner(io) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "process_extensions", since = "1.2.0")] |
||||||
|
impl AsRawFd for process::ChildStdin { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "process_extensions", since = "1.2.0")] |
||||||
|
impl AsRawFd for process::ChildStdout { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "process_extensions", since = "1.2.0")] |
||||||
|
impl AsRawFd for process::ChildStderr { |
||||||
|
fn as_raw_fd(&self) -> RawFd { |
||||||
|
self.as_inner().fd().raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for process::ChildStdin { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for process::ChildStdout { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")] |
||||||
|
impl IntoRawFd for process::ChildStderr { |
||||||
|
fn into_raw_fd(self) -> RawFd { |
||||||
|
self.into_inner().into_fd().into_raw() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Redox-specific extensions to primitives in the `std::thread` module.
|
||||||
|
|
||||||
|
#![stable(feature = "thread_extensions", since = "1.9.0")] |
||||||
|
|
||||||
|
use sys_common::{AsInner, IntoInner}; |
||||||
|
use thread::JoinHandle; |
||||||
|
|
||||||
|
#[stable(feature = "thread_extensions", since = "1.9.0")] |
||||||
|
#[allow(deprecated)] |
||||||
|
pub type RawPthread = usize; |
||||||
|
|
||||||
|
/// Redox-specific extensions to [`thread::JoinHandle`].
|
||||||
|
///
|
||||||
|
/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
|
||||||
|
#[stable(feature = "thread_extensions", since = "1.9.0")] |
||||||
|
pub trait JoinHandleExt { |
||||||
|
/// Extracts the raw pthread_t without taking ownership
|
||||||
|
#[stable(feature = "thread_extensions", since = "1.9.0")] |
||||||
|
fn as_pthread_t(&self) -> RawPthread; |
||||||
|
|
||||||
|
/// Consumes the thread, returning the raw pthread_t
|
||||||
|
///
|
||||||
|
/// This function **transfers ownership** of the underlying pthread_t to
|
||||||
|
/// the caller. Callers are then the unique owners of the pthread_t and
|
||||||
|
/// must either detach or join the pthread_t once it's no longer needed.
|
||||||
|
#[stable(feature = "thread_extensions", since = "1.9.0")] |
||||||
|
fn into_pthread_t(self) -> RawPthread; |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "thread_extensions", since = "1.9.0")] |
||||||
|
impl<T> JoinHandleExt for JoinHandle<T> { |
||||||
|
fn as_pthread_t(&self) -> RawPthread { |
||||||
|
self.as_inner().id() as RawPthread |
||||||
|
} |
||||||
|
|
||||||
|
fn into_pthread_t(self) -> RawPthread { |
||||||
|
self.into_inner().into_id() as RawPthread |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
#![cfg(target_thread_local)] |
||||||
|
#![unstable(feature = "thread_local_internals", issue = "0")] |
||||||
|
|
||||||
|
use cell::{Cell, UnsafeCell}; |
||||||
|
use mem; |
||||||
|
use ptr; |
||||||
|
|
||||||
|
|
||||||
|
pub struct Key<T> { |
||||||
|
inner: UnsafeCell<Option<T>>, |
||||||
|
|
||||||
|
// Metadata to keep track of the state of the destructor. Remember that
|
||||||
|
// these variables are thread-local, not global.
|
||||||
|
dtor_registered: Cell<bool>, |
||||||
|
dtor_running: Cell<bool>, |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl<T> ::marker::Sync for Key<T> { } |
||||||
|
|
||||||
|
impl<T> Key<T> { |
||||||
|
pub const fn new() -> Key<T> { |
||||||
|
Key { |
||||||
|
inner: UnsafeCell::new(None), |
||||||
|
dtor_registered: Cell::new(false), |
||||||
|
dtor_running: Cell::new(false) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { |
||||||
|
unsafe { |
||||||
|
if mem::needs_drop::<T>() && self.dtor_running.get() { |
||||||
|
return None |
||||||
|
} |
||||||
|
self.register_dtor(); |
||||||
|
} |
||||||
|
Some(&self.inner) |
||||||
|
} |
||||||
|
|
||||||
|
unsafe fn register_dtor(&self) { |
||||||
|
if !mem::needs_drop::<T>() || self.dtor_registered.get() { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
register_dtor(self as *const _ as *mut u8, |
||||||
|
destroy_value::<T>); |
||||||
|
self.dtor_registered.set(true); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { |
||||||
|
// The fallback implementation uses a vanilla OS-based TLS key to track
|
||||||
|
// the list of destructors that need to be run for this thread. The key
|
||||||
|
// then has its own destructor which runs all the other destructors.
|
||||||
|
//
|
||||||
|
// The destructor for DTORS is a little special in that it has a `while`
|
||||||
|
// loop to continuously drain the list of registered destructors. It
|
||||||
|
// *should* be the case that this loop always terminates because we
|
||||||
|
// provide the guarantee that a TLS key cannot be set after it is
|
||||||
|
// flagged for destruction.
|
||||||
|
use sys_common::thread_local as os; |
||||||
|
|
||||||
|
static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); |
||||||
|
type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; |
||||||
|
if DTORS.get().is_null() { |
||||||
|
let v: Box<List> = box Vec::new(); |
||||||
|
DTORS.set(Box::into_raw(v) as *mut u8); |
||||||
|
} |
||||||
|
let list: &mut List = &mut *(DTORS.get() as *mut List); |
||||||
|
list.push((t, dtor)); |
||||||
|
|
||||||
|
unsafe extern fn run_dtors(mut ptr: *mut u8) { |
||||||
|
while !ptr.is_null() { |
||||||
|
let list: Box<List> = Box::from_raw(ptr as *mut List); |
||||||
|
for (ptr, dtor) in list.into_iter() { |
||||||
|
dtor(ptr); |
||||||
|
} |
||||||
|
ptr = DTORS.get(); |
||||||
|
DTORS.set(ptr::null_mut()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub unsafe extern fn destroy_value<T>(ptr: *mut u8) { |
||||||
|
let ptr = ptr as *mut Key<T>; |
||||||
|
// Right before we run the user destructor be sure to flag the
|
||||||
|
// destructor as running for this thread so calls to `get` will return
|
||||||
|
// `None`.
|
||||||
|
(*ptr).dtor_running.set(true); |
||||||
|
|
||||||
|
// The macOS implementation of TLS apparently had an odd aspect to it
|
||||||
|
// where the pointer we have may be overwritten while this destructor
|
||||||
|
// is running. Specifically if a TLS destructor re-accesses TLS it may
|
||||||
|
// trigger a re-initialization of all TLS variables, paving over at
|
||||||
|
// least some destroyed ones with initial values.
|
||||||
|
//
|
||||||
|
// This means that if we drop a TLS value in place on macOS that we could
|
||||||
|
// revert the value to its original state halfway through the
|
||||||
|
// destructor, which would be bad!
|
||||||
|
//
|
||||||
|
// Hence, we use `ptr::read` on macOS (to move to a "safe" location)
|
||||||
|
// instead of drop_in_place.
|
||||||
|
if cfg!(target_os = "macos") { |
||||||
|
ptr::read((*ptr).inner.get()); |
||||||
|
} else { |
||||||
|
ptr::drop_in_place((*ptr).inner.get()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn requires_move_before_drop() -> bool { |
||||||
|
false |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue