extent_inode.c revision 9e85208e84bbdea9cfe6e8887502a1c4d92efbe5
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 22extern int optind; 23extern char *optarg; 24#endif 25 26#include "debugfs.h" 27 28ext2_ino_t current_ino; 29ext2_extent_handle_t current_handle; 30 31static 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 50static 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 65static char *orig_prompt, *extent_prompt; 66 67void 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 strcpy(extent_prompt, orig_prompt); 101 cp = strchr(extent_prompt, ':'); 102 if (cp) 103 *cp = 0; 104 sprintf(extent_prompt + strlen(extent_prompt), " (extent ino %d): ", 105 current_ino); 106 ss_add_request_table(sci_idx, &extent_cmds, 1, &ret); 107 ss_set_prompt(sci_idx, extent_prompt); 108 return; 109} 110 111void do_extent_close(int argc, char *argv[]) 112{ 113 int ret; 114 115 if (common_args_process(argc, argv, 1, 1, 116 "extent_close", "", 0)) 117 return; 118 119 if (!current_handle) { 120 com_err(argv[0], 0, "Extent handle not open"); 121 return; 122 } 123 124 ext2fs_extent_free(current_handle); 125 current_handle = NULL; 126 current_ino = 0; 127 ss_delete_request_table(sci_idx, &extent_cmds, &ret); 128 ss_set_prompt(sci_idx, orig_prompt); 129 free(extent_prompt); 130 extent_prompt = NULL; 131} 132 133static void generic_goto_node(const char *my_name, int argc, 134 char **argv, int op) 135{ 136 struct ext2fs_extent extent; 137 errcode_t retval; 138 139 if (my_name && common_args_process(argc, argv, 1, 1, 140 my_name, "", 0)) 141 return; 142 143 if (!current_handle) { 144 com_err(argv[0], 0, "Extent handle not open"); 145 return; 146 } 147 148 retval = ext2fs_extent_get(current_handle, op, &extent); 149 if (retval) { 150 com_err(argv[0], retval, 0); 151 return; 152 } 153 dbg_print_extent(0, &extent); 154} 155 156void do_current_node(int argc, char *argv[]) 157{ 158 generic_goto_node("current_node", argc, argv, EXT2_EXTENT_CURRENT); 159} 160 161void do_root_node(int argc, char *argv[]) 162{ 163 generic_goto_node("root_node", argc, argv, EXT2_EXTENT_ROOT); 164} 165 166void do_last_leaf(int argc, char *argv[]) 167{ 168 generic_goto_node("last_leaf", argc, argv, EXT2_EXTENT_LAST_LEAF); 169} 170 171void do_first_sib(int argc, char *argv[]) 172{ 173 generic_goto_node("first_sib", argc, argv, EXT2_EXTENT_FIRST_SIB); 174} 175 176void do_last_sib(int argc, char *argv[]) 177{ 178 generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_LAST_SIB); 179} 180 181void do_next_sib(int argc, char *argv[]) 182{ 183 generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_NEXT_SIB); 184} 185 186void do_prev_sib(int argc, char *argv[]) 187{ 188 generic_goto_node("prev_sib", argc, argv, EXT2_EXTENT_PREV_SIB); 189} 190 191void do_next_leaf(int argc, char *argv[]) 192{ 193 generic_goto_node("next_leaf", argc, argv, EXT2_EXTENT_NEXT_LEAF); 194} 195 196void do_prev_leaf(int argc, char *argv[]) 197{ 198 generic_goto_node("prev_leaf", argc, argv, EXT2_EXTENT_PREV_LEAF); 199} 200 201void do_next(int argc, char *argv[]) 202{ 203 generic_goto_node("next", argc, argv, EXT2_EXTENT_NEXT); 204} 205 206void do_prev(int argc, char *argv[]) 207{ 208 generic_goto_node("prev", argc, argv, EXT2_EXTENT_PREV); 209} 210 211void do_up(int argc, char *argv[]) 212{ 213 generic_goto_node("up", argc, argv, EXT2_EXTENT_UP); 214} 215 216void do_down(int argc, char *argv[]) 217{ 218 generic_goto_node("down", argc, argv, EXT2_EXTENT_DOWN); 219} 220 221void do_delete_node(int argc, char *argv[]) 222{ 223 struct ext2fs_extent extent; 224 errcode_t retval; 225 226 if (common_extent_args_process(argc, argv, 1, 1, "delete_node", 227 "", CHECK_FS_RW | CHECK_FS_BITMAPS)) 228 return; 229 230 retval = ext2fs_extent_delete(current_handle, 0); 231 if (retval) { 232 com_err(argv[0], retval, 0); 233 return; 234 } 235 236 retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT, 237 &extent); 238 if (retval) 239 return; 240 dbg_print_extent(0, &extent); 241} 242 243void do_replace_node(int argc, char *argv[]) 244{ 245 const char *usage = "[--uninit] <lblk> <len> <pblk>"; 246 errcode_t retval; 247 struct ext2fs_extent extent; 248 int err; 249 250 if (common_extent_args_process(argc, argv, 3, 5, "replace_node", 251 usage, CHECK_FS_RW | CHECK_FS_BITMAPS)) 252 return; 253 254 extent.e_flags = 0; 255 256 if (!strcmp(argv[1], "--uninit")) { 257 argc--; 258 argv++; 259 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; 260 } 261 262 if (argc != 4) { 263 fprintf(stderr, "Usage: %s %s\n", argv[0], usage); 264 return; 265 } 266 267 extent.e_lblk = parse_ulong(argv[1], argv[0], "logical block", &err); 268 if (err) 269 return; 270 271 extent.e_len = parse_ulong(argv[2], argv[0], "logical block", &err); 272 if (err) 273 return; 274 275 extent.e_pblk = parse_ulong(argv[3], argv[0], "logical block", &err); 276 if (err) 277 return; 278 279 retval = ext2fs_extent_replace(current_handle, 0, &extent); 280 if (retval) { 281 com_err(argv[0], retval, 0); 282 return; 283 } 284 do_current_node(argc, argv); 285} 286 287void do_split_node(int argc, char *argv[]) 288{ 289 errcode_t retval; 290 291 if (common_extent_args_process(argc, argv, 1, 1, "split_node", 292 "", CHECK_FS_RW | CHECK_FS_BITMAPS)) 293 return; 294 295 retval = ext2fs_extent_node_split(current_handle); 296 if (retval) { 297 com_err(argv[0], retval, 0); 298 return; 299 } 300 do_current_node(argc, argv); 301} 302 303void do_insert_node(int argc, char *argv[]) 304{ 305 const char *usage = "[--after] [--uninit] <lblk> <len> <pblk>"; 306 errcode_t retval; 307 struct ext2fs_extent extent; 308 char *cmd; 309 int err; 310 int flags = 0; 311 312 if (common_extent_args_process(argc, argv, 3, 6, "insert_node", 313 usage, CHECK_FS_RW | CHECK_FS_BITMAPS)) 314 return; 315 316 cmd = argv[0]; 317 318 extent.e_flags = 0; 319 320 while (argc > 2) { 321 if (!strcmp(argv[1], "--after")) { 322 argc--; 323 argv++; 324 flags |= EXT2_EXTENT_INSERT_AFTER; 325 continue; 326 } 327 if (!strcmp(argv[1], "--uninit")) { 328 argc--; 329 argv++; 330 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; 331 continue; 332 } 333 break; 334 } 335 336 if (argc != 4) { 337 fprintf(stderr, "usage: %s %s\n", cmd, usage); 338 return; 339 } 340 341 extent.e_lblk = parse_ulong(argv[1], cmd, 342 "logical block", &err); 343 if (err) 344 return; 345 346 extent.e_len = parse_ulong(argv[2], cmd, 347 "length", &err); 348 if (err) 349 return; 350 351 extent.e_pblk = parse_ulong(argv[3], cmd, 352 "pysical block", &err); 353 if (err) 354 return; 355 356 retval = ext2fs_extent_insert(current_handle, flags, &extent); 357 if (retval) { 358 com_err(cmd, retval, 0); 359 return; 360 } 361 do_current_node(argc, argv); 362} 363 364void do_set_bmap(int argc, char **argv) 365{ 366 const char *usage = "[--uninit] <lblk> <pblk>"; 367 struct ext2fs_extent extent; 368 errcode_t retval; 369 blk_t logical; 370 blk_t physical; 371 char *cmd = argv[0]; 372 int flags = 0; 373 int err; 374 375 if (common_extent_args_process(argc, argv, 3, 5, "set_bmap", 376 usage, CHECK_FS_RW | CHECK_FS_BITMAPS)) 377 return; 378 379 if (argc > 2 && !strcmp(argv[1], "--uninit")) { 380 argc--; 381 argv++; 382 flags |= EXT2_EXTENT_SET_BMAP_UNINIT; 383 } 384 385 if (argc != 3) { 386 fprintf(stderr, "Usage: %s %s\n", cmd, usage); 387 return; 388 } 389 390 logical = parse_ulong(argv[1], cmd, 391 "logical block", &err); 392 if (err) 393 return; 394 395 physical = parse_ulong(argv[2], cmd, 396 "physical block", &err); 397 if (err) 398 return; 399 400 retval = ext2fs_extent_set_bmap(current_handle, logical, 401 (blk64_t) 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 414void 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 465void 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 480void 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 513void 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], &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