Skip to content

Instantly share code, notes, and snippets.

@ben-cohen
Created February 19, 2025 20:01
Show Gist options
  • Select an option

  • Save ben-cohen/b9b8662f2abbe85db7646653913a9e44 to your computer and use it in GitHub Desktop.

Select an option

Save ben-cohen/b9b8662f2abbe85db7646653913a9e44 to your computer and use it in GitHub Desktop.
Show offsets of holes and data in a possibly sparse file on Linux
/*
* sparsedump: Show offsets of holes and data in a possibly sparse file on Linux
*
* Compile using:
* gcc -o sparsedump sparsedump.c -ggdb -Wall
*
* Ben Cohen, February 2025.
*/
/*
* Test cases:
* echo XXX > W
*
* truncate -s 10000000 X
*
* truncate -s 10000000 Y
* echo XXX >> Y
* truncate -s 20000000 Y
* echo XXX >> Y
*
* echo XXX >> Z
* truncate -s 10000000 Z
* echo XXX >> Z
* truncate -s 20000000 Z
*
* Output:
* $ ./sparsedump W
* OFFSET WHAT
* ------------------ ----
* 0x0000000000000000 DATA
* 0x0000000000000004 EOF
* $ ./sparsedump X
* OFFSET WHAT
* ------------------ ----
* 0x0000000000000000 HOLE
* 0x0000000000989680 EOF
* $ ./sparsedump Y
* OFFSET WHAT
* ------------------ ----
* 0x0000000000000000 HOLE
* 0x0000000000989000 DATA
* 0x000000000098a000 HOLE
* 0x0000000001312000 DATA
* 0x0000000001312d04 EOF
* $ ./sparsedump Z
* OFFSET WHAT
* ------------------ ----
* 0x0000000000000000 DATA
* 0x0000000000001000 HOLE
* 0x0000000000989000 DATA
* 0x000000000098a000 HOLE
* 0x0000000001312d00 EOF
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
off_t lseek_checked(int fd, off_t offset, int whence)
{
off_t result = lseek(fd, offset, whence);
if (errno == 0
|| (errno == ENXIO && (whence == SEEK_HOLE || whence == SEEK_DATA)))
{
return result;
}
perror("lseek");
exit(1);
}
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s <file>\n", argv[0]);
exit(1);
}
int fd = open(argv[1], O_RDONLY);
if (fd < 0)
{
perror("couldn't open file");
exit(1);
}
off_t end_of_file = lseek_checked(fd, 0, SEEK_END);
printf("OFFSET WHAT\n");
printf("------------------ ----\n");
if (lseek_checked(fd, 0, SEEK_HOLE) == 0)
{
printf("0x0000000000000000 HOLE\n");
}
off_t current_offset = 0;
bool looking_for_data = true;
while (true)
{
int whence = looking_for_data ? SEEK_DATA : SEEK_HOLE;
char *what = looking_for_data ? "DATA" : "HOLE";
current_offset = lseek_checked(fd, current_offset, whence);
if (current_offset == end_of_file || errno == ENXIO)
{
printf("0x%016lx EOF\n", end_of_file);
exit(0);
}
printf("0x%016lx %s\n", current_offset, what);
looking_for_data = !looking_for_data;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment