]> git.lizzy.rs Git - rust.git/commitdiff
std: Expand the area of std::fs
authorAlex Crichton <alex@alexcrichton.com>
Thu, 16 Apr 2015 06:21:13 +0000 (23:21 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 28 Apr 2015 00:16:44 +0000 (17:16 -0700)
This commit is an implementation of [RFC 1044][rfc] which adds additional
surface area to the `std::fs` module. All new APIs are `#[unstable]` behind
assorted feature names for each one.

[rfc]: https://github.com/rust-lang/rfcs/pull/1044

The new APIs added are:

* `fs::canonicalize` - bindings to `realpath` on unix and
  `GetFinalPathNameByHandle` on windows.
* `fs::symlink_metadata` - similar to `lstat` on unix
* `fs::FileType` and accessor methods as `is_{file,dir,symlink}`
* `fs::Metadata::file_type` - accessor for the raw file type
* `fs::DirEntry::metadata` - acquisition of metadata which is free on Windows
  but requires a syscall on unix.
* `fs::DirEntry::file_type` - access the file type which may not require a
  syscall on most platforms.
* `fs::DirEntry::file_name` - access just the file name without leading
  components.
* `fs::PathExt::symlink_metadata` - convenience method for the top-level
  function.
* `fs::PathExt::canonicalize` - convenience method for the top-level
  function.
* `fs::PathExt::read_link` - convenience method for the top-level
  function.
* `fs::PathExt::read_dir` - convenience method for the top-level
  function.
* `std::os::raw` - type definitions for raw OS/C types available on all
  platforms.
* `std::os::$platform` - new modules have been added for all currently supported
  platforms (e.g. those more specific than just `unix`).
* `std::os::$platform::raw` - platform-specific type definitions. These modules
  are populated with the bare essentials necessary for lowing I/O types into
  their raw representations, and currently largely consist of the `stat`
  definition for unix platforms.

This commit also deprecates `Metadata::{modified, accessed}` in favor of
inspecting the raw representations via the lowering methods of `Metadata`.

48 files changed:
src/librustc/lib.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/filesearch.rs
src/librustc/metadata/loader.rs
src/librustc_back/fs.rs [deleted file]
src/librustc_back/lib.rs
src/librustc_back/rpath.rs
src/librustc_trans/back/link.rs
src/libstd/fs.rs
src/libstd/os.rs [deleted file]
src/libstd/os/android/mod.rs [new file with mode: 0644]
src/libstd/os/android/raw.rs [new file with mode: 0644]
src/libstd/os/bitrig/mod.rs [new file with mode: 0644]
src/libstd/os/bitrig/raw.rs [new file with mode: 0644]
src/libstd/os/dragonfly/mod.rs [new file with mode: 0644]
src/libstd/os/dragonfly/raw.rs [new file with mode: 0644]
src/libstd/os/freebsd/mod.rs [new file with mode: 0644]
src/libstd/os/freebsd/raw.rs [new file with mode: 0644]
src/libstd/os/ios/mod.rs [new file with mode: 0644]
src/libstd/os/ios/raw.rs [new file with mode: 0644]
src/libstd/os/linux/mod.rs [new file with mode: 0644]
src/libstd/os/linux/raw.rs [new file with mode: 0644]
src/libstd/os/macos/mod.rs [new file with mode: 0644]
src/libstd/os/macos/raw.rs [new file with mode: 0644]
src/libstd/os/mod.rs [new file with mode: 0644]
src/libstd/os/nacl/mod.rs [new file with mode: 0644]
src/libstd/os/nacl/raw.rs [new file with mode: 0644]
src/libstd/os/openbsd/mod.rs [new file with mode: 0644]
src/libstd/os/openbsd/raw.rs [new file with mode: 0644]
src/libstd/os/raw.rs [new file with mode: 0644]
src/libstd/sys/unix/c.rs
src/libstd/sys/unix/ext.rs [deleted file]
src/libstd/sys/unix/ext/ffi.rs [new file with mode: 0644]
src/libstd/sys/unix/ext/fs.rs [new file with mode: 0644]
src/libstd/sys/unix/ext/io.rs [new file with mode: 0644]
src/libstd/sys/unix/ext/mod.rs [new file with mode: 0644]
src/libstd/sys/unix/ext/process.rs [new file with mode: 0644]
src/libstd/sys/unix/ext/raw.rs [new file with mode: 0644]
src/libstd/sys/unix/fs2.rs
src/libstd/sys/unix/mod.rs
src/libstd/sys/windows/ext.rs [deleted file]
src/libstd/sys/windows/ext/ffi.rs [new file with mode: 0644]
src/libstd/sys/windows/ext/fs.rs [new file with mode: 0644]
src/libstd/sys/windows/ext/io.rs [new file with mode: 0644]
src/libstd/sys/windows/ext/mod.rs [new file with mode: 0644]
src/libstd/sys/windows/ext/raw.rs [new file with mode: 0644]
src/libstd/sys/windows/fs2.rs
src/rt/rust_builtin.c

index d4012f2057b5dac8306e189e3401d6bc9b6a981c..6e8f515c7c2117474b27030295154f625aedfa29 100644 (file)
@@ -40,6 +40,7 @@
 #![feature(path_ext)]
 #![feature(str_char)]
 #![feature(into_cow)]
+#![feature(fs_canonicalize)]
 #![feature(slice_patterns)]
 #![cfg_attr(test, feature(test))]
 
@@ -139,7 +140,6 @@ pub mod middle {
 pub mod lint;
 
 pub mod util {
-    pub use rustc_back::fs;
     pub use rustc_back::sha2;
 
     pub mod common;
index 802c5815398f2c4398c25b24dd50d8594c491177..099a280c4b146b31fb05d41ba48871f7ef6ea946 100644 (file)
 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::token::InternedString;
 use syntax::parse::token;
 use syntax::visit;
-use util::fs;
 use log;
 
 pub struct CrateReader<'a> {
@@ -322,7 +323,7 @@ fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
             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()
                 });
index 1567f4b99475cb1fe345e0f1983f487cb695e12b..7d8cf5b22a9016c6b9dec3ff8a61b147a6ee6ca5 100644 (file)
@@ -18,7 +18,6 @@
 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<PathBuf>) -> Option<PathBuf> {
         path.and_then(|path| {
-            match myfs::realpath(&path) {
+            match fs::canonicalize(&path) {
                 Ok(canon) => Some(canon),
                 Err(e) => panic!("failed to get realpath: {}", e),
             }
index bbb2452ca29ee84d7334c1962b52e224859b849e..062a156637a358d1af5b286c08aad6791f02281f 100644 (file)
 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 @@ fn find_library_crate(&mut self) -> Option<Library> {
                                  .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 @@ fn find_commandline_library(&mut self, locs: &[String]) -> Option<Library> {
             // 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 (file)
index 37e3efb..0000000
+++ /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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::io;
-use std::path::{Path, PathBuf};
-
-#[cfg(windows)]
-pub fn realpath(original: &Path) -> io::Result<PathBuf> {
-    Ok(original.to_path_buf())
-}
-
-#[cfg(unix)]
-pub fn realpath(original: &Path) -> io::Result<PathBuf> {
-    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);
-    }
-}
index 22dea4757ed662a8942c198ab7ac0e7b5a38b655..3e55f7f8045b59b60ee38723f34655e43f987924 100644 (file)
@@ -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 archive;
 pub mod tempdir;
 pub mod arm;
-pub mod fs;
 pub mod mips;
 pub mod mipsel;
 pub mod rpath;
index 1daeb1cb223e279670efd5d089a07ef87b19a1a3..6674d3135a0bdb671dbd621a1979dd97df196fca 100644 (file)
@@ -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<PathBuf>,
 }
 
 pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec<String> {
@@ -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 @@ fn test_rpath_relative() {
                 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 @@ fn test_rpath_relative() {
                 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"));
index b53be98a06cc30198f16c20db0234319c5fde7af..bc26495b76be492f9ce2a52e23824e7a7ea7700e 100644 (file)
@@ -32,7 +32,7 @@
 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;
@@ -916,8 +916,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");
     }
 
@@ -1043,7 +1044,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));
     }
@@ -1258,7 +1258,7 @@ fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
                 }
             });
         } else {
-            cmd.arg(cratepath);
+            cmd.arg(&fix_windows_verbatim_for_gcc(cratepath));
         }
     }
 
