From 9891d6597770ed884c989885d04da46db5952f0a Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 16 May 2018 10:30:03 -0400 Subject: first pass at cow-extent-map --- src/cow-extent-map.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/cow-extent-map.c (limited to 'src') diff --git a/src/cow-extent-map.c b/src/cow-extent-map.c new file mode 100644 index 0000000..7cee70c --- /dev/null +++ b/src/cow-extent-map.c @@ -0,0 +1,93 @@ +#define _GNU_SOURCE /* for program_invocation_name */ +#include /* for assert(3p) */ +#include /* for errno, program_invocation_name */ +#include /* for error(3gnu) */ +#include /* for open(2) and O_RDONLY */ +#include /* for getopt_long(3gnu), struct option, optind, optarg */ +#include /* PRI* */ +#include /* for printf(3p), fprintf(3p), stderr */ +#include /* exit(3p), EXIT_SUCCESS, EXIT_FAILURE */ +#include /* for strcmp(3p) */ + +#include "extent-map.h" /* for uint32_t, fiemap stuff */ + +#define EXIT_INVALIDARGUMENT 2 +#define errusage(format, ...) do { \ + error(0, 0, format, ## __VA_ARGS__); \ + fprintf(stderr, "Try '%s --help' for more information.\n", program_invocation_name); \ + exit(EXIT_INVALIDARGUMENT); \ +} while(0) + +int print_extent(struct fiemap_extent extent) { + printf("logical=%"PRIu64" " + "physical=%"PRIu64" " + "length=%"PRIu64" " + "flags=0x%"PRIx32"\n", + extent.fe_logical, + extent.fe_physical, + extent.fe_length, + extent.fe_flags); + return 0; +} + +void usage() { + printf("Usage: %s [OPTIONS] FILENAME\n" + "Print a file extent map.\n" + "\n" + "OPTIONS:\n" + " --stream=data Map extents in the data stream (default).\n" + " --stream=xattr Map extents in the extended attribute stream.\n" + " --sync Sync the file before mapping extents (default).\n" + " --no-sync Don't sync the file before mapping extents.\n" + " -h, --help Display this help and exit.\n", + program_invocation_name); +} + +int main(int argc, char *argv[]) { + char *stream = "data"; + int sync = 1; + struct option long_options[] = { + {"stream", optional_argument, NULL, 1}, + {"sync", no_argument, &sync, 1}, + {"no-sync", no_argument, &sync, 0}, + {"help", no_argument, NULL, 'h'}, + {0}, + }; + int flag; + while ((flag = getopt_long(argc, argv, "h", long_options, NULL)) >= 0) { + switch (flag) { + case 0: + break; + case 1: + stream = optarg; + break; + case 'h': + usage(); + return EXIT_SUCCESS; + case '?': + fprintf(stderr, "Try '%s --help' for more information.\n", program_invocation_name); + return EXIT_INVALIDARGUMENT; + default: + assert(0); + } + } + if (argc - optind != 1) + errusage("wrong number of arguments"); + + uint32_t flags = sync ? FIEMAP_FLAG_SYNC : 0; + if (strcmp(stream, "data") == 0) { + /* do nothing */ + } else if (strcmp(stream, "xattr") == 0) { + flags |= FIEMAP_FLAG_XATTR; + } else { + errusage("invalid stream name"); + } + + char *filename = argv[optind]; + int fd = open(filename, O_RDONLY); + if (fd < 0) + error(EXIT_FAILURE, errno, "%s", filename); + + fiemap(fd, flags, print_extent); + return EXIT_SUCCESS;; +} -- cgit v1.2.3