Created
February 19, 2025 20:01
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * 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