@@ -1271,7 +1271,7 @@ fn add_dynamic_crate(cmd: &mut Command, sess: &Session, cratepath: &Path) {
         // 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)));
@@ -1325,3 +1325,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)
+}
index b5dfbf796d3bce212ab4c1053710a8334f27a32a..b47c0c696bffa08f83d3ea50f3081d41474ce396 100644 (file)
@@ -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,11 @@ pub struct WalkDir {
 #[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);
+
 impl File {
     /// Attempts to open a file in read-only mode.
     ///
@@ -485,6 +491,12 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
 }
 
 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 +512,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 +529,7 @@ pub fn is_dir(&self) -> bool { self.0.is_dir() }
     /// # }
     /// ```
     #[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 +574,11 @@ pub fn permissions(&self) -> Permissions {
                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 +587,21 @@ pub fn accessed(&self) -> u64 { self.0.accessed() }
                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<fs_imp::FileAttr> for Metadata {
+    fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 }
 }
 
 impl Permissions {
@@ -624,6 +654,18 @@ pub fn set_readonly(&mut self, readonly: bool) {
     }
 }
 
+#[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<fs_imp::FilePermissions> for Permissions {
     fn from_inner(f: fs_imp::FilePermissions) -> Permissions {
         Permissions(f)
@@ -674,6 +716,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<Metadata> {
+        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<FileType> {
+        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<fs_imp::DirEntry> for DirEntry {
+    fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 }
 }
 
 /// Removes a file from the underlying filesystem.
@@ -731,6 +814,25 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
     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<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
+    fs_imp::lstat(path.as_ref()).map(Metadata)
+}
+
 /// Rename a file or directory to a new name.
 ///
 /// # Errors
@@ -869,6 +971,13 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
     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<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    fs_imp::canonicalize(path.as_ref())
+}
+
 /// Creates a new, empty directory at the provided path
 ///
 /// # Errors
@@ -966,19 +1075,14 @@ pub fn remove_dir_all<P: AsRef<Path>>(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::FileAttr> { fs_imp::lstat(path) }
-    #[cfg(windows)]
-    fn lstat(path: &Path) -> io::Result<fs_imp::FileAttr> { fs_imp::stat(path) }
+    remove_dir(path)
 }
 
 /// Returns an iterator over the entries within a directory.
@@ -1073,11 +1177,37 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
 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<Metadata>;
 
+    /// 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<Metadata>;
+
+    /// 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<PathBuf>;
+
+    /// Reads the symlink at this path.
+    ///
+    /// For more information see `fs::read_link`.
+    fn read_link(&self) -> io::Result<PathBuf>;
+
+    /// Reads the directory at this path.
+    ///
+    /// For more information see `fs::read_dir`.
+    fn read_dir(&self) -> io::Result<ReadDir>;
+
     /// 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 +1228,16 @@ pub trait PathExt {
 
 impl PathExt for Path {
     fn metadata(&self) -> io::Result<Metadata> { metadata(self) }
-
+    fn symlink_metadata(&self) -> io::Result<Metadata> { symlink_metadata(self) }
+    fn canonicalize(&self) -> io::Result<PathBuf> { canonicalize(self) }
+    fn read_link(&self) -> io::Result<PathBuf> { read_link(self) }
+    fn read_dir(&self) -> io::Result<ReadDir> { 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)
     }
