In Linux filesystems like ext3, files are stored across one or more data blocks on disk. Each file has an inode that contains metadata and pointers to these blocks. To examine a file's physical storage layout, we need tools that can interpret the filesystem structure.
For ext2/ext3/ext4 filesystems, debugfs
is the most reliable tool. Here's how to use it:
# First get the file's inode number
ls -i filename
# Then use debugfs to examine blocks
sudo debugfs -R "stat <inode_number>" /dev/sdX
sudo debugfs -R "blocks <inode_number>" /dev/sdX
Let's analyze "/var/log/syslog":
$ ls -i /var/log/syslog
1234567 /var/log/syslog
$ sudo debugfs -R "stat <1234567>" /dev/sda1
Inode: 1234567 Type: regular Mode: 0644 Flags: 0x80000
...
Size: 1526784 Blocks: 2992
...
$ sudo debugfs -R "blocks <1234567>" /dev/sda1
123456 123457 123458 ... [list continues]
For a more user-friendly output, use filefrag
:
sudo filefrag -v /path/to/file
This shows extents (contiguous block ranges) with their physical locations.
The block numbers shown are filesystem-level blocks (typically 4KB). To map to physical disk sectors:
# Get block size (in bytes)
sudo dumpe2fs /dev/sdX | grep "Block size"
# Convert to disk sectors (usually 512 bytes)
block_number * (fs_block_size / sector_size)
- Always unmount filesystem or ensure it's in clean state
- Root privileges required
- Results may differ for sparse, compressed, or encrypted files
- Direct access to block devices can be dangerous
For developers needing this information programmatically:
#include <sys/ioctl.h>
#include <linux/fs.h>
int fd = open("/path/to/file", O_RDONLY);
unsigned long blocks[1024];
int count = ioctl(fd, FIBMAP, blocks);
Note: FIBMAP requires CAP_SYS_RAWIO capability.
In Unix-like systems, every file is associated with an inode that contains metadata about the file. This includes pointers to the actual data blocks where the file's content is stored. You can view a file's inode number using:
ls -i filename
For ext3/ext4 filesystems, we have several tools to inspect file block allocation:
1. Using debugfs
The most reliable method is using the debugfs
utility:
sudo debugfs /dev/sdX -R "stat /path/to/file"
Replace /dev/sdX
with your actual partition. For example:
sudo debugfs /dev/sda1 -R "stat /home/user/document.txt"
2. The filefrag Command
A simpler alternative is filefrag
:
sudo filefrag -v /path/to/file
Example output:
Filesystem type is: ef53
File size of /home/user/largefile.iso is 1073741824 (262144 blocks)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 32767: 34816.. 67583: 32768:
1: 32768.. 65535: 67584.. 100351: 32768:
2: 65536.. 98303: 100352.. 133119: 32768:
3: 98304.. 131071: 133120.. 165887: 32768:
...
Here's a bash script to list blocks for multiple files:
#!/bin/bash
if [ $# -eq 0 ]; then
echo "Usage: $0 file1 [file2 ...]"
exit 1
fi
for file in "$@"; do
if [ ! -e "$file" ]; then
echo "Error: $file does not exist"
continue
fi
echo -e "\nBlock information for $file:"
sudo filefrag -v "$file" | head -n 5
done
- These commands typically require root privileges
- The output format varies between filesystem types
- For mounted filesystems, the block numbers are logical unless using raw device access
- Block sizes may vary (commonly 4KB in modern systems)
If you need to access this information programmatically in C:
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
return 1;
}
int fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
struct filefrag_range fr;
if (ioctl(fd, FIBMAP, &fr) == -1) {
perror("ioctl");
close(fd);
return 1;
}
printf("Starting block: %lu\n", fr.fmr_physical);
close(fd);
return 0;
}
Compile with gcc -o fibmap fibmap.c
and run as root.