Auto merge of #30865 - alexcrichton:mtime-system-time, r=aturon

These accessors are used to get at the last modification, last access, and
creation time of the underlying file. Currently not all platforms provide the
creation time, so that currently returns `Option`.
This commit is contained in:
bors 2016-02-05 01:00:31 +00:00
commit 7bcced73b7
7 changed files with 183 additions and 8 deletions

View File

@ -25,6 +25,7 @@
use sys_common::io::read_to_end_uninitialized;
use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
use vec::Vec;
use time::SystemTime;
/// A reference to an open file on the filesystem.
///
@ -660,6 +661,52 @@ pub fn len(&self) -> u64 { self.0.size() }
pub fn permissions(&self) -> Permissions {
Permissions(self.0.perm())
}
/// Returns the last modification time listed in this metadata.
///
/// The returned value corresponds to the `mtime` field of `stat` on Unix
/// platforms and the `ftLastWriteTime` field on Windows platforms.
///
/// # Errors
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
#[unstable(feature = "fs_time", issue = "31399")]
pub fn modified(&self) -> io::Result<SystemTime> {
self.0.modified().map(FromInner::from_inner)
}
/// Returns the last access time of this metadata.
///
/// The returned value corresponds to the `atime` field of `stat` on Unix
/// platforms and the `ftLastAccessTime` field on Windows platforms.
///
/// Note that not all platforms will keep this field update in a file's
/// metadata, for example Windows has an option to disable updating this
/// time when files are accessed and Linux similarly has `noatime`.
///
/// # Errors
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
#[unstable(feature = "fs_time", issue = "31399")]
pub fn accessed(&self) -> io::Result<SystemTime> {
self.0.accessed().map(FromInner::from_inner)
}
/// Returns the creation time listed in the this metadata.
///
/// The returned value corresponds to the `birthtime` field of `stat` on
/// Unix platforms and the `ftCreationTime` field on Windows platforms.
///
/// # Errors
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
#[unstable(feature = "fs_time", issue = "31399")]
pub fn created(&self) -> io::Result<SystemTime> {
self.0.created().map(FromInner::from_inner)
}
}
impl AsInner<fs_imp::FileAttr> for Metadata {
@ -2468,4 +2515,24 @@ fn create_dir_all_with_junctions() {
assert!(link.is_dir());
assert!(d.exists());
}
#[test]
fn metadata_access_times() {
let tmpdir = tmpdir();
let b = tmpdir.join("b");
File::create(&b).unwrap();
let a = check!(fs::metadata(&tmpdir.path()));
let b = check!(fs::metadata(&b));
assert_eq!(check!(a.accessed()), check!(a.accessed()));
assert_eq!(check!(a.modified()), check!(a.modified()));
assert_eq!(check!(b.accessed()), check!(b.modified()));
if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
check!(a.created());
check!(b.created());
}
}
}

View File

@ -22,6 +22,7 @@
use sync::Arc;
use sys::fd::FileDesc;
use sys::platform::raw;
use sys::time::SystemTime;
use sys::{cvt, cvt_r};
use sys_common::{AsInner, FromInner};
@ -86,6 +87,67 @@ pub fn file_type(&self) -> FileType {
}
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
// FIXME: update SystemTime to store a timespec and don't lose precision
impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timeval {
tv_sec: self.stat.st_mtime,
tv_usec: (self.stat.st_mtime_nsec / 1000) as libc::suseconds_t,
}))
}
pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timeval {
tv_sec: self.stat.st_atime,
tv_usec: (self.stat.st_atime_nsec / 1000) as libc::suseconds_t,
}))
}
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timeval {
tv_sec: self.stat.st_birthtime,
tv_usec: (self.stat.st_birthtime_nsec / 1000) as libc::suseconds_t,
}))
}
}
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timespec {
tv_sec: self.stat.st_mtime,
tv_nsec: self.stat.st_mtime_nsec as libc::c_long,
}))
}
pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timespec {
tv_sec: self.stat.st_atime,
tv_nsec: self.stat.st_atime_nsec as libc::c_long,
}))
}
#[cfg(any(target_os = "bitrig",
target_os = "freebsd",
target_os = "openbsd"))]
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timespec {
tv_sec: self.stat.st_birthtime,
tv_nsec: self.stat.st_birthtime_nsec as libc::c_long,
}))
}
#[cfg(not(any(target_os = "bitrig",
target_os = "freebsd",
target_os = "openbsd")))]
pub fn created(&self) -> io::Result<SystemTime> {
Err(io::Error::new(io::ErrorKind::Other,
"creation time is not available on this platform \
currently"))
}
}
impl AsInner<raw::stat> for FileAttr {
fn as_inner(&self) -> &raw::stat { &self.stat }
}