@@ -1924,4 +2058,74 @@ fn mkdir_trailing_slash() {
         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.rs
deleted file mode 100644 (file)
index ee0f04c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! OS-specific functionality
-
-#![stable(feature = "os", since = "1.0.0")]
-
-#[cfg(unix)] pub use sys::ext as unix;
-#[cfg(windows)] pub use sys::ext as windows;
diff --git a/src/libstd/os/android/mod.rs b/src/libstd/os/android/mod.rs
new file mode 100644 (file)
index 0000000..346a903
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Android-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/android/raw.rs b/src/libstd/os/android/raw.rs
new file mode 100644 (file)
index 0000000..538ed7c
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Android-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 (file)
index 0000000..01ea542
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..aebc21a
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..677f8b7
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..22c811e
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..73b6fd2
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..a810eff
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..d471cf1
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..3266b38
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..43376a1
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Linux-specific definitions
+
+#![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 (file)
index 0000000..adce5f2
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Linux-specific raw type definitions
+
+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 (file)
index 0000000..bc5ff5b
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..03fcb76
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..cc4b1c9
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..6baed03
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..9defa83
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..1b1a100
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..632a8c3
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 0000000..44f4a1c
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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::<libc::$t>() == TypeId::of::<raw::$t>(),
+                    "{} is wrong", stringify!($t));
+        )*}
+    }
+
+    macro_rules! ok_size {
+        ($($t:ident)*) => {$(
+            assert!(mem::size_of::<libc::$t>() == mem::size_of::<raw::$t>(),
+                    "{} 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;
+    }
+}
index aa4bf821207648a3c4fe7cab02c37115bc2bae81..1e68eac5a67354b880b5a7e678a7ae8e67fda3ea 100644 (file)
@@ -161,6 +161,8 @@ pub fn utimes(filename: *const libc::c_char,
     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 (file)
index 66aaf26..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Experimental extensions to `std` for Unix platforms.
-//!
-//! For now, this module is limited to extracting file descriptors,
-//! but its functionality will grow over time.
-//!
-//! # Example
-//!
-//! ```no_run
-//! use std::fs::File;
-//! use std::os::unix::prelude::*;
-//!
-//! fn main() {
-//!     let f = File::create("foo.txt").unwrap();
-//!     let fd = f.as_raw_fd();
-//!
-//!     // use fd with native unix bindings
-//! }
-//! ```
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-/// Unix-specific extensions to general I/O primitives
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod io {
-    use fs;
-    use libc;
-    use net;
-    use sys_common::{net2, AsInner, FromInner};
-    use sys;
-
-    /// Raw file descriptors.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub type RawFd = libc::c_int;
-
-    /// A trait to extract the raw unix file descriptor from an underlying
-    /// object.
-    ///
-    /// This is only available on unix platforms and must be imported in order
-    /// to call the method. Windows platforms have a corresponding `AsRawHandle`
-    /// and `AsRawSocket` set of traits.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait AsRawFd {
-        /// Extracts the raw file descriptor.
-        ///
-        /// This method does **not** pass ownership of the raw file descriptor
-        /// to the caller. The descriptor is only guarantee to be valid while
-        /// the original object has not yet been destroyed.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_raw_fd(&self) -> RawFd;
-    }
-
-    /// A trait to express the ability to construct an object from a raw file
-    /// descriptor.
-    #[unstable(feature = "from_raw_os",
-               reason = "recent addition to std::os::unix::io")]
-    pub trait FromRawFd {
-        /// Constructs a new instances of `Self` from the given raw file
-        /// descriptor.
-        ///
-        /// This function **consumes ownership** of the specified file
-        /// descriptor. The returned object will take responsibility for closing
-        /// it when the object goes out of scope.
-        ///
-        /// This function is also unsafe as the primitives currently returned
-        /// have the contract that they are the sole owner of the file
-        /// descriptor they are wrapping. Usage of this function could
-        /// accidentally allow violating this contract which can cause memory
-        /// unsafety in code that relies on it being true.
-        unsafe fn from_raw_fd(fd: RawFd) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for fs::File {
-        fn as_raw_fd(&self) -> RawFd {
-            self.as_inner().fd().raw()
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for fs::File {
-        unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
-            fs::File::from_inner(sys::fs2::File::from_inner(fd))
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for net::TcpStream {
-        fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for net::TcpListener {
-        fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawFd for net::UdpSocket {
-        fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-    }
-
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for net::TcpStream {
-        unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
-            let socket = sys::net::Socket::from_inner(fd);
-            net::TcpStream::from_inner(net2::TcpStream::from_inner(socket))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for net::TcpListener {
-        unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
-            let socket = sys::net::Socket::from_inner(fd);
-            net::TcpListener::from_inner(net2::TcpListener::from_inner(socket))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawFd for net::UdpSocket {
-        unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
-            let socket = sys::net::Socket::from_inner(fd);
-            net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket))
-        }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OsString and OsStr
-////////////////////////////////////////////////////////////////////////////////
-
-/// Unix-specific extension to the primitives in the `std::ffi` module
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod ffi {
-    use ffi::{OsStr, OsString};
-    use mem;
-    use prelude::v1::*;
-    use sys::os_str::Buf;
-    use sys_common::{FromInner, IntoInner, AsInner};
-
-    /// Unix-specific extensions to `OsString`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStringExt {
-        /// Creates an `OsString` from a byte vector.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn from_vec(vec: Vec<u8>) -> Self;
-
-        /// Yields the underlying byte vector of this `OsString`.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn into_vec(self) -> Vec<u8>;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStringExt for OsString {
-        fn from_vec(vec: Vec<u8>) -> OsString {
-            FromInner::from_inner(Buf { inner: vec })
-        }
-        fn into_vec(self) -> Vec<u8> {
-            self.into_inner().inner
-        }
-    }
-
-    /// Unix-specific extensions to `OsStr`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStrExt {
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn from_bytes(slice: &[u8]) -> &Self;
-
-        /// Gets the underlying byte view of the `OsStr` slice.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_bytes(&self) -> &[u8];
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStrExt for OsStr {
-        fn from_bytes(slice: &[u8]) -> &OsStr {
-            unsafe { mem::transmute(slice) }
-        }
-        fn as_bytes(&self) -> &[u8] {
-            &self.as_inner().inner
-        }
-    }
-}
-
-/// Unix-specific extensions to primitives in the `std::fs` module.
-#[unstable(feature = "fs_ext",
-           reason = "may want a more useful mode abstraction")]
-pub mod fs {
-    use sys;
-    use sys_common::{FromInner, AsInner, AsInnerMut};
-    use fs::{Permissions, OpenOptions};
-    use path::Path;
-    use convert::AsRef;
-    use io;
-
-    /// Unix-specific extensions to `Permissions`
-    pub trait PermissionsExt {
-        fn mode(&self) -> i32;
-        fn set_mode(&mut self, mode: i32);
-    }
-
-    impl PermissionsExt for Permissions {
-        fn mode(&self) -> i32 { self.as_inner().mode() }
-
-        fn set_mode(&mut self, mode: i32) {
-            *self = FromInner::from_inner(FromInner::from_inner(mode));
-        }
-    }
-
-    /// Unix-specific extensions to `OpenOptions`
-    pub trait OpenOptionsExt {
-        /// Sets the mode bits that a new file will be created with.
-        ///
-        /// If a new file is created as part of a `File::open_opts` call then this
-        /// specified `mode` will be used as the permission bits for the new file.
-        fn mode(&mut self, mode: i32) -> &mut Self;
-    }
-
-    impl OpenOptionsExt for OpenOptions {
-        fn mode(&mut self, mode: i32) -> &mut OpenOptions {
-            self.as_inner_mut().mode(mode); self
-        }
-    }
-
-    /// Creates a new symbolic link on the filesystem.
-    ///
-    /// The `dst` path will be a symbolic link pointing to the `src` path.
-    ///
-    /// # Note
-    ///
-    /// On Windows, you must specify whether a symbolic link points to a file
-    /// or directory.  Use `os::windows::fs::symlink_file` to create a
-    /// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
-    /// symbolic link to a directory.  Additionally, the process must have
-    /// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
-    /// symbolic link.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(fs_ext)]
-    /// use std::os::unix::fs;
-    ///
-    /// # fn foo() -> std::io::Result<()> {
-    /// try!(fs::symlink("a.txt", "b.txt"));
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
-    {
-        sys::fs2::symlink(src.as_ref(), dst.as_ref())
-    }
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Process and Command
-////////////////////////////////////////////////////////////////////////////////
-
-/// Unix-specific extensions to primitives in the `std::process` module.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod process {
-    use prelude::v1::*;
-    use libc::{uid_t, gid_t};
-    use process;
-    use sys;
-    use sys_common::{AsInnerMut, AsInner};
-
-    /// Unix-specific extensions to the `std::process::Command` builder
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait CommandExt {
-        /// Sets the child process's user id. This translates to a
-        /// `setuid` call in the child process. Failure in the `setuid`
-        /// call will cause the spawn to fail.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn uid(&mut self, id: uid_t) -> &mut process::Command;
-
-        /// Similar to `uid`, but sets the group id of the child process. This has
-        /// the same semantics as the `uid` field.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn gid(&mut self, id: gid_t) -> &mut process::Command;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl CommandExt for process::Command {
-        fn uid(&mut self, id: uid_t) -> &mut process::Command {
-            self.as_inner_mut().uid = Some(id);
-            self
-        }
-
-        fn gid(&mut self, id: gid_t) -> &mut process::Command {
-            self.as_inner_mut().gid = Some(id);
-            self
-        }
-    }
-
-    /// Unix-specific extensions to `std::process::ExitStatus`
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait ExitStatusExt {
-        /// If the process was terminated by a signal, returns that signal.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn signal(&self) -> Option<i32>;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl ExitStatusExt for process::ExitStatus {
-        fn signal(&self) -> Option<i32> {
-            match *self.as_inner() {
-                sys::process2::ExitStatus::Signal(s) => Some(s),
-                _ => None
-            }
-        }
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Prelude
-////////////////////////////////////////////////////////////////////////////////
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    pub use super::io::{RawFd, AsRawFd};
-    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-    #[doc(no_inline)]
-    pub use super::fs::{PermissionsExt, OpenOptionsExt};
-    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::process::{CommandExt, ExitStatusExt};
-}
diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs
new file mode 100644 (file)
index 0000000..825e74c
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Unix-specific extension to the primitives in the `std::ffi` module
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use ffi::{OsStr, OsString};
+use mem;
+use prelude::v1::*;
+use sys::os_str::Buf;
+use sys_common::{FromInner, IntoInner, AsInner};
+
+/// Unix-specific extensions to `OsString`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+    /// Creates an `OsString` from a byte vector.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_vec(vec: Vec<u8>) -> Self;
+
+    /// Yields the underlying byte vector of this `OsString`.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn into_vec(self) -> Vec<u8>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+    fn from_vec(vec: Vec<u8>) -> OsString {
+        FromInner::from_inner(Buf { inner: vec })
+    }
+    fn into_vec(self) -> Vec<u8> {
+        self.into_inner().inner
+    }
+}
+
+/// Unix-specific extensions to `OsStr`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_bytes(slice: &[u8]) -> &Self;
+
+    /// Gets the underlying byte view of the `OsStr` slice.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_bytes(&self) -> &[u8];
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+    fn from_bytes(slice: &[u8]) -> &OsStr {
+        unsafe { mem::transmute(slice) }
+    }
+    fn as_bytes(&self) -> &[u8] {
+        &self.as_inner().inner
+    }
+}
diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs
new file mode 100644 (file)
index 0000000..ad6a856
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Unix-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use prelude::v1::*;
+
+use fs::{self, Permissions, OpenOptions};
+use io;
+use mem;
+use os::raw::c_long;
+use os::unix::raw;
+use path::Path;
+use sys::platform;
+use sys;
+use sys_common::{FromInner, AsInner, AsInnerMut};
+
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_READ: raw::mode_t = 0o400;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_WRITE: raw::mode_t = 0o200;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_EXECUTE: raw::mode_t = 0o100;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const USER_RWX: raw::mode_t = 0o700;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_READ: raw::mode_t = 0o040;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_WRITE: raw::mode_t = 0o020;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_EXECUTE: raw::mode_t = 0o010;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const GROUP_RWX: raw::mode_t = 0o070;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_READ: raw::mode_t = 0o004;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_WRITE: raw::mode_t = 0o002;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_EXECUTE: raw::mode_t = 0o001;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const OTHER_RWX: raw::mode_t = 0o007;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_READ: raw::mode_t = 0o444;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_WRITE: raw::mode_t = 0o222;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_EXECUTE: raw::mode_t = 0o111;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const ALL_RWX: raw::mode_t = 0o777;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const SETUID: raw::mode_t = 0o4000;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const SETGID: raw::mode_t = 0o2000;
+#[unstable(feature = "fs_mode", reason = "recently added API")]
+pub const STICKY_BIT: raw::mode_t = 0o1000;
+
+/// Unix-specific extensions to `Permissions`
+#[unstable(feature = "fs_ext",
+           reason = "may want a more useful mode abstraction")]
+pub trait PermissionsExt {
+    fn mode(&self) -> raw::mode_t;
+    fn set_mode(&mut self, mode: raw::mode_t);
+    fn from_mode(mode: raw::mode_t) -> Self;
+}
+
+impl PermissionsExt for Permissions {
+    fn mode(&self) -> raw::mode_t { self.as_inner().mode() }
+
+    fn set_mode(&mut self, mode: raw::mode_t) {
+        *self = FromInner::from_inner(FromInner::from_inner(mode));
+    }
+
+    fn from_mode(mode: raw::mode_t) -> Permissions {
+        FromInner::from_inner(FromInner::from_inner(mode))
+    }
+}
+
+/// Unix-specific extensions to `OpenOptions`
+#[unstable(feature = "fs_ext",
+           reason = "may want a more useful mode abstraction")]
+pub trait OpenOptionsExt {
+    /// Sets the mode bits that a new file will be created with.
+    ///
+    /// If a new file is created as part of a `File::open_opts` call then this
+    /// specified `mode` will be used as the permission bits for the new file.
+    fn mode(&mut self, mode: raw::mode_t) -> &mut Self;
+}
+
+impl OpenOptionsExt for OpenOptions {
+    fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions {
+        self.as_inner_mut().mode(mode); self
+    }
+}
+
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub struct Metadata(sys::fs2::FileAttr);
+
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub trait MetadataExt {
+    fn as_raw(&self) -> &Metadata;
+}
+
+impl MetadataExt for fs::Metadata {
+    fn as_raw(&self) -> &Metadata {
+        let inner: &sys::fs2::FileAttr = self.as_inner();
+        unsafe { mem::transmute(inner) }
+    }
+}
+
+impl AsInner<platform::raw::stat> for Metadata {
+    fn as_inner(&self) -> &platform::raw::stat { self.0.as_inner() }
+}
+
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+impl Metadata {
+    pub fn dev(&self) -> raw::dev_t { self.0.raw().st_dev as raw::dev_t }
+    pub fn ino(&self) -> raw::ino_t { self.0.raw().st_ino as raw::ino_t }
+    pub fn mode(&self) -> raw::mode_t { self.0.raw().st_mode as raw::mode_t }
+    pub fn nlink(&self) -> raw::nlink_t { self.0.raw().st_nlink as raw::nlink_t }
+    pub fn uid(&self) -> raw::uid_t { self.0.raw().st_uid as raw::uid_t }
+    pub fn gid(&self) -> raw::gid_t { self.0.raw().st_gid as raw::gid_t }
+    pub fn rdev(&self) -> raw::dev_t { self.0.raw().st_rdev as raw::dev_t }
+    pub fn size(&self) -> raw::off_t { self.0.raw().st_size as raw::off_t }
+    pub fn atime(&self) -> raw::time_t { self.0.raw().st_atime }
+    pub fn atime_nsec(&self) -> c_long { self.0.raw().st_atime }
+    pub fn mtime(&self) -> raw::time_t { self.0.raw().st_mtime }
+    pub fn mtime_nsec(&self) -> c_long { self.0.raw().st_mtime }
+    pub fn ctime(&self) -> raw::time_t { self.0.raw().st_ctime }
+    pub fn ctime_nsec(&self) -> c_long { self.0.raw().st_ctime }
+
+    pub fn blksize(&self) -> raw::blksize_t {
+        self.0.raw().st_blksize as raw::blksize_t
+    }
+    pub fn blocks(&self) -> raw::blkcnt_t {
+        self.0.raw().st_blocks as raw::blkcnt_t
+    }
+}
+
+#[unstable(feature = "dir_entry_ext", reason = "recently added API")]
+pub trait DirEntryExt {
+    fn ino(&self) -> raw::ino_t;
+}
+
+impl DirEntryExt for fs::DirEntry {
+    fn ino(&self) -> raw::ino_t { self.as_inner().ino() }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory.  Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory.  Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::symlink("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+    sys::fs2::symlink(src.as_ref(), dst.as_ref())
+}
diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs
new file mode 100644 (file)
index 0000000..8cb4b49
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use net;
+use os::raw;
+use sys;
+use sys_common::{net2, AsInner, FromInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guarantee to be valid while
+    /// the original object has not yet been destroyed.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[unstable(feature = "from_raw_os",
+           reason = "recent addition to std::os::unix::io")]
+pub trait FromRawFd {
+    /// Constructs a new instances of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for fs::File {
+    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+        fs::File::from_inner(sys::fs2::File::from_inner(fd))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for net::TcpStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpStream::from_inner(net2::TcpStream::from_inner(socket))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for net::TcpListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpListener::from_inner(net2::TcpListener::from_inner(socket))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawFd for net::UdpSocket {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket))
+    }
+}
diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs
new file mode 100644 (file)
index 0000000..6fde45a
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Experimental extensions to `std` for Unix platforms.
+//!
+//! For now, this module is limited to extracting file descriptors,
+//! but its functionality will grow over time.
+//!
+//! # Example
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() {
+//!     let f = File::create("foo.txt").unwrap();
+//!     let fd = f.as_raw_fd();
+//!
+//!     // use fd with native unix bindings
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod io;
+pub mod ffi;
+pub mod fs;
+pub mod process;
+pub mod raw;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    pub use super::io::{RawFd, AsRawFd};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)]
+    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt};
+    #[doc(no_inline)]
+    pub use super::fs::{DirEntryExt};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::process::{CommandExt, ExitStatusExt};
+}
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
new file mode 100644 (file)
index 0000000..8c9d0a8
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Unix-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use os::unix::raw::{uid_t, gid_t};
+use prelude::v1::*;
+use process;
+use sys;
+use sys_common::{AsInnerMut, AsInner};
+
+/// Unix-specific extensions to the `std::process::Command` builder
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+    /// Sets the child process's user id. This translates to a
+    /// `setuid` call in the child process. Failure in the `setuid`
+    /// call will cause the spawn to fail.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn uid(&mut self, id: uid_t) -> &mut process::Command;
+
+    /// Similar to `uid`, but sets the group id of the child process. This has
+    /// the same semantics as the `uid` field.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn gid(&mut self, id: gid_t) -> &mut process::Command;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+    fn uid(&mut self, id: uid_t) -> &mut process::Command {
+        self.as_inner_mut().uid = Some(id);
+        self
+    }
+
+    fn gid(&mut self, id: gid_t) -> &mut process::Command {
+        self.as_inner_mut().gid = Some(id);
+        self
+    }
+}
+
+/// Unix-specific extensions to `std::process::ExitStatus`
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+    /// If the process was terminated by a signal, returns that signal.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+    fn signal(&self) -> Option<i32> {
+        match *self.as_inner() {
+            sys::process2::ExitStatus::Signal(s) => Some(s),
+            _ => None
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs
new file mode 100644 (file)
index 0000000..8fe4b90
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Unix-specific primitives available on all unix platforms
+
+#![unstable(feature = "raw_ext", reason = "recently added API")]
+
+pub type uid_t = u32;
+pub type gid_t = u32;
+pub type pid_t = i32;
+
+#[doc(inline)]
+pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t};
+#[doc(inline)]
+pub use sys::platform::raw::{blkcnt_t, time_t};
index 8eb84b26f22f2f33d604b380cd57732b20f2664d..678d8065ce7b8ae506b52aa8fabd76fea0614e0e 100644 (file)
 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,10 @@ 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 }
