Rust
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Ownership and Borrowing
-
Section 4: Structuring Data
-
Section 5: Collections and Error Handling
-
Section 6: Traits and Generics
-
Section 7: Concurrency
-
Section 8: Building for the Web
-
Section 9: Memory and Performance
-
Section 10: More Standard Library and Ecosystem
-
Section 11: Advanced Rust
-
Section 12: Rust for Systems and WebAssembly
-
Section 13: Tooling and Best Practices
-
Section 14: Data Structures and Algorithms in Rust
-
Section 15: Practical Projects
-
Section 16: Interview Practice
-
Section 17: std::collections In Depth
-
Section 18: std::io and std::fs In Depth
-
Section 19: std::net
-
Section 20: std::option and std::result In Depth
-
Section 21: std::iter In Depth
-
Section 22: std::sync In Depth
-
Section 23: std::string and std::str
-
Section 24: Cargo and Crates.io Ecosystem
-
Section 25: Popular Crates Ecosystem
-
Section 26: Rust Memory Model Deep Dive
-
Section 27: More Practice Exercises
-
Section 28: More Interview Practice
-
Section 29: Async Rust Deep Dive
-
Section 30: Tokio Ecosystem In Depth
-
Section 31: Error Handling Ecosystem Deep Dive
-
Section 32: Serde In Depth
-
Section 33: Web Development with Rust Deep Dive
-
Section 34: Database Access Ecosystem
-
Section 35: Rust for Embedded Systems Deep Dive
-
Section 36: Rust Macros In Depth
-
Section 37: Advanced Trait System
-
Section 38: Unsafe Rust In Depth
-
Section 39: Rust CLI Development
-
Section 40: Testing Ecosystem Deep Dive
-
Section 41: WebAssembly Deep Dive
-
Section 42: Rust Design Patterns
-
Section 43: More Data Structures in Rust
-
Section 44: Final Practice Projects
-
Section 45: Rust Performance Optimization
-
Section 46: Rust Ecosystem Tooling
-
Section 47: More Interview and Review
102: File Permissions and Metadata
Think of a file on your hard drive like a physical package delivered to your door. The "content" of the file is what's inside the box—the actual product you ordered. But the box itself has a shipping label. That label tells you who sent it, how much it weighs, when it was mailed, and maybe a warning that says "Fragile" or "Do Not Open Until December."
In Rust, the content is the data you read or write, but the metadata is that shipping label. It's data about the data. Permissions are like the security seal on that box; they determine if you're allowed to open it, change what's inside, or if you're just allowed to look at the label and walk away.
Peeking at the Shipping Label
To get a handle on a file's metadata, we use std::fs::metadata. I usually use this when I need to verify a file exists or check its size before trying to load a massive dataset into memory—because trusting a user's input on file size is a great way to crash your program with an "out of memory" error.
use std::fs;
fn main() -> std::io::Result<()> {
let metadata = fs::metadata("config.toml")?;
println!("File size: {} bytes", metadata.len());
println!("Is it a directory? {}", metadata.is_dir());
println!("Last modified: {:?}", metadata.modified()?);
Ok(())
}
Notice that fs::metadata returns a Metadata struct. It's a lightweight call; you aren't opening the file itself, just asking the operating system for the info it already keeps in its index.
Changing the Rules of Access
Now, let's talk about permissions. In a professional environment, you'll often encounter scenarios where you want to protect a file from being accidentally overwritten by another part of your program or by a user. The most common operation in the Rust standard library for this is toggling the "read-only" status.
I remember a project where I wrote a setup script that generated a secrets.key file. If that file gets modified by a rogue script later, the whole system breaks. The fix? Set it to read-only immediately after creation.
use std::fs;
fn lock_file(path: &str) -> std::io::Result<()> {
let mut perms = fs::metadata(path)?.permissions();
// Make the file read-only
perms.set_readonly(true);
fs::set_permissions(path, perms)?;
Ok(())
}
Here's the trick: permissions() returns a Permissions object, but that object is just a snapshot. Changing perms.set_readonly(true) doesn't actually touch the disk. You have to pass that modified object back into fs::set_permissions to actually commit the change to the filesystem. It's a two-step dance: read the current state, modify the state in memory, then write the state back.
The OS Divide
One thing I should warn you about: permissions are a bit of a wildcard because they depend on the operating system. set_readonly is cross-platform and works pretty reliably. However, if you need to do something more granular—like setting specific Unix "chmod" bits (read/write/execute for owner/group/others)—you'll need to dive into the std::os::unix::fs::PermissionsExt trait.
Don't worry about that for now unless you're building a system tool specifically for Linux or macOS. For most application-level Rust, sticking to the standard Permissions methods is the safest bet to keep your code portable.
📋 Practical Task
Build a "Config Guard" Utility
Your task is to create a small utility that manages a configuration file named settings.conf. The program should follow this specific logic:
- First, create a file named
settings.confand write the text "version=1.0" into it. - Once written, use
fs::set_permissionsto make the file read-only. - Attempt to append the text "\nauthor=rust_mentor" to the same file.
- Use a
matchblock orif letto catch the error from the append attempt and print: "Access Denied: The configuration is locked!" - Finally, change the permissions back to writable and successfully append the text.
This will prove you can move between reading metadata, modifying permissions, and handling the resulting I/O errors when those permissions are enforced.
There are no comments for now.