Parse_LFS is a tool for reading and interpreting a Log-Structured File System (LFS) disk image.
It supports:
- Printing the full LFS directory tree (
ls) - Extracting and printing the contents of a file inside the LFS image (
cat)
The tool reconstructs filesystem metadata and structure by parsing Checkpoint Regions, Imaps, Inodes, and data blocks inside the image.
$ ./bin/parse_lfs ls ./sample_files/a.img
/
256 2025-04-15 19:00:18 UTC -rw------- bar.txt
0 2025-04-15 19:00:18 UTC -rw------- foo.txt
...
- Displays a hierarchical file tree starting from the root (
/) - Files are sorted alphabetically; directories appear after files at each depth
- Indentation reflects directory depth
- Uses the provided
ls_print_file()helper for consistent formatting
$ ./bin/parse_lfs cat /bar.txt ./sample_files/a.img
revised to the end of modernizing
and improving them"...
- Follows the given absolute path and outputs the file content
- Supports
.and..logically (though they do not exist in the image) - Paths must start with
/ - If the file cannot be found, the program prints:
parse_lfs error: Failed to find file.
and returns exit code 1.
LFS (Log-Structured File System) writes metadata and data in sequential log segments to optimize write performance and reduce random I/O. This project focuses on understanding how LFS organizes its structures and reconstructing filesystem information from a raw image.
LFS images contain:
- 1 KB metadata blocks (Checkpoint Region, Imap, Inode)
- 4 KB data blocks (file and directory data)
uint Image_Offset
uint Entry_Count
// repeated Entry_Count times
uint inumber_start
uint inumber_end
uint imap_disk_offset
Each entry maps a range of inumbers to the location of an Imap block.
uint Entry_Count
// repeated
uint inumber
uint inode_disk_offset
Each entry points to the location of one inode.
uint file_cursor
uint size
mode_t permissions
time_t mtime
uint Direct_Block_Count
uint direct_block_disk_offset
...
- Includes only direct block pointers (no indirects)
sizeis the actual file size—not necessarily equal to total data block space
Regular file: raw bytes Directory: sequence of entries
char name[] // ends with ',', not null-terminated
uint inumber
For example:
a,5
b,6
c,7
Entries in directories are not guaranteed to be sorted.
To find the data block for an inode:
- Read the CR and locate the Imap responsible for the inumber
- Read that Imap to find the inode’s location
- Read the inode
- Use direct block offsets to access data blocks
A practical development path:
- Parse the Checkpoint Region
- Parse each Imap listed in the CR
- Parse each referenced Inode
- Build in-memory structures for easy traversal
- Implement
ls - Implement
cat
Start with the simplest sample image (simple.img) before testing more complex cases.
./bin/parse_lfs ls <image_file>
./bin/parse_lfs cat <absolute_path> <image_file>
If the specified file cannot be found:
parse_lfs error: Failed to find file.
Program exits with code 1.
Sample tests are included:
cd tests/
./run-tests.sh
Use the -h flag for additional options.