+
 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 +74,35 @@ pub fn modified(&self) -> u64 {
         self.mktime(self.stat.st_mtime as u64, self.stat.st_mtime_nsec as u64)
     }
 
+    pub fn file_type(&self) -> FileType {
+        FileType { mode: self.stat.st_mode as mode_t }
+    }
+
+    pub fn raw(&self) -> &raw::stat { &self.stat }
+
     // times are in milliseconds (currently)
     fn mktime(&self, secs: u64, nsecs: u64) -> u64 {
         secs * 1000 + nsecs / 1000000
     }
 }
 
+impl AsInner<raw::stat> for FileAttr {
+    fn as_inner(&self) -> &raw::stat { &self.stat }
+}
+
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub trait MetadataExt {
+    fn as_raw_stat(&self) -> &raw::stat;
+}
+
+impl MetadataExt for ::fs::Metadata {
+    fn as_raw_stat(&self) -> &raw::stat { &self.as_inner().stat }
+}
+
+impl MetadataExt for ::os::unix::fs::Metadata {
+    fn as_raw_stat(&self) -> &raw::stat { self.as_inner() }
+}
+
 impl FilePermissions {
     pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
     pub fn set_readonly(&mut self, readonly: bool) {
@@ -91,11 +112,19 @@ pub fn set_readonly(&mut self, readonly: bool) {
             self.mode |= 0o222;
         }
     }
-    pub fn mode(&self) -> i32 { self.mode as i32 }
+    pub fn mode(&self) -> raw::mode_t { self.mode }
+}
+
+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<i32> for FilePermissions {
-    fn from_inner(mode: i32) -> FilePermissions {
+impl FromInner<raw::mode_t> for FilePermissions {
+    fn from_inner(mode: raw::mode_t) -> FilePermissions {
         FilePermissions { mode: mode as mode_t }
     }
 }
@@ -147,6 +176,33 @@ pub fn path(&self) -> PathBuf {
         self.root.join(<OsStr as OsStrExt>::from_bytes(self.name_bytes()))
     }
 
+    pub fn file_name(&self) -> OsString {
+        OsStr::from_bytes(self.name_bytes()).to_os_string()
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        lstat(&self.path())
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        extern {
+            fn rust_dir_get_mode(ptr: *mut libc::dirent_t) -> c_int;
+        }
+        unsafe {
+            match rust_dir_get_mode(self.dirent()) {
+                -1 => lstat(&self.path()).map(|m| m.file_type()),
+                n => Ok(FileType { mode: n as mode_t }),
+            }
+        }
+    }
+
+    pub fn ino(&self) -> raw::ino_t {
+        extern {
+            fn rust_dir_get_ino(ptr: *mut libc::dirent_t) -> raw::ino_t;
+        }
+        unsafe { rust_dir_get_ino(self.dirent()) }
+    }
+
     fn name_bytes(&self) -> &[u8] {
         extern {
             fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char;
@@ -191,7 +247,7 @@ pub fn create(&mut self, create: bool) {
         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 +284,10 @@ pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
     pub fn into_fd(self) -> FileDesc { self.0 }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
-        let mut stat: libc::stat = unsafe { mem::zeroed() };
-        try!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) }));
+        let mut stat: raw::stat = unsafe { mem::zeroed() };
+        try!(cvt(unsafe {
+            libc::fstat(self.0.raw(), &mut stat as *mut _ as *mut _)
+        }));
         Ok(FileAttr { stat: stat })
     }
 
