🎓 A1Learner
🔍

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?