unix-foundations Lesson 4 20 min read

What are File Permissions and How Do I Change Them?

Read, write, execute — who can do what with your files, and why Unix cares

Reading: Linux Text: Ch. 4–5, pp. 96–155

After this lesson, you will be able to:

  • Read and interpret the 10-character permission string (e.g., rwxr-xr--)
  • Convert between symbolic (rwxr-x---) and octal (750) permission notation
  • Change permissions with chmod using both symbolic (u+x) and octal (644) modes
  • Explain the meaning of read, write, and execute for both files and directories
  • Identify common permission patterns (644 for files, 755 for executables, 700 for private)

Why Does My Script Say “Permission Denied”?

You’ve written a shell script, you try to run it with ./myscript.sh, and you get:

bash: ./myscript.sh: Permission denied

The file is right there. You can cat it. You can read every line. But you can’t run it. What’s going on?

The answer is Unix’s permission system — a security model designed in the 1970s when multiple people shared the same physical computer. It controls who can read, write, and execute every file on the system. And even though you might be the only user on your VM, permissions still matter: they affect how your programs run, how your labs get graded, and how real-world servers stay secure.

Check Your Understanding
You wrote a bash script and try to run it with ./myscript.sh, but get "Permission denied." The file exists and you can read it with cat. What's the most likely fix?
A Run sudo ./myscript.sh — you need root access
B Run chmod +x myscript.sh — the file is missing execute permission
C Rename the file to remove the .sh extension
D Move the file to your home directory
Answer: B. "Permission denied" on a script almost always means it lacks execute (x) permission. chmod +x adds execute permission. You can read the file (cat works) because you have read permission — but running it as a program requires execute permission. Using sudo would work but is overkill and a bad habit.

Understanding and Changing Permissions

The Permission Model

Every file in Unix has three pieces of ownership information:

  1. Owner (user) — the person who created the file
  2. Group — a set of users who share access
  3. Other — everyone else on the system

And for each of these three categories, there are three permissions:

Permission Letter On Files On Directories
Read r View contents List contents with ls
Write w Modify contents Create/delete files inside
Execute x Run as program Enter with cd

That’s 3 categories × 3 permissions = 9 permission bits per file.

Reading ls -l Output

Let’s create a file and look at its permissions:

touch testfile.txt
ls -l testfile.txt
-rw-r--r-- 1 student student 0 Apr  7 09:15 testfile.txt

Breaking down -rw-r--r--:

-    rw-    r--    r--
│    │      │      │
│    │      │      └── Other: read only
│    │      └── Group: read only
│    └── Owner: read and write
└── File type: - = regular file, d = directory

Key Insight: “Other” does NOT mean “no one.” It means “every user on the system who isn’t the owner and isn’t in the file’s group.” On a shared server, that could be hundreds of people.

Changing Permissions with chmod

chmod (change mode) has two notations. Let’s learn both.

Symbolic notation — human-readable:

chmod u+x myscript.sh          # Add execute for owner (user)
chmod g-w myfile.txt            # Remove write for group
chmod o=  secret.txt            # Remove all permissions for other
chmod a+r readme.txt            # Add read for all (a = everyone)
chmod u=rwx,g=rx,o=r myfile     # Set exactly

The pattern is: who (u/g/o/a) + operator (+/-/=) + what (r/w/x).

Octal notation — compact and precise:

Each permission has a numeric value:

r (read)    = 4
w (write)   = 2
x (execute) = 1

Add them up for each category:

Octal Binary Permission
7 111 rwx (4+2+1)
6 110 rw- (4+2+0)
5 101 r-x (4+0+1)
4 100 r-- (4+0+0)
0 000 --- (0+0+0)

So chmod 755 myfile means:

  • Owner: 7 = rwx
  • Group: 5 = r-x
  • Other: 5 = r-x
  • Result: rwxr-xr-x

Key Insight: Octal is just binary in disguise. rwx = 111 binary = 7 octal. r-x = 101 binary = 5 octal. Once you see the pattern, converting becomes instant. Think of each rwx triplet as a 3-bit binary number.

Check Your Understanding
What permission string does chmod 641 produce?
A rw-rw---x
B rw-r----x
C rwxr--r--
D rw-r--r--
Answer: B. Break it digit by digit: 6 = rw- (4+2), 4 = r-- (4+0+0), 1 = --x (0+0+1). Result: rw-r----x. If you picked A, that's 661. If you picked D (rw-r--r--), that's 644 — you misread the last digit. Decompose each octal digit into its binary bits: 4=read, 2=write, 1=execute.
Why does this matter?

When your compiled C program won’t run and says “Permission denied,” it’s almost always a missing execute bit. When your program can’t read an input file, it’s a missing read bit. Octal notation shows up in Makefile targets, deployment scripts, and stat output — you’ll read these numbers all quarter.

Common Permission Patterns

You’ll use these constantly:

Octal String Use Case
755 rwxr-xr-x Executable programs, public directories
644 rw-r--r-- Source code, text files, configs
700 rwx------ Private directory (only you)
600 rw------- Private file (only you)
775 rwxrwxr-x Shared group directory
664 rw-rw-r-- Shared group file (Ubuntu default for new files)

Let’s Break Things (Safely)

The best way to understand permissions is to experiment. Let’s create a test environment:

mkdir ~/perm-test
cd ~/perm-test
echo "Hello from testfile" > testfile.txt
mkdir testdir
echo "Inside the directory" > testdir/inner.txt

Experiment 1: Remove read from a file

chmod u-r testfile.txt
cat testfile.txt             # Permission denied!
chmod u+r testfile.txt       # Fix it

Experiment 2: Remove execute from a directory