@@ -420,15 +478,19 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
     let p = try!(cstr(p));
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) }));
+    let mut stat: raw::stat = unsafe { mem::zeroed() };
+    try!(cvt(unsafe {
+        libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _)
+    }));
     Ok(FileAttr { stat: stat })
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
     let p = try!(cstr(p));
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) }));
+    let mut stat: raw::stat = unsafe { mem::zeroed() };
+    try!(cvt(unsafe {
+        libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _)
+    }));
     Ok(FileAttr { stat: stat })
 }
 
@@ -438,3 +500,17 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> {
     try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) }));
     Ok(())
 }
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+    let path = try!(CString::new(p.as_os_str().as_bytes()));
+    let mut buf = vec![0u8; 16 * 1024];
+    unsafe {
+        let r = c::realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _);
+        if r.is_null() {
+            return Err(io::Error::last_os_error())
+        }
+    }
+    let p = buf.iter().position(|i| *i == 0).unwrap();
+    buf.truncate(p);
+    Ok(PathBuf::from(OsString::from_vec(buf)))
+}
index d99753a6a4c800c47b0237b23fa2b5dfb328d652..78b798d3bffff06f849f2f53b22b71512edc623c 100644 (file)
 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 (file)
index dd747d2..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Experimental extensions to `std` for Windows.
-//!
-//! For now, this module is limited to extracting handles, file
-//! descriptors, and sockets, but its functionality will grow over
-//! time.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod io {
-    use fs;
-    use libc;
-    use net;
-    use sys_common::{net2, AsInner, FromInner};
-    use sys;
-
-    /// Raw HANDLEs.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub type RawHandle = libc::HANDLE;
-
-    /// Raw SOCKETs.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub type RawSocket = libc::SOCKET;
-
-    /// Extract raw handles.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait AsRawHandle {
-        /// Extracts the raw handle, without taking any ownership.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_raw_handle(&self) -> RawHandle;
-    }
-
-    /// Construct I/O objects from raw handles.
-    #[unstable(feature = "from_raw_os",
-               reason = "recent addition to the std::os::windows::io module")]
-    pub trait FromRawHandle {
-        /// Constructs a new I/O object from the specified raw handle.
-        ///
-        /// This function will **consume ownership** of the handle given,
-        /// passing responsibility for closing the handle to the returned
-        /// object.
-        ///
-        /// This function is also unsafe as the primitives currently returned
-        /// have the contract that they are the sole owner of the file
-        /// descriptor they are wrapping. Usage of this function could
-        /// accidentally allow violating this contract which can cause memory
-        /// unsafety in code that relies on it being true.
-        unsafe fn from_raw_handle(handle: RawHandle) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawHandle for fs::File {
-        fn as_raw_handle(&self) -> RawHandle {
-            self.as_inner().handle().raw()
-        }
-    }
-
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawHandle for fs::File {
-        unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
-            fs::File::from_inner(sys::fs2::File::from_inner(handle))
-        }
-    }
-
-    /// Extract raw sockets.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait AsRawSocket {
-        /// Extracts the underlying raw socket from this object.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn as_raw_socket(&self) -> RawSocket;
-    }
-
-    /// Create I/O objects from raw sockets.
-    #[unstable(feature = "from_raw_os", reason = "recent addition to module")]
-    pub trait FromRawSocket {
-        /// Creates a new I/O object from the given raw socket.
-        ///
-        /// This function will **consume ownership** of the socket provided and
-        /// it will be closed when the returned object goes out of scope.
-        ///
-        /// This function is also unsafe as the primitives currently returned
-        /// have the contract that they are the sole owner of the file
-        /// descriptor they are wrapping. Usage of this function could
-        /// accidentally allow violating this contract which can cause memory
-        /// unsafety in code that relies on it being true.
-        unsafe fn from_raw_socket(sock: RawSocket) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawSocket for net::TcpStream {
-        fn as_raw_socket(&self) -> RawSocket {
-            *self.as_inner().socket().as_inner()
-        }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawSocket for net::TcpListener {
-        fn as_raw_socket(&self) -> RawSocket {
-            *self.as_inner().socket().as_inner()
-        }
-    }
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl AsRawSocket for net::UdpSocket {
-        fn as_raw_socket(&self) -> RawSocket {
-            *self.as_inner().socket().as_inner()
-        }
-    }
-
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawSocket for net::TcpStream {
-        unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
-            let sock = sys::net::Socket::from_inner(sock);
-            net::TcpStream::from_inner(net2::TcpStream::from_inner(sock))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawSocket for net::TcpListener {
-        unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
-            let sock = sys::net::Socket::from_inner(sock);
-            net::TcpListener::from_inner(net2::TcpListener::from_inner(sock))
-        }
-    }
-    #[unstable(feature = "from_raw_os", reason = "trait is unstable")]
-    impl FromRawSocket for net::UdpSocket {
-        unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
-            let sock = sys::net::Socket::from_inner(sock);
-            net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock))
-        }
-    }
-}
-
-/// Windows-specific extensions to the primitives in the `std::ffi` module.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod ffi {
-    use ffi::{OsString, OsStr};
-    use sys::os_str::Buf;
-    use sys_common::wtf8::Wtf8Buf;
-    use sys_common::{FromInner, AsInner};
-
-    pub use sys_common::wtf8::EncodeWide;
-
-    /// Windows-specific extensions to `OsString`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStringExt {
-        /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
-        /// 16-bit code units.
-        ///
-        /// This is lossless: calling `.encode_wide()` on the resulting string
-        /// will always return the original code units.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn from_wide(wide: &[u16]) -> Self;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStringExt for OsString {
-        fn from_wide(wide: &[u16]) -> OsString {
-            FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
-        }
-    }
-
-    /// Windows-specific extensions to `OsStr`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub trait OsStrExt {
-        /// Re-encodes an `OsStr` as a wide character sequence,
-        /// i.e. potentially ill-formed UTF-16.
-        ///
-        /// This is lossless. Note that the encoding does not include a final
-        /// null.
-        #[stable(feature = "rust1", since = "1.0.0")]
-        fn encode_wide(&self) -> EncodeWide;
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl OsStrExt for OsStr {
-        fn encode_wide(&self) -> EncodeWide {
-            self.as_inner().inner.encode_wide()
-        }
-    }
-}
-
-/// Windows-specific extensions for the primitives in `std::fs`
-#[unstable(feature = "fs_ext", reason = "may require more thought/methods")]
-pub mod fs {
-    use fs::OpenOptions;
-    use sys;
-    use sys_common::AsInnerMut;
-    use path::Path;
-    use convert::AsRef;
-    use io;
-
-    /// Windows-specific extensions to `OpenOptions`
-    pub trait OpenOptionsExt {
-        /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
-        /// with the specified value.
-        fn desired_access(&mut self, access: i32) -> &mut Self;
-
-        /// Overrides the `dwCreationDisposition` argument to the call to
-        /// `CreateFile` with the specified value.
-        ///
-        /// This will override any values of the standard `create` flags, for
-        /// example.
-        fn creation_disposition(&mut self, val: i32) -> &mut Self;
-
-        /// Overrides the `dwFlagsAndAttributes` argument to the call to
-        /// `CreateFile` with the specified value.
-        ///
-        /// This will override any values of the standard flags on the
-        /// `OpenOptions` structure.
-        fn flags_and_attributes(&mut self, val: i32) -> &mut Self;
-
-        /// Overrides the `dwShareMode` argument to the call to `CreateFile` with
-        /// the specified value.
-        ///
-        /// This will override any values of the standard flags on the
-        /// `OpenOptions` structure.
-        fn share_mode(&mut self, val: i32) -> &mut Self;
-    }
-
-    impl OpenOptionsExt for OpenOptions {
-        fn desired_access(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().desired_access(access); self
-        }
-        fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().creation_disposition(access); self
-        }
-        fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().flags_and_attributes(access); self
-        }
-        fn share_mode(&mut self, access: i32) -> &mut OpenOptions {
-            self.as_inner_mut().share_mode(access); self
-        }
-    }
-
-    /// Creates a new file symbolic link on the filesystem.
-    ///
-    /// The `dst` path will be a file symbolic link pointing to the `src`
-    /// path.
-    ///
-    /// # Examples
-    ///
-    /// ```ignore
-    /// #![feature(fs_ext)]
-    /// use std::os::windows::fs;
-    ///
-    /// # fn foo() -> std::io::Result<()> {
-    /// try!(fs::symlink_file("a.txt", "b.txt"));
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
-                                                        -> io::Result<()>
-    {
-        sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false)
-    }
-
-    /// Creates a new directory symlink on the filesystem.
-    ///
-    /// The `dst` path will be a directory symbolic link pointing to the `src`
-    /// path.
-    ///
-    /// # Examples
-    ///
-    /// ```ignore
-    /// #![feature(fs_ext)]
-    /// use std::os::windows::fs;
-    ///
-    /// # fn foo() -> std::io::Result<()> {
-    /// try!(fs::symlink_file("a", "b"));
-    /// # Ok(())
-    /// # }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>> (src: P, dst: Q)
-                                                        -> io::Result<()>
-    {
-        sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true)
-    }
-}
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle};
-    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-    #[doc(no_inline)]
-    pub use super::fs::OpenOptionsExt;
-}
diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs
new file mode 100644 (file)
index 0000000..3fa96f4
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Windows-specific extensions to the primitives in the `std::ffi` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use ffi::{OsString, OsStr};
+use sys::os_str::Buf;
+use sys_common::wtf8::Wtf8Buf;
+use sys_common::{FromInner, AsInner};
+
+pub use sys_common::wtf8::EncodeWide;
+
+/// Windows-specific extensions to `OsString`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+    /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
+    /// 16-bit code units.
+    ///
+    /// This is lossless: calling `.encode_wide()` on the resulting string
+    /// will always return the original code units.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_wide(wide: &[u16]) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+    fn from_wide(wide: &[u16]) -> OsString {
+        FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
+    }
+}
+
+/// Windows-specific extensions to `OsStr`.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+    /// Re-encodes an `OsStr` as a wide character sequence,
+    /// i.e. potentially ill-formed UTF-16.
+    ///
+    /// This is lossless. Note that the encoding does not include a final
+    /// null.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn encode_wide(&self) -> EncodeWide;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+    fn encode_wide(&self) -> EncodeWide {
+        self.as_inner().inner.encode_wide()
+    }
+}
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
new file mode 100644 (file)
index 0000000..23c1fcf
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Windows-specific extensions for the primitives in `std::fs`
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use prelude::v1::*;
+
+use fs::{OpenOptions, Metadata};
+use io;
+use path::Path;
+use sys;
+use sys_common::{AsInnerMut, AsInner};
+
+/// Windows-specific extensions to `OpenOptions`
+#[unstable(feature = "fs_ext", reason = "may require more thought/methods")]
+pub trait OpenOptionsExt {
+    /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
+    /// with the specified value.
+    fn desired_access(&mut self, access: i32) -> &mut Self;
+
+    /// Overrides the `dwCreationDisposition` argument to the call to
+    /// `CreateFile` with the specified value.
+    ///
+    /// This will override any values of the standard `create` flags, for
+    /// example.
+    fn creation_disposition(&mut self, val: i32) -> &mut Self;
+
+    /// Overrides the `dwFlagsAndAttributes` argument to the call to
+    /// `CreateFile` with the specified value.
+    ///
+    /// This will override any values of the standard flags on the
+    /// `OpenOptions` structure.
+    fn flags_and_attributes(&mut self, val: i32) -> &mut Self;
+
+    /// Overrides the `dwShareMode` argument to the call to `CreateFile` with
+    /// the specified value.
+    ///
+    /// This will override any values of the standard flags on the
+    /// `OpenOptions` structure.
+    fn share_mode(&mut self, val: i32) -> &mut Self;
+}
+
+impl OpenOptionsExt for OpenOptions {
+    fn desired_access(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().desired_access(access); self
+    }
+    fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().creation_disposition(access); self
+    }
+    fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().flags_and_attributes(access); self
+    }
+    fn share_mode(&mut self, access: i32) -> &mut OpenOptions {
+        self.as_inner_mut().share_mode(access); self
+    }
+}
+
+/// Extension methods for `fs::Metadata` to access the raw fields contained
+/// within.
+#[unstable(feature = "metadata_ext", reason = "recently added API")]
+pub trait MetadataExt {
+    /// Returns the value of the `dwFileAttributes` field of this metadata.
+    ///
+    /// This field contains the file system attribute information for a file
+    /// or directory.
+    fn file_attributes(&self) -> u32;
+
+    /// Returns the value of the `ftCreationTime` field of this metadata.
+    ///
+    /// The returned 64-bit value represents the number of 100-nanosecond
+    /// intervals since January 1, 1601 (UTC).
+    fn creation_time(&self) -> u64;
+
+    /// Returns the value of the `ftLastAccessTime` field of this metadata.
+    ///
+    /// The returned 64-bit value represents the number of 100-nanosecond
+    /// intervals since January 1, 1601 (UTC).
+    fn last_access_time(&self) -> u64;
+
+    /// Returns the value of the `ftLastWriteTime` field of this metadata.
+    ///
+    /// The returned 64-bit value represents the number of 100-nanosecond
+    /// intervals since January 1, 1601 (UTC).
+    fn last_write_time(&self) -> u64;
+
+    /// Returns the value of the `nFileSize{High,Low}` fields of this
+    /// metadata.
+    ///
+    /// The returned value does not have meaning for directories.
+    fn file_size(&self) -> u64;
+}
+
+impl MetadataExt for Metadata {
+    fn file_attributes(&self) -> u32 { self.as_inner().attrs() }
+    fn creation_time(&self) -> u64 { self.as_inner().created() }
+    fn last_access_time(&self) -> u64 { self.as_inner().accessed() }
+    fn last_write_time(&self) -> u64 { self.as_inner().modified() }
+    fn file_size(&self) -> u64 { self.as_inner().size() }
+}
+
+/// Creates a new file symbolic link on the filesystem.
+///
+/// The `dst` path will be a file symbolic link pointing to the `src`
+/// path.
+///
+/// # Examples
+///
+/// ```ignore
+/// use std::os::windows::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::symlink_file("a.txt", "b.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
+                                                    -> io::Result<()> {
+    sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), false)
+}
+
+/// Creates a new directory symlink on the filesystem.
+///
+/// The `dst` path will be a directory symbolic link pointing to the `src`
+/// path.
+///
+/// # Examples
+///
+/// ```ignore
+/// use std::os::windows::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// try!(fs::symlink_file("a", "b"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
+                                                   -> io::Result<()> {
+    sys::fs2::symlink_inner(src.as_ref(), dst.as_ref(), true)
+}
diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs
new file mode 100644 (file)
index 0000000..b88a631
--- /dev/null
@@ -0,0 +1,131 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use os::windows::raw;
+use net;
+use sys_common::{net2, AsInner, FromInner};
+use sys;
+
+/// Raw HANDLEs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawHandle = raw::HANDLE;
+
+/// Raw SOCKETs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawSocket = raw::SOCKET;
+
+/// Extract raw handles.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawHandle {
+    /// Extracts the raw handle, without taking any ownership.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_handle(&self) -> RawHandle;
+}
+
+/// Construct I/O objects from raw handles.
+#[unstable(feature = "from_raw_os",
+           reason = "recent addition to the std::os::windows::io module")]
+pub trait FromRawHandle {
+    /// Constructs a new I/O object from the specified raw handle.
+    ///
+    /// This function will **consume ownership** of the handle given,
+    /// passing responsibility for closing the handle to the returned
+    /// object.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_handle(handle: RawHandle) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawHandle for fs::File {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as RawHandle
+    }
+}
+
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawHandle for fs::File {
+    unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
+        let handle = handle as ::libc::HANDLE;
+        fs::File::from_inner(sys::fs2::File::from_inner(handle))
+    }
+}
+
+/// Extract raw sockets.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawSocket {
+    /// Extracts the underlying raw socket from this object.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_socket(&self) -> RawSocket;
+}
+
+/// Create I/O objects from raw sockets.
+#[unstable(feature = "from_raw_os", reason = "recent addition to module")]
+pub trait FromRawSocket {
+    /// Creates a new I/O object from the given raw socket.
+    ///
+    /// This function will **consume ownership** of the socket provided and
+    /// it will be closed when the returned object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_socket(sock: RawSocket) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpStream {
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpListener {
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::UdpSocket {
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawSocket for net::TcpStream {
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::TcpStream::from_inner(net2::TcpStream::from_inner(sock))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawSocket for net::TcpListener {
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::TcpListener::from_inner(net2::TcpListener::from_inner(sock))
+    }
+}
+#[unstable(feature = "from_raw_os", reason = "trait is unstable")]
+impl FromRawSocket for net::UdpSocket {
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock))
+    }
+}
diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs
new file mode 100644 (file)
index 0000000..08dfa4c
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Experimental extensions to `std` for Windows.
+//!
+//! For now, this module is limited to extracting handles, file
+//! descriptors, and sockets, but its functionality will grow over
+//! time.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod raw;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    pub use super::io::{RawSocket, RawHandle, AsRawSocket, AsRawHandle};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)]
+    pub use super::fs::{OpenOptionsExt, MetadataExt};
+}
diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs
new file mode 100644 (file)
index 0000000..656e480
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Windows-specific primitives
+
+#![unstable(feature = "raw_ext", reason = "recently added API")]
+
+use os::raw;
+
+pub type HANDLE = *mut raw::c_void;
+#[cfg(target_pointer_width = "32")]
+pub type SOCKET = u32;
+#[cfg(target_pointer_width = "64")]
+pub type SOCKET = u64;
index 5ac9a0ace5801ba08d6b914935d5bea27f72792b..2c81c34d3a4a63cec3add657f5995fb1dcbf63c2 100644 (file)
 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,
