ismile@portfolio:~$ cat notes/0003-linux-for-backend-engineers-part-2.md
Linux for Backend Engineers Part 2
Linux for Backend Engineers
- Part 1: The Foundation
- Part 2: Files, Filesystems, and Permissions ← current
- Part 3: Processes and Threads
- Part 4: Memory Management
- Part 5: Signals and Communication
- Part 6: IPC, Networking, and Containers
6. Everything Is a File: The Linux I/O Model
Linux uses a clever trick; it pretends that almost everything is a file. Your documents, folders, keyboard, hard drive, and even information about your CPU appear as files in one giant tree starting at / (the root).
| "File" | What it really is |
|---|---|
/etc/hosts |
Plain text configuration file |
/dev/sda |
Physical hard drive interface |
/dev/null |
"The Void" (discards all data written to it) |
/proc/cpuinfo |
Live info about your CPU (generated by the kernel on the fly) |
/proc/1234/ |
Process #1234's information |
| A TCP socket | File descriptor mapped to a TCP/UDP network connection |
Because everything is a file, you can use the same simple commands (cat, ls, grep) to explore hardware, processes, and network connections.
Try This: Everything Is a File
# Inspect your CPU model
cat /proc/cpuinfo | grep "model name" | head -1
# Read current memory usage
cat /proc/meminfo | head -5
# Inspect metadata for your active shell process ($$ returns current PID)
cat /proc/$$/status | head -10
# Write output directly to the void
echo "disappear" > /dev/null6.1 File Types
In Linux, everything is a file, but there are different types:
| Type | Symbol in ls -l |
Description |
|---|---|---|
| Regular file | - |
Standard data (text files, compiled binaries, images) |
| Directory | d |
Container for other files |
| Symbolic link | l |
Shortcut file pointing to another path |
| Pipe | p |
Named pipe (FIFO), Inter-process communication pipe |
| Socket | s |
Unix domain socket |
🎯 Backend Context (Node.js): When inspecting file metadata using
fs.stat(path), the resultingStatsobject provides methods likestats.isFile(),stats.isDirectory(),stats.isSymbolicLink(), andstats.isSocket()to check these types programmatically.
6.2 Filesystem Hierarchy Standard (FHS)
Unlike Windows (C:, D:), Linux has a single unified tree starting at the root directory: /. Every file, directory, and mounted storage device lives somewhere under /.
| Directory | What Lives Here | Example |
|---|---|---|
/bin |
Essential user commands (available even in single-user mode) | ls, cp, mv, cat |
/sbin |
System binaries - admin/repair tools (usually root-only) | fdisk, mkfs, iptables |
/etc |
Configuration files - system-wide settings | /etc/apt/sources.list, /etc/ssh/sshd_config |
/var |
Variable data - files that change constantly | logs (/var/log), spool (/var/spool), temp (/var/tmp) |
/proc |
Virtual filesystem - kernel internals as files | /proc/cpuinfo, /proc/meminfo, /proc/[PID]/ |
/dev |
Device files - hardware interfaces | /dev/sda (first hard drive), /dev/tty (terminal) |
/home |
User home directories | /home/alice/documents/ |
/root |
Root user's home directory (not under /home) |
/root/.bashrc |
/usr |
User system resources - most software lives here | /usr/bin/, /usr/lib/, /usr/share/ |
/tmp |
Temporary files (cleared on reboot) | programs storing scratch data |
💡 Pro Tip: If you ever get lost exploring the filesystem, run
man hierin your terminal to read the official documentation on the layout.
7. Inodes: The Real Identity of a File
A filename is just a label. The real file is an inode, a data structure containing:
- Data blocks (the actual content)
- Inode (metadata: size, permissions, timestamps, pointers to data blocks)
- Directory entry (maps a filename to an inode number)
Directory entry: "report.txt" → Inode #49201
Directory entry: "copy.txt" → Inode #49201 (hard link)Hard Links vs. Symbolic Links
- Hard link: Another directory entry pointing to the same inode. Deleting the original does not delete the data while any link remains.
- Symbolic Link (Symlink): Creates a special file that contains the text path to another file. If the original file moves or is deleted, the symlink breaks.
# Create a test environment
cd ~/linux-practice
echo "original text" > original.txt
ln original.txt hard.txt # Hard link (Shares same Inode)
ln -s original.txt soft.txt # Soft link (Points to path)
# Check Inode numbers (-i flag)
ls -li original.txt hard.txt soft.txt
# Remove original file and check access
rm original.txt
cat hard.txt # Still works! Inode count is > 0
cat soft.txt # Error: No such file or directory (Broken link)🎯 Backend Context (Node.js):
fs.stat()resolves symbolic links and returns stats for the target file. To inspect a symlink itself, usefs.lstat().- Deleting a file in Node.js (
fs.unlink()) decrements the link count on the target Inode. The data blocks are only physically freed when the total link count reaches0and no active processes hold an open file descriptor to it.
8. The Linux Security Model: Permissions
- rwx r-- r-- 1 alice staff 1024 May 1 12:00 file.txt
│ │││ │││ │││
│ │││ │││ └┴┴─ Others
│ │││ └┴┴───── Group
│ └┴┴───────── User (Owner)
└───────────── File Type
File Type:
- Regular file
d Directory
l Symbolic link
Permissions:
r = Read
w = Write
x = Execute
- = No permissionEvery file has:
- Owner (user)
- Group
- Permissions for user, group, and others: read (
r), write (w), execute (x).
Example: -rw-r--r-- 1 alice staff 1024 May 1 12:00 file.txt
- Owner
alicecan read and write. - Group
staffcan read. - Others can read.
🎯 Backend Context (Node.js): Whenever your Node process attempts an I/O operation, the OS kernel evaluates the process's effective User ID (UID) and Group ID (GID) against the file's permissions. If access is denied, Node raises an
EACCESerror. Permissions can be updated programmatically viafs.chmod()andfs.chown().
8.1 Octal Permission Calculations
While symbolic string notation (rwxr-xr-x) is easy to read, permissions in shell scripts and backend systems are often calculated as 3-digit octal numbers.
Each permission corresponds to a bit value:
| Permission | Symbol | Octal Value | Meaning for Files | Meaning for Directories |
|---|---|---|---|---|
| Read | r |
4 | View contents | List directory contents (ls) |
| Write | w |
2 | Modify contents | Add/remove files inside |
| Execute | x |
1 | Run as binary/script | Enter directory (cd) |
| None | - |
0 | No permission | No permission |
To determine the octal digit for a user category, simply add up the active permission values:
Read (4) + Write (2) + Execute (1) = 7
Read (4) + Write (2) + None (0) = 6
Read (4) + None (0) + Execute (1) = 5
Read (4) + None (0) + None (0) = 4
None (0) + None (0) + None (0) = 0
755
│││
││└── Others → Read (4) + Execute (1) = 5 (r-x)
│└─── Group → Read (4) + Execute (1) = 5 (r-x)
└──── Owner → Read (4) + Write (2) + Execute (1) = 7 (rwx)
Common Permission Patterns
| Octal | String | Owner | Group | Others | Common Use Case |
|---|---|---|---|---|---|
755 |
rwxr-xr-x |
rwx (7) |
r-x (5) |
r-x (5) |
Executable scripts, web-server directories |
644 |
rw-r--r-- |
rw- (6) |
r-- (4) |
r-- (4) |
Standard readable files (HTML, images, configs) |
700 |
rwx------ |
rwx (7) |
--- (0) |
--- (0) |
Private directories (~/.ssh), root-only tools |
600 |
rw------- |
rw- (6) |
--- (0) |
--- (0) |
Private keys, sensitive credentials (.env) |
777 |
rwxrwxrwx |
rwx (7) |
rwx (7) |
rwx (7) |
Unsafe: Full public access (avoid in production) |
🛠️ Try It Yourself: Shell Usage
Change file modes in the terminal using chmod with octal values:
# Make a deployment script executable
chmod 755 deploy.sh
# Restrict an environment file to owner read/write only
chmod 600 .env
# Inspect numeric permissions with stat
stat -c "%a %n" deploy.sh .env
# Output:
# 755 deploy.sh
# 600 .env🎯 Backend Context (Node.js): Permissions can be set programmatically using
fs.chmod(). Always use JavaScript's octal literal prefix (0o) when passing permission modes:
fs.chmod("file.txt", 0o600, (err) => {
if (err) throw err;
console.log("Permissions updated to 600 (rw-------)");
});