summaryrefslogtreecommitdiff
path: root/lib/extent-map.c
blob: b698fa1c5ca4f0a147facf70d3685fb3a6cfe6e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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);
			}
		}
	}		
}