@@ -111,8 +120,31 @@ fn new(root: &Arc<PathBuf>, wfd: &libc::WIN32_FIND_DATAW) -> Option<DirEntry> {
     }
 
     pub fn path(&self) -> PathBuf {
+        self.root.join(&self.file_name())
+    }
+
+    pub fn file_name(&self) -> OsString {
         let filename = super::truncate_utf16_at_nul(&self.data.cFileName);
-        self.root.join(&<OsString as OsStringExt>::from_wide(filename))
+        OsString::from_wide(filename)
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        Ok(FileType::new(self.data.dwFileAttributes,
+                         self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK))
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        Ok(FileAttr {
+            data: c::WIN32_FILE_ATTRIBUTE_DATA {
+                dwFileAttributes: self.data.dwFileAttributes,
+                ftCreationTime: self.data.ftCreationTime,
+                ftLastAccessTime: self.data.ftLastAccessTime,
+                ftLastWriteTime: self.data.ftLastWriteTime,
+                nFileSizeHigh: self.data.nFileSizeHigh,
+                nFileSizeLow: self.data.nFileSizeLow,
+            },
+            is_symlink: self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK,
+        })
     }
 }
 
@@ -180,6 +212,13 @@ fn get_flags_and_attributes(&self) -> libc::DWORD {
 }
 
 impl File {
+    fn open_reparse_point(path: &Path) -> io::Result<File> {
+        let mut opts = OpenOptions::new();
+        opts.read(true);
+        opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32);
+        File::open(path, &opts)
+    }
+
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
         let path = to_utf16(path);
         let handle = unsafe {
@@ -224,7 +263,7 @@ pub fn file_attr(&self) -> io::Result<FileAttr> {
             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 +271,13 @@ pub fn file_attr(&self) -> io::Result<FileAttr> {
                     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 +307,41 @@ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
     }
 
     pub fn handle(&self) -> &Handle { &self.handle }
+
+    fn is_symlink(&self) -> bool {
+        self.readlink().is_ok()
+    }
+
+    fn readlink(&self) -> io::Result<PathBuf> {
+        let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+        let mut bytes = 0;
+
+        unsafe {
+            try!(cvt({
+                c::DeviceIoControl(self.handle.raw(),
+                                   c::FSCTL_GET_REPARSE_POINT,
+                                   0 as *mut _,
+                                   0,
+                                   space.as_mut_ptr() as *mut _,
+                                   space.len() as libc::DWORD,
+                                   &mut bytes,
+                                   0 as *mut _)
+            }));
+            let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _;
+            if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK {
+                return Err(io::Error::new(io::ErrorKind::Other, "not a symlink"))
+            }
+            let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
+                    &(*buf).rest as *const _ as *const _;
+            let path_buffer = &(*info).PathBuffer as *const _ as *const u16;
+            let subst_off = (*info).SubstituteNameOffset / 2;
+            let subst_ptr = path_buffer.offset(subst_off as isize);
+            let subst_len = (*info).SubstituteNameLength / 2;
+            let subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
+
+            Ok(PathBuf::from(OsString::from_wide(subst)))
+        }
+    }
 }
 
 impl FromInner<libc::HANDLE> for File {
@@ -285,27 +364,30 @@ pub fn to_utf16(s: &Path) -> Vec<u16> {
 }
 
 impl FileAttr {
-    pub fn is_dir(&self) -> bool {
-        self.data.dwFileAttributes & c::FILE_ATTRIBUTE_DIRECTORY != 0
-    }
-    pub fn is_file(&self) -> bool {
-        !self.is_dir()
-    }
     pub fn size(&self) -> u64 {
         ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64)
     }
+
     pub fn perm(&self) -> FilePermissions {
         FilePermissions { attrs: self.data.dwFileAttributes }
     }
 
-    pub fn accessed(&self) -> u64 { self.to_ms(&self.data.ftLastAccessTime) }
-    pub fn modified(&self) -> u64 { self.to_ms(&self.data.ftLastWriteTime) }
+    pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 }
+
+    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,6 +405,26 @@ pub fn set_readonly(&mut self, readonly: bool) {
     }
 }
 