View File

@ -146,6 +146,12 @@ pub fn sub_duration(&self, other: &Duration) -> SystemTime {
}
}
impl From<libc::timeval> for SystemTime {
fn from(t: libc::timeval) -> SystemTime {
SystemTime { t: t }
}
}
impl PartialEq for SystemTime {
fn eq(&self, other: &SystemTime) -> bool {
self.t.tv_sec == other.t.tv_sec && self.t.tv_usec == other.t.tv_usec
@ -282,6 +288,12 @@ pub fn sub_duration(&self, other: &Duration) -> SystemTime {
}
}
impl From<libc::timespec> for SystemTime {
fn from(t: libc::timespec) -> SystemTime {
SystemTime { t: Timespec { t: t } }
}
}
impl fmt::Debug for SystemTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SystemTime")

View File

@ -196,9 +196,9 @@ pub trait MetadataExt {
#[stable(feature = "metadata_ext", since = "1.1.0")]
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 creation_time(&self) -> u64 { self.as_inner().created_u64() }
fn last_access_time(&self) -> u64 { self.as_inner().accessed_u64() }
fn last_write_time(&self) -> u64 { self.as_inner().modified_u64() }
fn file_size(&self) -> u64 { self.as_inner().size() }
}

View File

@ -20,6 +20,7 @@
use slice;
use sync::Arc;
use sys::handle::Handle;
use sys::time::SystemTime;
use sys::{c, cvt};
use sys_common::FromInner;
@ -421,12 +422,28 @@ pub fn file_type(&self) -> FileType {
FileType::new(self.data.dwFileAttributes, self.reparse_tag)
}
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) }
pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(self.data.ftLastWriteTime))
}
fn to_u64(&self, ft: &c::FILETIME) -> u64 {
(ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32)
pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(self.data.ftLastAccessTime))
}
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(self.data.ftCreationTime))
}
pub fn modified_u64(&self) -> u64 {
to_u64(&self.data.ftLastWriteTime)
}
pub fn accessed_u64(&self) -> u64 {
to_u64(&self.data.ftLastAccessTime)
}
pub fn created_u64(&self) -> u64 {
to_u64(&self.data.ftCreationTime)
}
fn is_reparse_point(&self) -> bool {
@ -434,6 +451,10 @@ fn is_reparse_point(&self) -> bool {
}
}
fn to_u64(ft: &c::FILETIME) -> u64 {
(ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32)
}
impl FilePermissions {
pub fn readonly(&self) -> bool {
self.attrs & c::FILE_ATTRIBUTE_READONLY != 0

View File

@ -166,6 +166,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
impl From<c::FILETIME> for SystemTime {
fn from(t: c::FILETIME) -> SystemTime {
SystemTime { t: t }
}
}
fn dur2intervals(d: &Duration) -> i64 {
d.as_secs().checked_mul(INTERVALS_PER_SEC).and_then(|i| {
i.checked_add(d.subsec_nanos() as u64 / 100)

View File

@ -16,6 +16,7 @@
use fmt;
use ops::{Add, Sub};
use sys::time;
use sys_common::FromInner;
#[stable(feature = "time", since = "1.3.0")]
pub use self::duration::Duration;
@ -227,6 +228,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
impl FromInner<time::SystemTime> for SystemTime {
fn from_inner(time: time::SystemTime) -> SystemTime {
SystemTime(time)
}
}
#[cfg(test)]
mod tests {
use super::{Instant, SystemTime, Duration, UNIX_EPOCH};