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