From 60245b9290388671edac86d6db1619f60a9ccb68 Mon Sep 17 00:00:00 2001 From: Ziad Hatahet Date: Tue, 22 Oct 2013 18:25:07 -0700 Subject: [PATCH 1/2] Remove thread-blocking call to `libc::stat` in `Path::stat` Fixes #9958 --- src/librustpkg/conditions.rs | 5 +- src/librustpkg/util.rs | 4 +- src/librustpkg/workcache_support.rs | 14 +- src/libstd/path/mod.rs | 224 +--------------------------- src/libstd/path/posix.rs | 68 +++------ src/libstd/path/windows.rs | 47 +++--- src/libstd/rt/io/file.rs | 4 +- src/libstd/rt/io/mod.rs | 6 + src/libstd/rt/uv/uvio.rs | 3 + src/libstd/run.rs | 8 +- 10 files changed, 65 insertions(+), 318 deletions(-) diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index 19b310b450617..01bd4e6736ed3 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -12,15 +12,14 @@ pub use std::path::Path; pub use package_id::PkgId; -pub use std::libc; -pub use std::libc::stat; +pub use std::rt::io::FileStat; condition! { pub bad_path: (Path, ~str) -> Path; } condition! { - pub bad_stat: (Path, ~str) -> stat; + pub bad_stat: (Path, ~str) -> FileStat; } condition! { diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index a3a4a07cfc77a..9144c08cb7331 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -609,7 +609,7 @@ fn debug_flags() -> ~[~str] { ~[] } /// Returns the last-modified date as an Option pub fn datestamp(p: &Path) -> Option { debug!("Scrutinizing datestamp for {} - does it exist? {:?}", p.display(), os::path_exists(p)); - let out = p.stat().map(|stat| stat.st_mtime); + let out = p.stat().map(|stat| stat.modified); debug!("Date = {:?}", out); out.map(|t| { t as libc::time_t }) } diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs index 0352067a7e9ed..d49a581e07047 100644 --- a/src/librustpkg/workcache_support.rs +++ b/src/librustpkg/workcache_support.rs @@ -18,17 +18,17 @@ pub fn digest_file_with_date(path: &Path) -> ~str { use conditions::bad_path::cond; use cond1 = conditions::bad_stat::cond; - let mut sha = ~Sha1::new(); let s = io::read_whole_file_str(path); match s { Ok(s) => { - (*sha).input_str(s); + let mut sha = Sha1::new(); + sha.input_str(s); let st = match path.stat() { Some(st) => st, None => cond1.raise((path.clone(), format!("Couldn't get file access time"))) }; - (*sha).input_str(st.st_mtime.to_str()); - (*sha).result_str() + sha.input_str(st.modified.to_str()); + sha.result_str() } Err(e) => { let path = cond.raise((path.clone(), format!("Couldn't read file: {}", e))); @@ -43,13 +43,13 @@ pub fn digest_file_with_date(path: &Path) -> ~str { pub fn digest_only_date(path: &Path) -> ~str { use cond = conditions::bad_stat::cond; - let mut sha = ~Sha1::new(); + let mut sha = Sha1::new(); let st = match path.stat() { Some(st) => st, None => cond.raise((path.clone(), format!("Couldn't get file access time"))) }; - (*sha).input_str(st.st_mtime.to_str()); - (*sha).result_str() + sha.input_str(st.modified.to_str()); + sha.result_str() } /// Adds multiple discovered outputs diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index f71f67a30db84..18f137e8b0e56 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -688,228 +688,6 @@ fn from_utf8_with_replacement(mut v: &[u8]) -> ~str { } s } - -// FIXME (#9537): libc::stat should derive Default -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -mod stat { - #[allow(missing_doc)]; - - #[cfg(target_arch = "x86")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - __pad1: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - __pad2: 0, - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - __unused4: 0, - __unused5: 0, - } - } - } - - #[cfg(target_arch = "arm")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - __pad0: [0, ..4], - __st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - __pad3: [0, ..4], - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_ino: 0 - } - } - } - - #[cfg(target_arch = "mips")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_pad1: [0, ..3], - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_pad2: [0, ..2], - st_size: 0, - st_pad3: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_blksize: 0, - st_blocks: 0, - st_pad5: [0, ..14], - } - } - } - - #[cfg(target_arch = "x86_64")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_nlink: 0, - st_mode: 0, - st_uid: 0, - st_gid: 0, - __pad0: 0, - st_rdev: 0, - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - __unused: [0, 0, 0], - } - } - } -} - -#[cfg(target_os = "freebsd")] -mod stat { - #[allow(missing_doc)]; - - #[cfg(target_arch = "x86_64")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_size: 0, - st_blocks: 0, - st_blksize: 0, - st_flags: 0, - st_gen: 0, - st_lspare: 0, - st_birthtime: 0, - st_birthtime_nsec: 0, - __unused: [0, 0], - } - } - } -} - -#[cfg(target_os = "macos")] -mod stat { - #[allow(missing_doc)]; - - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_mode: 0, - st_nlink: 0, - st_ino: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_birthtime: 0, - st_birthtime_nsec: 0, - st_size: 0, - st_blocks: 0, - st_blksize: 0, - st_flags: 0, - st_gen: 0, - st_lspare: 0, - st_qspare: [0, 0], - } - } - } -} - -#[cfg(target_os = "win32")] -mod stat { - #[allow(missing_doc)]; - - pub mod arch { - use libc; - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_size: 0, - st_atime: 0, - st_mtime: 0, - st_ctime: 0, - } - } - } -} - #[cfg(test)] mod tests { use super::{GenericPath, PosixPath, WindowsPath}; @@ -921,7 +699,7 @@ mod tests { let path: PosixPath = PosixPath::new(input.to_c_str()); assert_eq!(path.as_vec(), input.as_bytes()); - let input = "\\foo\\bar\\baz"; + let input = r"\foo\bar\baz"; let path: WindowsPath = WindowsPath::new(input.to_c_str()); assert_eq!(path.as_str().unwrap(), input.as_slice()); } diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 87821105d37e1..d92c2974f7691 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -25,7 +25,7 @@ use vec::{CopyableVector, RSplitIterator, SplitIterator, Vector, VectorVector}; use super::{BytesContainer, GenericPath, GenericPathUnsafe}; #[cfg(not(target_os = "win32"))] -use libc; +use rt::io::{FileStat, file, io_error}; /// Iterator that yields successive components of a Path as &[u8] pub type ComponentIter<'self> = SplitIterator<'self, u8>; @@ -445,16 +445,13 @@ static dot_dot_static: &'static [u8] = bytes!(".."); // Stat support #[cfg(not(target_os = "win32"))] impl Path { - /// Calls stat() on the represented file and returns the resulting libc::stat - pub fn stat(&self) -> Option { - #[fixed_stack_segment]; #[inline(never)]; - do self.with_c_str |buf| { - let mut st = super::stat::arch::default_stat(); - match unsafe { libc::stat(buf as *libc::c_char, &mut st) } { - 0 => Some(st), - _ => None - } + /// Calls stat() on the represented file and returns the resulting rt::io::FileStat + pub fn stat(&self) -> Option { + let mut file_stat: Option = None; + do io_error::cond.trap(|_| { /* Ignore error, will return None */ }).inside { + file_stat = file::stat(self); } + file_stat } /// Returns whether the represented file exists @@ -466,10 +463,10 @@ impl Path { } /// Returns the filesize of the represented file - pub fn get_size(&self) -> Option { + pub fn get_size(&self) -> Option { match self.stat() { None => None, - Some(st) => Some(st.st_size as i64) + Some(st) => Some(st.size) } } @@ -477,7 +474,7 @@ impl Path { pub fn get_mode(&self) -> Option { match self.stat() { None => None, - Some(st) => Some(st.st_mode as uint) + Some(st) => Some(st.mode as uint) } } } @@ -486,54 +483,27 @@ impl Path { #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] impl Path { - /// Returns the atime of the represented file, as (secs, nsecs) - pub fn get_atime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(st) => Some((st.st_atime as i64, st.st_atime_nsec as int)) - } - } - - /// Returns the mtime of the represented file, as (secs, nsecs) - pub fn get_mtime(&self) -> Option<(i64, int)> { + /// Returns the atime of the represented file, as msecs + pub fn get_atime(&self) -> Option { match self.stat() { None => None, - Some(st) => Some((st.st_mtime as i64, st.st_mtime_nsec as int)) + Some(st) => Some(st.accessed) } } - /// Returns the ctime of the represented file, as (secs, nsecs) - pub fn get_ctime(&self) -> Option<(i64, int)> { + /// Returns the mtime of the represented file, as msecs + pub fn get_mtime(&self) -> Option { match self.stat() { None => None, - Some(st) => Some((st.st_ctime as i64, st.st_ctime_nsec as int)) - } - } -} - -#[cfg(unix)] -impl Path { - /// Calls lstat() on the represented file and returns the resulting libc::stat - pub fn lstat(&self) -> Option { - #[fixed_stack_segment]; #[inline(never)]; - do self.with_c_str |buf| { - let mut st = super::stat::arch::default_stat(); - match unsafe { libc::lstat(buf, &mut st) } { - 0 => Some(st), - _ => None - } + Some(st) => Some(st.modified) } } -} -#[cfg(target_os = "freebsd")] -#[cfg(target_os = "macos")] -impl Path { - /// Returns the birthtime of the represented file - pub fn get_birthtime(&self) -> Option<(i64, int)> { + /// Returns the ctime of the represented file, as msecs + pub fn get_ctime(&self) -> Option { match self.stat() { None => None, - Some(st) => Some((st.st_birthtime as i64, st.st_birthtime_nsec as int)) + Some(st) => Some(st.created) } } } diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 0de2bd4c742b9..dfd654ac13c73 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -24,7 +24,7 @@ use vec::Vector; use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; #[cfg(target_os = "win32")] -use libc; +use rt::io::{FileStat, file, io_error}; /// Iterator that yields successive components of a Path as &str /// @@ -1059,16 +1059,13 @@ fn prefix_is_sep(p: Option, c: u8) -> bool { // Stat support #[cfg(target_os = "win32")] impl Path { - /// Calls stat() on the represented file and returns the resulting libc::stat - pub fn stat(&self) -> Option { - #[fixed_stack_segment]; #[inline(never)]; - do self.with_c_str |buf| { - let mut st = super::stat::arch::default_stat(); - match unsafe { libc::stat(buf, &mut st) } { - 0 => Some(st), - _ => None - } + /// Calls stat() on the represented file and returns the resulting rt::io::FileStat + pub fn stat(&self) -> Option { + let mut file_stat: Option = None; + do io_error::cond.trap(|_| { /* Ignore error, will return None */ }).inside { + file_stat = file::stat(self); } + file_stat } /// Returns whether the represented file exists @@ -1080,10 +1077,10 @@ impl Path { } /// Returns the filesize of the represented file - pub fn get_size(&self) -> Option { + pub fn get_size(&self) -> Option { match self.stat() { None => None, - Some(st) => Some(st.st_size as i64) + Some(st) => Some(st.size) } } @@ -1091,37 +1088,31 @@ impl Path { pub fn get_mode(&self) -> Option { match self.stat() { None => None, - Some(st) => Some(st.st_mode as uint) + Some(st) => Some(st.mode as uint) } } - /// Returns the atime of the represented file, as (secs, nsecs) - /// - /// nsecs is always 0 - pub fn get_atime(&self) -> Option<(i64, int)> { + /// Returns the atime of the represented file, as msecs + pub fn get_atime(&self) -> Option { match self.stat() { None => None, - Some(st) => Some((st.st_atime as i64, 0)) + Some(st) => Some(st.accessed) } } - /// Returns the mtime of the represented file, as (secs, nsecs) - /// - /// nsecs is always 0 - pub fn get_mtime(&self) -> Option<(i64, int)> { + /// Returns the mtime of the represented file, as msecs + pub fn get_mtime(&self) -> Option { match self.stat() { None => None, - Some(st) => Some((st.st_mtime as i64, 0)) + Some(st) => Some(st.modified) } } - /// Returns the ctime of the represented file, as (secs, nsecs) - /// - /// nsecs is always 0 - pub fn get_ctime(&self) -> Option<(i64, int)> { + /// Returns the ctime of the represented file, as msecs + pub fn get_ctime(&self) -> Option { match self.stat() { None => None, - Some(st) => Some((st.st_ctime as i64, 0)) + Some(st) => Some(st.created) } } } diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index a5d593d2454da..e25b03be361a5 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -59,8 +59,8 @@ use path::Path; /// }).inside { /// let stream = match open(p, Create, ReadWrite) { /// Some(s) => s, -/// None => fail!("whoops! I'm sure this raised, anyways.."); -/// } +/// None => fail!("whoops! I'm sure this raised, anyways..") +/// }; /// // do some stuff with that stream /// /// // the file stream will be closed at the end of this block diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index c0971b5d3cd5d..97d44da765a5a 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -654,6 +654,12 @@ pub struct FileStat { is_file: bool, /// `true` if the file pointed at by the `PathInfo` is a directory is_dir: bool, + /// The file pointed at by the `PathInfo`'s device + device: u64, + /// The file pointed at by the `PathInfo`'s mode + mode: u64, + /// The file pointed at by the `PathInfo`'s inode + inode: u64, /// The file pointed at by the `PathInfo`'s size in bytes size: u64, /// The file pointed at by the `PathInfo`'s creation time diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index d5893d6d01414..c7e51b3485dd9 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -635,6 +635,9 @@ impl IoFactory for UvIoFactory { path: Path::new(path_str.as_slice()), is_file: stat.is_file(), is_dir: stat.is_dir(), + device: stat.st_dev, + mode: stat.st_mode, + inode: stat.st_ino, size: stat.st_size, created: stat.st_ctim.tv_sec as u64, modified: stat.st_mtim.tv_sec as u64, diff --git a/src/libstd/run.rs b/src/libstd/run.rs index a406058631823..36e73a6dd51b9 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -584,8 +584,8 @@ mod tests { let parent_stat = parent_dir.stat().unwrap(); let child_stat = child_dir.stat().unwrap(); - assert_eq!(parent_stat.st_dev, child_stat.st_dev); - assert_eq!(parent_stat.st_ino, child_stat.st_ino); + assert_eq!(parent_stat.device, child_stat.device); + assert_eq!(parent_stat.inode, child_stat.inode); } #[test] @@ -601,8 +601,8 @@ mod tests { let parent_stat = parent_dir.stat().unwrap(); let child_stat = child_dir.stat().unwrap(); - assert_eq!(parent_stat.st_dev, child_stat.st_dev); - assert_eq!(parent_stat.st_ino, child_stat.st_ino); + assert_eq!(parent_stat.device, child_stat.device); + assert_eq!(parent_stat.inode, child_stat.inode); } #[cfg(unix,not(target_os="android"))] From dabf3774385aeddaa58b7b25ee39f6034a786b35 Mon Sep 17 00:00:00 2001 From: Ziad Hatahet Date: Wed, 23 Oct 2013 11:16:35 -0700 Subject: [PATCH 2/2] Made uv_stat_t.{st_dev, st_ino} public, #9958 --- src/libstd/rt/uv/uvll.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 96c5dd068d0b2..367585b0f0ee4 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -138,13 +138,13 @@ pub struct uv_timespec_t { } pub struct uv_stat_t { - priv st_dev: libc::uint64_t, + st_dev: libc::uint64_t, st_mode: libc::uint64_t, priv st_nlink: libc::uint64_t, priv st_uid: libc::uint64_t, priv st_gid: libc::uint64_t, priv st_rdev: libc::uint64_t, - priv st_ino: libc::uint64_t, + st_ino: libc::uint64_t, st_size: libc::uint64_t, priv st_blksize: libc::uint64_t, priv st_blocks: libc::uint64_t,