#include <stdio.h> /* printf */
#include <sys/ioctl.h> /* ioctl */
#include <sys/stat.h> /* stat, fstat */
#include <fcntl.h> /* open, O_RDONLY */
#include <linux/fs.h> /* FIBMAP, FIGETBSZ */
#include <assert.h> /* assert */
#include <string.h> /* strerror */
#include <errno.h> /* errno */
#include <unistd.h> /* close */
static int SHOW_BLOCK_NUM = 0; /* Number the blocks */
static int PRINT_HEADER = 0; /* Show summary at the beginning */
static int PRINT_FOOTER = 0; /* Show summary at the end */
static int SHOW_FRAGMENTS = 1; /* Indicates fragmentation with a '*' */
int main(int argc, char **argv)
{
int fd; /* The open file descriptor */
int retval; /* Return value of system calls */
int blocksize; /* The logical size of the block */
struct stat st; /* Structure retrieved from fstat */
const char *filename; /* Name of file to retrieve the blocks */
unsigned long i; /* Loop counter */
unsigned long block; /* The block number retrieved from ioctl */
unsigned long bcount; /* The number of blocks in the file */
unsigned long previous = 0; /* Used to determine if there's fragmentation */
/* There is 1 required argument to the program */
if (argc < 2)
{
printf("Usage: %s <filename>\n", argv[0]);
return 1;
}
/* Open the specified file for read-only */
filename = argv[1];
fd = open(filename, O_RDONLY);
if (fd == -1)
{
perror("open");
return 2;
}
/* Get the block size of the filesystem where the file resides */
retval = ioctl(fd, FIGETBSZ, &blocksize);
if (retval == -1)
{
perror("ioctl");
return 3;
}
/* Get all of the info (metadata) about the file */
retval = fstat(fd, &st);
if (retval == -1)
{
perror("fstat");
return 4;
}
/* Account for partial blocks */
bcount = (st.st_size + blocksize - 1) / blocksize;
if (PRINT_HEADER)
printf("File: %s Size (bytes): %lu Blocks: %lu Blocksize: %i\n",
filename, (unsigned long)st.st_size, bcount, blocksize);
/* Show block numbers (block ID/address) for each block */
for(i = 0; i < bcount; i++)
{
block = i;
/* Get next block ID */
retval = ioctl(fd, FIBMAP, &block);
if (retval == -1)
{
printf("FIBMAP ioctl failed: %s\n", strerror(errno));
return 5;
}
if (SHOW_BLOCK_NUM)
printf("%3lu %10lu", i + 1, block);
else
printf("%lu", block);
/* Show non-contiguous (fragmented) blocks with an asterisk */
/* This makes it easier to identify extents and fragmentation */
if (SHOW_FRAGMENTS)
if (previous && (block - previous - 1))
printf("*");
printf("\n");
previous = block;
}
if (PRINT_FOOTER)
printf("File: %s Size (bytes): %lu Blocks: %lu Blocksize: %i\n",
filename, (unsigned long)st.st_size, bcount, blocksize);
close(fd);
return 0;
}