Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a method for setting permissions directly on an open file. #37886

Merged
merged 1 commit into from
Nov 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/libstd/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<fs_imp::File> for File {
Expand Down Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions src/libstd/sys/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions src/libstd/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
18 changes: 18 additions & 0 deletions src/libstd/sys/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<c::HANDLE> for File {
Expand Down