diff options
Diffstat (limited to 'lib/extent-map.c')
-rw-r--r-- | lib/extent-map.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/lib/extent-map.c b/lib/extent-map.c new file mode 100644 index 0000000..b698fa1 --- /dev/null +++ b/lib/extent-map.c @@ -0,0 +1,41 @@ +#include <errno.h> /* for errno */ +#include <error.h> /* for error(3gnu) */ +#include <linux/fiemap.h> /* for all of the other fiemap stuff */ +#include <linux/fs.h> /* for FS_IOC_FIEMAP */ +#include <stdlib.h> /* for calloc(3p), exit(3p), EXIT_SUCCESS, EXIT_FAILURE */ +#include <sys/ioctl.h> /* for ioctl(2) */ +#include <unistd.h> /* for sysconf(3p), _SC_PAGESIZE */ + +#include "extent-map.h" + +void fiemap(int fd, uint32_t flags, int (*handle_extent)(struct fiemap_extent)) { + const size_t fm_size = sysconf(_SC_PAGESIZE);; + struct fiemap *fm = calloc(1, fm_size); + if (!fm) + error(EXIT_FAILURE, errno, "malloc"); + uint64_t bytes_mapped = 0; + while (1) { + *fm = (struct fiemap){ + .fm_start = bytes_mapped, + .fm_length = FIEMAP_MAX_OFFSET - bytes_mapped, + .fm_flags = flags, + .fm_extent_count = (fm_size - sizeof(struct fiemap)) / sizeof(struct fiemap_extent), + }; + + if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0) + error(EXIT_FAILURE, errno, "ioctl (FS_IOC_FIEMAP)"); + + for (size_t i = 0; i < fm->fm_extent_count; i++) { + int r = handle_extent(fm->fm_extents[i]); + if (r) { + free(fm); + exit(r); + } + + if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) { + free(fm); + exit(EXIT_SUCCESS); + } + } + } +} |