+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 }
+}
+
 pub fn mkdir(p: &Path) -> io::Result<()> {
     let p = to_utf16(p);
     try!(cvt(unsafe {
@@ -374,40 +476,8 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let mut opts = OpenOptions::new();
-    opts.read(true);
-    opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32);
-    let file = try!(File::open(p, &opts));
-
-    let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-    let mut bytes = 0;
-
-    unsafe {
-        try!(cvt({
-            c::DeviceIoControl(file.handle.raw(),
-                               c::FSCTL_GET_REPARSE_POINT,
-                               0 as *mut _,
-                               0,
-                               space.as_mut_ptr() as *mut _,
-                               space.len() as libc::DWORD,
-                               &mut bytes,
-                               0 as *mut _)
-        }));
-        let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _;
-        if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK {
-            return Err(io::Error::new(io::ErrorKind::Other, "not a symlink"))
-        }
-        let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
-                &(*buf).rest as *const _ as *const _;
-        let path_buffer = &(*info).PathBuffer as *const _ as *const u16;
-        let subst_off = (*info).SubstituteNameOffset / 2;
-        let subst_ptr = path_buffer.offset(subst_off as isize);
-        let subst_len = (*info).SubstituteNameLength / 2;
-        let subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
-
-        Ok(PathBuf::from(OsString::from_wide(subst)))
-    }
-
+    let file = try!(File::open_reparse_point(p));
+    file.readlink()
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
@@ -435,12 +505,28 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let p = to_utf16(p);
+    let attr = try!(lstat(p));
+    if attr.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+        let opts = OpenOptions::new();
+        let file = try!(File::open(p, &opts));
+        file.file_attr()
+    } else {
+        Ok(attr)
+    }
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    let utf16 = to_utf16(p);
     unsafe {
         let mut attr: FileAttr = mem::zeroed();
-        try!(cvt(c::GetFileAttributesExW(p.as_ptr(),
+        try!(cvt(c::GetFileAttributesExW(utf16.as_ptr(),
                                          c::GetFileExInfoStandard,
                                          &mut attr.data as *mut _ as *mut _)));
+        if attr.is_reparse_point() {
+            attr.is_symlink = File::open_reparse_point(p).map(|f| {
+                f.is_symlink()
+            }).unwrap_or(false);
+        }
         Ok(attr)
     }
 }
@@ -465,3 +551,17 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> {
     }));
     Ok(())
 }
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+    use sys::c::compat::kernel32::GetFinalPathNameByHandleW;
+
+    let mut opts = OpenOptions::new();
+    opts.read(true);
+    let f = try!(File::open(p, &opts));
+    super::fill_utf16_buf(|buf, sz| unsafe {
+        GetFinalPathNameByHandleW(f.handle.raw(), buf, sz,
+                                  libc::VOLUME_NAME_DOS)
+    }, |buf| {
+        PathBuf::from(OsString::from_wide(buf))
+    })
+}
index db1a602b404f60028282d84073bb3f7a2206dc98..362439c146912dae5f05ebcd51de749e8d90e22d 100644 (file)
 #include <stdlib.h>
 
 #if !defined(__WIN32__)
-#include <sys/time.h>
-#include <sys/types.h>
 #include <dirent.h>
+#include <pthread.h>
 #include <signal.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
 #include <unistd.h>
-#include <pthread.h>
 #else
 #include <windows.h>
 #include <wincrypt.h>
 //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 <errno.h>
 // In DragonFly __error() is an inline function and as such