diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 767f17681b4c2..b0b1b4df6e306 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -39,6 +39,7 @@ #![feature(path_ext)] #![feature(str_char)] #![feature(into_cow)] +#![feature(fs_canonicalize)] #![feature(slice_patterns)] #![cfg_attr(test, feature(test))] @@ -138,7 +139,6 @@ pub mod plugin; pub mod lint; pub mod util { - pub use rustc_back::fs; pub use rustc_back::sha2; pub mod common; diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 241d8fd00252c..12112fd45ebe9 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -21,8 +21,10 @@ use metadata::decoder; use metadata::loader; use metadata::loader::CratePaths; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::rc::Rc; +use std::fs; + use syntax::ast; use syntax::abi; use syntax::attr; @@ -32,7 +34,6 @@ use syntax::parse; use syntax::parse::token::InternedString; use syntax::parse::token; use syntax::visit; -use util::fs; use log; pub struct CrateReader<'a> { @@ -322,7 +323,7 @@ impl<'a> CrateReader<'a> { let source = self.sess.cstore.get_used_crate_source(cnum).unwrap(); if let Some(locs) = self.sess.opts.externs.get(name) { let found = locs.iter().any(|l| { - let l = fs::realpath(&Path::new(&l[..])).ok(); + let l = fs::canonicalize(l).ok(); source.dylib.as_ref().map(|p| &p.0) == l.as_ref() || source.rlib.as_ref().map(|p| &p.0) == l.as_ref() }); diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 1567f4b99475c..7d8cf5b22a901 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -18,7 +18,6 @@ use std::fs; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use util::fs as myfs; use session::search_paths::{SearchPaths, PathKind}; #[derive(Copy, Clone)] @@ -191,7 +190,7 @@ pub fn get_or_default_sysroot() -> PathBuf { // Follow symlinks. If the resolved path is relative, make it absolute. fn canonicalize(path: Option) -> Option { path.and_then(|path| { - match myfs::realpath(&path) { + match fs::canonicalize(&path) { Ok(canon) => Some(canon), Err(e) => panic!("failed to get realpath: {}", e), } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index bbb2452ca29ee..062a156637a35 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -225,12 +225,12 @@ use metadata::encoder; use metadata::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; use syntax::codemap::Span; use syntax::diagnostic::SpanHandler; -use util::fs; use util::common; use rustc_back::target::Target; use std::cmp; use std::collections::HashMap; +use std::fs; use std::io::prelude::*; use std::io; use std::path::{Path, PathBuf}; @@ -430,9 +430,9 @@ impl<'a> Context<'a> { .or_insert_with(|| (HashMap::new(), HashMap::new())); let (ref mut rlibs, ref mut dylibs) = *slot; if rlib { - rlibs.insert(fs::realpath(path).unwrap(), kind); + rlibs.insert(fs::canonicalize(path).unwrap(), kind); } else { - dylibs.insert(fs::realpath(path).unwrap(), kind); + dylibs.insert(fs::canonicalize(path).unwrap(), kind); } FileMatches @@ -660,10 +660,10 @@ impl<'a> Context<'a> { // there's at most one rlib and at most one dylib. for loc in locs { if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { - rlibs.insert(fs::realpath(&loc).unwrap(), + rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag); } else { - dylibs.insert(fs::realpath(&loc).unwrap(), + dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag); } } diff --git a/src/librustc_back/fs.rs b/src/librustc_back/fs.rs deleted file mode 100644 index 37e3efb4d83fe..0000000000000 --- a/src/librustc_back/fs.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::io; -use std::path::{Path, PathBuf}; - -#[cfg(windows)] -pub fn realpath(original: &Path) -> io::Result { - Ok(original.to_path_buf()) -} - -#[cfg(unix)] -pub fn realpath(original: &Path) -> io::Result { - use libc; - use std::ffi::{OsString, CString}; - use std::os::unix::prelude::*; - - extern { - fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char) - -> *mut libc::c_char; - } - - let path = try!(CString::new(original.as_os_str().as_bytes())); - let mut buf = vec![0u8; 16 * 1024]; - unsafe { - let r = realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _); - if r.is_null() { - return Err(io::Error::last_os_error()) - } - } - let p = buf.iter().position(|i| *i == 0).unwrap(); - buf.truncate(p); - Ok(PathBuf::from(OsString::from_vec(buf))) -} - -#[cfg(all(not(windows), test))] -mod tests { - use tempdir::TempDir; - use std::fs::{self, File}; - use super::realpath; - - #[test] - fn realpath_works() { - let tmpdir = TempDir::new("rustc-fs").unwrap(); - let tmpdir = realpath(tmpdir.path()).unwrap(); - let file = tmpdir.join("test"); - let dir = tmpdir.join("test2"); - let link = dir.join("link"); - let linkdir = tmpdir.join("test3"); - - File::create(&file).unwrap(); - fs::create_dir(&dir).unwrap(); - fs::soft_link(&file, &link).unwrap(); - fs::soft_link(&dir, &linkdir).unwrap(); - - assert_eq!(realpath(&tmpdir).unwrap(), tmpdir); - assert_eq!(realpath(&file).unwrap(), file); - assert_eq!(realpath(&link).unwrap(), file); - assert_eq!(realpath(&linkdir).unwrap(), dir); - assert_eq!(realpath(&linkdir.join("link")).unwrap(), file); - } - - #[test] - fn realpath_works_tricky() { - let tmpdir = TempDir::new("rustc-fs").unwrap(); - let tmpdir = realpath(tmpdir.path()).unwrap(); - - let a = tmpdir.join("a"); - let b = a.join("b"); - let c = b.join("c"); - let d = a.join("d"); - let e = d.join("e"); - let f = a.join("f"); - - fs::create_dir_all(&b).unwrap(); - fs::create_dir_all(&d).unwrap(); - File::create(&f).unwrap(); - fs::soft_link("../d/e", &c).unwrap(); - fs::soft_link("../f", &e).unwrap(); - - assert_eq!(realpath(&c).unwrap(), f); - assert_eq!(realpath(&e).unwrap(), f); - } -} diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 22dea4757ed66..3e55f7f8045b5 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -41,6 +41,7 @@ #![feature(path_ext)] #![feature(step_by)] #![feature(libc)] +#![feature(fs_canonicalize)] #![cfg_attr(test, feature(test, rand))] extern crate syntax; @@ -53,7 +54,6 @@ pub mod abi; pub mod archive; pub mod tempdir; pub mod arm; -pub mod fs; pub mod mips; pub mod mipsel; pub mod rpath; diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs index 1daeb1cb223e2..6674d3135a0bd 100644 --- a/src/librustc_back/rpath.rs +++ b/src/librustc_back/rpath.rs @@ -10,8 +10,8 @@ use std::collections::HashSet; use std::env; -use std::io; use std::path::{Path, PathBuf}; +use std::fs; use syntax::ast; pub struct RPathConfig<'a> { @@ -20,7 +20,6 @@ pub struct RPathConfig<'a> { pub is_like_osx: bool, pub has_rpath: bool, pub get_install_prefix_lib_path: &'a mut FnMut() -> PathBuf, - pub realpath: &'a mut FnMut(&Path) -> io::Result, } pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { @@ -95,11 +94,11 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String }; let cwd = env::current_dir().unwrap(); - let mut lib = (config.realpath)(&cwd.join(lib)).unwrap(); + let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or(cwd.join(lib)); lib.pop(); let mut output = cwd.join(&config.out_filename); output.pop(); - let output = (config.realpath)(&output).unwrap(); + let output = fs::canonicalize(&output).unwrap_or(output); let relative = path_relative_from(&lib, &output) .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib)); // FIXME (#9639): This needs to handle non-utf8 paths @@ -231,7 +230,6 @@ mod tests { is_like_osx: true, out_filename: PathBuf::from("bin/rustc"), get_install_prefix_lib_path: &mut || panic!(), - realpath: &mut |p| Ok(p.to_path_buf()), }; let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so")); @@ -243,7 +241,6 @@ mod tests { get_install_prefix_lib_path: &mut || panic!(), has_rpath: true, is_like_osx: false, - realpath: &mut |p| Ok(p.to_path_buf()), }; let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so")); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index c72072f069650..92c9549b37727 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -32,7 +32,7 @@ use std::ffi::OsString; use std::fs::{self, PathExt}; use std::io::{self, Read, Write}; use std::mem; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; use std::process::Command; use std::str; use flate; @@ -872,7 +872,7 @@ fn link_args(cmd: &mut Command, // target descriptor let t = &sess.target.target; - cmd.arg("-L").arg(&lib_path); + cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(&lib_path)); cmd.arg("-o").arg(out_filename).arg(obj_filename); @@ -924,8 +924,9 @@ fn link_args(cmd: &mut Command, // stripped away as much as it could. This has not been seen to impact // link times negatively. // - // -dead_strip can't be part of the pre_link_args because it's also used for partial - // linking when using multiple codegen units (-r). So we insert it here. + // -dead_strip can't be part of the pre_link_args because it's also used + // for partial linking when using multiple codegen units (-r). So we + // insert it here. cmd.arg("-Wl,-dead_strip"); } @@ -1051,7 +1052,6 @@ fn link_args(cmd: &mut Command, has_rpath: sess.target.target.options.has_rpath, is_like_osx: sess.target.target.options.is_like_osx, get_install_prefix_lib_path: &mut get_install_prefix_lib_path, - realpath: &mut ::util::fs::realpath }; cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); } @@ -1266,7 +1266,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, } }); } else { - cmd.arg(cratepath); + cmd.arg(&fix_windows_verbatim_for_gcc(cratepath)); } } @@ -1279,7 +1279,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, // Just need to tell the linker about where the library lives and // what its name is if let Some(dir) = cratepath.parent() { - cmd.arg("-L").arg(dir); + cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(dir)); } let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); cmd.arg(&format!("-l{}", unlib(&sess.target, filestem))); @@ -1333,3 +1333,29 @@ fn add_upstream_native_libraries(cmd: &mut Command, sess: &Session) { } } } + +// Unfortunately, on windows, gcc cannot accept paths of the form `\\?\C:\...` +// (a verbatim path). This form of path is generally pretty rare, but the +// implementation of `fs::canonicalize` currently generates paths of this form, +// meaning that we're going to be passing quite a few of these down to gcc. +// +// For now we just strip the "verbatim prefix" of `\\?\` from the path. This +// will probably lose information in some cases, but there's not a whole lot +// more we can do with a buggy gcc... +fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf { + if !cfg!(windows) { + return p.to_path_buf() + } + let mut components = p.components(); + let prefix = match components.next() { + Some(path::Component::Prefix(p)) => p, + _ => return p.to_path_buf(), + }; + let disk = match prefix.kind() { + path::Prefix::VerbatimDisk(disk) => disk, + _ => return p.to_path_buf(), + }; + let mut base = OsString::from(format!("{}:", disk as char)); + base.push(components.as_path()); + PathBuf::from(base) +} diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index b5dfbf796d3bc..2b15a4ff83ed1 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -20,6 +20,7 @@ use core::prelude::*; use fmt; +use ffi::OsString; use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write}; use path::{Path, PathBuf}; use sys::fs2 as fs_imp; @@ -146,6 +147,20 @@ pub struct OpenOptions(fs_imp::OpenOptions); #[stable(feature = "rust1", since = "1.0.0")] pub struct Permissions(fs_imp::FilePermissions); +/// An structure representing a type of file with accessors for each file type. +#[unstable(feature = "file_type", reason = "recently added API")] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct FileType(fs_imp::FileType); + +/// A builder used to create directories in various manners. +/// +/// This builder also supports platform-specific options. +#[unstable(feature = "dir_builder", reason = "recently added API")] +pub struct DirBuilder { + inner: fs_imp::DirBuilder, + recursive: bool, +} + impl File { /// Attempts to open a file in read-only mode. /// @@ -485,6 +500,12 @@ impl AsInnerMut for OpenOptions { } impl Metadata { + /// Returns the file type for this metadata. + #[unstable(feature = "file_type", reason = "recently added API")] + pub fn file_type(&self) -> FileType { + FileType(self.0.file_type()) + } + /// Returns whether this metadata is for a directory. /// /// # Examples @@ -500,7 +521,7 @@ impl Metadata { /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_dir(&self) -> bool { self.0.is_dir() } + pub fn is_dir(&self) -> bool { self.file_type().is_dir() } /// Returns whether this metadata is for a regular file. /// @@ -517,7 +538,7 @@ impl Metadata { /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_file(&self) -> bool { self.0.is_file() } + pub fn is_file(&self) -> bool { self.file_type().is_file() } /// Returns the size of the file, in bytes, this metadata is for. /// @@ -562,7 +583,11 @@ impl Metadata { reason = "the return type of u64 is not quite appropriate for \ this method and may change if the standard library \ gains a type to represent a moment in time")] - pub fn accessed(&self) -> u64 { self.0.accessed() } + #[deprecated(since = "1.1.0", + reason = "use os::platform::fs::MetadataExt extension traits")] + pub fn accessed(&self) -> u64 { + self.adjust_time(self.0.accessed()) + } /// Returns the most recent modification time for a file. /// @@ -571,7 +596,21 @@ impl Metadata { reason = "the return type of u64 is not quite appropriate for \ this method and may change if the standard library \ gains a type to represent a moment in time")] - pub fn modified(&self) -> u64 { self.0.modified() } + #[deprecated(since = "1.1.0", + reason = "use os::platform::fs::MetadataExt extension traits")] + pub fn modified(&self) -> u64 { + self.adjust_time(self.0.modified()) + } + + fn adjust_time(&self, val: u64) -> u64 { + // FILETIME (what `val` represents) is in 100ns intervals and there are + // 10000 intervals in a millisecond. + if cfg!(windows) {val / 10000} else {val} + } +} + +impl AsInner for Metadata { + fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 } } impl Permissions { @@ -624,6 +663,18 @@ impl Permissions { } } +#[unstable(feature = "file_type", reason = "recently added API")] +impl FileType { + /// Test whether this file type represents a directory. + pub fn is_dir(&self) -> bool { self.0.is_dir() } + + /// Test whether this file type represents a regular file. + pub fn is_file(&self) -> bool { self.0.is_file() } + + /// Test whether this file type represents a symbolic link. + pub fn is_symlink(&self) -> bool { self.0.is_symlink() } +} + impl FromInner for Permissions { fn from_inner(f: fs_imp::FilePermissions) -> Permissions { Permissions(f) @@ -674,6 +725,47 @@ impl DirEntry { /// The exact text, of course, depends on what files you have in `.`. #[stable(feature = "rust1", since = "1.0.0")] pub fn path(&self) -> PathBuf { self.0.path() } + + /// Return the metadata for the file that this entry points at. + /// + /// This function will not traverse symlinks if this entry points at a + /// symlink. + /// + /// # Platform behavior + /// + /// On Windows this function is cheap to call (no extra system calls + /// needed), but on Unix platforms this function is the equivalent of + /// calling `symlink_metadata` on the path. + #[unstable(feature = "dir_entry_ext", reason = "recently added API")] + pub fn metadata(&self) -> io::Result { + self.0.metadata().map(Metadata) + } + + /// Return the file type for the file that this entry points at. + /// + /// This function will not traverse symlinks if this entry points at a + /// symlink. + /// + /// # Platform behavior + /// + /// On Windows and most Unix platforms this function is free (no extra + /// system calls needed), but some Unix platforms may require the equivalent + /// call to `symlink_metadata` to learn about the target file type. + #[unstable(feature = "dir_entry_ext", reason = "recently added API")] + pub fn file_type(&self) -> io::Result { + self.0.file_type().map(FileType) + } + + /// Returns the bare file name of this directory entry without any other + /// leading path component. + #[unstable(feature = "dir_entry_ext", reason = "recently added API")] + pub fn file_name(&self) -> OsString { + self.0.file_name() + } +} + +impl AsInner for DirEntry { + fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 } } /// Removes a file from the underlying filesystem. @@ -731,6 +823,25 @@ pub fn metadata>(path: P) -> io::Result { fs_imp::stat(path.as_ref()).map(Metadata) } +/// Query the metadata about a file without following symlinks. +/// +/// # Examples +/// +/// ```rust +/// #![feature(symlink_metadata)] +/// # fn foo() -> std::io::Result<()> { +/// use std::fs; +/// +/// let attr = try!(fs::symlink_metadata("/some/file/path.txt")); +/// // inspect attr ... +/// # Ok(()) +/// # } +/// ``` +#[unstable(feature = "symlink_metadata", reason = "recently added API")] +pub fn symlink_metadata>(path: P) -> io::Result { + fs_imp::lstat(path.as_ref()).map(Metadata) +} + /// Rename a file or directory to a new name. /// /// # Errors @@ -869,6 +980,13 @@ pub fn read_link>(path: P) -> io::Result { fs_imp::readlink(path.as_ref()) } +/// Returns the canonical form of a path with all intermediate components +/// normalized and symbolic links resolved. +#[unstable(feature = "fs_canonicalize", reason = "recently added API")] +pub fn canonicalize>(path: P) -> io::Result { + fs_imp::canonicalize(path.as_ref()) +} + /// Creates a new, empty directory at the provided path /// /// # Errors @@ -888,7 +1006,7 @@ pub fn read_link>(path: P) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir>(path: P) -> io::Result<()> { - fs_imp::mkdir(path.as_ref()) + DirBuilder::new().create(path.as_ref()) } /// Recursively create a directory and all of its parent components if they @@ -913,10 +1031,7 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir_all>(path: P) -> io::Result<()> { - let path = path.as_ref(); - if path == Path::new("") || path.is_dir() { return Ok(()) } - if let Some(p) = path.parent() { try!(create_dir_all(p)) } - create_dir(path) + DirBuilder::new().recursive(true).create(path.as_ref()) } /// Removes an existing, empty directory. @@ -966,19 +1081,14 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { let path = path.as_ref(); for child in try!(read_dir(path)) { let child = try!(child).path(); - let stat = try!(lstat(&*child)); + let stat = try!(symlink_metadata(&*child)); if stat.is_dir() { try!(remove_dir_all(&*child)); } else { try!(remove_file(&*child)); } } - return remove_dir(path); - - #[cfg(unix)] - fn lstat(path: &Path) -> io::Result { fs_imp::lstat(path) } - #[cfg(windows)] - fn lstat(path: &Path) -> io::Result { fs_imp::stat(path) } + remove_dir(path) } /// Returns an iterator over the entries within a directory. @@ -1073,11 +1183,37 @@ impl Iterator for WalkDir { pub trait PathExt { /// Gets information on the file, directory, etc at this path. /// - /// Consult the `fs::stat` documentation for more info. + /// Consult the `fs::metadata` documentation for more info. /// - /// This call preserves identical runtime/error semantics with `file::stat`. + /// This call preserves identical runtime/error semantics with + /// `fs::metadata`. fn metadata(&self) -> io::Result; + /// Gets information on the file, directory, etc at this path. + /// + /// Consult the `fs::symlink_metadata` documentation for more info. + /// + /// This call preserves identical runtime/error semantics with + /// `fs::symlink_metadata`. + fn symlink_metadata(&self) -> io::Result; + + /// Returns the canonical form of a path, normalizing all components and + /// eliminate all symlinks. + /// + /// This call preserves identical runtime/error semantics with + /// `fs::canonicalize`. + fn canonicalize(&self) -> io::Result; + + /// Reads the symlink at this path. + /// + /// For more information see `fs::read_link`. + fn read_link(&self) -> io::Result; + + /// Reads the directory at this path. + /// + /// For more information see `fs::read_dir`. + fn read_dir(&self) -> io::Result; + /// Boolean value indicator whether the underlying file exists on the local /// filesystem. Returns false in exactly the cases where `fs::stat` fails. fn exists(&self) -> bool; @@ -1098,12 +1234,16 @@ pub trait PathExt { impl PathExt for Path { fn metadata(&self) -> io::Result { metadata(self) } - + fn symlink_metadata(&self) -> io::Result { symlink_metadata(self) } + fn canonicalize(&self) -> io::Result { canonicalize(self) } + fn read_link(&self) -> io::Result { read_link(self) } + fn read_dir(&self) -> io::Result { read_dir(self) } fn exists(&self) -> bool { metadata(self).is_ok() } fn is_file(&self) -> bool { metadata(self).map(|s| s.is_file()).unwrap_or(false) } + fn is_dir(&self) -> bool { metadata(self).map(|s| s.is_dir()).unwrap_or(false) } @@ -1152,6 +1292,52 @@ pub fn set_permissions>(path: P, perm: Permissions) -> io::Result fs_imp::set_perm(path.as_ref(), perm.0) } +impl DirBuilder { + /// Creates a new set of options with default mode/security settings for all + /// platforms and also non-recursive. + pub fn new() -> DirBuilder { + DirBuilder { + inner: fs_imp::DirBuilder::new(), + recursive: false, + } + } + + /// Indicate that directories create should be created recursively, creating + /// all parent directories if they do not exist with the same security and + /// permissions settings. + /// + /// This option defaults to `false` + pub fn recursive(&mut self, recursive: bool) -> &mut Self { + self.recursive = recursive; + self + } + + /// Create the specified directory with the options configured in this + /// builder. + pub fn create>(&self, path: P) -> io::Result<()> { + let path = path.as_ref(); + if self.recursive { + self.create_dir_all(path) + } else { + self.inner.mkdir(path) + } + } + + fn create_dir_all(&self, path: &Path) -> io::Result<()> { + if path == Path::new("") || path.is_dir() { return Ok(()) } + if let Some(p) = path.parent() { + try!(self.create_dir_all(p)) + } + self.inner.mkdir(path) + } +} + +impl AsInnerMut for DirBuilder { + fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder { + &mut self.inner + } +} + #[cfg(test)] mod tests { #![allow(deprecated)] //rand @@ -1924,4 +2110,74 @@ mod tests { let path = tmpdir.join("file"); check!(fs::create_dir_all(&path.join("a/"))); } + + #[test] + #[cfg(not(windows))] + fn realpath_works() { + let tmpdir = tmpdir(); + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let file = tmpdir.join("test"); + let dir = tmpdir.join("test2"); + let link = dir.join("link"); + let linkdir = tmpdir.join("test3"); + + File::create(&file).unwrap(); + fs::create_dir(&dir).unwrap(); + fs::soft_link(&file, &link).unwrap(); + fs::soft_link(&dir, &linkdir).unwrap(); + + assert!(link.symlink_metadata().unwrap().file_type().is_symlink()); + + assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir); + assert_eq!(fs::canonicalize(&file).unwrap(), file); + assert_eq!(fs::canonicalize(&link).unwrap(), file); + assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir); + assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file); + } + + #[test] + #[cfg(not(windows))] + fn realpath_works_tricky() { + let tmpdir = tmpdir(); + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + + let a = tmpdir.join("a"); + let b = a.join("b"); + let c = b.join("c"); + let d = a.join("d"); + let e = d.join("e"); + let f = a.join("f"); + + fs::create_dir_all(&b).unwrap(); + fs::create_dir_all(&d).unwrap(); + File::create(&f).unwrap(); + fs::soft_link("../d/e", &c).unwrap(); + fs::soft_link("../f", &e).unwrap(); + + assert_eq!(fs::canonicalize(&c).unwrap(), f); + assert_eq!(fs::canonicalize(&e).unwrap(), f); + } + + #[test] + fn dir_entry_methods() { + let tmpdir = tmpdir(); + + fs::create_dir_all(&tmpdir.join("a")).unwrap(); + File::create(&tmpdir.join("b")).unwrap(); + + for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) { + let fname = file.file_name(); + match fname.to_str() { + Some("a") => { + assert!(file.file_type().unwrap().is_dir()); + assert!(file.metadata().unwrap().is_dir()); + } + Some("b") => { + assert!(file.file_type().unwrap().is_file()); + assert!(file.metadata().unwrap().is_file()); + } + f => panic!("unknown file name: {:?}", f), + } + } + } } diff --git a/src/libstd/os.rs b/src/libstd/os/android/mod.rs similarity index 63% rename from src/libstd/os.rs rename to src/libstd/os/android/mod.rs index ee0f04cb9911c..346a903c4d9a9 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os/android/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! OS-specific functionality +//! Android-specific definitions -#![stable(feature = "os", since = "1.0.0")] +#![unstable(feature = "raw_ext", reason = "recently added API")] -#[cfg(unix)] pub use sys::ext as unix; -#[cfg(windows)] pub use sys::ext as windows; +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/android/raw.rs b/src/libstd/os/android/raw.rs new file mode 100644 index 0000000000000..538ed7c4688c7 --- /dev/null +++ b/src/libstd/os/android/raw.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Android-specific raw type definitions + +use os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong}; +use os::unix::raw::{uid_t, gid_t}; + +pub type blkcnt_t = u32; +pub type blksize_t = u32; +pub type dev_t = u32; +pub type ino_t = u32; +pub type mode_t = u16; +pub type nlink_t = u16; +pub type off_t = i32; +pub type time_t = i32; + +#[repr(C)] +pub struct stat { + pub st_dev: c_ulonglong, + pub __pad0: [c_uchar; 4], + pub __st_ino: ino_t, + pub st_mode: c_uint, + pub st_nlink: c_uint, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: c_ulonglong, + pub __pad3: [c_uchar; 4], + pub st_size: c_longlong, + pub st_blksize: blksize_t, + pub st_blocks: c_ulonglong, + pub st_atime: time_t, + pub st_atime_nsec: c_ulong, + pub st_mtime: time_t, + pub st_mtime_nsec: c_ulong, + pub st_ctime: time_t, + pub st_ctime_nsec: c_ulong, + pub st_ino: c_ulonglong, +} diff --git a/src/libstd/os/bitrig/mod.rs b/src/libstd/os/bitrig/mod.rs new file mode 100644 index 0000000000000..01ea542b3b713 --- /dev/null +++ b/src/libstd/os/bitrig/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Bitrig-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/bitrig/raw.rs b/src/libstd/os/bitrig/raw.rs new file mode 100644 index 0000000000000..aebc21aa71856 --- /dev/null +++ b/src/libstd/os/bitrig/raw.rs @@ -0,0 +1,48 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Bitrig-specific raw type definitions + +use os::raw::c_long; +use os::unix::raw::{uid_t, gid_t}; + +pub type blkcnt_t = i64; +pub type blksize_t = u32; +pub type dev_t = i32; +pub type fflags_t = u32; // type not declared, but struct stat have u_int32_t +pub type ino_t = u64; +pub type mode_t = u32; +pub type nlink_t = u32; +pub type off_t = i64; +pub type time_t = i64; + +#[repr(C)] +pub struct stat { + pub st_mode: mode_t, + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: fflags_t, + pub st_gen: u32, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, +} diff --git a/src/libstd/os/dragonfly/mod.rs b/src/libstd/os/dragonfly/mod.rs new file mode 100644 index 0000000000000..677f8b706cdbd --- /dev/null +++ b/src/libstd/os/dragonfly/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Dragonfly-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/dragonfly/raw.rs b/src/libstd/os/dragonfly/raw.rs new file mode 100644 index 0000000000000..22c811ead4335 --- /dev/null +++ b/src/libstd/os/dragonfly/raw.rs @@ -0,0 +1,50 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Dragonfly-specific raw type definitions + +use os::raw::c_long; +use os::unix::raw::{pid_t, uid_t, gid_t}; + +pub type blkcnt_t = i64; +pub type blksize_t = u32; +pub type dev_t = u32; +pub type fflags_t = u32; +pub type ino_t = u64; +pub type mode_t = u16; +pub type nlink_t = u16; +pub type off_t = i64; +pub type time_t = i64; + +#[repr(C)] +pub struct stat { + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_dev: dev_t, + pub st_mode: mode_t, + pub st_padding1: u16, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: fflags_t, + pub st_gen: uint32_t, + pub st_lspare: int32_t, + pub st_qspare1: int64_t, + pub st_qspare2: int64_t, +} diff --git a/src/libstd/os/freebsd/mod.rs b/src/libstd/os/freebsd/mod.rs new file mode 100644 index 0000000000000..73b6fd211371c --- /dev/null +++ b/src/libstd/os/freebsd/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! FreeBSD-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/freebsd/raw.rs b/src/libstd/os/freebsd/raw.rs new file mode 100644 index 0000000000000..a810eff45d32e --- /dev/null +++ b/src/libstd/os/freebsd/raw.rs @@ -0,0 +1,50 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! FreeBSD-specific raw type definitions + +use os::raw::c_long; +use os::unix::raw::{uid_t, gid_t, pid_t}; + +pub type blkcnt_t = i64; +pub type blksize_t = i64; +pub type dev_t = u32; +pub type fflags_t = u32; +pub type ino_t = u32; +pub type mode_t = u16; +pub type nlink_t = u16; +pub type off_t = i64; +pub type time_t = i64; + +#[repr(C)] +pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: fflags_t, + pub st_gen: u32, + pub st_lspare: i32, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, + pub __unused: [u8; 2], +} diff --git a/src/libstd/os/ios/mod.rs b/src/libstd/os/ios/mod.rs new file mode 100644 index 0000000000000..d471cf12fe63e --- /dev/null +++ b/src/libstd/os/ios/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! iOS-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/ios/raw.rs b/src/libstd/os/ios/raw.rs new file mode 100644 index 0000000000000..3266b3846d899 --- /dev/null +++ b/src/libstd/os/ios/raw.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! iOS-specific raw type definitions + +use os::raw::c_long; +use os::unix::raw::{uid_t, gid_t, pid_t}; + +pub type blkcnt_t = i64; +pub type blksize_t = i32; +pub type dev_t = i32; +pub type ino_t = u64; +pub type mode_t = u16; +pub type nlink_t = u16; +pub type off_t = i64; +pub type time_t = c_long; + +#[repr(C)] +pub struct stat { + pub st_dev: dev_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_ino: ino_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: u32, + pub st_gen: u32, + pub st_lspare: i32, + pub st_qspare: [i64; 2], +} diff --git a/src/libstd/os/linux/mod.rs b/src/libstd/os/linux/mod.rs new file mode 100644 index 0000000000000..43376a1baeb92 --- /dev/null +++ b/src/libstd/os/linux/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Linux-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs new file mode 100644 index 0000000000000..adce5f22ebc10 --- /dev/null +++ b/src/libstd/os/linux/raw.rs @@ -0,0 +1,170 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Linux-specific raw type definitions + +pub type dev_t = u64; +pub type mode_t = u32; + +#[doc(inline)] +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"))] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::{c_long, c_short}; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i32; + pub type blksize_t = i32; + pub type ino_t = u32; + pub type nlink_t = u32; + pub type off_t = i32; + pub type time_t = i32; + + #[repr(C)] + pub struct stat { + pub st_dev: dev_t, + pub __pad1: c_short, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub __pad2: c_short, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub __unused4: c_long, + pub __unused5: c_long, + } +} + +#[cfg(any(target_arch = "mips", + target_arch = "mipsel"))] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::c_long; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i32; + pub type blksize_t = i32; + pub type ino_t = u32; + pub type nlink_t = u32; + pub type off_t = i32; + pub type time_t = i32; + + #[repr(C)] + pub struct stat { + pub st_dev: c_ulong, + pub st_pad1: [c_long; 3], + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: c_ulong, + pub st_pad2: [c_long; 2], + pub st_size: off_t, + pub st_pad3: c_long, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_pad5: [c_long; 14], + } +} + +#[cfg(target_arch = "aarch64")] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::{c_long, c_int}; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i64; + pub type blksize_t = i32; + pub type ino_t = u64; + pub type nlink_t = u32; + pub type off_t = i64; + pub type time_t = i64; + + #[repr(C)] + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub __pad1: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub __pad2: c_int, + pub st_blocks: blkcnt_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub __unused: [c_int; 2], + } +} + +#[cfg(target_arch = "x86_64")] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::{c_long, c_int}; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i64; + pub type blksize_t = i64; + pub type ino_t = u64; + pub type nlink_t = u64; + pub type off_t = i64; + pub type time_t = i64; + + #[repr(C)] + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub __pad0: c_int, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub __unused: [c_long; 3], + } +} diff --git a/src/libstd/os/macos/mod.rs b/src/libstd/os/macos/mod.rs new file mode 100644 index 0000000000000..bc5ff5b25d2fa --- /dev/null +++ b/src/libstd/os/macos/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! MacOS-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/macos/raw.rs b/src/libstd/os/macos/raw.rs new file mode 100644 index 0000000000000..03fcb768c119a --- /dev/null +++ b/src/libstd/os/macos/raw.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! MacOS-specific raw type definitions + +use os::raw::c_long; +use os::unix::raw::{uid_t, gid_t}; + +pub type blkcnt_t = i64; +pub type blksize_t = i32; +pub type dev_t = i32; +pub type ino_t = u64; +pub type mode_t = u16; +pub type nlink_t = u16; +pub type off_t = i64; +pub type time_t = c_long; + +#[repr(C)] +pub struct stat { + pub st_dev: dev_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_ino: ino_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: u32, + pub st_gen: u32, + pub st_lspare: i32, + pub st_qspare: [i64; 2], +} diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs new file mode 100644 index 0000000000000..cc4b1c944e786 --- /dev/null +++ b/src/libstd/os/mod.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! OS-specific functionality + +#![stable(feature = "os", since = "1.0.0")] +#![allow(missing_docs, bad_style)] + +#[cfg(unix)] pub use sys::ext as unix; +#[cfg(windows)] pub use sys::ext as windows; + +#[cfg(target_os = "android")] pub mod android; +#[cfg(target_os = "bitrig")] pub mod bitrig; +#[cfg(target_os = "dragonfly")] pub mod dragonfly; +#[cfg(target_os = "freebsd")] pub mod freebsd; +#[cfg(target_os = "ios")] pub mod ios; +#[cfg(target_os = "linux")] pub mod linux; +#[cfg(target_os = "macos")] pub mod macos; +#[cfg(target_os = "nacl")] pub mod nacl; +#[cfg(target_os = "openbsd")] pub mod openbsd; + +pub mod raw; diff --git a/src/libstd/os/nacl/mod.rs b/src/libstd/os/nacl/mod.rs new file mode 100644 index 0000000000000..6baed03951467 --- /dev/null +++ b/src/libstd/os/nacl/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Nacl-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/nacl/raw.rs b/src/libstd/os/nacl/raw.rs new file mode 100644 index 0000000000000..9defa8301ea34 --- /dev/null +++ b/src/libstd/os/nacl/raw.rs @@ -0,0 +1,169 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Nacl-specific raw type definitions + +pub type dev_t = u64; +pub type mode_t = u32; + +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"))] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::{c_long, c_short}; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i32; + pub type blksize_t = i32; + pub type ino_t = u32; + pub type nlink_t = u32; + pub type off_t = i32; + pub type time_t = i32; + + #[repr(C)] + pub struct stat { + pub st_dev: dev_t, + pub __pad1: c_short, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub __pad2: c_short, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub __unused4: c_long, + pub __unused5: c_long, + } +} + +#[cfg(any(target_arch = "mips", + target_arch = "mipsel"))] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::c_long; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i32; + pub type blksize_t = i32; + pub type ino_t = u32; + pub type nlink_t = u32; + pub type off_t = i32; + pub type time_t = i32; + + #[repr(C)] + pub struct stat { + pub st_dev: c_ulong, + pub st_pad1: [c_long; 3], + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: c_ulong, + pub st_pad2: [c_long; 2], + pub st_size: off_t, + pub st_pad3: c_long, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_pad5: [c_long; 14], + } +} + +#[cfg(target_arch = "aarch64")] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::{c_long, c_int}; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i64; + pub type blksize_t = i32; + pub type ino_t = u64; + pub type nlink_t = u32; + pub type off_t = i64; + pub type time_t = i64; + + #[repr(C)] + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub __pad1: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub __pad2: c_int, + pub st_blocks: blkcnt_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub __unused: [c_int; 2], + } +} + +#[cfg(target_arch = "x86_64")] +mod arch { + use super::{dev_t, mode_t}; + use os::raw::{c_long, c_int}; + use os::unix::raw::{gid_t, uid_t}; + + pub type blkcnt_t = i64; + pub type blksize_t = i64; + pub type ino_t = u64; + pub type nlink_t = u64; + pub type off_t = i64; + pub type time_t = i64; + + #[repr(C)] + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub __pad0: c_int, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub __unused: [c_long; 3], + } +} diff --git a/src/libstd/os/openbsd/mod.rs b/src/libstd/os/openbsd/mod.rs new file mode 100644 index 0000000000000..1b1a10055902b --- /dev/null +++ b/src/libstd/os/openbsd/mod.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! OpenBSD-specific definitions + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub mod raw; + +pub mod fs { + pub use sys::fs2::MetadataExt; +} diff --git a/src/libstd/os/openbsd/raw.rs b/src/libstd/os/openbsd/raw.rs new file mode 100644 index 0000000000000..632a8c336b78d --- /dev/null +++ b/src/libstd/os/openbsd/raw.rs @@ -0,0 +1,48 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! OpenBSD-specific raw type definitions + +use os::raw::c_long; +use os::unix::raw::{uid_t, gid_t, pid_t}; + +pub type blkcnt_t = i64; +pub type blksize_t = u32; +pub type dev_t = i32; +pub type fflags_t = u32; // type not declared, but struct stat have u_int32_t +pub type ino_t = u64; +pub type mode_t = u32; +pub type nlink_t = u32; +pub type off_t = i64; +pub type time_t = i64; + +#[repr(C)] +pub struct stat { + pub st_mode: mode_t, + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: fflags_t, + pub st_gen: u32, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, +} diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs new file mode 100644 index 0000000000000..44f4a1c828b54 --- /dev/null +++ b/src/libstd/os/raw.rs @@ -0,0 +1,92 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Raw OS-specific types for the current platform/architecture + +#![unstable(feature = "raw_os", reason = "recently added API")] + +#[cfg(target_arch = "aarch64")] pub type c_char = u8; +#[cfg(not(target_arch = "aarch64"))] pub type c_char = i8; +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +#[cfg(any(target_pointer_width = "32", windows))] pub type c_long = i32; +#[cfg(any(target_pointer_width = "32", windows))] pub type c_ulong = u32; +#[cfg(all(target_pointer_width = "64", not(windows)))] pub type c_long = i64; +#[cfg(all(target_pointer_width = "64", not(windows)))] pub type c_ulong = u64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type c_float = f32; +pub type c_double = f64; + +/// Type used to construct void pointers for use with C. +/// +/// This type is only useful as a pointer target. Do not use it as a +/// return type for FFI functions which have the `void` return type in +/// C. Use the unit type `()` or omit the return type instead. +// NB: For LLVM to recognize the void pointer type and by extension +// functions like malloc(), we need to have it represented as i8* in +// LLVM bitcode. The enum used here ensures this and prevents misuse +// of the "raw" type by only having private variants.. We need two +// variants, because the compiler complains about the repr attribute +// otherwise. +#[repr(u8)] +pub enum c_void { + #[doc(hidden)] __variant1, + #[doc(hidden)] __variant2, +} + +#[cfg(test)] +mod tests { + use any::TypeId; + use libc; + use mem; + + macro_rules! ok { + ($($t:ident)*) => {$( + assert!(TypeId::of::() == TypeId::of::(), + "{} is wrong", stringify!($t)); + )*} + } + + macro_rules! ok_size { + ($($t:ident)*) => {$( + assert!(mem::size_of::() == mem::size_of::(), + "{} is wrong", stringify!($t)); + )*} + } + + #[test] + fn same() { + use os::raw; + ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong + c_longlong c_ulonglong c_float c_double); + } + + #[cfg(unix)] + fn unix() { + { + use os::unix::raw; + ok!(uid_t gid_t dev_t ino_t mode_t nlink_t off_t blksize_t blkcnt_t); + } + { + use sys::platform::raw; + ok_size!(stat); + } + } + + #[cfg(windows)] + fn windows() { + use os::windows::raw; + } +} diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index aa4bf82120764..1e68eac5a6735 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -161,6 +161,8 @@ extern { pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; pub fn setgroups(ngroups: libc::c_int, ptr: *const libc::c_void) -> libc::c_int; + pub fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char) + -> *mut libc::c_char; } #[cfg(any(target_os = "macos", target_os = "ios"))] diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs deleted file mode 100644 index 66aaf26b09b72..0000000000000 --- a/src/libstd/sys/unix/ext.rs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Experimental extensions to `std` for Unix platforms. -//! -//! For now, this module is limited to extracting file descriptors, -//! but its functionality will grow over time. -//! -//! # Example -//! -//! ```no_run -//! use std::fs::File; -//! use std::os::unix::prelude::*; -//! -//! fn main() { -//! let f = File::create("foo.txt").unwrap(); -//! let fd = f.as_raw_fd(); -//! -//! // use fd with native unix bindings -//! } -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] - -/// Unix-specific extensions to general I/O primitives -#[stable(feature = "rust1", since = "1.0.0")] -pub mod io { - use fs; - use libc; - use net; - use sys_common::{net2, AsInner, FromInner}; - use sys; - - /// Raw file descriptors. - #[stable(feature = "rust1", since = "1.0.0")] - pub type RawFd = libc::c_int; - - /// A trait to extract the raw unix file descriptor from an underlying - /// object. - /// - /// This is only available on unix platforms and must be imported in order - /// to call the method. Windows platforms have a corresponding `AsRawHandle` - /// and `AsRawSocket` set of traits. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guarantee to be valid while - /// the original object has not yet been destroyed. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; - } - - /// A trait to express the ability to construct an object from a raw file - /// descriptor. - #[unstable(feature = "from_raw_os", - reason = "recent addition to std::os::unix::io")] - pub trait FromRawFd { - /// Constructs a new instances of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - unsafe fn from_raw_fd(fd: RawFd) -> Self; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs2::File::from_inner(fd)) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } - } - - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(net2::TcpStream::from_inner(socket)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(net2::TcpListener::from_inner(socket)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket)) - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// OsString and OsStr -//////////////////////////////////////////////////////////////////////////////// - -/// Unix-specific extension to the primitives in the `std::ffi` module -#[stable(feature = "rust1", since = "1.0.0")] -pub mod ffi { - use ffi::{OsStr, OsString}; - use mem; - use prelude::v1::*; - use sys::os_str::Buf; - use sys_common::{FromInner, IntoInner, AsInner}; - - /// Unix-specific extensions to `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStringExt { - /// Creates an `OsString` from a byte vector. - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec) -> Self; - - /// Yields the underlying byte vector of this `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl OsStringExt for OsString { - fn from_vec(vec: Vec) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec { - self.into_inner().inner - } - } - - /// Unix-specific extensions to `OsStr`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the `OsStr` slice. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } - } -} - -/// Unix-specific extensions to primitives in the `std::fs` module. -#[unstable(feature = "fs_ext", - reason = "may want a more useful mode abstraction")] -pub mod fs { - use sys; - use sys_common::{FromInner, AsInner, AsInnerMut}; - use fs::{Permissions, OpenOptions}; - use path::Path; - use convert::AsRef; - use io; - - /// Unix-specific extensions to `Permissions` - pub trait PermissionsExt { - fn mode(&self) -> i32; - fn set_mode(&mut self, mode: i32); - } - - impl PermissionsExt for Permissions { - fn mode(&self) -> i32 { self.as_inner().mode() } - - fn set_mode(&mut self, mode: i32) { - *self = FromInner::from_inner(FromInner::from_inner(mode)); - } - } - - /// Unix-specific extensions to `OpenOptions` - pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of a `File::open_opts` call then this - /// specified `mode` will be used as the permission bits for the new file. - fn mode(&mut self, mode: i32) -> &mut Self; - } - - impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: i32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - } - - /// Creates a new symbolic link on the filesystem. - /// - /// The `dst` path will be a symbolic link pointing to the `src` path. - /// - /// # Note - /// - /// On Windows, you must specify whether a symbolic link points to a file - /// or directory. Use `os::windows::fs::symlink_file` to create a - /// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a - /// symbolic link to a directory. Additionally, the process must have - /// `SeCreateSymbolicLinkPrivilege` in order to be able to create a - /// symbolic link. - /// - /// # Examples - /// - /// ``` - /// #![feature(fs_ext)] - /// use std::os::unix::fs; - /// - /// # fn foo() -> std::io::Result<()> { - /// try!(fs::symlink("a.txt", "b.txt")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> - { - sys::fs2::symlink(src.as_ref(), dst.as_ref()) - } - -} - -//////////////////////////////////////////////////////////////////////////////// -// Process and Command -//////////////////////////////////////////////////////////////////////////////// - -/// Unix-specific extensions to primitives in the `std::process` module. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod process { - use prelude::v1::*; - use libc::{uid_t, gid_t}; - use process; - use sys; - use sys_common::{AsInnerMut, AsInner}; - - /// Unix-specific extensions to the `std::process::Command` builder - #[stable(feature = "rust1", since = "1.0.0")] - pub trait CommandExt { - /// Sets the child process's user id. This translates to a - /// `setuid` call in the child process. Failure in the `setuid` - /// call will cause the spawn to fail. - #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: uid_t) -> &mut process::Command; - - /// Similar to `uid`, but sets the group id of the child process. This has - /// the same semantics as the `uid` field. - #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: gid_t) -> &mut process::Command; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl CommandExt for process::Command { - fn uid(&mut self, id: uid_t) -> &mut process::Command { - self.as_inner_mut().uid = Some(id); - self - } - - fn gid(&mut self, id: gid_t) -> &mut process::Command { - self.as_inner_mut().gid = Some(id); - self - } - } - - /// Unix-specific extensions to `std::process::ExitStatus` - #[stable(feature = "rust1", since = "1.0.0")] - pub trait ExitStatusExt { - /// If the process was terminated by a signal, returns that signal. - #[stable(feature = "rust1", since = "1.0.0")] - fn signal(&self) -> Option; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ExitStatusExt for process::ExitStatus { - fn signal(&self) -> Option { - match *self.as_inner() { - sys::process2::ExitStatus::Signal(s) => Some(s), - _ => None - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Prelude -//////////////////////////////////////////////////////////////////////////////// - -/// A prelude for conveniently writing platform-specific code. -/// -/// Includes all extension traits, and some important type definitions. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] - pub use super::io::{RawFd, AsRawFd}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] - pub use super::fs::{PermissionsExt, OpenOptionsExt}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::process::{CommandExt, ExitStatusExt}; -} diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs new file mode 100644 index 0000000000000..825e74cabdebb --- /dev/null +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -0,0 +1,62 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extension to the primitives in the `std::ffi` module + +#![stable(feature = "rust1", since = "1.0.0")] + +use ffi::{OsStr, OsString}; +use mem; +use prelude::v1::*; +use sys::os_str::Buf; +use sys_common::{FromInner, IntoInner, AsInner}; + +/// Unix-specific extensions to `OsString`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt { + /// Creates an `OsString` from a byte vector. + #[stable(feature = "rust1", since = "1.0.0")] + fn from_vec(vec: Vec) -> Self; + + /// Yields the underlying byte vector of this `OsString`. + #[stable(feature = "rust1", since = "1.0.0")] + fn into_vec(self) -> Vec; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + fn from_vec(vec: Vec) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + fn into_vec(self) -> Vec { + self.into_inner().inner + } +} + +/// Unix-specific extensions to `OsStr`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt { + #[stable(feature = "rust1", since = "1.0.0")] + fn from_bytes(slice: &[u8]) -> &Self; + + /// Gets the underlying byte view of the `OsStr` slice. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_bytes(&self) -> &[u8]; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + fn from_bytes(slice: &[u8]) -> &OsStr { + unsafe { mem::transmute(slice) } + } + fn as_bytes(&self) -> &[u8] { + &self.as_inner().inner + } +} diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs new file mode 100644 index 0000000000000..2e4ed38e50fe7 --- /dev/null +++ b/src/libstd/sys/unix/ext/fs.rs @@ -0,0 +1,207 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extensions to primitives in the `std::fs` module. + +#![stable(feature = "rust1", since = "1.0.0")] + +use prelude::v1::*; + +use fs::{self, Permissions, OpenOptions}; +use io; +use mem; +use os::raw::c_long; +use os::unix::raw; +use path::Path; +use sys::platform; +use sys; +use sys_common::{FromInner, AsInner, AsInnerMut}; + +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_READ: raw::mode_t = 0o400; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_WRITE: raw::mode_t = 0o200; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_EXECUTE: raw::mode_t = 0o100; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const USER_RWX: raw::mode_t = 0o700; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_READ: raw::mode_t = 0o040; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_WRITE: raw::mode_t = 0o020; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_EXECUTE: raw::mode_t = 0o010; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const GROUP_RWX: raw::mode_t = 0o070; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_READ: raw::mode_t = 0o004; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_WRITE: raw::mode_t = 0o002; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_EXECUTE: raw::mode_t = 0o001; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const OTHER_RWX: raw::mode_t = 0o007; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_READ: raw::mode_t = 0o444; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_WRITE: raw::mode_t = 0o222; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_EXECUTE: raw::mode_t = 0o111; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const ALL_RWX: raw::mode_t = 0o777; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const SETUID: raw::mode_t = 0o4000; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const SETGID: raw::mode_t = 0o2000; +#[unstable(feature = "fs_mode", reason = "recently added API")] +pub const STICKY_BIT: raw::mode_t = 0o1000; + +/// Unix-specific extensions to `Permissions` +#[unstable(feature = "fs_ext", + reason = "may want a more useful mode abstraction")] +pub trait PermissionsExt { + fn mode(&self) -> raw::mode_t; + fn set_mode(&mut self, mode: raw::mode_t); + fn from_mode(mode: raw::mode_t) -> Self; +} + +impl PermissionsExt for Permissions { + fn mode(&self) -> raw::mode_t { self.as_inner().mode() } + + fn set_mode(&mut self, mode: raw::mode_t) { + *self = FromInner::from_inner(FromInner::from_inner(mode)); + } + + fn from_mode(mode: raw::mode_t) -> Permissions { + FromInner::from_inner(FromInner::from_inner(mode)) + } +} + +/// Unix-specific extensions to `OpenOptions` +#[unstable(feature = "fs_ext", + reason = "may want a more useful mode abstraction")] +pub trait OpenOptionsExt { + /// Sets the mode bits that a new file will be created with. + /// + /// If a new file is created as part of a `File::open_opts` call then this + /// specified `mode` will be used as the permission bits for the new file. + fn mode(&mut self, mode: raw::mode_t) -> &mut Self; +} + +impl OpenOptionsExt for OpenOptions { + fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions { + self.as_inner_mut().mode(mode); self + } +} + +#[unstable(feature = "metadata_ext", reason = "recently added API")] +pub struct Metadata(sys::fs2::FileAttr); + +#[unstable(feature = "metadata_ext", reason = "recently added API")] +pub trait MetadataExt { + fn as_raw(&self) -> &Metadata; +} + +impl MetadataExt for fs::Metadata { + fn as_raw(&self) -> &Metadata { + let inner: &sys::fs2::FileAttr = self.as_inner(); + unsafe { mem::transmute(inner) } + } +} + +impl AsInner for Metadata { + fn as_inner(&self) -> &platform::raw::stat { self.0.as_inner() } +} + +// Hm, why are there casts here to the returned type, shouldn't the types always +// be the same? Right you are! Turns out, however, on android at least the types +// in the raw `stat` structure are not the same as the types being returned. Who +// knew! +// +// As a result to make sure this compiles for all platforms we do the manual +// casts and rely on manual lowering to `stat` if the raw type is desired. +#[unstable(feature = "metadata_ext", reason = "recently added API")] +impl Metadata { + pub fn dev(&self) -> raw::dev_t { self.0.raw().st_dev as raw::dev_t } + pub fn ino(&self) -> raw::ino_t { self.0.raw().st_ino as raw::ino_t } + pub fn mode(&self) -> raw::mode_t { self.0.raw().st_mode as raw::mode_t } + pub fn nlink(&self) -> raw::nlink_t { self.0.raw().st_nlink as raw::nlink_t } + pub fn uid(&self) -> raw::uid_t { self.0.raw().st_uid as raw::uid_t } + pub fn gid(&self) -> raw::gid_t { self.0.raw().st_gid as raw::gid_t } + pub fn rdev(&self) -> raw::dev_t { self.0.raw().st_rdev as raw::dev_t } + pub fn size(&self) -> raw::off_t { self.0.raw().st_size as raw::off_t } + pub fn atime(&self) -> raw::time_t { self.0.raw().st_atime } + pub fn atime_nsec(&self) -> c_long { self.0.raw().st_atime } + pub fn mtime(&self) -> raw::time_t { self.0.raw().st_mtime } + pub fn mtime_nsec(&self) -> c_long { self.0.raw().st_mtime } + pub fn ctime(&self) -> raw::time_t { self.0.raw().st_ctime } + pub fn ctime_nsec(&self) -> c_long { self.0.raw().st_ctime } + + pub fn blksize(&self) -> raw::blksize_t { + self.0.raw().st_blksize as raw::blksize_t + } + pub fn blocks(&self) -> raw::blkcnt_t { + self.0.raw().st_blocks as raw::blkcnt_t + } +} + +#[unstable(feature = "dir_entry_ext", reason = "recently added API")] +pub trait DirEntryExt { + fn ino(&self) -> raw::ino_t; +} + +impl DirEntryExt for fs::DirEntry { + fn ino(&self) -> raw::ino_t { self.as_inner().ino() } +} + +/// Creates a new symbolic link on the filesystem. +/// +/// The `dst` path will be a symbolic link pointing to the `src` path. +/// +/// # Note +/// +/// On Windows, you must specify whether a symbolic link points to a file +/// or directory. Use `os::windows::fs::symlink_file` to create a +/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a +/// symbolic link to a directory. Additionally, the process must have +/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a +/// symbolic link. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::symlink("a.txt", "b.txt")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> +{ + sys::fs2::symlink(src.as_ref(), dst.as_ref()) +} + +#[unstable(feature = "dir_builder", reason = "recently added API")] +/// An extension trait for `fs::DirBuilder` for unix-specific options. +pub trait DirBuilderExt { + /// Sets the mode to create new directories with. This option defaults to + /// 0o777. + fn mode(&mut self, mode: raw::mode_t) -> &mut Self; +} + +impl DirBuilderExt for fs::DirBuilder { + fn mode(&mut self, mode: raw::mode_t) -> &mut fs::DirBuilder { + self.as_inner_mut().set_mode(mode); + self + } +} + diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs new file mode 100644 index 0000000000000..8cb4b4907f6dc --- /dev/null +++ b/src/libstd/sys/unix/ext/io.rs @@ -0,0 +1,108 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extensions to general I/O primitives + +#![stable(feature = "rust1", since = "1.0.0")] + +use fs; +use net; +use os::raw; +use sys; +use sys_common::{net2, AsInner, FromInner}; + +/// Raw file descriptors. +#[stable(feature = "rust1", since = "1.0.0")] +pub type RawFd = raw::c_int; + +/// A trait to extract the raw unix file descriptor from an underlying +/// object. +/// +/// This is only available on unix platforms and must be imported in order +/// to call the method. Windows platforms have a corresponding `AsRawHandle` +/// and `AsRawSocket` set of traits. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This method does **not** pass ownership of the raw file descriptor + /// to the caller. The descriptor is only guarantee to be valid while + /// the original object has not yet been destroyed. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +#[unstable(feature = "from_raw_os", + reason = "recent addition to std::os::unix::io")] +pub trait FromRawFd { + /// Constructs a new instances of `Self` from the given raw file + /// descriptor. + /// + /// This function **consumes ownership** of the specified file + /// descriptor. The returned object will take responsibility for closing + /// it when the object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for fs::File { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for fs::File { + unsafe fn from_raw_fd(fd: RawFd) -> fs::File { + fs::File::from_inner(sys::fs2::File::from_inner(fd)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } +} + +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + let socket = sys::net::Socket::from_inner(fd); + net::TcpStream::from_inner(net2::TcpStream::from_inner(socket)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + let socket = sys::net::Socket::from_inner(fd); + net::TcpListener::from_inner(net2::TcpListener::from_inner(socket)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawFd for net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + let socket = sys::net::Socket::from_inner(fd); + net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket)) + } +} diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs new file mode 100644 index 0000000000000..6fde45a7301f9 --- /dev/null +++ b/src/libstd/sys/unix/ext/mod.rs @@ -0,0 +1,53 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Experimental extensions to `std` for Unix platforms. +//! +//! For now, this module is limited to extracting file descriptors, +//! but its functionality will grow over time. +//! +//! # Example +//! +//! ```no_run +//! use std::fs::File; +//! use std::os::unix::prelude::*; +//! +//! fn main() { +//! let f = File::create("foo.txt").unwrap(); +//! let fd = f.as_raw_fd(); +//! +//! // use fd with native unix bindings +//! } +//! ``` + +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod io; +pub mod ffi; +pub mod fs; +pub mod process; +pub mod raw; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] + pub use super::io::{RawFd, AsRawFd}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt}; + #[doc(no_inline)] + pub use super::fs::{DirEntryExt}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use super::process::{CommandExt, ExitStatusExt}; +} diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs new file mode 100644 index 0000000000000..8c9d0a86583fb --- /dev/null +++ b/src/libstd/sys/unix/ext/process.rs @@ -0,0 +1,65 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific extensions to primitives in the `std::process` module. + +#![stable(feature = "rust1", since = "1.0.0")] + +use os::unix::raw::{uid_t, gid_t}; +use prelude::v1::*; +use process; +use sys; +use sys_common::{AsInnerMut, AsInner}; + +/// Unix-specific extensions to the `std::process::Command` builder +#[stable(feature = "rust1", since = "1.0.0")] +pub trait CommandExt { + /// Sets the child process's user id. This translates to a + /// `setuid` call in the child process. Failure in the `setuid` + /// call will cause the spawn to fail. + #[stable(feature = "rust1", since = "1.0.0")] + fn uid(&mut self, id: uid_t) -> &mut process::Command; + + /// Similar to `uid`, but sets the group id of the child process. This has + /// the same semantics as the `uid` field. + #[stable(feature = "rust1", since = "1.0.0")] + fn gid(&mut self, id: gid_t) -> &mut process::Command; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl CommandExt for process::Command { + fn uid(&mut self, id: uid_t) -> &mut process::Command { + self.as_inner_mut().uid = Some(id); + self + } + + fn gid(&mut self, id: gid_t) -> &mut process::Command { + self.as_inner_mut().gid = Some(id); + self + } +} + +/// Unix-specific extensions to `std::process::ExitStatus` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait ExitStatusExt { + /// If the process was terminated by a signal, returns that signal. + #[stable(feature = "rust1", since = "1.0.0")] + fn signal(&self) -> Option; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExitStatusExt for process::ExitStatus { + fn signal(&self) -> Option { + match *self.as_inner() { + sys::process2::ExitStatus::Signal(s) => Some(s), + _ => None + } + } +} diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs new file mode 100644 index 0000000000000..8fe4b90456a4c --- /dev/null +++ b/src/libstd/sys/unix/ext/raw.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unix-specific primitives available on all unix platforms + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +pub type uid_t = u32; +pub type gid_t = u32; +pub type pid_t = i32; + +#[doc(inline)] +pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t}; +#[doc(inline)] +pub use sys::platform::raw::{blkcnt_t, time_t}; diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index 8eb84b26f22f2..350161c751cb8 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -21,14 +21,15 @@ use path::{Path, PathBuf}; use ptr; use sync::Arc; use sys::fd::FileDesc; +use sys::platform::raw; use sys::{c, cvt, cvt_r}; -use sys_common::FromInner; +use sys_common::{AsInner, FromInner}; use vec::Vec; pub struct File(FileDesc); pub struct FileAttr { - stat: libc::stat, + stat: raw::stat, } pub struct ReadDir { @@ -57,13 +58,12 @@ pub struct OpenOptions { #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { mode: mode_t } +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct FileType { mode: mode_t } + +pub struct DirBuilder { mode: mode_t } + impl FileAttr { - pub fn is_dir(&self) -> bool { - (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFDIR - } - pub fn is_file(&self) -> bool { - (self.stat.st_mode as mode_t) & libc::S_IFMT == libc::S_IFREG - } pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 } @@ -76,12 +76,35 @@ impl FileAttr { self.mktime(self.stat.st_mtime as u64, self.stat.st_mtime_nsec as u64) } + pub fn file_type(&self) -> FileType { + FileType { mode: self.stat.st_mode as mode_t } + } + + pub fn raw(&self) -> &raw::stat { &self.stat } + // times are in milliseconds (currently) fn mktime(&self, secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } } +impl AsInner for FileAttr { + fn as_inner(&self) -> &raw::stat { &self.stat } +} + +#[unstable(feature = "metadata_ext", reason = "recently added API")] +pub trait MetadataExt { + fn as_raw_stat(&self) -> &raw::stat; +} + +impl MetadataExt for ::fs::Metadata { + fn as_raw_stat(&self) -> &raw::stat { &self.as_inner().stat } +} + +impl MetadataExt for ::os::unix::fs::Metadata { + fn as_raw_stat(&self) -> &raw::stat { self.as_inner() } +} + impl FilePermissions { pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 } pub fn set_readonly(&mut self, readonly: bool) { @@ -91,11 +114,19 @@ impl FilePermissions { self.mode |= 0o222; } } - pub fn mode(&self) -> i32 { self.mode as i32 } + pub fn mode(&self) -> raw::mode_t { self.mode } } -impl FromInner for FilePermissions { - fn from_inner(mode: i32) -> FilePermissions { +impl FileType { + pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) } + pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) } + pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) } + + fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } +} + +impl FromInner for FilePermissions { + fn from_inner(mode: raw::mode_t) -> FilePermissions { FilePermissions { mode: mode as mode_t } } } @@ -147,6 +178,33 @@ impl DirEntry { self.root.join(::from_bytes(self.name_bytes())) } + pub fn file_name(&self) -> OsString { + OsStr::from_bytes(self.name_bytes()).to_os_string() + } + + pub fn metadata(&self) -> io::Result { + lstat(&self.path()) + } + + pub fn file_type(&self) -> io::Result { + extern { + fn rust_dir_get_mode(ptr: *mut libc::dirent_t) -> c_int; + } + unsafe { + match rust_dir_get_mode(self.dirent()) { + -1 => lstat(&self.path()).map(|m| m.file_type()), + n => Ok(FileType { mode: n as mode_t }), + } + } + } + + pub fn ino(&self) -> raw::ino_t { + extern { + fn rust_dir_get_ino(ptr: *mut libc::dirent_t) -> raw::ino_t; + } + unsafe { rust_dir_get_ino(self.dirent()) } + } + fn name_bytes(&self) -> &[u8] { extern { fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char; @@ -191,7 +249,7 @@ impl OpenOptions { self.flag(libc::O_CREAT, create); } - pub fn mode(&mut self, mode: i32) { + pub fn mode(&mut self, mode: raw::mode_t) { self.mode = mode as mode_t; } @@ -228,8 +286,10 @@ impl File { pub fn into_fd(self) -> FileDesc { self.0 } pub fn file_attr(&self) -> io::Result { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - try!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) })); + let mut stat: raw::stat = unsafe { mem::zeroed() }; + try!(cvt(unsafe { + libc::fstat(self.0.raw(), &mut stat as *mut _ as *mut _) + })); Ok(FileAttr { stat: stat }) } @@ -284,6 +344,22 @@ impl File { pub fn fd(&self) -> &FileDesc { &self.0 } } +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder { mode: 0o777 } + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let p = try!(cstr(p)); + try!(cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })); + Ok(()) + } + + pub fn set_mode(&mut self, mode: mode_t) { + self.mode = mode; + } +} + fn cstr(path: &Path) -> io::Result { path.as_os_str().to_cstring().ok_or( io::Error::new(io::ErrorKind::InvalidInput, "path contained a null")) @@ -343,12 +419,6 @@ impl fmt::Debug for File { } } -pub fn mkdir(p: &Path) -> io::Result<()> { - let p = try!(cstr(p)); - try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) })); - Ok(()) -} - pub fn readdir(p: &Path) -> io::Result { let root = Arc::new(p.to_path_buf()); let p = try!(cstr(p)); @@ -420,15 +490,19 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result { let p = try!(cstr(p)); - let mut stat: libc::stat = unsafe { mem::zeroed() }; - try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) })); + let mut stat: raw::stat = unsafe { mem::zeroed() }; + try!(cvt(unsafe { + libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) + })); Ok(FileAttr { stat: stat }) } pub fn lstat(p: &Path) -> io::Result { let p = try!(cstr(p)); - let mut stat: libc::stat = unsafe { mem::zeroed() }; - try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) })); + let mut stat: raw::stat = unsafe { mem::zeroed() }; + try!(cvt(unsafe { + libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) + })); Ok(FileAttr { stat: stat }) } @@ -438,3 +512,17 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) })); Ok(()) } + +pub fn canonicalize(p: &Path) -> io::Result { + let path = try!(CString::new(p.as_os_str().as_bytes())); + let mut buf = vec![0u8; 16 * 1024]; + unsafe { + let r = c::realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _); + if r.is_null() { + return Err(io::Error::last_os_error()) + } + } + let p = buf.iter().position(|i| *i == 0).unwrap(); + buf.truncate(p); + Ok(PathBuf::from(OsString::from_vec(buf))) +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index d99753a6a4c80..78b798d3bffff 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -18,6 +18,16 @@ use libc; use num::One; use ops::Neg; +#[cfg(target_os = "android")] pub use os::android as platform; +#[cfg(target_os = "bitrig")] pub use os::bitrig as platform; +#[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform; +#[cfg(target_os = "freebsd")] pub use os::freebsd as platform; +#[cfg(target_os = "ios")] pub use os::ios as platform; +#[cfg(target_os = "linux")] pub use os::linux as platform; +#[cfg(target_os = "macos")] pub use os::macos as platform; +#[cfg(target_os = "nacl")] pub use os::nacl as platform; +#[cfg(target_os = "openbsd")] pub use os::openbsd as platform; + pub mod backtrace; pub mod c; pub mod condvar; diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs deleted file mode 100644 index dd747d202a04b..0000000000000 --- a/src/libstd/sys/windows/ext.rs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Experimental extensions to `std` for Windows. -//! -//! For now, this module is limited to extracting handles, file -//! descriptors, and sockets, but its functionality will grow over -//! time. - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod io { - use fs; - use libc; - use net; - use sys_common::{net2, AsInner, FromInner}; - use sys; - - /// Raw HANDLEs. - #[stable(feature = "rust1", since = "1.0.0")] - pub type RawHandle = libc::HANDLE; - - /// Raw SOCKETs. - #[stable(feature = "rust1", since = "1.0.0")] - pub type RawSocket = libc::SOCKET; - - /// Extract raw handles. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait AsRawHandle { - /// Extracts the raw handle, without taking any ownership. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_handle(&self) -> RawHandle; - } - - /// Construct I/O objects from raw handles. - #[unstable(feature = "from_raw_os", - reason = "recent addition to the std::os::windows::io module")] - pub trait FromRawHandle { - /// Constructs a new I/O object from the specified raw handle. - /// - /// This function will **consume ownership** of the handle given, - /// passing responsibility for closing the handle to the returned - /// object. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - unsafe fn from_raw_handle(handle: RawHandle) -> Self; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawHandle for fs::File { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() - } - } - - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawHandle for fs::File { - unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - fs::File::from_inner(sys::fs2::File::from_inner(handle)) - } - } - - /// Extract raw sockets. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait AsRawSocket { - /// Extracts the underlying raw socket from this object. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_socket(&self) -> RawSocket; - } - - /// Create I/O objects from raw sockets. - #[unstable(feature = "from_raw_os", reason = "recent addition to module")] - pub trait FromRawSocket { - /// Creates a new I/O object from the given raw socket. - /// - /// This function will **consume ownership** of the socket provided and - /// it will be closed when the returned object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - unsafe fn from_raw_socket(sock: RawSocket) -> Self; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for net::TcpStream { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for net::TcpListener { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for net::UdpSocket { - fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() - } - } - - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawSocket for net::TcpStream { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(sock); - net::TcpStream::from_inner(net2::TcpStream::from_inner(sock)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawSocket for net::TcpListener { - unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(sock); - net::TcpListener::from_inner(net2::TcpListener::from_inner(sock)) - } - } - #[unstable(feature = "from_raw_os", reason = "trait is unstable")] - impl FromRawSocket for net::UdpSocket { - unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(sock); - net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock)) - } - } -} - -/// Windows-specific extensions to the primitives in the `std::ffi` module. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod ffi { - use ffi::{OsString, OsStr}; - use sys::os_str::Buf; - use sys_common::wtf8::Wtf8Buf; - use sys_common::{FromInner, AsInner}; - - pub use sys_common::wtf8::EncodeWide; - - /// Windows-specific extensions to `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStringExt { - /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of - /// 16-bit code units. - /// - /// This is lossless: calling `.encode_wide()` on the resulting string - /// will always return the original code units. - #[stable(feature = "rust1", since = "1.0.0")] - fn from_wide(wide: &[u16]) -> Self; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl OsStringExt for OsString { - fn from_wide(wide: &[u16]) -> OsString { - FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) }) - } - } - - /// Windows-specific extensions to `OsStr`. - #[stable(feature = "rust1", since = "1.0.0")] - pub trait OsStrExt { - /// Re-encodes an `OsStr` as a wide character sequence, - /// i.e. potentially ill-formed UTF-16. - /// - /// This is lossless. Note that the encoding does not include a final - /// null. - #[stable(feature = "rust1", since = "1.0.0")] - fn encode_wide(&self) -> EncodeWide; - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl OsStrExt for OsStr { - fn encode_wide(&self) -> EncodeWide { - self.as_inner().inner.encode_wide() - } - } -} - -/// Windows-specific extensions for the primitives in `std::fs` -#[unstable(feature = "fs_ext", reason = "may require more thought/methods")] -pub mod fs { - use fs::OpenOptions; - use sys; - use sys_common::AsInnerMut; - use path::Path; - use convert::AsRef; - use io; - - /// Windows-specific extensions to `OpenOptions` - pub trait OpenOptionsExt { - /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` - /// with the specified value. - fn desired_access(&mut self, access: i32) -> &mut Self; - - /// Overrides the `dwCreationDisposition` argument to the call to - /// `CreateFile` with the specified value. - /// - /// This will override any values of the standard `create` flags, for - /// example. - fn creation_disposition(&mut self, val: i32) -> &mut Self; - - /// Overrides the `dwFlagsAndAttributes` argument to the call to - /// `CreateFile` with the specified value. - /// - /// This will override any values of the standard flags on the - /// `OpenOptions` structure. - fn flags_and_attributes(&mut self, val: i32) -> &mut Self; - - /// Overrides the `dwShareMode` argument to the call to `CreateFile` with - /// the specified value. - /// - /// This will override any values of the standard flags on the - /// `OpenOptions` structure. - fn share_mode(&mut self, val: i32) -> &mut Self; - } - - impl OpenOptionsExt for OpenOptions { - fn desired_access(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().desired_access(access); self - } - fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().creation_disposition(access); self - } - fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().flags_and_attributes(access); self - } - fn share_mode(&mut self, access: i32) -> &mut OpenOptions { - self.as_inner_mut().share_mode(access); self - } - } - - /// Creates a new file symbolic link on the filesystem. - /// - /// The `dst` path will be a file symbolic link pointing to the `src` - /// path. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(fs_ext)] - /// use std::os::windows::fs; - /// - /// # fn foo() -> std::io::Result<()> { - /// try!(fs::symlink_file("a.txt", "b.txt")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symlink_file, Q: AsRef>(src: P, dst: Q) - -> io::Result<()> - { - sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false) - } - - /// Creates a new directory symlink on the filesystem. - /// - /// The `dst` path will be a directory symbolic link pointing to the `src` - /// path. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(fs_ext)] - /// use std::os::windows::fs; - /// - /// # fn foo() -> std::io::Result<()> { - /// try!(fs::symlink_file("a", "b")); - /// # Ok(()) - /// # } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symlink_dir, Q: AsRef> (src: P, dst: Q) - -> io::Result<()> - { - sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true) - } -} - -/// A prelude for conveniently writing platform-specific code. -/// -/// Includes all extension traits, and some important type definitions. -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] - pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle}; - #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] - pub use super::fs::OpenOptionsExt; -} diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs new file mode 100644 index 0000000000000..3fa96f4dd13e9 --- /dev/null +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -0,0 +1,58 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Windows-specific extensions to the primitives in the `std::ffi` module. + +#![stable(feature = "rust1", since = "1.0.0")] + +use ffi::{OsString, OsStr}; +use sys::os_str::Buf; +use sys_common::wtf8::Wtf8Buf; +use sys_common::{FromInner, AsInner}; + +pub use sys_common::wtf8::EncodeWide; + +/// Windows-specific extensions to `OsString`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt { + /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of + /// 16-bit code units. + /// + /// This is lossless: calling `.encode_wide()` on the resulting string + /// will always return the original code units. + #[stable(feature = "rust1", since = "1.0.0")] + fn from_wide(wide: &[u16]) -> Self; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + fn from_wide(wide: &[u16]) -> OsString { + FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) }) + } +} + +/// Windows-specific extensions to `OsStr`. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt { + /// Re-encodes an `OsStr` as a wide character sequence, + /// i.e. potentially ill-formed UTF-16. + /// + /// This is lossless. Note that the encoding does not include a final + /// null. + #[stable(feature = "rust1", since = "1.0.0")] + fn encode_wide(&self) -> EncodeWide; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + fn encode_wide(&self) -> EncodeWide { + self.as_inner().inner.encode_wide() + } +} diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs new file mode 100644 index 0000000000000..23c1fcf4b3c6e --- /dev/null +++ b/src/libstd/sys/windows/ext/fs.rs @@ -0,0 +1,150 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Windows-specific extensions for the primitives in `std::fs` + +#![stable(feature = "rust1", since = "1.0.0")] + +use prelude::v1::*; + +use fs::{OpenOptions, Metadata}; +use io; +use path::Path; +use sys; +use sys_common::{AsInnerMut, AsInner}; + +/// Windows-specific extensions to `OpenOptions` +#[unstable(feature = "fs_ext", reason = "may require more thought/methods")] +pub trait OpenOptionsExt { + /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` + /// with the specified value. + fn desired_access(&mut self, access: i32) -> &mut Self; + + /// Overrides the `dwCreationDisposition` argument to the call to + /// `CreateFile` with the specified value. + /// + /// This will override any values of the standard `create` flags, for + /// example. + fn creation_disposition(&mut self, val: i32) -> &mut Self; + + /// Overrides the `dwFlagsAndAttributes` argument to the call to + /// `CreateFile` with the specified value. + /// + /// This will override any values of the standard flags on the + /// `OpenOptions` structure. + fn flags_and_attributes(&mut self, val: i32) -> &mut Self; + + /// Overrides the `dwShareMode` argument to the call to `CreateFile` with + /// the specified value. + /// + /// This will override any values of the standard flags on the + /// `OpenOptions` structure. + fn share_mode(&mut self, val: i32) -> &mut Self; +} + +impl OpenOptionsExt for OpenOptions { + fn desired_access(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().desired_access(access); self + } + fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().creation_disposition(access); self + } + fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().flags_and_attributes(access); self + } + fn share_mode(&mut self, access: i32) -> &mut OpenOptions { + self.as_inner_mut().share_mode(access); self + } +} + +/// Extension methods for `fs::Metadata` to access the raw fields contained +/// within. +#[unstable(feature = "metadata_ext", reason = "recently added API")] +pub trait MetadataExt { + /// Returns the value of the `dwFileAttributes` field of this metadata. + /// + /// This field contains the file system attribute information for a file + /// or directory. + fn file_attributes(&self) -> u32; + + /// Returns the value of the `ftCreationTime` field of this metadata. + /// + /// The returned 64-bit value represents the number of 100-nanosecond + /// intervals since January 1, 1601 (UTC). + fn creation_time(&self) -> u64; + + /// Returns the value of the `ftLastAccessTime` field of this metadata. + /// + /// The returned 64-bit value represents the number of 100-nanosecond + /// intervals since January 1, 1601 (UTC). + fn last_access_time(&self) -> u64; + + /// Returns the value of the `ftLastWriteTime` field of this metadata. + /// + /// The returned 64-bit value represents the number of 100-nanosecond + /// intervals since January 1, 1601 (UTC). + fn last_write_time(&self) -> u64; + + /// Returns the value of the `nFileSize{High,Low}` fields of this + /// metadata. + /// + /// The returned value does not have meaning for directories. + fn file_size(&self) -> u64; +} + +impl MetadataExt for Metadata { + fn file_attributes(&self) -> u32 { self.as_inner().attrs() } + fn creation_time(&self) -> u64 { self.as_inner().created() } + fn last_access_time(&self) -> u64 { self.as_inner().accessed() } + fn last_write_time(&self) -> u64 { self.as_inner().modified() } + fn file_size(&self) -> u64 { self.as_inner().size() } +} + +/// Creates a new file symbolic link on the filesystem. +/// +/// The `dst` path will be a file symbolic link pointing to the `src` +/// path. +/// +/// # Examples +/// +/// ```ignore +/// use std::os::windows::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::symlink_file("a.txt", "b.txt")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn symlink_file, Q: AsRef>(src: P, dst: Q) + -> io::Result<()> { + sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false) +} + +/// Creates a new directory symlink on the filesystem. +/// +/// The `dst` path will be a directory symbolic link pointing to the `src` +/// path. +/// +/// # Examples +/// +/// ```ignore +/// use std::os::windows::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::symlink_file("a", "b")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn symlink_dir, Q: AsRef>(src: P, dst: Q) + -> io::Result<()> { + sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true) +} diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs new file mode 100644 index 0000000000000..b88a6316eee8b --- /dev/null +++ b/src/libstd/sys/windows/ext/io.rs @@ -0,0 +1,131 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "rust1", since = "1.0.0")] + +use fs; +use os::windows::raw; +use net; +use sys_common::{net2, AsInner, FromInner}; +use sys; + +/// Raw HANDLEs. +#[stable(feature = "rust1", since = "1.0.0")] +pub type RawHandle = raw::HANDLE; + +/// Raw SOCKETs. +#[stable(feature = "rust1", since = "1.0.0")] +pub type RawSocket = raw::SOCKET; + +/// Extract raw handles. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawHandle { + /// Extracts the raw handle, without taking any ownership. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_handle(&self) -> RawHandle; +} + +/// Construct I/O objects from raw handles. +#[unstable(feature = "from_raw_os", + reason = "recent addition to the std::os::windows::io module")] +pub trait FromRawHandle { + /// Constructs a new I/O object from the specified raw handle. + /// + /// This function will **consume ownership** of the handle given, + /// passing responsibility for closing the handle to the returned + /// object. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_handle(handle: RawHandle) -> Self; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawHandle for fs::File { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle().raw() as RawHandle + } +} + +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawHandle for fs::File { + unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { + let handle = handle as ::libc::HANDLE; + fs::File::from_inner(sys::fs2::File::from_inner(handle)) + } +} + +/// Extract raw sockets. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawSocket { + /// Extracts the underlying raw socket from this object. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_socket(&self) -> RawSocket; +} + +/// Create I/O objects from raw sockets. +#[unstable(feature = "from_raw_os", reason = "recent addition to module")] +pub trait FromRawSocket { + /// Creates a new I/O object from the given raw socket. + /// + /// This function will **consume ownership** of the socket provided and + /// it will be closed when the returned object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_socket(sock: RawSocket) -> Self; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::TcpStream { + fn as_raw_socket(&self) -> RawSocket { + *self.as_inner().socket().as_inner() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::TcpListener { + fn as_raw_socket(&self) -> RawSocket { + *self.as_inner().socket().as_inner() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::UdpSocket { + fn as_raw_socket(&self) -> RawSocket { + *self.as_inner().socket().as_inner() + } +} + +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawSocket for net::TcpStream { + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { + let sock = sys::net::Socket::from_inner(sock); + net::TcpStream::from_inner(net2::TcpStream::from_inner(sock)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawSocket for net::TcpListener { + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { + let sock = sys::net::Socket::from_inner(sock); + net::TcpListener::from_inner(net2::TcpListener::from_inner(sock)) + } +} +#[unstable(feature = "from_raw_os", reason = "trait is unstable")] +impl FromRawSocket for net::UdpSocket { + unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { + let sock = sys::net::Socket::from_inner(sock); + net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock)) + } +} diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs new file mode 100644 index 0000000000000..08dfa4cc87753 --- /dev/null +++ b/src/libstd/sys/windows/ext/mod.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Experimental extensions to `std` for Windows. +//! +//! For now, this module is limited to extracting handles, file +//! descriptors, and sockets, but its functionality will grow over +//! time. + +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod ffi; +pub mod fs; +pub mod io; +pub mod raw; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] + pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + pub use super::fs::{OpenOptionsExt, MetadataExt}; +} diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs new file mode 100644 index 0000000000000..656e480ad0963 --- /dev/null +++ b/src/libstd/sys/windows/ext/raw.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Windows-specific primitives + +#![unstable(feature = "raw_ext", reason = "recently added API")] + +use os::raw; + +pub type HANDLE = *mut raw::c_void; +#[cfg(target_pointer_width = "32")] +pub type SOCKET = u32; +#[cfg(target_pointer_width = "64")] +pub type SOCKET = u64; diff --git a/src/libstd/sys/windows/fs2.rs b/src/libstd/sys/windows/fs2.rs index 5ac9a0ace5801..5b748280986f7 100644 --- a/src/libstd/sys/windows/fs2.rs +++ b/src/libstd/sys/windows/fs2.rs @@ -27,7 +27,16 @@ use sys_common::FromInner; use vec::Vec; pub struct File { handle: Handle } -pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA } + +pub struct FileAttr { + data: c::WIN32_FILE_ATTRIBUTE_DATA, + is_symlink: bool, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum FileType { + Dir, File, Symlink, ReparsePoint +} pub struct ReadDir { handle: FindNextFileHandle, @@ -61,6 +70,8 @@ pub struct OpenOptions { #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { attrs: libc::DWORD } +pub struct DirBuilder; + impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { @@ -111,8 +122,31 @@ impl DirEntry { } pub fn path(&self) -> PathBuf { + self.root.join(&self.file_name()) + } + + pub fn file_name(&self) -> OsString { let filename = super::truncate_utf16_at_nul(&self.data.cFileName); - self.root.join(&::from_wide(filename)) + OsString::from_wide(filename) + } + + pub fn file_type(&self) -> io::Result { + Ok(FileType::new(self.data.dwFileAttributes, + self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK)) + } + + pub fn metadata(&self) -> io::Result { + Ok(FileAttr { + data: c::WIN32_FILE_ATTRIBUTE_DATA { + dwFileAttributes: self.data.dwFileAttributes, + ftCreationTime: self.data.ftCreationTime, + ftLastAccessTime: self.data.ftLastAccessTime, + ftLastWriteTime: self.data.ftLastWriteTime, + nFileSizeHigh: self.data.nFileSizeHigh, + nFileSizeLow: self.data.nFileSizeLow, + }, + is_symlink: self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK, + }) } } @@ -180,6 +214,13 @@ impl OpenOptions { } impl File { + fn open_reparse_point(path: &Path) -> io::Result { + let mut opts = OpenOptions::new(); + opts.read(true); + opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32); + File::open(path, &opts) + } + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = to_utf16(path); let handle = unsafe { @@ -224,7 +265,7 @@ impl File { let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed(); try!(cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))); - Ok(FileAttr { + let mut attr = FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA { dwFileAttributes: info.dwFileAttributes, ftCreationTime: info.ftCreationTime, @@ -232,8 +273,13 @@ impl File { ftLastWriteTime: info.ftLastWriteTime, nFileSizeHigh: info.nFileSizeHigh, nFileSizeLow: info.nFileSizeLow, - } - }) + }, + is_symlink: false, + }; + if attr.is_reparse_point() { + attr.is_symlink = self.is_symlink(); + } + Ok(attr) } } @@ -263,6 +309,41 @@ impl File { } pub fn handle(&self) -> &Handle { &self.handle } + + fn is_symlink(&self) -> bool { + self.readlink().is_ok() + } + + fn readlink(&self) -> io::Result { + let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut bytes = 0; + + unsafe { + try!(cvt({ + c::DeviceIoControl(self.handle.raw(), + c::FSCTL_GET_REPARSE_POINT, + 0 as *mut _, + 0, + space.as_mut_ptr() as *mut _, + space.len() as libc::DWORD, + &mut bytes, + 0 as *mut _) + })); + let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _; + if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK { + return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) + } + let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = + &(*buf).rest as *const _ as *const _; + let path_buffer = &(*info).PathBuffer as *const _ as *const u16; + let subst_off = (*info).SubstituteNameOffset / 2; + let subst_ptr = path_buffer.offset(subst_off as isize); + let subst_len = (*info).SubstituteNameLength / 2; + let subst = slice::from_raw_parts(subst_ptr, subst_len as usize); + + Ok(PathBuf::from(OsString::from_wide(subst))) + } + } } impl FromInner for File { @@ -285,27 +366,30 @@ pub fn to_utf16(s: &Path) -> Vec { } impl FileAttr { - pub fn is_dir(&self) -> bool { - self.data.dwFileAttributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 - } - pub fn is_file(&self) -> bool { - !self.is_dir() - } pub fn size(&self) -> u64 { ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64) } + pub fn perm(&self) -> FilePermissions { FilePermissions { attrs: self.data.dwFileAttributes } } - pub fn accessed(&self) -> u64 { self.to_ms(&self.data.ftLastAccessTime) } - pub fn modified(&self) -> u64 { self.to_ms(&self.data.ftLastWriteTime) } + pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 } + + pub fn file_type(&self) -> FileType { + FileType::new(self.data.dwFileAttributes, self.is_symlink) + } + + pub fn created(&self) -> u64 { self.to_u64(&self.data.ftCreationTime) } + pub fn accessed(&self) -> u64 { self.to_u64(&self.data.ftLastAccessTime) } + pub fn modified(&self) -> u64 { self.to_u64(&self.data.ftLastWriteTime) } - fn to_ms(&self, ft: &libc::FILETIME) -> u64 { - // FILETIME is in 100ns intervals and there are 10000 intervals in a - // millisecond. - let bits = (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32); - bits / 10000 + fn to_u64(&self, ft: &libc::FILETIME) -> u64 { + (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32) + } + + fn is_reparse_point(&self) -> bool { + self.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 } } @@ -323,12 +407,36 @@ impl FilePermissions { } } -pub fn mkdir(p: &Path) -> io::Result<()> { - let p = to_utf16(p); - try!(cvt(unsafe { - libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) - })); - Ok(()) +impl FileType { + fn new(attrs: libc::DWORD, is_symlink: bool) -> FileType { + if attrs & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + if is_symlink { + FileType::Symlink + } else { + FileType::ReparsePoint + } + } else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 { + FileType::Dir + } else { + FileType::File + } + } + + pub fn is_dir(&self) -> bool { *self == FileType::Dir } + pub fn is_file(&self) -> bool { *self == FileType::File } + pub fn is_symlink(&self) -> bool { *self == FileType::Symlink } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { DirBuilder } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let p = to_utf16(p); + try!(cvt(unsafe { + libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) + })); + Ok(()) + } } pub fn readdir(p: &Path) -> io::Result { @@ -374,40 +482,8 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - opts.read(true); - opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32); - let file = try!(File::open(p, &opts)); - - let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let mut bytes = 0; - - unsafe { - try!(cvt({ - c::DeviceIoControl(file.handle.raw(), - c::FSCTL_GET_REPARSE_POINT, - 0 as *mut _, - 0, - space.as_mut_ptr() as *mut _, - space.len() as libc::DWORD, - &mut bytes, - 0 as *mut _) - })); - let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _; - if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK { - return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) - } - let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = - &(*buf).rest as *const _ as *const _; - let path_buffer = &(*info).PathBuffer as *const _ as *const u16; - let subst_off = (*info).SubstituteNameOffset / 2; - let subst_ptr = path_buffer.offset(subst_off as isize); - let subst_len = (*info).SubstituteNameLength / 2; - let subst = slice::from_raw_parts(subst_ptr, subst_len as usize); - - Ok(PathBuf::from(OsString::from_wide(subst))) - } - + let file = try!(File::open_reparse_point(p)); + file.readlink() } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { @@ -435,12 +511,28 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result { - let p = to_utf16(p); + let attr = try!(lstat(p)); + if attr.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + let opts = OpenOptions::new(); + let file = try!(File::open(p, &opts)); + file.file_attr() + } else { + Ok(attr) + } +} + +pub fn lstat(p: &Path) -> io::Result { + let utf16 = to_utf16(p); unsafe { let mut attr: FileAttr = mem::zeroed(); - try!(cvt(c::GetFileAttributesExW(p.as_ptr(), + try!(cvt(c::GetFileAttributesExW(utf16.as_ptr(), c::GetFileExInfoStandard, &mut attr.data as *mut _ as *mut _))); + if attr.is_reparse_point() { + attr.is_symlink = File::open_reparse_point(p).map(|f| { + f.is_symlink() + }).unwrap_or(false); + } Ok(attr) } } @@ -465,3 +557,17 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { })); Ok(()) } + +pub fn canonicalize(p: &Path) -> io::Result { + use sys::c::compat::kernel32::GetFinalPathNameByHandleW; + + let mut opts = OpenOptions::new(); + opts.read(true); + let f = try!(File::open(p, &opts)); + super::fill_utf16_buf(|buf, sz| unsafe { + GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, + libc::VOLUME_NAME_DOS) + }, |buf| { + PathBuf::from(OsString::from_wide(buf)) + }) +} diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c index db1a602b404f6..362439c146912 100644 --- a/src/rt/rust_builtin.c +++ b/src/rt/rust_builtin.c @@ -15,12 +15,13 @@ #include #if !defined(__WIN32__) -#include -#include #include +#include #include +#include +#include +#include #include -#include #else #include #include @@ -41,44 +42,31 @@ //include valgrind.h after stdint.h so that uintptr_t is defined for msys2 w64 #include "valgrind/valgrind.h" -#ifdef __APPLE__ -#if (TARGET_OS_IPHONE) -extern char **environ; -#endif -#endif - -#if defined(__FreeBSD__) || defined(__linux__) || defined(__ANDROID__) || \ - defined(__DragonFly__) || defined(__Bitrig__) || defined(__OpenBSD__) -extern char **environ; -#endif - -#if defined(__WIN32__) -char** -rust_env_pairs() { - return 0; -} -#else -char** -rust_env_pairs() { -#if defined(__APPLE__) && !(TARGET_OS_IPHONE) - char **environ = *_NSGetEnviron(); -#endif - return environ; -} -#endif - +#ifndef _WIN32 char* -#if defined(__WIN32__) -rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) { - return entry_ptr->cFileName; -} -#else rust_list_dir_val(struct dirent* entry_ptr) { return entry_ptr->d_name; } + +int +rust_dir_get_mode(struct dirent* entry_ptr) { +#if defined(_DIRENT_HAVE_D_TYPE) + switch (entry_ptr->d_type) { + case DT_BLK: return S_IFBLK; + case DT_CHR: return S_IFCHR; + case DT_FIFO: return S_IFIFO; + case DT_LNK: return S_IFLNK; + case DT_REG: return S_IFREG; + case DT_SOCK: return S_IFSOCK; + } #endif + return -1; +} -#ifndef _WIN32 +ino_t +rust_dir_get_ino(struct dirent* entry_ptr) { + return entry_ptr->d_ino; +} DIR* rust_opendir(char *dirname) { @@ -94,21 +82,6 @@ int rust_dirent_t_size() { return sizeof(struct dirent); } - -#else - -void -rust_opendir() { -} - -void -rust_readdir() { -} - -void -rust_dirent_t_size() { -} - #endif uintptr_t @@ -173,26 +146,6 @@ rust_valgrind_stack_deregister(unsigned int id) { VALGRIND_STACK_DEREGISTER(id); } -#if defined(__WIN32__) - -void -rust_unset_sigprocmask() { - // empty stub for windows to keep linker happy -} - -#else - -void -rust_unset_sigprocmask() { - // this can't be safely converted to rust code because the - // representation of sigset_t is platform-dependent - sigset_t sset; - sigemptyset(&sset); - sigprocmask(SIG_SETMASK, &sset, NULL); -} - -#endif - #if defined(__DragonFly__) #include // In DragonFly __error() is an inline function and as such