xref: /aosp_15_r20/external/e2fsprogs/misc/filefrag.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * filefrag.c -- report if a particular file is fragmented
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright 2003 by Theodore Ts'o.
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Public
8*6a54128fSAndroid Build Coastguard Worker  * License.
9*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker  */
11*6a54128fSAndroid Build Coastguard Worker 
12*6a54128fSAndroid Build Coastguard Worker #include "config.h"
13*6a54128fSAndroid Build Coastguard Worker #ifndef __linux__
14*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
15*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
16*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
17*6a54128fSAndroid Build Coastguard Worker 
main(void)18*6a54128fSAndroid Build Coastguard Worker int main(void) {
19*6a54128fSAndroid Build Coastguard Worker 	fputs("This program is only supported on Linux!\n", stderr);
20*6a54128fSAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
21*6a54128fSAndroid Build Coastguard Worker }
22*6a54128fSAndroid Build Coastguard Worker #else
23*6a54128fSAndroid Build Coastguard Worker #ifndef _LARGEFILE_SOURCE
24*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE_SOURCE
25*6a54128fSAndroid Build Coastguard Worker #endif
26*6a54128fSAndroid Build Coastguard Worker #ifndef _LARGEFILE64_SOURCE
27*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
28*6a54128fSAndroid Build Coastguard Worker #endif
29*6a54128fSAndroid Build Coastguard Worker 
30*6a54128fSAndroid Build Coastguard Worker 
31*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
32*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
33*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
34*6a54128fSAndroid Build Coastguard Worker #include <string.h>
35*6a54128fSAndroid Build Coastguard Worker #include <time.h>
36*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
37*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
38*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETOPT_H
39*6a54128fSAndroid Build Coastguard Worker #include <getopt.h>
40*6a54128fSAndroid Build Coastguard Worker #else
41*6a54128fSAndroid Build Coastguard Worker extern char *optarg;
42*6a54128fSAndroid Build Coastguard Worker extern int optind;
43*6a54128fSAndroid Build Coastguard Worker #endif
44*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
45*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
46*6a54128fSAndroid Build Coastguard Worker #include <sys/vfs.h>
47*6a54128fSAndroid Build Coastguard Worker #include <sys/ioctl.h>
48*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_LINUX_FD_H
49*6a54128fSAndroid Build Coastguard Worker #include <linux/fd.h>
50*6a54128fSAndroid Build Coastguard Worker #endif
51*6a54128fSAndroid Build Coastguard Worker #include <ext2fs/ext2fs.h>
52*6a54128fSAndroid Build Coastguard Worker #include <ext2fs/ext2_types.h>
53*6a54128fSAndroid Build Coastguard Worker #include <ext2fs/fiemap.h>
54*6a54128fSAndroid Build Coastguard Worker #include "../version.h"
55*6a54128fSAndroid Build Coastguard Worker 
56*6a54128fSAndroid Build Coastguard Worker int verbose = 0;
57*6a54128fSAndroid Build Coastguard Worker unsigned int blocksize;	/* Use specified blocksize (default 1kB) */
58*6a54128fSAndroid Build Coastguard Worker int sync_file = 0;	/* fsync file before getting the mapping */
59*6a54128fSAndroid Build Coastguard Worker int precache_file = 0;	/* precache the file before getting the mapping */
60*6a54128fSAndroid Build Coastguard Worker int xattr_map = 0;	/* get xattr mapping */
61*6a54128fSAndroid Build Coastguard Worker int force_bmap;		/* force use of FIBMAP instead of FIEMAP */
62*6a54128fSAndroid Build Coastguard Worker int force_extent;	/* print output in extent format always */
63*6a54128fSAndroid Build Coastguard Worker int use_extent_cache;	/* Use extent cache */
64*6a54128fSAndroid Build Coastguard Worker int logical_width = 8;
65*6a54128fSAndroid Build Coastguard Worker int physical_width = 10;
66*6a54128fSAndroid Build Coastguard Worker const char *ext_fmt = "%4d: %*llu..%*llu: %*llu..%*llu: %6llu: %s\n";
67*6a54128fSAndroid Build Coastguard Worker const char *hex_fmt = "%4d: %*llx..%*llx: %*llx..%*llx: %6llx: %s\n";
68*6a54128fSAndroid Build Coastguard Worker 
69*6a54128fSAndroid Build Coastguard Worker #define FILEFRAG_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
70*6a54128fSAndroid Build Coastguard Worker 
71*6a54128fSAndroid Build Coastguard Worker #define FIBMAP		_IO(0x00, 1)	/* bmap access */
72*6a54128fSAndroid Build Coastguard Worker #define FIGETBSZ	_IO(0x00, 2)	/* get the block size used for bmap */
73*6a54128fSAndroid Build Coastguard Worker 
74*6a54128fSAndroid Build Coastguard Worker #define LUSTRE_SUPER_MAGIC 0x0BD00BD0
75*6a54128fSAndroid Build Coastguard Worker 
76*6a54128fSAndroid Build Coastguard Worker #define	EXT4_EXTENTS_FL			0x00080000 /* Inode uses extents */
77*6a54128fSAndroid Build Coastguard Worker #define	EXT3_IOC_GETFLAGS		_IOR('f', 1, long)
78*6a54128fSAndroid Build Coastguard Worker 
ulong_log2(unsigned long arg)79*6a54128fSAndroid Build Coastguard Worker static int ulong_log2(unsigned long arg)
80*6a54128fSAndroid Build Coastguard Worker {
81*6a54128fSAndroid Build Coastguard Worker 	int     l = 0;
82*6a54128fSAndroid Build Coastguard Worker 
83*6a54128fSAndroid Build Coastguard Worker 	arg >>= 1;
84*6a54128fSAndroid Build Coastguard Worker 	while (arg) {
85*6a54128fSAndroid Build Coastguard Worker 		l++;
86*6a54128fSAndroid Build Coastguard Worker 		arg >>= 1;
87*6a54128fSAndroid Build Coastguard Worker 	}
88*6a54128fSAndroid Build Coastguard Worker 	return l;
89*6a54128fSAndroid Build Coastguard Worker }
90*6a54128fSAndroid Build Coastguard Worker 
ulong_log10(unsigned long long arg)91*6a54128fSAndroid Build Coastguard Worker static int ulong_log10(unsigned long long arg)
92*6a54128fSAndroid Build Coastguard Worker {
93*6a54128fSAndroid Build Coastguard Worker 	int     l = 0;
94*6a54128fSAndroid Build Coastguard Worker 
95*6a54128fSAndroid Build Coastguard Worker 	arg = arg / 10;
96*6a54128fSAndroid Build Coastguard Worker 	while (arg) {
97*6a54128fSAndroid Build Coastguard Worker 		l++;
98*6a54128fSAndroid Build Coastguard Worker 		arg = arg / 10;
99*6a54128fSAndroid Build Coastguard Worker 	}
100*6a54128fSAndroid Build Coastguard Worker 	return l;
101*6a54128fSAndroid Build Coastguard Worker }
102*6a54128fSAndroid Build Coastguard Worker 
div_ceil(unsigned int a,unsigned int b)103*6a54128fSAndroid Build Coastguard Worker static unsigned int div_ceil(unsigned int a, unsigned int b)
104*6a54128fSAndroid Build Coastguard Worker {
105*6a54128fSAndroid Build Coastguard Worker 	if (!a)
106*6a54128fSAndroid Build Coastguard Worker 		return 0;
107*6a54128fSAndroid Build Coastguard Worker 	return ((a - 1) / b) + 1;
108*6a54128fSAndroid Build Coastguard Worker }
109*6a54128fSAndroid Build Coastguard Worker 
get_bmap(int fd,unsigned long block,unsigned long * phy_blk)110*6a54128fSAndroid Build Coastguard Worker static int get_bmap(int fd, unsigned long block, unsigned long *phy_blk)
111*6a54128fSAndroid Build Coastguard Worker {
112*6a54128fSAndroid Build Coastguard Worker 	int	ret;
113*6a54128fSAndroid Build Coastguard Worker 	unsigned int b;
114*6a54128fSAndroid Build Coastguard Worker 
115*6a54128fSAndroid Build Coastguard Worker 	b = block;
116*6a54128fSAndroid Build Coastguard Worker 	ret = ioctl(fd, FIBMAP, &b); /* FIBMAP takes pointer to integer */
117*6a54128fSAndroid Build Coastguard Worker 	if (ret < 0)
118*6a54128fSAndroid Build Coastguard Worker 		return -errno;
119*6a54128fSAndroid Build Coastguard Worker 	*phy_blk = b;
120*6a54128fSAndroid Build Coastguard Worker 
121*6a54128fSAndroid Build Coastguard Worker 	return ret;
122*6a54128fSAndroid Build Coastguard Worker }
123*6a54128fSAndroid Build Coastguard Worker 
print_extent_header(void)124*6a54128fSAndroid Build Coastguard Worker static void print_extent_header(void)
125*6a54128fSAndroid Build Coastguard Worker {
126*6a54128fSAndroid Build Coastguard Worker 	printf(" ext: %*s %*s length: %*s flags:\n",
127*6a54128fSAndroid Build Coastguard Worker 	       logical_width * 2 + 3,
128*6a54128fSAndroid Build Coastguard Worker 	       "logical_offset:",
129*6a54128fSAndroid Build Coastguard Worker 	       physical_width * 2 + 3, "physical_offset:",
130*6a54128fSAndroid Build Coastguard Worker 	       physical_width + 1,
131*6a54128fSAndroid Build Coastguard Worker 	       "expected:");
132*6a54128fSAndroid Build Coastguard Worker }
133*6a54128fSAndroid Build Coastguard Worker 
print_flag(__u32 * flags,__u32 mask,char * buf,const char * name)134*6a54128fSAndroid Build Coastguard Worker static void print_flag(__u32 *flags, __u32 mask, char *buf, const char *name)
135*6a54128fSAndroid Build Coastguard Worker {
136*6a54128fSAndroid Build Coastguard Worker 	char hex[sizeof(mask) * 2 + 4]; /* 2 chars/byte + 0x, + NUL */
137*6a54128fSAndroid Build Coastguard Worker 
138*6a54128fSAndroid Build Coastguard Worker 	if ((*flags & mask) == 0)
139*6a54128fSAndroid Build Coastguard Worker 		return;
140*6a54128fSAndroid Build Coastguard Worker 
141*6a54128fSAndroid Build Coastguard Worker 	if (name == NULL) {
142*6a54128fSAndroid Build Coastguard Worker 		sprintf(hex, "%#04x,", mask);
143*6a54128fSAndroid Build Coastguard Worker 		name = hex;
144*6a54128fSAndroid Build Coastguard Worker 	}
145*6a54128fSAndroid Build Coastguard Worker 	strcat(buf, name);
146*6a54128fSAndroid Build Coastguard Worker 	*flags &= ~mask;
147*6a54128fSAndroid Build Coastguard Worker }
148*6a54128fSAndroid Build Coastguard Worker 
print_flags(__u32 fe_flags,char * flags,int len,int print_unknown)149*6a54128fSAndroid Build Coastguard Worker static void print_flags(__u32 fe_flags, char *flags, int len, int print_unknown)
150*6a54128fSAndroid Build Coastguard Worker {
151*6a54128fSAndroid Build Coastguard Worker 	__u32 mask;
152*6a54128fSAndroid Build Coastguard Worker 
153*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_LAST, flags, "last,");
154*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_UNKNOWN, flags, "unknown_loc,");
155*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_DELALLOC, flags, "delalloc,");
156*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_ENCODED, flags, "encoded,");
157*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_DATA_ENCRYPTED, flags,"encrypted,");
158*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_NOT_ALIGNED, flags, "not_aligned,");
159*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_DATA_INLINE, flags, "inline,");
160*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_DATA_TAIL, flags, "tail_packed,");
161*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_UNWRITTEN, flags, "unwritten,");
162*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_MERGED, flags, "merged,");
163*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, FIEMAP_EXTENT_SHARED, flags, "shared,");
164*6a54128fSAndroid Build Coastguard Worker 	print_flag(&fe_flags, EXT4_FIEMAP_EXTENT_HOLE, flags, "hole,");
165*6a54128fSAndroid Build Coastguard Worker 
166*6a54128fSAndroid Build Coastguard Worker 	if (!print_unknown)
167*6a54128fSAndroid Build Coastguard Worker 		goto out;
168*6a54128fSAndroid Build Coastguard Worker 
169*6a54128fSAndroid Build Coastguard Worker 	/* print any unknown flags as hex values */
170*6a54128fSAndroid Build Coastguard Worker 	for (mask = 1; fe_flags != 0 && mask != 0; mask <<= 1)
171*6a54128fSAndroid Build Coastguard Worker 		print_flag(&fe_flags, mask, flags, NULL);
172*6a54128fSAndroid Build Coastguard Worker out:
173*6a54128fSAndroid Build Coastguard Worker 	/* Remove trailing comma, if any */
174*6a54128fSAndroid Build Coastguard Worker 	if (flags[0])
175*6a54128fSAndroid Build Coastguard Worker 		flags[strnlen(flags, len) - 1] = '\0';
176*6a54128fSAndroid Build Coastguard Worker 
177*6a54128fSAndroid Build Coastguard Worker }
178*6a54128fSAndroid Build Coastguard Worker 
print_extent_info(struct fiemap_extent * fm_extent,int cur_ex,unsigned long long expected,int blk_shift,ext2fs_struct_stat * st)179*6a54128fSAndroid Build Coastguard Worker static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex,
180*6a54128fSAndroid Build Coastguard Worker 			      unsigned long long expected, int blk_shift,
181*6a54128fSAndroid Build Coastguard Worker 			      ext2fs_struct_stat *st)
182*6a54128fSAndroid Build Coastguard Worker {
183*6a54128fSAndroid Build Coastguard Worker 	unsigned long long physical_blk;
184*6a54128fSAndroid Build Coastguard Worker 	unsigned long long logical_blk;
185*6a54128fSAndroid Build Coastguard Worker 	unsigned long long ext_len;
186*6a54128fSAndroid Build Coastguard Worker 	unsigned long long ext_blks;
187*6a54128fSAndroid Build Coastguard Worker 	unsigned long long ext_blks_phys;
188*6a54128fSAndroid Build Coastguard Worker 	char flags[256] = "";
189*6a54128fSAndroid Build Coastguard Worker 
190*6a54128fSAndroid Build Coastguard Worker 	/* For inline data all offsets should be in bytes, not blocks */
191*6a54128fSAndroid Build Coastguard Worker 	if (fm_extent->fe_flags & FIEMAP_EXTENT_DATA_INLINE)
192*6a54128fSAndroid Build Coastguard Worker 		blk_shift = 0;
193*6a54128fSAndroid Build Coastguard Worker 
194*6a54128fSAndroid Build Coastguard Worker 	ext_len = fm_extent->fe_length >> blk_shift;
195*6a54128fSAndroid Build Coastguard Worker 	ext_blks = (fm_extent->fe_length - 1) >> blk_shift;
196*6a54128fSAndroid Build Coastguard Worker 	logical_blk = fm_extent->fe_logical >> blk_shift;
197*6a54128fSAndroid Build Coastguard Worker 	if (fm_extent->fe_flags & FIEMAP_EXTENT_UNKNOWN) {
198*6a54128fSAndroid Build Coastguard Worker 		physical_blk = 0;
199*6a54128fSAndroid Build Coastguard Worker 	} else {
200*6a54128fSAndroid Build Coastguard Worker 		physical_blk = fm_extent->fe_physical >> blk_shift;
201*6a54128fSAndroid Build Coastguard Worker 	}
202*6a54128fSAndroid Build Coastguard Worker 
203*6a54128fSAndroid Build Coastguard Worker 	if (expected &&
204*6a54128fSAndroid Build Coastguard Worker 	    !(fm_extent->fe_flags & FIEMAP_EXTENT_UNKNOWN) &&
205*6a54128fSAndroid Build Coastguard Worker 	    !(fm_extent->fe_flags & EXT4_FIEMAP_EXTENT_HOLE))
206*6a54128fSAndroid Build Coastguard Worker 		sprintf(flags, ext_fmt == hex_fmt ? "%*llx: " : "%*llu: ",
207*6a54128fSAndroid Build Coastguard Worker 			physical_width, expected >> blk_shift);
208*6a54128fSAndroid Build Coastguard Worker 	else
209*6a54128fSAndroid Build Coastguard Worker 		sprintf(flags, "%.*s  ", physical_width, "                   ");
210*6a54128fSAndroid Build Coastguard Worker 
211*6a54128fSAndroid Build Coastguard Worker 	print_flags(fm_extent->fe_flags, flags, sizeof(flags), 1);
212*6a54128fSAndroid Build Coastguard Worker 
213*6a54128fSAndroid Build Coastguard Worker 	if (fm_extent->fe_logical + fm_extent->fe_length >=
214*6a54128fSAndroid Build Coastguard Worker 	    (unsigned long long)st->st_size)
215*6a54128fSAndroid Build Coastguard Worker 		strcat(flags, flags[0] ? ",eof" : "eof");
216*6a54128fSAndroid Build Coastguard Worker 
217*6a54128fSAndroid Build Coastguard Worker 	if ((fm_extent->fe_flags & FIEMAP_EXTENT_UNKNOWN) ||
218*6a54128fSAndroid Build Coastguard Worker 	    (fm_extent->fe_flags & EXT4_FIEMAP_EXTENT_HOLE)) {
219*6a54128fSAndroid Build Coastguard Worker 		ext_len = 0;
220*6a54128fSAndroid Build Coastguard Worker 		ext_blks_phys = 0;
221*6a54128fSAndroid Build Coastguard Worker 	} else
222*6a54128fSAndroid Build Coastguard Worker 		ext_blks_phys = ext_blks;
223*6a54128fSAndroid Build Coastguard Worker 
224*6a54128fSAndroid Build Coastguard Worker 	printf(ext_fmt, cur_ex, logical_width, logical_blk,
225*6a54128fSAndroid Build Coastguard Worker 	       logical_width, logical_blk + ext_blks,
226*6a54128fSAndroid Build Coastguard Worker 	       physical_width, physical_blk,
227*6a54128fSAndroid Build Coastguard Worker 	       physical_width, physical_blk + ext_blks_phys,
228*6a54128fSAndroid Build Coastguard Worker 	       ext_len, flags);
229*6a54128fSAndroid Build Coastguard Worker }
230*6a54128fSAndroid Build Coastguard Worker 
filefrag_fiemap(int fd,int blk_shift,int * num_extents,ext2fs_struct_stat * st)231*6a54128fSAndroid Build Coastguard Worker static int filefrag_fiemap(int fd, int blk_shift, int *num_extents,
232*6a54128fSAndroid Build Coastguard Worker 			   ext2fs_struct_stat *st)
233*6a54128fSAndroid Build Coastguard Worker {
234*6a54128fSAndroid Build Coastguard Worker 	__u64 buf[2048];	/* __u64 for proper field alignment */
235*6a54128fSAndroid Build Coastguard Worker 	struct fiemap *fiemap = (struct fiemap *)buf;
236*6a54128fSAndroid Build Coastguard Worker 	struct fiemap_extent *fm_ext = &fiemap->fm_extents[0];
237*6a54128fSAndroid Build Coastguard Worker 	struct fiemap_extent fm_last;
238*6a54128fSAndroid Build Coastguard Worker 	int count = (sizeof(buf) - sizeof(*fiemap)) /
239*6a54128fSAndroid Build Coastguard Worker 			sizeof(struct fiemap_extent);
240*6a54128fSAndroid Build Coastguard Worker 	unsigned long long expected = 0;
241*6a54128fSAndroid Build Coastguard Worker 	unsigned long long expected_dense = 0;
242*6a54128fSAndroid Build Coastguard Worker 	unsigned long flags = 0;
243*6a54128fSAndroid Build Coastguard Worker 	unsigned int i;
244*6a54128fSAndroid Build Coastguard Worker 	unsigned long cmd = FS_IOC_FIEMAP;
245*6a54128fSAndroid Build Coastguard Worker 	int fiemap_header_printed = 0;
246*6a54128fSAndroid Build Coastguard Worker 	int tot_extents = 0, n = 0;
247*6a54128fSAndroid Build Coastguard Worker 	int last = 0;
248*6a54128fSAndroid Build Coastguard Worker 	int rc;
249*6a54128fSAndroid Build Coastguard Worker 
250*6a54128fSAndroid Build Coastguard Worker 	memset(fiemap, 0, sizeof(struct fiemap));
251*6a54128fSAndroid Build Coastguard Worker 	memset(&fm_last, 0, sizeof(fm_last));
252*6a54128fSAndroid Build Coastguard Worker 
253*6a54128fSAndroid Build Coastguard Worker 	if (sync_file)
254*6a54128fSAndroid Build Coastguard Worker 		flags |= FIEMAP_FLAG_SYNC;
255*6a54128fSAndroid Build Coastguard Worker 
256*6a54128fSAndroid Build Coastguard Worker 	if (precache_file)
257*6a54128fSAndroid Build Coastguard Worker 		flags |= FIEMAP_FLAG_CACHE;
258*6a54128fSAndroid Build Coastguard Worker 
259*6a54128fSAndroid Build Coastguard Worker 	if (xattr_map)
260*6a54128fSAndroid Build Coastguard Worker 		flags |= FIEMAP_FLAG_XATTR;
261*6a54128fSAndroid Build Coastguard Worker 
262*6a54128fSAndroid Build Coastguard Worker 	if (use_extent_cache)
263*6a54128fSAndroid Build Coastguard Worker 		cmd = EXT4_IOC_GET_ES_CACHE;
264*6a54128fSAndroid Build Coastguard Worker 
265*6a54128fSAndroid Build Coastguard Worker 	do {
266*6a54128fSAndroid Build Coastguard Worker 		fiemap->fm_length = ~0ULL;
267*6a54128fSAndroid Build Coastguard Worker 		fiemap->fm_flags = flags;
268*6a54128fSAndroid Build Coastguard Worker 		fiemap->fm_extent_count = count;
269*6a54128fSAndroid Build Coastguard Worker 		rc = ioctl(fd, cmd, (unsigned long) fiemap);
270*6a54128fSAndroid Build Coastguard Worker 		if (rc < 0) {
271*6a54128fSAndroid Build Coastguard Worker 			static int fiemap_incompat_printed;
272*6a54128fSAndroid Build Coastguard Worker 
273*6a54128fSAndroid Build Coastguard Worker 			rc = -errno;
274*6a54128fSAndroid Build Coastguard Worker 			if (rc == -EBADR && !fiemap_incompat_printed) {
275*6a54128fSAndroid Build Coastguard Worker 				fprintf(stderr, "FIEMAP failed with unknown "
276*6a54128fSAndroid Build Coastguard Worker 						"flags %x\n",
277*6a54128fSAndroid Build Coastguard Worker 				       fiemap->fm_flags);
278*6a54128fSAndroid Build Coastguard Worker 				fiemap_incompat_printed = 1;
279*6a54128fSAndroid Build Coastguard Worker 			}
280*6a54128fSAndroid Build Coastguard Worker 			return rc;
281*6a54128fSAndroid Build Coastguard Worker 		}
282*6a54128fSAndroid Build Coastguard Worker 
283*6a54128fSAndroid Build Coastguard Worker 		/* If 0 extents are returned, then more ioctls are not needed */
284*6a54128fSAndroid Build Coastguard Worker 		if (fiemap->fm_mapped_extents == 0)
285*6a54128fSAndroid Build Coastguard Worker 			break;
286*6a54128fSAndroid Build Coastguard Worker 
287*6a54128fSAndroid Build Coastguard Worker 		if (verbose && !fiemap_header_printed) {
288*6a54128fSAndroid Build Coastguard Worker 			print_extent_header();
289*6a54128fSAndroid Build Coastguard Worker 			fiemap_header_printed = 1;
290*6a54128fSAndroid Build Coastguard Worker 		}
291*6a54128fSAndroid Build Coastguard Worker 
292*6a54128fSAndroid Build Coastguard Worker 		for (i = 0; i < fiemap->fm_mapped_extents; i++) {
293*6a54128fSAndroid Build Coastguard Worker 			expected_dense = fm_last.fe_physical +
294*6a54128fSAndroid Build Coastguard Worker 					 fm_last.fe_length;
295*6a54128fSAndroid Build Coastguard Worker 			expected = fm_last.fe_physical +
296*6a54128fSAndroid Build Coastguard Worker 				   fm_ext[i].fe_logical - fm_last.fe_logical;
297*6a54128fSAndroid Build Coastguard Worker 			if (fm_ext[i].fe_logical != 0 &&
298*6a54128fSAndroid Build Coastguard Worker 			    fm_ext[i].fe_physical != expected &&
299*6a54128fSAndroid Build Coastguard Worker 			    fm_ext[i].fe_physical != expected_dense) {
300*6a54128fSAndroid Build Coastguard Worker 				tot_extents++;
301*6a54128fSAndroid Build Coastguard Worker 			} else {
302*6a54128fSAndroid Build Coastguard Worker 				expected = 0;
303*6a54128fSAndroid Build Coastguard Worker 				if (!tot_extents)
304*6a54128fSAndroid Build Coastguard Worker 					tot_extents = 1;
305*6a54128fSAndroid Build Coastguard Worker 			}
306*6a54128fSAndroid Build Coastguard Worker 			if (verbose)
307*6a54128fSAndroid Build Coastguard Worker 				print_extent_info(&fm_ext[i], n, expected,
308*6a54128fSAndroid Build Coastguard Worker 						  blk_shift, st);
309*6a54128fSAndroid Build Coastguard Worker 			if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
310*6a54128fSAndroid Build Coastguard Worker 				last = 1;
311*6a54128fSAndroid Build Coastguard Worker 			fm_last = fm_ext[i];
312*6a54128fSAndroid Build Coastguard Worker 			n++;
313*6a54128fSAndroid Build Coastguard Worker 		}
314*6a54128fSAndroid Build Coastguard Worker 
315*6a54128fSAndroid Build Coastguard Worker 		fiemap->fm_start = (fm_ext[i - 1].fe_logical +
316*6a54128fSAndroid Build Coastguard Worker 				    fm_ext[i - 1].fe_length);
317*6a54128fSAndroid Build Coastguard Worker 	} while (last == 0);
318*6a54128fSAndroid Build Coastguard Worker 
319*6a54128fSAndroid Build Coastguard Worker 	*num_extents = tot_extents;
320*6a54128fSAndroid Build Coastguard Worker 
321*6a54128fSAndroid Build Coastguard Worker 	return 0;
322*6a54128fSAndroid Build Coastguard Worker }
323*6a54128fSAndroid Build Coastguard Worker 
324*6a54128fSAndroid Build Coastguard Worker #define EXT2_DIRECT	12
325*6a54128fSAndroid Build Coastguard Worker 
filefrag_fibmap(int fd,int blk_shift,int * num_extents,ext2fs_struct_stat * st,unsigned long numblocks,int is_ext2)326*6a54128fSAndroid Build Coastguard Worker static int filefrag_fibmap(int fd, int blk_shift, int *num_extents,
327*6a54128fSAndroid Build Coastguard Worker 			   ext2fs_struct_stat *st,
328*6a54128fSAndroid Build Coastguard Worker 			   unsigned long numblocks, int is_ext2)
329*6a54128fSAndroid Build Coastguard Worker {
330*6a54128fSAndroid Build Coastguard Worker 	struct fiemap_extent	fm_ext, fm_last;
331*6a54128fSAndroid Build Coastguard Worker 	unsigned long		i, last_block;
332*6a54128fSAndroid Build Coastguard Worker 	unsigned long long	logical, expected = 0;
333*6a54128fSAndroid Build Coastguard Worker 				/* Blocks per indirect block */
334*6a54128fSAndroid Build Coastguard Worker 	const long		bpib = st->st_blksize / 4;
335*6a54128fSAndroid Build Coastguard Worker 	int			count;
336*6a54128fSAndroid Build Coastguard Worker 
337*6a54128fSAndroid Build Coastguard Worker 	memset(&fm_ext, 0, sizeof(fm_ext));
338*6a54128fSAndroid Build Coastguard Worker 	memset(&fm_last, 0, sizeof(fm_last));
339*6a54128fSAndroid Build Coastguard Worker 	if (force_extent) {
340*6a54128fSAndroid Build Coastguard Worker 		fm_ext.fe_flags = FIEMAP_EXTENT_MERGED;
341*6a54128fSAndroid Build Coastguard Worker 	}
342*6a54128fSAndroid Build Coastguard Worker 
343*6a54128fSAndroid Build Coastguard Worker 	if (sync_file && fsync(fd) != 0)
344*6a54128fSAndroid Build Coastguard Worker 		return -errno;
345*6a54128fSAndroid Build Coastguard Worker 
346*6a54128fSAndroid Build Coastguard Worker 	for (i = 0, logical = 0, *num_extents = 0, count = last_block = 0;
347*6a54128fSAndroid Build Coastguard Worker 	     i < numblocks;
348*6a54128fSAndroid Build Coastguard Worker 	     i++, logical += st->st_blksize) {
349*6a54128fSAndroid Build Coastguard Worker 		unsigned long block = 0;
350*6a54128fSAndroid Build Coastguard Worker 		int rc;
351*6a54128fSAndroid Build Coastguard Worker 
352*6a54128fSAndroid Build Coastguard Worker 		if (is_ext2 && last_block) {
353*6a54128fSAndroid Build Coastguard Worker 			if (((i - EXT2_DIRECT) % bpib) == 0)
354*6a54128fSAndroid Build Coastguard Worker 				last_block++;
355*6a54128fSAndroid Build Coastguard Worker 			if (((i - EXT2_DIRECT - bpib) % (bpib * bpib)) == 0)
356*6a54128fSAndroid Build Coastguard Worker 				last_block++;
357*6a54128fSAndroid Build Coastguard Worker 			if (((i - EXT2_DIRECT - bpib - bpib * bpib) %
358*6a54128fSAndroid Build Coastguard Worker 			     (((unsigned long long)bpib) * bpib * bpib)) == 0)
359*6a54128fSAndroid Build Coastguard Worker 				last_block++;
360*6a54128fSAndroid Build Coastguard Worker 		}
361*6a54128fSAndroid Build Coastguard Worker 		rc = get_bmap(fd, i, &block);
362*6a54128fSAndroid Build Coastguard Worker 		if (rc < 0)
363*6a54128fSAndroid Build Coastguard Worker 			return rc;
364*6a54128fSAndroid Build Coastguard Worker 		if (block == 0)
365*6a54128fSAndroid Build Coastguard Worker 			continue;
366*6a54128fSAndroid Build Coastguard Worker 
367*6a54128fSAndroid Build Coastguard Worker 		if (*num_extents == 0 || block != last_block + 1 ||
368*6a54128fSAndroid Build Coastguard Worker 		    fm_ext.fe_logical + fm_ext.fe_length != logical) {
369*6a54128fSAndroid Build Coastguard Worker 			/*
370*6a54128fSAndroid Build Coastguard Worker 			 * This is the start of a new extent; figure out where
371*6a54128fSAndroid Build Coastguard Worker 			 * we expected it to be and report the extent.
372*6a54128fSAndroid Build Coastguard Worker 			 */
373*6a54128fSAndroid Build Coastguard Worker 			if (*num_extents != 0 && fm_last.fe_length) {
374*6a54128fSAndroid Build Coastguard Worker 				expected = fm_last.fe_physical +
375*6a54128fSAndroid Build Coastguard Worker 					(fm_ext.fe_logical - fm_last.fe_logical);
376*6a54128fSAndroid Build Coastguard Worker 				if (expected == fm_ext.fe_physical)
377*6a54128fSAndroid Build Coastguard Worker 					expected = 0;
378*6a54128fSAndroid Build Coastguard Worker 			}
379*6a54128fSAndroid Build Coastguard Worker 			if (force_extent && *num_extents == 0)
380*6a54128fSAndroid Build Coastguard Worker 				print_extent_header();
381*6a54128fSAndroid Build Coastguard Worker 			if (force_extent && *num_extents != 0) {
382*6a54128fSAndroid Build Coastguard Worker 				print_extent_info(&fm_ext, *num_extents - 1,
383*6a54128fSAndroid Build Coastguard Worker 						  expected, blk_shift, st);
384*6a54128fSAndroid Build Coastguard Worker 			}
385*6a54128fSAndroid Build Coastguard Worker 			if (verbose && expected != 0) {
386*6a54128fSAndroid Build Coastguard Worker 				printf("Discontinuity: Block %llu is at %llu "
387*6a54128fSAndroid Build Coastguard Worker 				       "(was %llu)\n",
388*6a54128fSAndroid Build Coastguard Worker 				       (unsigned long long) (fm_ext.fe_logical / st->st_blksize),
389*6a54128fSAndroid Build Coastguard Worker 				       (unsigned long long) (fm_ext.fe_physical / st->st_blksize),
390*6a54128fSAndroid Build Coastguard Worker 				       (unsigned long long) (expected / st->st_blksize));
391*6a54128fSAndroid Build Coastguard Worker 			}
392*6a54128fSAndroid Build Coastguard Worker 			/* create the new extent */
393*6a54128fSAndroid Build Coastguard Worker 			fm_last = fm_ext;
394*6a54128fSAndroid Build Coastguard Worker 			(*num_extents)++;
395*6a54128fSAndroid Build Coastguard Worker 			fm_ext.fe_physical = block * st->st_blksize;
396*6a54128fSAndroid Build Coastguard Worker 			fm_ext.fe_logical = logical;
397*6a54128fSAndroid Build Coastguard Worker 			fm_ext.fe_length = 0;
398*6a54128fSAndroid Build Coastguard Worker 		}
399*6a54128fSAndroid Build Coastguard Worker 		fm_ext.fe_length += st->st_blksize;
400*6a54128fSAndroid Build Coastguard Worker 		last_block = block;
401*6a54128fSAndroid Build Coastguard Worker 	}
402*6a54128fSAndroid Build Coastguard Worker 	if (force_extent && *num_extents != 0) {
403*6a54128fSAndroid Build Coastguard Worker 		if (fm_last.fe_length) {
404*6a54128fSAndroid Build Coastguard Worker 			expected = fm_last.fe_physical +
405*6a54128fSAndroid Build Coastguard Worker 				   (fm_ext.fe_logical - fm_last.fe_logical);
406*6a54128fSAndroid Build Coastguard Worker 			if (expected == fm_ext.fe_physical)
407*6a54128fSAndroid Build Coastguard Worker 				expected = 0;
408*6a54128fSAndroid Build Coastguard Worker 		}
409*6a54128fSAndroid Build Coastguard Worker 		print_extent_info(&fm_ext, *num_extents - 1, expected,
410*6a54128fSAndroid Build Coastguard Worker 				  blk_shift, st);
411*6a54128fSAndroid Build Coastguard Worker 	}
412*6a54128fSAndroid Build Coastguard Worker 
413*6a54128fSAndroid Build Coastguard Worker 	return count;
414*6a54128fSAndroid Build Coastguard Worker }
415*6a54128fSAndroid Build Coastguard Worker 
frag_report(const char * filename)416*6a54128fSAndroid Build Coastguard Worker static int frag_report(const char *filename)
417*6a54128fSAndroid Build Coastguard Worker {
418*6a54128fSAndroid Build Coastguard Worker 	static struct statfs fsinfo;
419*6a54128fSAndroid Build Coastguard Worker 	static unsigned int blksize;
420*6a54128fSAndroid Build Coastguard Worker 	ext2fs_struct_stat st;
421*6a54128fSAndroid Build Coastguard Worker 	int		blk_shift;
422*6a54128fSAndroid Build Coastguard Worker 	long		fd;
423*6a54128fSAndroid Build Coastguard Worker 	unsigned long long	numblocks;
424*6a54128fSAndroid Build Coastguard Worker 	int		data_blocks_per_cyl = 1;
425*6a54128fSAndroid Build Coastguard Worker 	int		num_extents = 1, expected = ~0;
426*6a54128fSAndroid Build Coastguard Worker 	int		is_ext2 = 0;
427*6a54128fSAndroid Build Coastguard Worker 	static dev_t	last_device;
428*6a54128fSAndroid Build Coastguard Worker 	int		width;
429*6a54128fSAndroid Build Coastguard Worker 	int		rc = 0;
430*6a54128fSAndroid Build Coastguard Worker 
431*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
432*6a54128fSAndroid Build Coastguard Worker 	fd = open64(filename, O_RDONLY);
433*6a54128fSAndroid Build Coastguard Worker #else
434*6a54128fSAndroid Build Coastguard Worker 	fd = open(filename, O_RDONLY);
435*6a54128fSAndroid Build Coastguard Worker #endif
436*6a54128fSAndroid Build Coastguard Worker 	if (fd < 0) {
437*6a54128fSAndroid Build Coastguard Worker 		rc = -errno;
438*6a54128fSAndroid Build Coastguard Worker 		perror("open");
439*6a54128fSAndroid Build Coastguard Worker 		return rc;
440*6a54128fSAndroid Build Coastguard Worker 	}
441*6a54128fSAndroid Build Coastguard Worker 
442*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
443*6a54128fSAndroid Build Coastguard Worker 	if (fstat64(fd, &st) < 0) {
444*6a54128fSAndroid Build Coastguard Worker #else
445*6a54128fSAndroid Build Coastguard Worker 	if (fstat(fd, &st) < 0) {
446*6a54128fSAndroid Build Coastguard Worker #endif
447*6a54128fSAndroid Build Coastguard Worker 		rc = -errno;
448*6a54128fSAndroid Build Coastguard Worker 		perror("stat");
449*6a54128fSAndroid Build Coastguard Worker 		goto out_close;
450*6a54128fSAndroid Build Coastguard Worker 	}
451*6a54128fSAndroid Build Coastguard Worker 
452*6a54128fSAndroid Build Coastguard Worker 	if ((last_device != st.st_dev) || !st.st_dev) {
453*6a54128fSAndroid Build Coastguard Worker 		if (fstatfs(fd, &fsinfo) < 0) {
454*6a54128fSAndroid Build Coastguard Worker 			rc = -errno;
455*6a54128fSAndroid Build Coastguard Worker 			perror("fstatfs");
456*6a54128fSAndroid Build Coastguard Worker 			goto out_close;
457*6a54128fSAndroid Build Coastguard Worker 		}
458*6a54128fSAndroid Build Coastguard Worker 		if ((ioctl(fd, FIGETBSZ, &blksize) < 0) || !blksize)
459*6a54128fSAndroid Build Coastguard Worker 			blksize = fsinfo.f_bsize;
460*6a54128fSAndroid Build Coastguard Worker 		if (verbose)
461*6a54128fSAndroid Build Coastguard Worker 			printf("Filesystem type is: %lx\n",
462*6a54128fSAndroid Build Coastguard Worker 			       (unsigned long)fsinfo.f_type);
463*6a54128fSAndroid Build Coastguard Worker 	}
464*6a54128fSAndroid Build Coastguard Worker 	st.st_blksize = blksize;
465*6a54128fSAndroid Build Coastguard Worker 	if (fsinfo.f_type == 0xef51 || fsinfo.f_type == 0xef52 ||
466*6a54128fSAndroid Build Coastguard Worker 	    fsinfo.f_type == 0xef53) {
467*6a54128fSAndroid Build Coastguard Worker 		unsigned int	flags;
468*6a54128fSAndroid Build Coastguard Worker 
469*6a54128fSAndroid Build Coastguard Worker 		if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) == 0 &&
470*6a54128fSAndroid Build Coastguard Worker 		    !(flags & EXT4_EXTENTS_FL))
471*6a54128fSAndroid Build Coastguard Worker 			is_ext2 = 1;
472*6a54128fSAndroid Build Coastguard Worker 	}
473*6a54128fSAndroid Build Coastguard Worker 
474*6a54128fSAndroid Build Coastguard Worker 	if (is_ext2) {
475*6a54128fSAndroid Build Coastguard Worker 		long cylgroups = div_ceil(fsinfo.f_blocks, blksize * 8);
476*6a54128fSAndroid Build Coastguard Worker 
477*6a54128fSAndroid Build Coastguard Worker 		if (verbose && last_device != st.st_dev)
478*6a54128fSAndroid Build Coastguard Worker 			printf("Filesystem cylinder groups approximately %ld\n",
479*6a54128fSAndroid Build Coastguard Worker 			       cylgroups);
480*6a54128fSAndroid Build Coastguard Worker 
481*6a54128fSAndroid Build Coastguard Worker 		data_blocks_per_cyl = blksize * 8 -
482*6a54128fSAndroid Build Coastguard Worker 					(fsinfo.f_files / 8 / cylgroups) - 3;
483*6a54128fSAndroid Build Coastguard Worker 	}
484*6a54128fSAndroid Build Coastguard Worker 	last_device = st.st_dev;
485*6a54128fSAndroid Build Coastguard Worker 
486*6a54128fSAndroid Build Coastguard Worker 	width = ulong_log10(fsinfo.f_blocks);
487*6a54128fSAndroid Build Coastguard Worker 	if (width > physical_width)
488*6a54128fSAndroid Build Coastguard Worker 		physical_width = width;
489*6a54128fSAndroid Build Coastguard Worker 
490*6a54128fSAndroid Build Coastguard Worker 	numblocks = (st.st_size + blksize - 1) / blksize;
491*6a54128fSAndroid Build Coastguard Worker 	if (blocksize != 0)
492*6a54128fSAndroid Build Coastguard Worker 		blk_shift = ulong_log2(blocksize);
493*6a54128fSAndroid Build Coastguard Worker 	else
494*6a54128fSAndroid Build Coastguard Worker 		blk_shift = ulong_log2(blksize);
495*6a54128fSAndroid Build Coastguard Worker 
496*6a54128fSAndroid Build Coastguard Worker 	if (use_extent_cache)
497*6a54128fSAndroid Build Coastguard Worker 		width = 10;
498*6a54128fSAndroid Build Coastguard Worker 	else
499*6a54128fSAndroid Build Coastguard Worker 		width = ulong_log10(numblocks);
500*6a54128fSAndroid Build Coastguard Worker 	if (width > logical_width)
501*6a54128fSAndroid Build Coastguard Worker 		logical_width = width;
502*6a54128fSAndroid Build Coastguard Worker 	if (verbose) {
503*6a54128fSAndroid Build Coastguard Worker 		__u32 state;
504*6a54128fSAndroid Build Coastguard Worker 
505*6a54128fSAndroid Build Coastguard Worker 		printf("File size of %s is %llu (%llu block%s of %d bytes)",
506*6a54128fSAndroid Build Coastguard Worker 		       filename, (unsigned long long) st.st_size,
507*6a54128fSAndroid Build Coastguard Worker 		       (unsigned long long) (numblocks * blksize >> blk_shift),
508*6a54128fSAndroid Build Coastguard Worker 		       numblocks == 1 ? "" : "s", 1 << blk_shift);
509*6a54128fSAndroid Build Coastguard Worker 		if (use_extent_cache &&
510*6a54128fSAndroid Build Coastguard Worker 		    ioctl(fd, EXT4_IOC_GETSTATE, &state) == 0 &&
511*6a54128fSAndroid Build Coastguard Worker 		    (state & EXT4_STATE_FLAG_EXT_PRECACHED))
512*6a54128fSAndroid Build Coastguard Worker 			fputs(" -- pre-cached", stdout);
513*6a54128fSAndroid Build Coastguard Worker 		fputc('\n', stdout);
514*6a54128fSAndroid Build Coastguard Worker 	}
515*6a54128fSAndroid Build Coastguard Worker 
516*6a54128fSAndroid Build Coastguard Worker 	if (!force_bmap) {
517*6a54128fSAndroid Build Coastguard Worker 		rc = filefrag_fiemap(fd, blk_shift, &num_extents, &st);
518*6a54128fSAndroid Build Coastguard Worker 		expected = 0;
519*6a54128fSAndroid Build Coastguard Worker 		if (rc < 0 &&
520*6a54128fSAndroid Build Coastguard Worker 		    (use_extent_cache || precache_file || xattr_map)) {
521*6a54128fSAndroid Build Coastguard Worker 			if (rc != -EBADR)
522*6a54128fSAndroid Build Coastguard Worker 				fprintf(stderr, "%s: %s: %s\n ",
523*6a54128fSAndroid Build Coastguard Worker 					filename,
524*6a54128fSAndroid Build Coastguard Worker 					use_extent_cache ?
525*6a54128fSAndroid Build Coastguard Worker 					"EXT4_IOC_GET_ES_CACHE" :
526*6a54128fSAndroid Build Coastguard Worker 					"FS_IOC_FIEMAP", strerror(-rc));
527*6a54128fSAndroid Build Coastguard Worker 			goto out_close;
528*6a54128fSAndroid Build Coastguard Worker 		}
529*6a54128fSAndroid Build Coastguard Worker 	}
530*6a54128fSAndroid Build Coastguard Worker 
531*6a54128fSAndroid Build Coastguard Worker 	if (force_bmap || rc < 0) { /* FIEMAP failed, try FIBMAP instead */
532*6a54128fSAndroid Build Coastguard Worker 		expected = filefrag_fibmap(fd, blk_shift, &num_extents,
533*6a54128fSAndroid Build Coastguard Worker 					   &st, numblocks, is_ext2);
534*6a54128fSAndroid Build Coastguard Worker 		if (expected < 0) {
535*6a54128fSAndroid Build Coastguard Worker 			if (expected == -EINVAL || expected == -ENOTTY) {
536*6a54128fSAndroid Build Coastguard Worker 				fprintf(stderr, "%s: FIBMAP%s unsupported\n",
537*6a54128fSAndroid Build Coastguard Worker 					filename, force_bmap ? "" : "/FIEMAP");
538*6a54128fSAndroid Build Coastguard Worker 			} else if (expected == -EPERM) {
539*6a54128fSAndroid Build Coastguard Worker 				fprintf(stderr,
540*6a54128fSAndroid Build Coastguard Worker 					"%s: FIBMAP requires root privileges\n",
541*6a54128fSAndroid Build Coastguard Worker 					filename);
542*6a54128fSAndroid Build Coastguard Worker 			} else {
543*6a54128fSAndroid Build Coastguard Worker 				fprintf(stderr, "%s: FIBMAP error: %s",
544*6a54128fSAndroid Build Coastguard Worker 					filename, strerror(expected));
545*6a54128fSAndroid Build Coastguard Worker 			}
546*6a54128fSAndroid Build Coastguard Worker 			rc = expected;
547*6a54128fSAndroid Build Coastguard Worker 			goto out_close;
548*6a54128fSAndroid Build Coastguard Worker 		} else {
549*6a54128fSAndroid Build Coastguard Worker 			rc = 0;
550*6a54128fSAndroid Build Coastguard Worker 		}
551*6a54128fSAndroid Build Coastguard Worker 		expected = expected / data_blocks_per_cyl + 1;
552*6a54128fSAndroid Build Coastguard Worker 	}
553*6a54128fSAndroid Build Coastguard Worker 
554*6a54128fSAndroid Build Coastguard Worker 	if (num_extents == 1)
555*6a54128fSAndroid Build Coastguard Worker 		printf("%s: 1 extent found", filename);
556*6a54128fSAndroid Build Coastguard Worker 	else
557*6a54128fSAndroid Build Coastguard Worker 		printf("%s: %d extents found", filename, num_extents);
558*6a54128fSAndroid Build Coastguard Worker 	/* count, and thus expected, only set for indirect FIBMAP'd files */
559*6a54128fSAndroid Build Coastguard Worker 	if (is_ext2 && expected && expected < num_extents)
560*6a54128fSAndroid Build Coastguard Worker 		printf(", perfection would be %d extent%s\n", expected,
561*6a54128fSAndroid Build Coastguard Worker 			(expected > 1) ? "s" : "");
562*6a54128fSAndroid Build Coastguard Worker 	else
563*6a54128fSAndroid Build Coastguard Worker 		fputc('\n', stdout);
564*6a54128fSAndroid Build Coastguard Worker out_close:
565*6a54128fSAndroid Build Coastguard Worker 	close(fd);
566*6a54128fSAndroid Build Coastguard Worker 
567*6a54128fSAndroid Build Coastguard Worker 	return rc;
568*6a54128fSAndroid Build Coastguard Worker }
569*6a54128fSAndroid Build Coastguard Worker 
570*6a54128fSAndroid Build Coastguard Worker static void usage(const char *progname)
571*6a54128fSAndroid Build Coastguard Worker {
572*6a54128fSAndroid Build Coastguard Worker 	fprintf(stderr, "Usage: %s [-b{blocksize}[KMG]] [-BeEksvxX] file ...\n",
573*6a54128fSAndroid Build Coastguard Worker 		progname);
574*6a54128fSAndroid Build Coastguard Worker 	exit(1);
575*6a54128fSAndroid Build Coastguard Worker }
576*6a54128fSAndroid Build Coastguard Worker 
577*6a54128fSAndroid Build Coastguard Worker int main(int argc, char**argv)
578*6a54128fSAndroid Build Coastguard Worker {
579*6a54128fSAndroid Build Coastguard Worker 	char **cpp;
580*6a54128fSAndroid Build Coastguard Worker 	int rc = 0, c;
581*6a54128fSAndroid Build Coastguard Worker 	int version = 0;
582*6a54128fSAndroid Build Coastguard Worker 
583*6a54128fSAndroid Build Coastguard Worker 	while ((c = getopt(argc, argv, "Bb::eEkPsvVxX")) != EOF) {
584*6a54128fSAndroid Build Coastguard Worker 		switch (c) {
585*6a54128fSAndroid Build Coastguard Worker 		case 'B':
586*6a54128fSAndroid Build Coastguard Worker 			force_bmap++;
587*6a54128fSAndroid Build Coastguard Worker 			break;
588*6a54128fSAndroid Build Coastguard Worker 		case 'b':
589*6a54128fSAndroid Build Coastguard Worker 			if (optarg) {
590*6a54128fSAndroid Build Coastguard Worker 				char *end;
591*6a54128fSAndroid Build Coastguard Worker 				unsigned long val;
592*6a54128fSAndroid Build Coastguard Worker 
593*6a54128fSAndroid Build Coastguard Worker 				val = strtoul(optarg, &end, 0);
594*6a54128fSAndroid Build Coastguard Worker 				if (end) {
595*6a54128fSAndroid Build Coastguard Worker #if __GNUC_PREREQ (7, 0)
596*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic push
597*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
598*6a54128fSAndroid Build Coastguard Worker #endif
599*6a54128fSAndroid Build Coastguard Worker 					switch (end[0]) {
600*6a54128fSAndroid Build Coastguard Worker 					case 'g':
601*6a54128fSAndroid Build Coastguard Worker 					case 'G':
602*6a54128fSAndroid Build Coastguard Worker 						val *= 1024;
603*6a54128fSAndroid Build Coastguard Worker 						/* fall through */
604*6a54128fSAndroid Build Coastguard Worker 					case 'm':
605*6a54128fSAndroid Build Coastguard Worker 					case 'M':
606*6a54128fSAndroid Build Coastguard Worker 						val *= 1024;
607*6a54128fSAndroid Build Coastguard Worker 						/* fall through */
608*6a54128fSAndroid Build Coastguard Worker 					case 'k':
609*6a54128fSAndroid Build Coastguard Worker 					case 'K':
610*6a54128fSAndroid Build Coastguard Worker 						val *= 1024;
611*6a54128fSAndroid Build Coastguard Worker 						break;
612*6a54128fSAndroid Build Coastguard Worker 					default:
613*6a54128fSAndroid Build Coastguard Worker 						break;
614*6a54128fSAndroid Build Coastguard Worker 					}
615*6a54128fSAndroid Build Coastguard Worker #if __GNUC_PREREQ (7, 0)
616*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic pop
617*6a54128fSAndroid Build Coastguard Worker #endif
618*6a54128fSAndroid Build Coastguard Worker 				}
619*6a54128fSAndroid Build Coastguard Worker 				/* Specifying too large a blocksize will just
620*6a54128fSAndroid Build Coastguard Worker 				 * shift all extents down to zero length. Even
621*6a54128fSAndroid Build Coastguard Worker 				 * 1GB is questionable, but caveat emptor. */
622*6a54128fSAndroid Build Coastguard Worker 				if (val > 1024 * 1024 * 1024) {
623*6a54128fSAndroid Build Coastguard Worker 					fprintf(stderr,
624*6a54128fSAndroid Build Coastguard Worker 						"%s: blocksize %lu over 1GB\n",
625*6a54128fSAndroid Build Coastguard Worker 						argv[0], val);
626*6a54128fSAndroid Build Coastguard Worker 					usage(argv[0]);
627*6a54128fSAndroid Build Coastguard Worker 				}
628*6a54128fSAndroid Build Coastguard Worker 				blocksize = val;
629*6a54128fSAndroid Build Coastguard Worker 			} else { /* Allow -b without argument for compat. Remove
630*6a54128fSAndroid Build Coastguard Worker 				  * this eventually so "-b {blocksize}" works */
631*6a54128fSAndroid Build Coastguard Worker 				fprintf(stderr, "%s: -b needs a blocksize "
632*6a54128fSAndroid Build Coastguard Worker 					"option, assuming 1024-byte blocks.\n",
633*6a54128fSAndroid Build Coastguard Worker 					argv[0]);
634*6a54128fSAndroid Build Coastguard Worker 				blocksize = 1024;
635*6a54128fSAndroid Build Coastguard Worker 			}
636*6a54128fSAndroid Build Coastguard Worker 			break;
637*6a54128fSAndroid Build Coastguard Worker 		case 'E':
638*6a54128fSAndroid Build Coastguard Worker 			use_extent_cache++;
639*6a54128fSAndroid Build Coastguard Worker 			/* fallthrough */
640*6a54128fSAndroid Build Coastguard Worker 		case 'e':
641*6a54128fSAndroid Build Coastguard Worker 			force_extent++;
642*6a54128fSAndroid Build Coastguard Worker 			if (!verbose)
643*6a54128fSAndroid Build Coastguard Worker 				verbose++;
644*6a54128fSAndroid Build Coastguard Worker 			break;
645*6a54128fSAndroid Build Coastguard Worker 		case 'k':
646*6a54128fSAndroid Build Coastguard Worker 			blocksize = 1024;
647*6a54128fSAndroid Build Coastguard Worker 			break;
648*6a54128fSAndroid Build Coastguard Worker 		case 'P':
649*6a54128fSAndroid Build Coastguard Worker 			precache_file++;
650*6a54128fSAndroid Build Coastguard Worker 			break;
651*6a54128fSAndroid Build Coastguard Worker 		case 's':
652*6a54128fSAndroid Build Coastguard Worker 			sync_file++;
653*6a54128fSAndroid Build Coastguard Worker 			break;
654*6a54128fSAndroid Build Coastguard Worker 		case 'v':
655*6a54128fSAndroid Build Coastguard Worker 			verbose++;
656*6a54128fSAndroid Build Coastguard Worker 			break;
657*6a54128fSAndroid Build Coastguard Worker 		case 'V':
658*6a54128fSAndroid Build Coastguard Worker 			version++;
659*6a54128fSAndroid Build Coastguard Worker 			break;
660*6a54128fSAndroid Build Coastguard Worker 		case 'x':
661*6a54128fSAndroid Build Coastguard Worker 			xattr_map++;
662*6a54128fSAndroid Build Coastguard Worker 			break;
663*6a54128fSAndroid Build Coastguard Worker 		case 'X':
664*6a54128fSAndroid Build Coastguard Worker 			ext_fmt = hex_fmt;
665*6a54128fSAndroid Build Coastguard Worker 			break;
666*6a54128fSAndroid Build Coastguard Worker 		default:
667*6a54128fSAndroid Build Coastguard Worker 			usage(argv[0]);
668*6a54128fSAndroid Build Coastguard Worker 			break;
669*6a54128fSAndroid Build Coastguard Worker 		}
670*6a54128fSAndroid Build Coastguard Worker 	}
671*6a54128fSAndroid Build Coastguard Worker 	if (version) {
672*6a54128fSAndroid Build Coastguard Worker 		/* Print version number and exit */
673*6a54128fSAndroid Build Coastguard Worker 		printf("filefrag %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
674*6a54128fSAndroid Build Coastguard Worker 		if (version + verbose > 1) {
675*6a54128fSAndroid Build Coastguard Worker 			char flags[256] = "";
676*6a54128fSAndroid Build Coastguard Worker 
677*6a54128fSAndroid Build Coastguard Worker 			print_flags(0xffffffff, flags, sizeof(flags), 0);
678*6a54128fSAndroid Build Coastguard Worker 			printf("supported: %s\n", flags);
679*6a54128fSAndroid Build Coastguard Worker 		}
680*6a54128fSAndroid Build Coastguard Worker 		exit(0);
681*6a54128fSAndroid Build Coastguard Worker 	}
682*6a54128fSAndroid Build Coastguard Worker 
683*6a54128fSAndroid Build Coastguard Worker 	if (optind == argc)
684*6a54128fSAndroid Build Coastguard Worker 		usage(argv[0]);
685*6a54128fSAndroid Build Coastguard Worker 
686*6a54128fSAndroid Build Coastguard Worker 	for (cpp = argv + optind; *cpp != NULL; cpp++) {
687*6a54128fSAndroid Build Coastguard Worker 		int rc2 = frag_report(*cpp);
688*6a54128fSAndroid Build Coastguard Worker 
689*6a54128fSAndroid Build Coastguard Worker 		if (rc2 < 0 && rc == 0)
690*6a54128fSAndroid Build Coastguard Worker 			rc = rc2;
691*6a54128fSAndroid Build Coastguard Worker 	}
692*6a54128fSAndroid Build Coastguard Worker 
693*6a54128fSAndroid Build Coastguard Worker 	return -rc;
694*6a54128fSAndroid Build Coastguard Worker }
695*6a54128fSAndroid Build Coastguard Worker #endif
696