xref: /freebsd/bin/cp/tests/sparse.c (revision 8b418c83d175fde3b1f65210509ddcf2ac248d9f)
1*8b418c83SDag-Erling Smørgrav /*-
2*8b418c83SDag-Erling Smørgrav  * Copyright (c) 2023 Klara, Inc.
3*8b418c83SDag-Erling Smørgrav  *
4*8b418c83SDag-Erling Smørgrav  * SPDX-License-Identifier: BSD-2-Clause
5*8b418c83SDag-Erling Smørgrav  */
6*8b418c83SDag-Erling Smørgrav 
7*8b418c83SDag-Erling Smørgrav #include <err.h>
8*8b418c83SDag-Erling Smørgrav #include <fcntl.h>
9*8b418c83SDag-Erling Smørgrav #include <stdbool.h>
10*8b418c83SDag-Erling Smørgrav #include <stdio.h>
11*8b418c83SDag-Erling Smørgrav #include <stdlib.h>
12*8b418c83SDag-Erling Smørgrav #include <sysexits.h>
13*8b418c83SDag-Erling Smørgrav #include <unistd.h>
14*8b418c83SDag-Erling Smørgrav 
15*8b418c83SDag-Erling Smørgrav static bool verbose;
16*8b418c83SDag-Erling Smørgrav 
17*8b418c83SDag-Erling Smørgrav /*
18*8b418c83SDag-Erling Smørgrav  * Returns true if the file named by its argument is sparse, i.e. if
19*8b418c83SDag-Erling Smørgrav  * seeking to SEEK_HOLE returns a different value than seeking to
20*8b418c83SDag-Erling Smørgrav  * SEEK_END.
21*8b418c83SDag-Erling Smørgrav  */
22*8b418c83SDag-Erling Smørgrav static bool
sparse(const char * filename)23*8b418c83SDag-Erling Smørgrav sparse(const char *filename)
24*8b418c83SDag-Erling Smørgrav {
25*8b418c83SDag-Erling Smørgrav 	off_t hole, end;
26*8b418c83SDag-Erling Smørgrav 	int fd;
27*8b418c83SDag-Erling Smørgrav 
28*8b418c83SDag-Erling Smørgrav 	if ((fd = open(filename, O_RDONLY)) < 0 ||
29*8b418c83SDag-Erling Smørgrav 	    (hole = lseek(fd, 0, SEEK_HOLE)) < 0 ||
30*8b418c83SDag-Erling Smørgrav 	    (end = lseek(fd, 0, SEEK_END)) < 0)
31*8b418c83SDag-Erling Smørgrav 		err(1, "%s", filename);
32*8b418c83SDag-Erling Smørgrav 	close(fd);
33*8b418c83SDag-Erling Smørgrav 	if (end > hole) {
34*8b418c83SDag-Erling Smørgrav 		if (verbose)
35*8b418c83SDag-Erling Smørgrav 			printf("%s: hole at %zu\n", filename, (size_t)hole);
36*8b418c83SDag-Erling Smørgrav 		return (true);
37*8b418c83SDag-Erling Smørgrav 	}
38*8b418c83SDag-Erling Smørgrav 	return (false);
39*8b418c83SDag-Erling Smørgrav }
40*8b418c83SDag-Erling Smørgrav 
41*8b418c83SDag-Erling Smørgrav static void
usage(void)42*8b418c83SDag-Erling Smørgrav usage(void)
43*8b418c83SDag-Erling Smørgrav {
44*8b418c83SDag-Erling Smørgrav 
45*8b418c83SDag-Erling Smørgrav 	fprintf(stderr, "usage: sparse [-v] file [...]\n");
46*8b418c83SDag-Erling Smørgrav 	exit(EX_USAGE);
47*8b418c83SDag-Erling Smørgrav }
48*8b418c83SDag-Erling Smørgrav 
49*8b418c83SDag-Erling Smørgrav int
main(int argc,char * argv[])50*8b418c83SDag-Erling Smørgrav main(int argc, char *argv[])
51*8b418c83SDag-Erling Smørgrav {
52*8b418c83SDag-Erling Smørgrav 	int opt, rv;
53*8b418c83SDag-Erling Smørgrav 
54*8b418c83SDag-Erling Smørgrav 	while ((opt = getopt(argc, argv, "v")) != -1) {
55*8b418c83SDag-Erling Smørgrav 		switch (opt) {
56*8b418c83SDag-Erling Smørgrav 		case 'v':
57*8b418c83SDag-Erling Smørgrav 			verbose = true;
58*8b418c83SDag-Erling Smørgrav 			break;
59*8b418c83SDag-Erling Smørgrav 		default:
60*8b418c83SDag-Erling Smørgrav 			usage();
61*8b418c83SDag-Erling Smørgrav 			break;
62*8b418c83SDag-Erling Smørgrav 		}
63*8b418c83SDag-Erling Smørgrav 	}
64*8b418c83SDag-Erling Smørgrav 	argc -= optind;
65*8b418c83SDag-Erling Smørgrav 	argv += optind;
66*8b418c83SDag-Erling Smørgrav 	if (argc == 0)
67*8b418c83SDag-Erling Smørgrav 		usage();
68*8b418c83SDag-Erling Smørgrav 	rv = EXIT_SUCCESS;
69*8b418c83SDag-Erling Smørgrav 	while (argc-- > 0)
70*8b418c83SDag-Erling Smørgrav 		if (!sparse(*argv++))
71*8b418c83SDag-Erling Smørgrav 			rv = EXIT_FAILURE;
72*8b418c83SDag-Erling Smørgrav 	exit(rv);
73*8b418c83SDag-Erling Smørgrav }
74