diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index df5741d00a2c1..e91e808c5489a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -348,6 +348,41 @@ impl File { inner: self.inner.duplicate()? }) } + + /// Changes the permissions on the underlying file. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `fchmod` function on Unix and + /// the `SetFileInformationByHandle` function on Windows. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: ../io/index.html#platform-specific-behavior + /// + /// # Errors + /// + /// This function will return an error if the user lacks permission change + /// attributes on the underlying file. It may also return an error in other + /// os-specific unspecified cases. + /// + /// # Examples + /// + /// ``` + /// #![feature(set_permissions_atomic)] + /// # fn foo() -> std::io::Result<()> { + /// use std::fs::File; + /// + /// let file = File::open("foo.txt")?; + /// let mut perms = file.metadata()?.permissions(); + /// perms.set_readonly(true); + /// file.set_permissions(perms)?; + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "set_permissions_atomic", issue="37916")] + pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { + self.inner.set_permissions(perm.0) + } } impl AsInner for File { @@ -2469,6 +2504,24 @@ mod tests { check!(fs::set_permissions(&file, p)); } + #[test] + fn fchmod_works() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let file = check!(File::create(&path)); + let attr = check!(fs::metadata(&path)); + assert!(!attr.permissions().readonly()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(file.set_permissions(p.clone())); + let attr = check!(fs::metadata(&path)); + assert!(attr.permissions().readonly()); + + p.set_readonly(false); + check!(file.set_permissions(p)); + } + #[test] fn sync_doesnt_kill_anything() { let tmpdir = tmpdir(); diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0b43fd2ac8c4d..9ee0458b5da36 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -526,6 +526,11 @@ impl File { pub fn fd(&self) -> &FileDesc { &self.0 } pub fn into_fd(self) -> FileDesc { self.0 } + + pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { + cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; + Ok(()) + } } impl DirBuilder { diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index dfc998b88e37f..1a563127f7f06 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -389,6 +389,15 @@ pub enum FILE_INFO_BY_HANDLE_CLASS { MaximumFileInfoByHandlesClass } +#[repr(C)] +pub struct FILE_BASIC_INFO { + pub CreationTime: LARGE_INTEGER, + pub LastAccessTime: LARGE_INTEGER, + pub LastWriteTime: LARGE_INTEGER, + pub ChangeTime: LARGE_INTEGER, + pub FileAttributes: DWORD, +} + #[repr(C)] pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: LARGE_INTEGER, diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 98fd15f863ba1..7d7d78bbd8730 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -417,6 +417,24 @@ impl File { Ok(PathBuf::from(OsString::from_wide(subst))) } } + + pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { + let mut info = c::FILE_BASIC_INFO { + CreationTime: 0, + LastAccessTime: 0, + LastWriteTime: 0, + ChangeTime: 0, + FileAttributes: perm.attrs, + }; + let size = mem::size_of_val(&info); + cvt(unsafe { + c::SetFileInformationByHandle(self.handle.raw(), + c::FileBasicInfo, + &mut info as *mut _ as *mut _, + size as c::DWORD) + })?; + Ok(()) + } } impl FromInner for File {