The metadata that says no
Lesson 7-3 showed that every file carries metadata. One piece of it, permissions, is the gatekeeper: it tells the OS who may do what with the file, and the OS checks it on every open. You will collide with permissions in your first weeks of real work — a script that fails with PermissionError, a downloaded tool that "won't run" until chmod +x, an SSH key that ssh refuses to use because it is readable by others. This lesson is so those moments take seconds instead of an afternoon.
On macOS and Linux, each file stores three permission flags for three audiences:
- Flags: r (read the bytes), w (write/change them), x (execute the file as a program).
- Audiences: the file's owner, the file's group (a named set of users), and others (everyone else).
That is 9 yes/no switches per file, and the kernel consults them before your code sees a single byte. A denied check surfaces in Python as the PermissionError exception — the request crossed into the OS, and the OS said no.
Code exercise · python
Run this. os.chmod sets a file's permission bits; 0o400 means "owner may read, and nothing else is allowed". stat.filemode renders the 9 switches the way ls -l does. The write attempt then fails with PermissionError before a single byte moves.
Reading and writing the numbers
Permissions are usually written as three octal (base-8) digits, one per audience, because each digit packs the three flags as a sum: r = 4, w = 2, x = 1. So 7 = rwx (4+2+1), 6 = rw-, 5 = r-x, 4 = r--, 0 = ---. Python spells octal with the 0o prefix, the same idea as 0b and 0x from lesson 2-1. The combinations you will actually type:
| Mode | Meaning | Typical use |
|---|---|---|
755 | owner rwx, everyone else r-x | programs and scripts |
644 | owner rw-, everyone else r-- | ordinary data files |
600 | owner rw-, no one else anything | private config, credentials |
400 | owner read-only | SSH private keys |
In the terminal, the tool is chmod (change mode): chmod 755 deploy.sh, or the shortcut chmod +x tool.sh to switch on execute for everyone. The execute bit is why a freshly written script answers Permission denied when you try to run it: the shell asked the OS to execute a file whose x switches are off.
One honest caveat: the root user (the administrator account the OS itself uses) bypasses these checks. Permissions protect against accidents and other users, not against whoever owns the machine.
Code exercise · python
Your turn. Create "tool.sh" containing "echo hi\n", then use os.chmod to give it mode 755 (owner rwx, group and others r-x) and print its filemode string. This is exactly what chmod +x does when you make a script runnable.
Quiz
You clone a project and run ./deploy.sh, and the shell answers "Permission denied". The file exists and you can read it with cat. What is going on, and what fixes it?