chmod u-x testdir
cd testdir                   # Permission denied!
ls testdir                   # Might show names but no details
cat testdir/inner.txt        # Permission denied!
chmod u+x testdir            # Fix it

The Trick: For directories, x means “traverse” or “search.” Without x, you can’t cd into the directory and you can’t access anything inside it by name — even if you know the filename. A directory with r but no x shows you names but won’t let you access them. A directory with x but no r lets you access files by name but won’t let you list them.

Experiment 3: Remove write from a directory

chmod u-w testdir
touch testdir/newfile.txt    # Permission denied!
rm testdir/inner.txt         # Permission denied!
echo "append" >> testdir/inner.txt    # This WORKS! (file write, not dir write)
chmod u+w testdir            # Fix it

Common Pitfall: Deleting a file is a directory operation, not a file operation. You need write permission on the directory to delete a file inside it — the file’s own permissions don’t matter for deletion. This surprises everyone the first time.

Check Your Understanding
A directory has permissions r-x for the owner. The owner tries to create a new file inside it with touch newfile.txt. What happens?
A The file is created successfully because the owner has read permission
B The file is created but with no permissions
C Permission denied — creating files requires write permission on the directory
D Permission denied — creating files requires execute permission on the directory
Answer: C. Creating (and deleting) files are directory-level write operations. The directory's w bit controls whether you can add or remove entries. The r bit lets you list contents, and the x bit lets you traverse into it. You need w specifically to modify what's in the directory.

Solving the “Permission Denied” Mystery

Now back to our opening question. Why couldn’t we run ./myscript.sh?

echo '#!/bin/bash' > myscript.sh
echo 'echo "Hello from script!"' >> myscript.sh
ls -l myscript.sh
-rw-r--r-- 1 student student 42 Apr  7 09:30 myscript.sh

No x permission! New files never get execute permission by default — that’s a safety feature. Fix it:

chmod u+x myscript.sh        # Or chmod 755 myscript.sh
./myscript.sh                 # Hello from script!

The umask: Why Defaults Are What They Are

The umask controls default permissions for new files. Check yours:

umask

Typical output: 0002. The umask is subtracted from the base:

  • Files base: 666 (no execute by default) → 666 - 002 = 664rw-rw-r--
  • Directories base: 777777 - 002 = 775rwxrwxr-x

From Java: In CSCD 210, file access was mostly invisible — the JVM and OS handled it. Java’s File.setReadable() exists but you probably never used it. In C and Unix, permissions are fundamental. You’ll encounter them when compiling programs (need x), reading input files (need r), and writing output files (need w). Getting “Permission denied” is one of the most common errors, and now you know how to fix it.

Checking Detailed File Info

stat testfile.txt

This shows permissions in both octal and symbolic notation, plus owner, group, size, and timestamps. Useful when ls -l doesn’t give you enough detail.

Who Am I? What Groups Am I In?

id                           # Your user ID, group ID, and all groups
groups                       # Just your group memberships
cat /etc/passwd | head -5    # All user accounts on the system

Common Pitfall: Never use chmod 777 as a quick fix. It means “anyone on this system can read, write, and execute this file.” On a shared server, that’s a security violation. On a grading server, it might let other students copy your work. Fix the specific permission that’s missing instead.

Check Your Understanding
You compile a C program and try to run it with ./myprogram, but get "Permission denied." You check with ls -l and see -rw-r--r--. What's the fix?
A chmod 777 myprogram
B chmod a+r myprogram
C sudo ./myprogram
D chmod u+x myprogram
Answer: D. The file is missing execute permission — that's what the absent x in -rw-r--r-- tells you. chmod u+x adds execute for the owner, which is the minimum needed. Option A works but gives everyone full access — a security problem. Option B adds read permission, which is already there. Option C uses root privileges to bypass the problem instead of fixing it.
Why does this matter?

In C development, gcc normally sets the execute bit on compiled output automatically. But if you’re writing shell scripts, creating test runners, or working with Makefile targets, you’ll need to set permissions yourself. Understanding the permission model prevents the “just chmod 777 everything” habit that causes real security problems on shared servers.

Recursive Changes

To change permissions on a directory and everything inside it:

chmod -R 755 myproject/

Be careful — this applies the same permissions to files and directories, which may give execute permission to files that shouldn’t have it.

Quick Check: What does chmod 640 secret.txt do?

Sets permissions to rw-r-----: owner can read and write (6 = 4+2), group can read only (4), and other has no access (0).

Quick Check: Why can you modify a file inside a directory even if the directory doesn't have write permission?

Directory write permission controls creating and deleting files in the directory. Modifying a file’s contents uses the file’s write permission, not the directory’s. These are separate operations.

Quick Check: A file has permissions r-x------. Can the owner modify it?

No. The owner has read and execute but not write (r-x). The owner would need to chmod u+w the file first. However, the owner can always change the permissions back since they own the file.


Permissions Are Your First Security Lesson

File permissions are the simplest form of access control in Unix, and they set the stage for everything else in computer security. When you set a file to 600, you’re saying “only I can see this.” When you set a directory to 755, you’re saying “everyone can browse, but only I can change things.”

These concepts scale up: server configurations, SSH keys, database access, Docker containers — they all build on this same owner/group/other model.

Next up: I/O redirection and pipes. You’ve been seeing command output on your screen, but what if you want to send it to a file? Or chain multiple commands together? That’s where Unix gets really powerful.

Big Picture: In C, you’ll use functions like fopen() that can fail with “Permission denied” if the file permissions don’t allow the requested access. Understanding permissions now means you’ll debug those errors instantly in Week 8 instead of staring at a cryptic error message.