A small C learning project built around implementing parts of ls, specifically -a and -l, to understand how Unix directory listing and file metadata actually work under the hood.
This repo is intentionally narrow in scope. The focus is not on recreating all of ls, but on learning the mechanics behind:
- traversing directories with
opendirandreaddir - understanding how directory entries relate to lower-level concepts like
getdents - reading file metadata with
lstat - decoding
st_modeusing bit operations - turning raw mode bits into human-readable Unix permission strings
- resolving UID/GID into owner and group names
- formatting timestamps and sizes for a long listing view
This project is a learning attempt in C.
The goal was to move beyond using shell tools as black boxes and instead understand what happens when a program like ls:
- reads a directory
- decides whether to hide dotfiles
- fetches metadata for each entry
- parses permission bits
- prints a long-format listing
It is best read as a systems programming exercise rather than a finished utility.
The repository centers on one source file:
ls.c— a minimalls-style implementation
Currently supported flags:
-ato include hidden entries-lto print a long-format view
Current long-format output includes:
- file type indicator
- rwx permissions
- owner
- group
- size
- last modified time
- filename
.
├── ls.c
└── README.md
The program opens a directory with opendir and iterates entries using readdir. This is the user-space interface typically used for directory listing, and it helps build intuition for lower-level directory entry retrieval such as getdents.
For long-format output, the program calls lstat on each directory entry to retrieve file metadata from the kernel, including mode bits, ownership, file size, and modification time.
One of the main learning goals here is understanding how Unix permissions are encoded in st_mode.
The code manually checks:
- file type bits
- user read/write/execute bits
- group read/write/execute bits
- other read/write/execute bits
and converts them into a string such as:
-rwxr-xr-x
This is the core bitmasking exercise in the project.
The program maps:
st_uidto a username usinggetpwuidst_gidto a group name usinggetgrgid
This is part of understanding how raw metadata becomes human-readable command output.
Compile with:
makeDirect compilation is also fine:
cc -D_DEFAULT_SOURCE -Wall -Wextra -Wpedantic -std=c11 ls.c -o lsmake run
./ls
./ls -a
./ls -l
./ls -la
./ls -la /some/path- learning C through direct use of POSIX filesystem APIs
- understanding the relationship between directory entries and file metadata
- working with structs like
direntandstat - using bitwise checks to decode permissions
- translating low-level system data into a CLI interface
This is still a learning implementation, so some things are intentionally incomplete:
- only
-aand-lare implemented - output formatting is simple and tab-based
- permission parsing does not yet cover every special case
- there is no sorting layer
- build/test automation is not present yet
If this evolves further, the most useful next steps would be:
- improve formatting to more closely match real
ls - handle special permission bits like
setuid,setgid, and sticky bit - support more file types in the permission prefix
- add a
Makefile - compile cleanly under stricter feature-macro and warning settings
- add tests for option parsing and output behavior
lsbtw is a compact C learning project about implementing a small part of ls to understand directory traversal, metadata inspection, and Unix permission parsing at the systems level.