#[stable(feature = "rust1", since = "1.0.0")]
pub struct OpenOptions(fs_imp::OpenOptions);
+/// Representation of the various timestamps on a file.
+#[derive(Copy, Clone, Debug, Default)]
+#[unstable(feature = "file_set_times", issue = "98245")]
+pub struct FileTimes(fs_imp::FileTimes);
+
/// Representation of the various permissions on a file.
///
/// This module only currently provides one bit of information,
pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
self.inner.set_permissions(perm.0)
}
+
+ /// Changes the timestamps of the underlying file.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// This function currently corresponds to the `futimens` function on Unix (falling back to
+ /// `futimes` on macOS before 10.13) and the `SetFileTime` function on Windows. Note that this
+ /// [may change in the future][changes].
+ ///
+ /// [changes]: io#platform-specific-behavior
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the user lacks permission to change timestamps on the
+ /// underlying file. It may also return an error in other os-specific unspecified cases.
+ ///
+ /// This function may return an error if the operating system lacks support to change one or
+ /// more of the timestamps set in the `FileTimes` structure.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(file_set_times)]
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// use std::fs::{self, File, FileTimes};
+ ///
+ /// let src = fs::metadata("src")?;
+ /// let dest = File::options().write(true).open("dest")?;
+ /// let times = FileTimes::new()
+ /// .set_accessed(src.accessed()?)
+ /// .set_modified(src.modified()?);
+ /// dest.set_times(times)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "file_set_times", issue = "98245")]
+ #[doc(alias = "futimens")]
+ #[doc(alias = "futimes")]
+ #[doc(alias = "SetFileTime")]
+ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+ self.inner.set_times(times.0)
+ }
}
// In addition to the `impl`s here, `File` also has `impl`s for
}
}
+impl FileTimes {
+ /// Create a new `FileTimes` with no times set.
+ ///
+ /// Using the resulting `FileTimes` in [`File::set_times`] will not modify any timestamps.
+ #[unstable(feature = "file_set_times", issue = "98245")]
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Set the last access time of a file.
+ #[unstable(feature = "file_set_times", issue = "98245")]
+ pub fn set_accessed(mut self, t: SystemTime) -> Self {
+ self.0.set_accessed(t.into_inner());
+ self
+ }
+
+ /// Set the last modified time of a file.
+ #[unstable(feature = "file_set_times", issue = "98245")]
+ pub fn set_modified(mut self, t: SystemTime) -> Self {
+ self.0.set_modified(t.into_inner());
+ self
+ }
+}
+
impl Permissions {
/// Returns `true` if these permissions describe a readonly (unwritable) file.
///
mode: mode_t,
}
+#[derive(Copy, Clone)]
+pub struct FileTimes([libc::timespec; 2]);
+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType {
mode: mode_t,
}
}
+impl FileTimes {
+ pub fn set_accessed(&mut self, t: SystemTime) {
+ self.0[0] = t.t.to_timespec().expect("Invalid system time");
+ }
+
+ pub fn set_modified(&mut self, t: SystemTime) {
+ self.0[1] = t.t.to_timespec().expect("Invalid system time");
+ }
+}
+
+struct TimespecDebugAdapter<'a>(&'a libc::timespec);
+
+impl fmt::Debug for TimespecDebugAdapter<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("timespec")
+ .field("tv_sec", &self.0.tv_sec)
+ .field("tv_nsec", &self.0.tv_nsec)
+ .finish()
+ }
+}
+
+impl fmt::Debug for FileTimes {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FileTimes")
+ .field("accessed", &TimespecDebugAdapter(&self.0[0]))
+ .field("modified", &TimespecDebugAdapter(&self.0[1]))
+ .finish()
+ }
+}
+
+impl Default for FileTimes {
+ fn default() -> Self {
+ let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ };
+ Self([omit; 2])
+ }
+}
+
impl FileType {
pub fn is_dir(&self) -> bool {
self.is(libc::S_IFDIR)
cvt_r(|| unsafe { libc::fchmod(self.as_raw_fd(), perm.mode) })?;
Ok(())
}
+
+ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+ cfg_if::cfg_if! {
+ // futimens requires macOS 10.13
+ if #[cfg(target_os = "macos")] {
+ fn ts_to_tv(ts: &libc::timespec) -> libc::timeval {
+ libc::timeval { tv_sec: ts.tv_sec, tv_usec: (ts.tv_nsec / 1000) as _ }
+ }
+ cvt(unsafe {
+ weak!(fn futimens(c_int, *const libc::timespec) -> c_int);
+ futimens.get()
+ .map(|futimens| futimens(self.as_raw_fd(), times.0.as_ptr()))
+ .unwrap_or_else(|| {
+ let timevals = [ts_to_tv(×.0[0]), ts_to_tv(×.0[1])];
+ libc::futimes(self.as_raw_fd(), timevals.as_ptr())
+ })
+ })?;
+ } else {
+ cvt(unsafe { libc::futimens(self.as_raw_fd(), times.0.as_ptr()) })?;
+ }
+ }
+
+ Ok(())
+ }
}
impl DirBuilder {
#[derive(Clone, Debug)]
pub struct OpenOptions {}
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
pub struct FilePermissions(!);
pub struct FileType(!);
}
}
+impl FileTimes {
+ pub fn set_accessed(&mut self, _t: SystemTime) {}
+ pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
impl FileType {
pub fn is_dir(&self) -> bool {
self.0
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
self.0
}
+
+ pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+ self.0
+ }
}
impl DirBuilder {
readonly: bool,
}
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {
+ accessed: Option<wasi::Timestamp>,
+ modified: Option<wasi::Timestamp>,
+}
+
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct FileType {
bits: wasi::Filetype,
}
}
+impl FileTimes {
+ pub fn set_accessed(&mut self, t: SystemTime) {
+ self.accessed = Some(t.to_wasi_timestamp_or_panic());
+ }
+
+ pub fn set_modified(&mut self, t: SystemTime) {
+ self.modified = Some(t.to_wasi_timestamp_or_panic());
+ }
+}
+
impl FileType {
pub fn is_dir(&self) -> bool {
self.bits == wasi::FILETYPE_DIRECTORY
unsupported()
}
+ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+ self.fd.filestat_set_times(
+ times.accessed.unwrap_or(0),
+ times.modified.unwrap_or(0),
+ times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM)
+ | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM),
+ )
+ }
+
pub fn read_link(&self, file: &Path) -> io::Result<PathBuf> {
read_link(&self.fd, file)
}
SystemTime(Duration::from_nanos(ts))
}
+ pub fn to_wasi_timestamp_or_panic(&self) -> wasi::Timestamp {
+ self.0.as_nanos().try_into().expect("time does not fit in WASI timestamp")
+ }
+
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
}
#[repr(C)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Default)]
pub struct FILETIME {
pub dwLowDateTime: DWORD,
pub dwHighDateTime: DWORD,
pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL;
+ pub fn SetFileTime(
+ hFile: BorrowedHandle<'_>,
+ lpCreationTime: Option<&FILETIME>,
+ lpLastAccessTime: Option<&FILETIME>,
+ lpLastWriteTime: Option<&FILETIME>,
+ ) -> BOOL;
pub fn SetLastError(dwErrCode: DWORD);
pub fn GetCommandLineW() -> LPWSTR;
pub fn GetTempPathW(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD;
attrs: c::DWORD,
}
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {
+ accessed: c::FILETIME,
+ modified: c::FILETIME,
+}
+
#[derive(Debug)]
pub struct DirBuilder;
})?;
Ok(())
}
+
+ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+ cvt(unsafe {
+ c::SetFileTime(self.as_handle(), None, Some(×.accessed), Some(×.modified))
+ })?;
+ Ok(())
+ }
+
/// Get only basic file information such as attributes and file times.
fn basic_info(&self) -> io::Result<c::FILE_BASIC_INFO> {
unsafe {
}
}
+impl FileTimes {
+ pub fn set_accessed(&mut self, t: SystemTime) {
+ self.accessed = t.into_inner();
+ }
+
+ pub fn set_modified(&mut self, t: SystemTime) {
+ self.modified = t.into_inner();
+ }
+}
+
impl FileType {
fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
FileType { attributes: attrs, reparse_tag }
use crate::fmt;
use crate::mem;
use crate::sys::c;
+use crate::sys_common::IntoInner;
use crate::time::Duration;
use core::hash::{Hash, Hasher};
}
}
+impl IntoInner<c::FILETIME> for SystemTime {
+ fn into_inner(self) -> c::FILETIME {
+ self.t
+ }
+}
+
impl Hash for SystemTime {
fn hash<H: Hasher>(&self, state: &mut H) {
self.intervals().hash(state)
use crate::fmt;
use crate::ops::{Add, AddAssign, Sub, SubAssign};
use crate::sys::time;
-use crate::sys_common::FromInner;
+use crate::sys_common::{FromInner, IntoInner};
#[stable(feature = "time", since = "1.3.0")]
pub use core::time::Duration;
SystemTime(time)
}
}
+
+impl IntoInner<time::SystemTime> for SystemTime {
+ fn into_inner(self) -> time::SystemTime {
+ self.0
+ }
+}