1 /*
2 * extent_inode.c --- direct extent tree manipulation
3 *
4 * Copyright (C) 2012 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <ctype.h>
12 #include <string.h>
13 #include <time.h>
14 #ifdef HAVE_ERRNO_H
15 #include <errno.h>
16 #endif
17 #include <sys/types.h>
18 #ifdef HAVE_GETOPT_H
19 #include <getopt.h>
20 #else
21 extern int optind;
22 extern char *optarg;
23 #endif
24
25 #include "debugfs.h"
26
27 static ext2_ino_t current_ino;
28 static ext2_extent_handle_t current_handle;
29
dbg_print_extent(char * desc,struct ext2fs_extent * extent)30 static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
31 {
32 if (desc)
33 printf("%s: ", desc);
34 printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
35 extent->e_lblk, extent->e_lblk + extent->e_len - 1,
36 extent->e_len, extent->e_pblk);
37 if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
38 fputs("LEAF ", stdout);
39 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
40 fputs("UNINIT ", stdout);
41 if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
42 fputs("2ND_VISIT ", stdout);
43 if (!extent->e_flags)
44 fputs("(none)", stdout);
45 fputc('\n', stdout);
46
47 }
48
common_extent_args_process(int argc,char * argv[],int min_argc,int max_argc,const char * cmd,const char * usage,int flags)49 static int common_extent_args_process(int argc, char *argv[], int min_argc,
50 int max_argc, const char *cmd,
51 const char *usage, int flags)
52 {
53 if (common_args_process(argc, argv, min_argc, max_argc, cmd,
54 usage, flags))
55 return 1;
56
57 if (!current_handle) {
58 com_err(cmd, 0, "Extent handle not open");
59 return 1;
60 }
61 return 0;
62 }
63
64 static char *orig_prompt, *extent_prompt;
65
do_extent_open(int argc,char * argv[])66 void do_extent_open(int argc, char *argv[])
67 {
68 ext2_ino_t inode;
69 int ret;
70 errcode_t retval;
71 char *cp;
72
73 if (check_fs_open(argv[0]))
74 return;
75
76 if (argc == 1) {
77 if (current_ino)
78 printf("Current inode is %d\n", current_ino);
79 else
80 printf("No current inode\n");
81 return;
82 }
83
84 if (common_inode_args_process(argc, argv, &inode, 0))
85 return;
86
87 current_ino = 0;
88
89 retval = ext2fs_extent_open(current_fs, inode, ¤t_handle);
90 if (retval) {
91 com_err(argv[1], retval, "while opening extent handle");
92 return;
93 }
94
95 current_ino = inode;
96
97 orig_prompt = ss_get_prompt(sci_idx);
98 extent_prompt = malloc(strlen(orig_prompt) + 32);
99 strcpy(extent_prompt, orig_prompt);
100 cp = strchr(extent_prompt, ':');
101 if (cp)
102 *cp = 0;
103 sprintf(extent_prompt + strlen(extent_prompt), " (extent ino %d): ",
104 current_ino);
105 ss_add_request_table(sci_idx, &extent_cmds, 1, &ret);
106 ss_set_prompt(sci_idx, extent_prompt);
107 return;
108 }
109
do_extent_close(int argc,char * argv[])110 void do_extent_close(int argc, char *argv[])
111 {
112 int ret;
113
114 if (common_args_process(argc, argv, 1, 1,
115 "extent_close", "", 0))
116 return;
117
118 if (!current_handle) {
119 com_err(argv[0], 0, "Extent handle not open");
120 return;
121 }
122
123 ext2fs_extent_free(current_handle);
124 current_handle = NULL;
125 current_ino = 0;
126 ss_delete_request_table(sci_idx, &extent_cmds, &ret);
127 ss_set_prompt(sci_idx, orig_prompt);
128 free(extent_prompt);
129 extent_prompt = NULL;
130 }
131
generic_goto_node(const char * my_name,int argc,char ** argv,int op)132 static void generic_goto_node(const char *my_name, int argc,
133 char **argv, int op)
134 {
135 struct ext2fs_extent extent;
136 errcode_t retval;
137
138 if (my_name && common_args_process(argc, argv, 1, 1,
139 my_name, "", 0))
140 return;
141
142 if (!current_handle) {
143 com_err(argv[0], 0, "Extent handle not open");
144 return;
145 }
146
147 retval = ext2fs_extent_get(current_handle, op, &extent);
148 if (retval) {
149 com_err(argv[0], retval, 0);
150 return;
151 }
152 dbg_print_extent(0, &extent);
153 }
154
do_current_node(int argc,char * argv[])155 void do_current_node(int argc, char *argv[])
156 {
157 generic_goto_node("current_node", argc, argv, EXT2_EXTENT_CURRENT);
158 }
159
do_root_node(int argc,char * argv[])160 void do_root_node(int argc, char *argv[])
161 {
162 generic_goto_node("root_node", argc, argv, EXT2_EXTENT_ROOT);
163 }
164
do_last_leaf(int argc,char * argv[])165 void do_last_leaf(int argc, char *argv[])
166 {
167 generic_goto_node("last_leaf", argc, argv, EXT2_EXTENT_LAST_LEAF);
168 }
169
do_first_sib(int argc,char * argv[])170 void do_first_sib(int argc, char *argv[])
171 {
172 generic_goto_node("first_sib", argc, argv, EXT2_EXTENT_FIRST_SIB);
173 }
174
do_last_sib(int argc,char * argv[])175 void do_last_sib(int argc, char *argv[])
176 {
177 generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_LAST_SIB);
178 }
179
do_next_sib(int argc,char * argv[])180 void do_next_sib(int argc, char *argv[])
181 {
182 generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_NEXT_SIB);
183 }
184
do_prev_sib(int argc,char * argv[])185 void do_prev_sib(int argc, char *argv[])
186 {
187 generic_goto_node("prev_sib", argc, argv, EXT2_EXTENT_PREV_SIB);
188 }
189
do_next_leaf(int argc,char * argv[])190 void do_next_leaf(int argc, char *argv[])
191 {
192 generic_goto_node("next_leaf", argc, argv, EXT2_EXTENT_NEXT_LEAF);
193 }
194
do_prev_leaf(int argc,char * argv[])195 void do_prev_leaf(int argc, char *argv[])
196 {
197 generic_goto_node("prev_leaf", argc, argv, EXT2_EXTENT_PREV_LEAF);
198 }
199
do_next(int argc,char * argv[])200 void do_next(int argc, char *argv[])
201 {
202 generic_goto_node("next", argc, argv, EXT2_EXTENT_NEXT);
203 }
204
do_prev(int argc,char * argv[])205 void do_prev(int argc, char *argv[])
206 {
207 generic_goto_node("prev", argc, argv, EXT2_EXTENT_PREV);
208 }
209
do_up(int argc,char * argv[])210 void do_up(int argc, char *argv[])
211 {
212 generic_goto_node("up", argc, argv, EXT2_EXTENT_UP);
213 }
214
do_down(int argc,char * argv[])215 void do_down(int argc, char *argv[])
216 {
217 generic_goto_node("down", argc, argv, EXT2_EXTENT_DOWN);
218 }
219
do_delete_node(int argc,char * argv[])220 void do_delete_node(int argc, char *argv[])
221 {
222 struct ext2fs_extent extent;
223 errcode_t retval;
224
225 if (common_extent_args_process(argc, argv, 1, 1, "delete_node",
226 "", CHECK_FS_RW | CHECK_FS_BITMAPS))
227 return;
228
229 retval = ext2fs_extent_delete(current_handle, 0);
230 if (retval) {
231 com_err(argv[0], retval, 0);
232 return;
233 }
234
235 retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
236 &extent);
237 if (retval)
238 return;
239 dbg_print_extent(0, &extent);
240 }
241
do_replace_node(int argc,char * argv[])242 void do_replace_node(int argc, char *argv[])
243 {
244 const char *usage = "[--uninit] <lblk> <len> <pblk>";
245 errcode_t retval;
246 struct ext2fs_extent extent;
247 int err;
248
249 if (common_extent_args_process(argc, argv, 3, 5, "replace_node",
250 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
251 return;
252
253 extent.e_flags = 0;
254
255 if (!strcmp(argv[1], "--uninit")) {
256 argc--;
257 argv++;
258 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
259 }
260
261 if (argc != 4) {
262 fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
263 return;
264 }
265
266 err = strtoblk(argv[0], argv[1], &extent.e_lblk);
267 if (err)
268 return;
269
270 extent.e_len = parse_ulong(argv[2], argv[0], "logical block", &err);
271 if (err)
272 return;
273
274 err = strtoblk(argv[0], argv[3], &extent.e_pblk);
275 if (err)
276 return;
277
278 retval = ext2fs_extent_replace(current_handle, 0, &extent);
279 if (retval) {
280 com_err(argv[0], retval, 0);
281 return;
282 }
283 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
284 }
285
do_split_node(int argc,char * argv[])286 void do_split_node(int argc, char *argv[])
287 {
288 errcode_t retval;
289
290 if (common_extent_args_process(argc, argv, 1, 1, "split_node",
291 "", CHECK_FS_RW | CHECK_FS_BITMAPS))
292 return;
293
294 retval = ext2fs_extent_node_split(current_handle);
295 if (retval) {
296 com_err(argv[0], retval, 0);
297 return;
298 }
299 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
300 }
301
do_insert_node(int argc,char * argv[])302 void do_insert_node(int argc, char *argv[])
303 {
304 const char *usage = "[--after] [--uninit] <lblk> <len> <pblk>";
305 errcode_t retval;
306 struct ext2fs_extent extent;
307 char *cmd;
308 int err;
309 int flags = 0;
310
311 if (common_extent_args_process(argc, argv, 3, 6, "insert_node",
312 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
313 return;
314
315 cmd = argv[0];
316
317 extent.e_flags = 0;
318
319 while (argc > 2) {
320 if (!strcmp(argv[1], "--after")) {
321 argc--;
322 argv++;
323 flags |= EXT2_EXTENT_INSERT_AFTER;
324 continue;
325 }
326 if (!strcmp(argv[1], "--uninit")) {
327 argc--;
328 argv++;
329 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
330 continue;
331 }
332 break;
333 }
334
335 if (argc != 4) {
336 fprintf(stderr, "usage: %s %s\n", cmd, usage);
337 return;
338 }
339
340 err = strtoblk(cmd, argv[1], &extent.e_lblk);
341 if (err)
342 return;
343
344 extent.e_len = parse_ulong(argv[2], cmd,
345 "length", &err);
346 if (err)
347 return;
348
349 err = strtoblk(cmd, argv[3], &extent.e_pblk);
350 if (err)
351 return;
352
353 retval = ext2fs_extent_insert(current_handle, flags, &extent);
354 if (retval) {
355 com_err(cmd, retval, 0);
356 return;
357 }
358 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
359 }
360
do_set_bmap(int argc,char ** argv)361 void do_set_bmap(int argc, char **argv)
362 {
363 const char *usage = "[--uninit] <lblk> <pblk>";
364 struct ext2fs_extent extent;
365 errcode_t retval;
366 blk64_t logical;
367 blk64_t physical;
368 char *cmd = argv[0];
369 int flags = 0;
370 int err;
371
372 if (common_extent_args_process(argc, argv, 3, 5, "set_bmap",
373 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
374 return;
375
376 if (argc > 2 && !strcmp(argv[1], "--uninit")) {
377 argc--;
378 argv++;
379 flags |= EXT2_EXTENT_SET_BMAP_UNINIT;
380 }
381
382 if (argc != 3) {
383 fprintf(stderr, "Usage: %s %s\n", cmd, usage);
384 return;
385 }
386
387 err = strtoblk(cmd, argv[1], &logical);
388 if (err)
389 return;
390
391 err = strtoblk(cmd, argv[2], &physical);
392 if (err)
393 return;
394
395 retval = ext2fs_extent_set_bmap(current_handle, logical,
396 physical, flags);
397 if (retval) {
398 com_err(cmd, retval, 0);
399 return;
400 }
401
402 retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
403 &extent);
404 if (retval)
405 return;
406 dbg_print_extent(0, &extent);
407 }
408
do_print_all(int argc,char ** argv)409 void do_print_all(int argc, char **argv)
410 {
411 const char *usage = "[--leaf-only|--reverse|--reverse-leaf]";
412 struct ext2fs_extent extent;
413 errcode_t retval;
414 errcode_t end_err = EXT2_ET_EXTENT_NO_NEXT;
415 int op = EXT2_EXTENT_NEXT;
416 int first_op = EXT2_EXTENT_ROOT;
417
418
419 if (common_extent_args_process(argc, argv, 1, 2, "print_all",
420 usage, 0))
421 return;
422
423 if (argc == 2) {
424 if (!strcmp(argv[1], "--leaf-only"))
425 op = EXT2_EXTENT_NEXT_LEAF;
426 else if (!strcmp(argv[1], "--reverse")) {
427 op = EXT2_EXTENT_PREV;
428 first_op = EXT2_EXTENT_LAST_LEAF;
429 end_err = EXT2_ET_EXTENT_NO_PREV;
430 } else if (!strcmp(argv[1], "--reverse-leaf")) {
431 op = EXT2_EXTENT_PREV_LEAF;
432 first_op = EXT2_EXTENT_LAST_LEAF;
433 end_err = EXT2_ET_EXTENT_NO_PREV;
434 } else {
435 fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
436 return;
437 }
438 }
439
440 retval = ext2fs_extent_get(current_handle, first_op, &extent);
441 if (retval) {
442 com_err(argv[0], retval, 0);
443 return;
444 }
445 dbg_print_extent(0, &extent);
446
447 while (1) {
448 retval = ext2fs_extent_get(current_handle, op, &extent);
449 if (retval == end_err)
450 break;
451
452 if (retval) {
453 com_err(argv[0], retval, 0);
454 return;
455 }
456 dbg_print_extent(0, &extent);
457 }
458 }
459
do_fix_parents(int argc,char ** argv)460 void do_fix_parents(int argc, char **argv)
461 {
462 errcode_t retval;
463
464 if (common_extent_args_process(argc, argv, 1, 1, "fix_parents", "",
465 CHECK_FS_RW))
466 return;
467
468 retval = ext2fs_extent_fix_parents(current_handle);
469 if (retval) {
470 com_err(argv[0], retval, 0);
471 return;
472 }
473 }
474
do_info(int argc,char ** argv)475 void do_info(int argc, char **argv)
476 {
477 struct ext2fs_extent extent;
478 struct ext2_extent_info info;
479 errcode_t retval;
480
481 if (common_extent_args_process(argc, argv, 1, 1, "info", "", 0))
482 return;
483
484 retval = ext2fs_extent_get_info(current_handle, &info);
485 if (retval) {
486 com_err(argv[0], retval, 0);
487 return;
488 }
489
490 retval = ext2fs_extent_get(current_handle,
491 EXT2_EXTENT_CURRENT, &extent);
492 if (retval) {
493 com_err(argv[0], retval, 0);
494 return;
495 }
496
497 dbg_print_extent(0, &extent);
498
499 printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
500 info.curr_entry, info.num_entries, info.max_entries,
501 info.bytes_avail, info.curr_level, info.max_depth);
502 printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
503 info.max_pblk);
504 printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
505 info.max_uninit_len);
506 }
507
do_goto_block(int argc,char ** argv)508 void do_goto_block(int argc, char **argv)
509 {
510 errcode_t retval;
511 blk64_t blk;
512 int level = 0, err;
513
514 if (common_extent_args_process(argc, argv, 2, 3, "goto_block",
515 "block [level]", 0))
516 return;
517
518 if (strtoblk(argv[0], argv[1], &blk))
519 return;
520
521 if (argc == 3) {
522 level = parse_ulong(argv[2], argv[0], "level", &err);
523 if (err)
524 return;
525 }
526
527 retval = ext2fs_extent_goto2(current_handle, level, (blk64_t) blk);
528
529 if (retval) {
530 com_err(argv[0], retval,
531 "while trying to go to block %llu, level %d",
532 (unsigned long long) blk, level);
533 return;
534 }
535
536 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
537 }
538