Rust File Permissions
File permissions are the rules about who may do what with a file. Permissions are one part of that metadata.
Ask the one portable question
readonly() works on every system. A fresh file answers false:
let perms = fs::metadata("note.txt")?.permissions();
println!("readonly = {}", perms.readonly());Protect a finished file
Change the value. Then hand it back with fs::set_permissions:
let mut perms = fs::metadata("note.txt")?.permissions();
perms.set_readonly(true);
fs::set_permissions("note.txt", perms)?;
println!("readonly now = {}", fs::metadata("note.txt")?.permissions().readonly());Set the mode on Unix
PermissionsExt adds mode() and set_mode(). The mask 0o777 keeps only the nine permission bits:
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata("note.txt")?.permissions();
perms.set_mode(0o644);
fs::set_permissions("note.txt", perms)?;
println!("mode = {:o}", fs::metadata("note.txt")?.permissions().mode() & 0o777);Make a script runnable
The execute bits are the difference. 0o755 adds them for everyone:
let mut perms = fs::metadata("note.txt")?.permissions();
perms.set_mode(0o755);
fs::set_permissions("note.txt", perms)?;
println!("mode = {:o}", fs::metadata("note.txt")?.permissions().mode() & 0o777);Read the digits
Each octal digit is one group of three bits. 7 means read, write, and execute. 5 means read and execute:
let mode = 0o755;
println!("owner = {}", (mode >> 6) & 0o7);
println!("group = {}", (mode >> 3) & 0o7);
println!("others = {}", mode & 0o7);Example
use std::fs;
#[cfg(unix)]
fn mode_now(path: &str) -> String {
use std::os::unix::fs::PermissionsExt;
format!("{:o}", fs::metadata(path).unwrap().permissions().mode() & 0o777)
}
#[cfg(not(unix))]
fn mode_now(_path: &str) -> String {
String::from("n/a")
}
fn main() {
fs::write("report.txt", "final numbers").expect("could not write the report");
println!("readonly = {}", fs::metadata("report.txt").unwrap().permissions().readonly());
let mut perms = fs::metadata("report.txt").unwrap().permissions();
perms.set_readonly(true);
fs::set_permissions("report.txt", perms).expect("could not protect the report");
println!("readonly = {}", fs::metadata("report.txt").unwrap().permissions().readonly());
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata("report.txt").unwrap().permissions();
perms.set_mode(0o600);
fs::set_permissions("report.txt", perms).expect("could not set the mode");
println!("mode = {}", mode_now("report.txt"));
let mut perms = fs::metadata("report.txt").unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions("report.txt", perms).expect("could not set the mode");
println!("mode = {}", mode_now("report.txt"));
}
let mut perms = fs::metadata("report.txt").unwrap().permissions();
perms.set_readonly(false);
fs::set_permissions("report.txt", perms).expect("could not unprotect the report");
fs::remove_file("report.txt").expect("could not clean up");
}Key points
- Use metadata.permissions() to read a file's permissions as a Permissions value
- Use permissions.readonly() for the one question every system answers the same way
- Use set_readonly(true) plus fs::set_permissions to protect a finished file from changes
- On Linux and Mac, permissions are mode bits: read, write, and execute, for the owner, the group, and everyone else
- The mode is written in octal: 0o644 is a normal data file, and 0o755 is a runnable script
- File permissions state who may do what with a file.
In this example, the report starts writable. The program prints readonly = false. Then it protects the file, and the same question answers true. The Unix block then sets the mode twice. First 0o600, so only the owner can read and write. Then 0o755, the script setting. On Windows the mode lines print n/a instead. The last steps unprotect the file, so the cleanup can delete it.
Note
std::os::unix::fs::PermissionsExt reads and sets the raw mode.
Windows has no mode bits.
So that trait exists on Unix only.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What does the octal mode 0o755 allow the file's owner to do?