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
42
43
44
45
46
47
48
|
#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_SUCCESS, EXIT_FAILURE */
#include <sys/ioctl.h> /* for ioctl(2) */
#include <unistd.h> /* for sysconf(3p), _SC_PAGESIZE */
#include "extent-map.h"
int 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)
return -errno;
if (fm->fm_mapped_extents == 0) {
if (bytes_mapped != 0)
error(EXIT_FAILURE, 0, "FS_IOC_FIEMAP is misbehaving");
return EXIT_SUCCESS;
}
for (size_t i = 0; i < fm->fm_mapped_extents; i++) {
bytes_mapped += fm->fm_extents[i].fe_length;
int r = handle_extent(fm->fm_extents[i]);
if (r) {
free(fm);
return r;
}
if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) {
free(fm);
return EXIT_SUCCESS;
}
}
}
}
|