]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/fiemap.c
xfsprogs: move __u*/__s* typedefs to per-port headers
[thirdparty/xfsprogs-dev.git] / io / fiemap.c
CommitLineData
8f0e0912
CH
1/*
2 * Copyright (c) 2010 Red Hat, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
6b803e5a
CH
19#include "xfs.h"
20#include "command.h"
8f0e0912
CH
21#include <linux/fiemap.h>
22#include <linux/fs.h>
23#include "init.h"
24#include "io.h"
25
26static cmdinfo_t fiemap_cmd;
27
28static void
29fiemap_help(void)
30{
31 printf(_(
32"\n"
33" prints the block mapping for a file's data or attribute forks"
34"\n"
35" Example:\n"
36" 'fiemap -v' - tabular format verbose map\n"
37"\n"
38" fiemap prints the map of disk blocks used by the current file.\n"
39" The map lists each extent used by the file, as well as regions in the\n"
40" file that do not have any corresponding blocks (holes).\n"
41" By default, each line of the listing takes the following form:\n"
42" extent: [startoffset..endoffset]: startblock..endblock\n"
43" Holes are marked by replacing the startblock..endblock with 'hole'.\n"
44" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
45" -a -- prints the attribute fork map instead of the data fork.\n"
46" -l -- also displays the length of each extent in 512-byte blocks.\n"
47" -n -- query n extents.\n"
48" -v -- Verbose information\n"
49"\n"));
50}
51
52static int
53numlen(
54 __u64 val,
55 int base)
56{
57 __u64 tmp;
58 int len;
59
60 for (len = 0, tmp = val; tmp > 0; tmp = tmp/base)
61 len++;
62 return (len == 0 ? 1 : len);
63}
64
65static void
66print_verbose(
67 struct fiemap_extent *extent,
68 int blocksize,
69 int foff_w,
70 int boff_w,
71 int tot_w,
72 int flg_w,
73 int max_extents,
74 int *cur_extent,
75 __u64 *last_logical)
76{
77 __u64 lstart;
ef45fa5e 78 __u64 llast;
8f0e0912
CH
79 __u64 len;
80 __u64 block;
81 char lbuf[48];
82 char bbuf[48];
83 char flgbuf[16];
84
ef45fa5e 85 llast = *last_logical / blocksize;
8f0e0912
CH
86 lstart = extent->fe_logical / blocksize;
87 len = extent->fe_length / blocksize;
88 block = extent->fe_physical / blocksize;
89
90 memset(lbuf, 0, sizeof(lbuf));
91 memset(bbuf, 0, sizeof(bbuf));
92
b3a5164e
ES
93 if (*cur_extent == 0) {
94 printf("%4s: %-*s %-*s %*s %*s\n", _("EXT"),
95 foff_w, _("FILE-OFFSET"),
96 boff_w, _("BLOCK-RANGE"),
97 tot_w, _("TOTAL"),
98 flg_w, _("FLAGS"));
99 }
100
ef45fa5e
DC
101 if (lstart != llast) {
102 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", llast,
8f0e0912
CH
103 lstart - 1ULL);
104 printf("%4d: %-*s %-*s %*llu\n", *cur_extent, foff_w, lbuf,
ef45fa5e 105 boff_w, _("hole"), tot_w, lstart - llast);
8f0e0912
CH
106 (*cur_extent)++;
107 memset(lbuf, 0, sizeof(lbuf));
108 }
109
110 if ((*cur_extent + 1) == max_extents)
111 return;
112
113 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", lstart,
114 lstart + len - 1ULL);
115 snprintf(bbuf, sizeof(bbuf), "%llu..%llu", block, block + len - 1ULL);
116 snprintf(flgbuf, sizeof(flgbuf), "0x%x", extent->fe_flags);
117 printf("%4d: %-*s %-*s %*llu %*s\n", *cur_extent, foff_w, lbuf,
118 boff_w, bbuf, tot_w, len, flg_w, flgbuf);
119
120 (*cur_extent)++;
1b7b28f7 121 *last_logical = extent->fe_logical + extent->fe_length;
8f0e0912
CH
122}
123
124static void
125print_plain(
126 struct fiemap_extent *extent,
127 int lflag,
128 int blocksize,
129 int max_extents,
130 int *cur_extent,
131 __u64 *last_logical)
132{
133 __u64 lstart;
ef45fa5e 134 __u64 llast;
8f0e0912
CH
135 __u64 block;
136 __u64 len;
137
ef45fa5e 138 llast = *last_logical / blocksize;
8f0e0912
CH
139 lstart = extent->fe_logical / blocksize;
140 len = extent->fe_length / blocksize;
141 block = extent->fe_physical / blocksize;
142
ef45fa5e 143 if (lstart != llast) {
8f0e0912 144 printf("\t%d: [%llu..%llu]: hole", *cur_extent,
ef45fa5e 145 llast, lstart - 1ULL);
8f0e0912 146 if (lflag)
ef45fa5e 147 printf(_(" %llu blocks\n"), lstart - llast);
8f0e0912
CH
148 else
149 printf("\n");
150 (*cur_extent)++;
151 }
152
153 if ((*cur_extent + 1) == max_extents)
154 return;
155
156 printf("\t%d: [%llu..%llu]: %llu..%llu", *cur_extent,
157 lstart, lstart + len - 1ULL, block,
158 block + len - 1ULL);
159
160 if (lflag)
161 printf(_(" %llu blocks\n"), len);
162 else
163 printf("\n");
164 (*cur_extent)++;
1b7b28f7 165 *last_logical = extent->fe_logical + extent->fe_length;
8f0e0912
CH
166}
167
b3a5164e
ES
168/*
169 * Calculate the proper extent table format based on first
170 * set of extents
171 */
172static void
173calc_print_format(
174 struct fiemap *fiemap,
175 __u64 blocksize,
176 int *foff_w,
177 int *boff_w,
178 int *tot_w,
179 int *flg_w)
180{
181 int i;
182 char lbuf[32];
183 char bbuf[32];
184 __u64 logical;
185 __u64 block;
186 __u64 len;
187 struct fiemap_extent *extent;
188
189 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
190
191 extent = &fiemap->fm_extents[i];
192 logical = extent->fe_logical / blocksize;
193 len = extent->fe_length / blocksize;
194 block = extent->fe_physical / blocksize;
195
196 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]", logical,
197 logical + len - 1);
198 snprintf(bbuf, sizeof(bbuf), "%llu..%llu", block,
199 block + len - 1);
200 *foff_w = max(*foff_w, strlen(lbuf));
201 *boff_w = max(*boff_w, strlen(bbuf));
202 *tot_w = max(*tot_w, numlen(len, 10));
203 *flg_w = max(*flg_w, numlen(extent->fe_flags, 16));
204 if (extent->fe_flags & FIEMAP_EXTENT_LAST)
205 break;
206 }
207}
208
8f0e0912
CH
209int
210fiemap_f(
211 int argc,
212 char **argv)
213{
214 struct fiemap *fiemap;
215 int max_extents = 0;
216 int num_extents = 32;
217 int last = 0;
8f0e0912
CH
218 int lflag = 0;
219 int vflag = 0;
220 int fiemap_flags = FIEMAP_FLAG_SYNC;
221 int c;
222 int i;
223 int map_size;
224 int ret;
225 int cur_extent = 0;
226 int foff_w = 16; /* 16 just for a good minimum range */
227 int boff_w = 16;
228 int tot_w = 5; /* 5 since its just one number */
229 int flg_w = 5;
230 __u64 blocksize = 512;
231 __u64 last_logical = 0;
232 struct stat st;
233
234 while ((c = getopt(argc, argv, "aln:v")) != EOF) {
235 switch (c) {
236 case 'a':
237 fiemap_flags |= FIEMAP_FLAG_XATTR;
238 break;
239 case 'l':
240 lflag = 1;
241 break;
242 case 'n':
243 max_extents = atoi(optarg);
8f0e0912
CH
244 break;
245 case 'v':
246 vflag++;
247 break;
248 default:
249 return command_usage(&fiemap_cmd);
250 }
251 }
252
253 if (max_extents)
254 num_extents = min(num_extents, max_extents);
255 map_size = sizeof(struct fiemap) +
256 (num_extents * sizeof(struct fiemap_extent));
257 fiemap = malloc(map_size);
258 if (!fiemap) {
259 fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
260 progname, map_size);
261 exitcode = 1;
262 return 0;
263 }
264
265 printf("%s:\n", file->name);
266
8f0e0912
CH
267 while (!last && ((cur_extent + 1) != max_extents)) {
268 if (max_extents)
269 num_extents = min(num_extents,
270 max_extents - (cur_extent + 1));
271
272 memset(fiemap, 0, map_size);
273 fiemap->fm_flags = fiemap_flags;
274 fiemap->fm_start = last_logical;
1b7b28f7 275 fiemap->fm_length = -1LL;
8f0e0912
CH
276 fiemap->fm_extent_count = num_extents;
277
278 ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
279 if (ret < 0) {
280 fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
281 "%s\n", progname, file->name, strerror(errno));
282 free(fiemap);
283 exitcode = 1;
284 return 0;
285 }
286
287 /* No more extents to map, exit */
288 if (!fiemap->fm_mapped_extents)
289 break;
290
291 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
292 struct fiemap_extent *extent;
293
294 extent = &fiemap->fm_extents[i];
b3a5164e
ES
295 if (vflag) {
296 if (cur_extent == 0) {
297 calc_print_format(fiemap, blocksize,
298 &foff_w, &boff_w,
299 &tot_w, &flg_w);
300 }
301
8f0e0912
CH
302 print_verbose(extent, blocksize, foff_w,
303 boff_w, tot_w, flg_w,
304 max_extents, &cur_extent,
305 &last_logical);
b3a5164e 306 } else
8f0e0912
CH
307 print_plain(extent, lflag, blocksize,
308 max_extents, &cur_extent,
309 &last_logical);
ef45fa5e 310
8f0e0912
CH
311 if (extent->fe_flags & FIEMAP_EXTENT_LAST) {
312 last = 1;
313 break;
314 }
315
316 if ((cur_extent + 1) == max_extents)
317 break;
318 }
319 }
320
321 if ((cur_extent + 1) == max_extents)
322 goto out;
323
324 memset(&st, 0, sizeof(st));
325 if (fstat(file->fd, &st)) {
326 fprintf(stderr, "%s: fstat failed: %s\n", progname,
327 strerror(errno));
328 free(fiemap);
329 exitcode = 1;
330 return 0;
331 }
332
ef45fa5e 333 if (cur_extent && last_logical < st.st_size) {
8f0e0912
CH
334 char lbuf[32];
335
336 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
ef45fa5e 337 last_logical / blocksize, (st.st_size / blocksize) - 1);
8f0e0912
CH
338 if (vflag) {
339 printf("%4d: %-*s %-*s %*llu\n", cur_extent,
340 foff_w, lbuf, boff_w, _("hole"), tot_w,
ef45fa5e 341 (st.st_size - last_logical) / blocksize);
8f0e0912
CH
342 } else {
343 printf("\t%d: %s %s", cur_extent, lbuf,
344 _("hole"));
345 if (lflag)
346 printf(_(" %llu blocks\n"),
ef45fa5e 347 (st.st_size - last_logical) / blocksize);
8f0e0912
CH
348 else
349 printf("\n");
350 }
351 }
352
353out:
354 free(fiemap);
355 return 0;
356}
357
358void
359fiemap_init(void)
360{
361 fiemap_cmd.name = "fiemap";
362 fiemap_cmd.cfunc = fiemap_f;
363 fiemap_cmd.argmin = 0;
364 fiemap_cmd.argmax = -1;
365 fiemap_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
366 fiemap_cmd.args = _("[-alv] [-n nx]");
367 fiemap_cmd.oneline = _("print block mapping for a file");
368 fiemap_cmd.help = fiemap_help;
369
370 add_command(&fiemap_cmd);
371}