How to List and Analyze File Data Blocks on ext3 Filesystem in Linux


5 views

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.