extent.c revision 9fd6a96d9bf089d8d0ece3bba23b0ef19d03c102
1/* 2 * extent.c --- routines to implement extents support 3 * 4 * Copyright (C) 2007 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#include <stdio.h> 13#include <string.h> 14#if HAVE_UNISTD_H 15#include <unistd.h> 16#endif 17#if HAVE_ERRNO_H 18#include <errno.h> 19#endif 20#if HAVE_SYS_STAT_H 21#include <sys/stat.h> 22#endif 23#if HAVE_SYS_TYPES_H 24#include <sys/types.h> 25#endif 26 27#include "ext2_fs.h" 28#include "ext2fsP.h" 29#include "e2image.h" 30#include "ss/ss.h" 31 32/* 33 * Definitions to be dropped in lib/ext2fs/ext2fs.h 34 */ 35 36/* 37 * Private definitions 38 */ 39 40struct extent_path { 41 char *buf; 42 int entries; 43 int max_entries; 44 int left; 45 int visit_num; 46 int flags; 47 blk64_t end_blk; 48 void *curr; 49}; 50 51 52struct ext2_extent_handle { 53 errcode_t magic; 54 ext2_filsys fs; 55 ext2_ino_t ino; 56 struct ext2_inode *inode; 57 int type; 58 int level; 59 int max_depth; 60 struct extent_path *path; 61}; 62 63struct ext2_extent_path { 64 errcode_t magic; 65 int leaf_height; 66 blk64_t lblk; 67}; 68 69/* 70 * Useful Debugging stuff 71 */ 72 73#ifdef DEBUG 74static void dbg_show_header(struct ext3_extent_header *eh) 75{ 76 printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n", 77 eh->eh_magic, eh->eh_entries, eh->eh_max, eh->eh_depth, 78 eh->eh_generation); 79} 80 81static void dbg_show_index(struct ext3_extent_idx *ix) 82{ 83 printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n", 84 ix->ei_block, ix->ei_leaf, ix->ei_leaf_hi, ix->ei_unused); 85} 86 87static void dbg_show_extent(struct ext3_extent *ex) 88{ 89 printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n", 90 ex->ee_block, ex->ee_block + ex->ee_len - 1, 91 ex->ee_len, ex->ee_start, ex->ee_start_hi); 92} 93 94static void dbg_print_extent(char *desc, struct ext2fs_extent *extent) 95{ 96 if (desc) 97 printf("%s: ", desc); 98 printf("extent: lblk %llu--%llu, len %lu, pblk %llu, flags: ", 99 extent->e_lblk, extent->e_lblk + extent->e_len - 1, 100 extent->e_len, extent->e_pblk); 101 if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) 102 fputs("LEAF ", stdout); 103 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) 104 fputs("UNINIT ", stdout); 105 if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) 106 fputs("2ND_VISIT ", stdout); 107 if (!extent->e_flags) 108 fputs("(none)", stdout); 109 fputc('\n', stdout); 110 111} 112 113#define dbg_printf(fmt, args...) printf(fmt, ## args) 114#else 115#define dbg_show_header(eh) do { } while (0) 116#define dbg_show_index(ix) do { } while (0) 117#define dbg_show_extent(ex) do { } while (0) 118#define dbg_print_extent(desc, ex) do { } while (0) 119#define dbg_printf(fmt, args...) do { } while (0) 120#endif 121 122/* 123 * Verify the extent header as being sane 124 */ 125errcode_t ext2fs_extent_header_verify(void *ptr, int size) 126{ 127 int eh_max, entry_size; 128 struct ext3_extent_header *eh = ptr; 129 130 dbg_show_header(eh); 131 if (ext2fs_le16_to_cpu(eh->eh_magic) != EXT3_EXT_MAGIC) 132 return EXT2_ET_EXTENT_HEADER_BAD; 133 if (ext2fs_le16_to_cpu(eh->eh_entries) > ext2fs_le16_to_cpu(eh->eh_max)) 134 return EXT2_ET_EXTENT_HEADER_BAD; 135 if (eh->eh_depth == 0) 136 entry_size = sizeof(struct ext3_extent); 137 else 138 entry_size = sizeof(struct ext3_extent_idx); 139 140 eh_max = (size - sizeof(*eh)) / entry_size; 141 /* Allow two extent-sized items at the end of the block, for 142 * ext4_extent_tail with checksum in the future. */ 143 if ((ext2fs_le16_to_cpu(eh->eh_max) > eh_max) || 144 (ext2fs_le16_to_cpu(eh->eh_max) < (eh_max - 2))) 145 return EXT2_ET_EXTENT_HEADER_BAD; 146 147 return 0; 148} 149 150 151/* 152 * Begin functions to handle an inode's extent information 153 */ 154extern void ext2fs_extent_free(ext2_extent_handle_t handle) 155{ 156 int i; 157 158 if (!handle) 159 return; 160 161 if (handle->inode) 162 ext2fs_free_mem(&handle->inode); 163 if (handle->path) { 164 for (i=1; i < handle->max_depth; i++) { 165 if (handle->path[i].buf) 166 ext2fs_free_mem(&handle->path[i].buf); 167 } 168 ext2fs_free_mem(&handle->path); 169 } 170 ext2fs_free_mem(&handle); 171} 172 173extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino, 174 ext2_extent_handle_t *ret_handle) 175{ 176 struct ext2_extent_handle *handle; 177 errcode_t retval; 178 int isize = EXT2_INODE_SIZE(fs->super); 179 int i; 180 struct ext3_extent_header *eh; 181 182 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 183 184 if ((ino == 0) || (ino > fs->super->s_inodes_count)) 185 return EXT2_ET_BAD_INODE_NUM; 186 187 retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle); 188 if (retval) 189 return retval; 190 memset(handle, 0, sizeof(struct ext2_extent_handle)); 191 192 retval = ext2fs_get_mem(isize, &handle->inode); 193 if (retval) 194 goto errout; 195 196 handle->ino = ino; 197 handle->fs = fs; 198 199 retval = ext2fs_read_inode_full(fs, ino, handle->inode, isize); 200 if (retval) 201 goto errout; 202 203 eh = (struct ext3_extent_header *) &handle->inode->i_block[0]; 204 205 for (i=0; i < EXT2_N_BLOCKS; i++) 206 if (handle->inode->i_block[i]) 207 break; 208 if (i >= EXT2_N_BLOCKS) { 209 eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC); 210 eh->eh_depth = 0; 211 eh->eh_entries = 0; 212 i = (sizeof(handle->inode->i_block) - sizeof(*eh)) / 213 sizeof(struct ext3_extent); 214 eh->eh_max = ext2fs_cpu_to_le16(i); 215 handle->inode->i_flags |= EXT4_EXTENTS_FL; 216 } 217 218 if (!(handle->inode->i_flags & EXT4_EXTENTS_FL)) 219 return EXT2_ET_INODE_NOT_EXTENT; 220 221 retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block)); 222 if (retval) 223 return (retval); 224 225 handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth); 226 handle->type = ext2fs_le16_to_cpu(eh->eh_magic); 227 228 retval = ext2fs_get_mem(((handle->max_depth+1) * 229 sizeof(struct extent_path)), 230 &handle->path); 231 memset(handle->path, 0, 232 (handle->max_depth+1) * sizeof(struct extent_path)); 233 handle->path[0].buf = (char *) handle->inode->i_block; 234 235 handle->path[0].left = handle->path[0].entries = 236 ext2fs_le16_to_cpu(eh->eh_entries); 237 handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max); 238 handle->path[0].curr = 0; 239 handle->path[0].end_blk = 240 ((((__u64) handle->inode->i_size_high << 32) + 241 handle->inode->i_size + (fs->blocksize - 1)) 242 >> EXT2_BLOCK_SIZE_BITS(fs->super)); 243 handle->path[0].visit_num = 1; 244 handle->level = 0; 245 handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE; 246 247 *ret_handle = handle; 248 return 0; 249 250errout: 251 ext2fs_extent_free(handle); 252 return retval; 253} 254 255/* 256 * This function is responsible for (optionally) moving through the 257 * extent tree and then returning the current extent 258 */ 259errcode_t ext2fs_extent_get(ext2_extent_handle_t handle, 260 int flags, struct ext2fs_extent *extent) 261{ 262 struct extent_path *path, *newpath; 263 struct ext3_extent_header *eh; 264 struct ext3_extent_idx *ix = 0; 265 struct ext3_extent *ex; 266 errcode_t retval; 267 blk_t blk; 268 blk64_t end_blk; 269 int orig_op, op; 270 271 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 272 273 if (!handle->path) 274 return EXT2_ET_NO_CURRENT_NODE; 275 276 orig_op = op = flags & EXT2_EXTENT_MOVE_MASK; 277 278retry: 279 path = handle->path + handle->level; 280 if ((orig_op == EXT2_EXTENT_NEXT) || 281 (orig_op == EXT2_EXTENT_NEXT_LEAF)) { 282 if (handle->level < handle->max_depth) { 283 /* interior node */ 284 if (path->visit_num == 0) { 285 path->visit_num++; 286 op = EXT2_EXTENT_DOWN; 287 } else if (path->left > 0) 288 op = EXT2_EXTENT_NEXT_SIB; 289 else if (handle->level > 0) 290 op = EXT2_EXTENT_UP; 291 else 292 return EXT2_ET_EXTENT_NO_NEXT; 293 } else { 294 /* leaf node */ 295 if (path->left > 0) 296 op = EXT2_EXTENT_NEXT_SIB; 297 else if (handle->level > 0) 298 op = EXT2_EXTENT_UP; 299 else 300 return EXT2_ET_EXTENT_NO_NEXT; 301 } 302 if (op != EXT2_EXTENT_NEXT_SIB) { 303 dbg_printf("<<<< OP = %s\n", 304 (op == EXT2_EXTENT_DOWN) ? "down" : 305 ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); 306 } 307 } 308 309 if ((orig_op == EXT2_EXTENT_PREV) || 310 (orig_op == EXT2_EXTENT_PREV_LEAF)) { 311 if (handle->level < handle->max_depth) { 312 /* interior node */ 313 if (path->visit_num > 0 ) { 314 /* path->visit_num = 0; */ 315 op = EXT2_EXTENT_DOWN_AND_LAST; 316 } else if (path->left < path->entries-1) 317 op = EXT2_EXTENT_PREV_SIB; 318 else if (handle->level > 0) 319 op = EXT2_EXTENT_UP; 320 else 321 return EXT2_ET_EXTENT_NO_PREV; 322 } else { 323 /* leaf node */ 324 if (path->left < path->entries-1) 325 op = EXT2_EXTENT_PREV_SIB; 326 else if (handle->level > 0) 327 op = EXT2_EXTENT_UP; 328 else 329 return EXT2_ET_EXTENT_NO_PREV; 330 } 331 if (op != EXT2_EXTENT_PREV_SIB) { 332 dbg_printf("<<<< OP = %s\n", 333 (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" : 334 ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); 335 } 336 } 337 338 if (orig_op == EXT2_EXTENT_LAST_LEAF) { 339 if ((handle->level < handle->max_depth) && 340 (path->left == 0)) 341 op = EXT2_EXTENT_DOWN; 342 else 343 op = EXT2_EXTENT_LAST_SIB; 344 dbg_printf("<<<< OP = %s\n", 345 (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib"); 346 } 347 348 switch (op) { 349 case EXT2_EXTENT_CURRENT: 350 ix = path->curr; 351 break; 352 case EXT2_EXTENT_ROOT: 353 handle->level = 0; 354 path = handle->path + handle->level; 355 case EXT2_EXTENT_FIRST_SIB: 356 path->left = path->entries; 357 path->curr = 0; 358 case EXT2_EXTENT_NEXT_SIB: 359 if (path->left <= 0) 360 return EXT2_ET_EXTENT_NO_NEXT; 361 if (path->curr) { 362 ix = path->curr; 363 ix++; 364 } else { 365 eh = (struct ext3_extent_header *) path->buf; 366 ix = EXT_FIRST_INDEX(eh); 367 } 368 path->left--; 369 path->curr = ix; 370 path->visit_num = 0; 371 break; 372 case EXT2_EXTENT_PREV_SIB: 373 if (!path->curr || 374 path->left+1 >= path->entries) 375 return EXT2_ET_EXTENT_NO_PREV; 376 ix = path->curr; 377 ix--; 378 path->curr = ix; 379 path->left++; 380 if (handle->level < handle->max_depth) 381 path->visit_num = 1; 382 break; 383 case EXT2_EXTENT_LAST_SIB: 384 eh = (struct ext3_extent_header *) path->buf; 385 path->curr = EXT_LAST_EXTENT(eh); 386 ix = path->curr; 387 path->left = 0; 388 path->visit_num = 0; 389 break; 390 case EXT2_EXTENT_UP: 391 if (handle->level <= 0) 392 return EXT2_ET_EXTENT_NO_UP; 393 handle->level--; 394 path--; 395 ix = path->curr; 396 if ((orig_op == EXT2_EXTENT_PREV) || 397 (orig_op == EXT2_EXTENT_PREV_LEAF)) 398 path->visit_num = 0; 399 break; 400 case EXT2_EXTENT_DOWN: 401 case EXT2_EXTENT_DOWN_AND_LAST: 402 if (!path->curr ||(handle->level >= handle->max_depth)) 403 return EXT2_ET_EXTENT_NO_DOWN; 404 405 ix = path->curr; 406 newpath = path + 1; 407 if (!newpath->buf) { 408 retval = ext2fs_get_mem(handle->fs->blocksize, 409 &newpath->buf); 410 if (retval) 411 return retval; 412 } 413 blk = ext2fs_le32_to_cpu(ix->ei_leaf) + 414 ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); 415 if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) && 416 (handle->fs->io != handle->fs->image_io)) 417 memset(newpath->buf, 0, handle->fs->blocksize); 418 else { 419 retval = io_channel_read_blk(handle->fs->io, 420 blk, 1, newpath->buf); 421 if (retval) 422 return retval; 423 } 424 handle->level++; 425 426 eh = (struct ext3_extent_header *) newpath->buf; 427 428 retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize); 429 if (retval) 430 return retval; 431 432 newpath->left = newpath->entries = 433 ext2fs_le16_to_cpu(eh->eh_entries); 434 newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max); 435 436 if (path->left > 0) { 437 ix++; 438 newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block); 439 } else 440 newpath->end_blk = path->end_blk; 441 442 path = newpath; 443 if (op == EXT2_EXTENT_DOWN) { 444 ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh); 445 path->curr = ix; 446 path->left = path->entries - 1; 447 path->visit_num = 0; 448 } else { 449 ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh); 450 path->curr = ix; 451 path->left = 0; 452 if (handle->level < handle->max_depth) 453 path->visit_num = 1; 454 } 455 456 dbg_printf("Down to level %d/%d, end_blk=%llu\n", 457 handle->level, handle->max_depth, 458 path->end_blk); 459 460 break; 461 default: 462 return EXT2_ET_OP_NOT_SUPPORTED; 463 } 464 465 if (!ix) 466 return EXT2_ET_NO_CURRENT_NODE; 467 468 extent->e_flags = 0; 469 dbg_printf("(Left %d)\n", path->left); 470 471 if (handle->level == handle->max_depth) { 472 ex = (struct ext3_extent *) ix; 473 474 extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) + 475 ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); 476 extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block); 477 extent->e_len = ext2fs_le16_to_cpu(ex->ee_len); 478 extent->e_flags |= EXT2_EXTENT_FLAGS_LEAF; 479 if (extent->e_len > EXT_INIT_MAX_LEN) { 480 extent->e_len -= EXT_INIT_MAX_LEN; 481 extent->e_flags |= EXT2_EXTENT_FLAGS_UNINIT; 482 } 483 } else { 484 extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) + 485 ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); 486 extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block); 487 if (path->left > 0) { 488 ix++; 489 end_blk = ext2fs_le32_to_cpu(ix->ei_block); 490 } else 491 end_blk = path->end_blk; 492 493 extent->e_len = end_blk - extent->e_lblk; 494 } 495 if (path->visit_num) 496 extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT; 497 498 if (((orig_op == EXT2_EXTENT_NEXT_LEAF) || 499 (orig_op == EXT2_EXTENT_PREV_LEAF)) && 500 (handle->level != handle->max_depth)) 501 goto retry; 502 503 if ((orig_op == EXT2_EXTENT_LAST_LEAF) && 504 ((handle->level != handle->max_depth) || 505 (path->left != 0))) 506 goto retry; 507 508 return 0; 509} 510 511static errcode_t update_path(ext2_extent_handle_t handle) 512{ 513 blk64_t blk; 514 errcode_t retval; 515 struct ext3_extent_idx *ix; 516 517 if (handle->level == 0) { 518 retval = ext2fs_write_inode_full(handle->fs, handle->ino, 519 handle->inode, EXT2_INODE_SIZE(handle->fs->super)); 520 } else { 521 ix = handle->path[handle->level - 1].curr; 522 blk = ext2fs_le32_to_cpu(ix->ei_leaf) + 523 ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); 524 525 retval = io_channel_write_blk(handle->fs->io, 526 blk, 1, handle->path[handle->level].buf); 527 } 528 return retval; 529} 530 531#if 0 532errcode_t ext2fs_extent_save_path(ext2_extent_handle_t handle, 533 ext2_extent_path_t *ret_path) 534{ 535 ext2_extent_path_t save_path; 536 struct ext2fs_extent extent; 537 struct ext2_extent_info info; 538 errcode_t retval; 539 540 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); 541 if (retval) 542 return retval; 543 544 retval = ext2fs_extent_get_info(handle, &info); 545 if (retval) 546 return retval; 547 548 retval = ext2fs_get_mem(sizeof(struct ext2_extent_path), &save_path); 549 if (retval) 550 return retval; 551 memset(save_path, 0, sizeof(struct ext2_extent_path)); 552 553 save_path->magic = EXT2_ET_MAGIC_EXTENT_PATH; 554 save_path->leaf_height = info.max_depth - info.curr_level - 1; 555 save_path->lblk = extent.e_lblk; 556 557 *ret_path = save_path; 558 return 0; 559} 560 561errcode_t ext2fs_extent_free_path(ext2_extent_path_t path) 562{ 563 EXT2_CHECK_MAGIC(path, EXT2_ET_MAGIC_EXTENT_PATH); 564 565 ext2fs_free_mem(&path); 566 return 0; 567} 568#endif 569 570/* 571 * Go to the node at leaf_level which contains logical block blk. 572 * 573 * leaf_level is height from the leaf node level, i.e. 574 * leaf_level 0 is at leaf node, leaf_level 1 is 1 above etc. 575 * 576 * If "blk" has no mapping (hole) then handle is left at last 577 * extent before blk. 578 */ 579static errcode_t extent_goto(ext2_extent_handle_t handle, 580 int leaf_level, blk64_t blk) 581{ 582 struct ext2fs_extent extent; 583 errcode_t retval; 584 585 retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); 586 if (retval) 587 return retval; 588 589 if (leaf_level > handle->max_depth) { 590 dbg_printf("leaf level %d greater than tree depth %d\n", 591 leaf_level, handle->max_depth); 592 return EXT2_ET_OP_NOT_SUPPORTED; 593 } 594 595 dbg_print_extent("root", &extent); 596 while (1) { 597 if (handle->max_depth - handle->level == leaf_level) { 598 /* block is in this &extent */ 599 if ((blk >= extent.e_lblk) && 600 (blk < extent.e_lblk + extent.e_len)) 601 return 0; 602 if (blk < extent.e_lblk) { 603 retval = ext2fs_extent_get(handle, 604 EXT2_EXTENT_PREV_SIB, 605 &extent); 606 return EXT2_ET_EXTENT_NOT_FOUND; 607 } 608 retval = ext2fs_extent_get(handle, 609 EXT2_EXTENT_NEXT_SIB, 610 &extent); 611 if (retval == EXT2_ET_EXTENT_NO_NEXT) 612 return EXT2_ET_EXTENT_NOT_FOUND; 613 if (retval) 614 return retval; 615 continue; 616 } 617 618 retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_SIB, 619 &extent); 620 if (retval == EXT2_ET_EXTENT_NO_NEXT) 621 goto go_down; 622 if (retval) 623 return retval; 624 625 dbg_print_extent("next", &extent); 626 if (blk == extent.e_lblk) 627 goto go_down; 628 if (blk > extent.e_lblk) 629 continue; 630 631 retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_SIB, 632 &extent); 633 if (retval) 634 return retval; 635 636 dbg_print_extent("prev", &extent); 637 638 go_down: 639 retval = ext2fs_extent_get(handle, EXT2_EXTENT_DOWN, 640 &extent); 641 if (retval) 642 return retval; 643 644 dbg_print_extent("down", &extent); 645 } 646} 647 648errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, 649 blk64_t blk) 650{ 651 return extent_goto(handle, 0, blk); 652} 653 654errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, 655 int flags EXT2FS_ATTR((unused)), 656 struct ext2fs_extent *extent) 657{ 658 struct extent_path *path; 659 struct ext3_extent_idx *ix; 660 struct ext3_extent *ex; 661 662 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 663 664 if (!(handle->fs->flags & EXT2_FLAG_RW)) 665 return EXT2_ET_RO_FILSYS; 666 667 if (!handle->path) 668 return EXT2_ET_NO_CURRENT_NODE; 669 670 path = handle->path + handle->level; 671 if (!path->curr) 672 return EXT2_ET_NO_CURRENT_NODE; 673 674 if (handle->level == handle->max_depth) { 675 ex = path->curr; 676 677 ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk); 678 ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF); 679 ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32); 680 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) { 681 if (extent->e_len > EXT_UNINIT_MAX_LEN) 682 return EXT2_ET_EXTENT_INVALID_LENGTH; 683 ex->ee_len = ext2fs_cpu_to_le16(extent->e_len + 684 EXT_INIT_MAX_LEN); 685 } else { 686 if (extent->e_len > EXT_INIT_MAX_LEN) 687 return EXT2_ET_EXTENT_INVALID_LENGTH; 688 ex->ee_len = ext2fs_cpu_to_le16(extent->e_len); 689 } 690 } else { 691 ix = path->curr; 692 693 ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF); 694 ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32); 695 ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk); 696 ix->ei_unused = 0; 697 } 698 update_path(handle); 699 return 0; 700} 701 702/* 703 * allocate a new block, move half the current node to it, and update parent 704 * 705 * handle will be left pointing at original record. 706 */ 707static errcode_t extent_node_split(ext2_extent_handle_t handle, int flags) 708{ 709 errcode_t retval = 0; 710 blk_t new_node_pblk; 711 blk64_t new_node_start; 712 blk64_t orig_lblk; 713 blk64_t goal_blk = 0; 714 int orig_height; 715 char *block_buf = NULL; 716 struct ext2fs_extent extent; 717 struct extent_path *path, *newpath = 0; 718 struct ext3_extent *ex; 719 struct ext3_extent_header *eh, *neweh; 720 char *cp; 721 int tocopy; 722 int new_root = 0; 723 struct ext2_extent_info info; 724 725 /* basic sanity */ 726 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 727 728 if (!(handle->fs->flags & EXT2_FLAG_RW)) 729 return EXT2_ET_RO_FILSYS; 730 731 if (!handle->path) 732 return EXT2_ET_NO_CURRENT_NODE; 733 734 dbg_printf("splitting node at level %d\n", handle->level); 735 736 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); 737 if (retval) 738 goto done; 739 740 retval = ext2fs_extent_get_info(handle, &info); 741 if (retval) 742 goto done; 743 744 /* save the position we were originally splitting... */ 745 orig_height = info.max_depth - info.curr_level; 746 orig_lblk = extent.e_lblk; 747 748 /* Is there room in the parent for a new entry? */ 749 if (handle->level && 750 (handle->path[handle->level - 1].entries >= 751 handle->path[handle->level - 1].max_entries)) { 752 753 dbg_printf("parent level %d full; splitting it too\n", 754 handle->level - 1); 755 /* split the parent */ 756 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); 757 if (retval) 758 goto done; 759 goal_blk = extent.e_pblk; 760 761 retval = extent_node_split(handle, 0); 762 if (retval) 763 goto done; 764 765 /* get handle back to our original split position */ 766 retval = extent_goto(handle, orig_height, orig_lblk); 767 if (retval) 768 goto done; 769 } 770 771 /* At this point, parent should have room for this split */ 772 path = handle->path + handle->level; 773 if (!path->curr) 774 return EXT2_ET_NO_CURRENT_NODE; 775 776 /* extent header of the current node we'll split */ 777 eh = (struct ext3_extent_header *)path->buf; 778 779 /* splitting root level means moving them all out */ 780 if (handle->level == 0) { 781 new_root = 1; 782 tocopy = ext2fs_le16_to_cpu(eh->eh_entries); 783 retval = ext2fs_get_mem(((handle->max_depth+2) * 784 sizeof(struct extent_path)), 785 &newpath); 786 if (retval) 787 goto done; 788 memset(newpath, 0, 789 ((handle->max_depth+2) * sizeof(struct extent_path))); 790 } else { 791 tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2; 792 } 793 794 dbg_printf("will copy out %d of %d entries at level %d\n", 795 tocopy, ext2fs_le16_to_cpu(eh->eh_entries), 796 handle->level); 797 798 if (!tocopy) { 799 dbg_printf("Nothing to copy to new block!\n"); 800 retval = EXT2_ET_CANT_SPLIT_EXTENT; 801 goto done; 802 } 803 804 /* first we need a new block, or can do nothing. */ 805 block_buf = malloc(handle->fs->blocksize); 806 if (!block_buf) { 807 retval = ENOMEM; 808 goto done; 809 } 810 811 if (!goal_blk) { 812 dgrp_t group = ext2fs_group_of_ino(handle->fs, handle->ino); 813 __u8 log_flex = handle->fs->super->s_log_groups_per_flex; 814 815 if (log_flex) 816 group = group & ~((1 << (log_flex)) - 1); 817 goal_blk = (group * handle->fs->super->s_blocks_per_group) + 818 handle->fs->super->s_first_data_block; 819 } 820 retval = ext2fs_alloc_block(handle->fs, (blk_t) goal_blk, block_buf, 821 &new_node_pblk); 822 if (retval) 823 goto done; 824 825 dbg_printf("will copy to new node at block %lu\n", new_node_pblk); 826 827 /* Copy data into new block buffer */ 828 /* First the header for the new block... */ 829 neweh = (struct ext3_extent_header *) block_buf; 830 memcpy(neweh, eh, sizeof(struct ext3_extent_header)); 831 neweh->eh_entries = ext2fs_cpu_to_le16(tocopy); 832 neweh->eh_max = ext2fs_cpu_to_le16((handle->fs->blocksize - 833 sizeof(struct ext3_extent_header)) / 834 sizeof(struct ext3_extent)); 835 836 /* then the entries for the new block... */ 837 memcpy(EXT_FIRST_INDEX(neweh), 838 EXT_FIRST_INDEX(eh) + 839 (ext2fs_le16_to_cpu(eh->eh_entries) - tocopy), 840 sizeof(struct ext3_extent_idx) * tocopy); 841 842 new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block); 843 844 /* ...and write the new node block out to disk. */ 845 retval = io_channel_write_blk(handle->fs->io, new_node_pblk, 1, block_buf); 846 847 if (retval) 848 goto done; 849 850 /* OK! we've created the new node; now adjust the tree */ 851 852 /* current path now has fewer active entries, we copied some out */ 853 if (handle->level == 0) { 854 memcpy(newpath, path, 855 sizeof(struct extent_path) * (handle->max_depth+1)); 856 handle->path = newpath; 857 newpath = path; 858 path = handle->path; 859 path->entries = 1; 860 path->left = path->max_entries - 1; 861 handle->max_depth++; 862 eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth); 863 } else { 864 path->entries -= tocopy; 865 path->left -= tocopy; 866 } 867 868 eh->eh_entries = ext2fs_cpu_to_le16(path->entries); 869 /* this writes out the node, incl. the modified header */ 870 retval = update_path(handle); 871 if (retval) 872 goto done; 873 874 /* now go up and insert/replace index for new node we created */ 875 if (new_root) { 876 retval = ext2fs_extent_get(handle, EXT2_EXTENT_FIRST_SIB, &extent); 877 if (retval) 878 goto done; 879 880 extent.e_lblk = new_node_start; 881 extent.e_pblk = new_node_pblk; 882 extent.e_len = handle->path[0].end_blk - extent.e_lblk; 883 retval = ext2fs_extent_replace(handle, 0, &extent); 884 if (retval) 885 goto done; 886 } else { 887 __u32 new_node_length; 888 889 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); 890 /* will insert after this one; it's length is shorter now */ 891 new_node_length = new_node_start - extent.e_lblk; 892 extent.e_len -= new_node_length; 893 retval = ext2fs_extent_replace(handle, 0, &extent); 894 if (retval) 895 goto done; 896 897 /* now set up the new extent and insert it */ 898 extent.e_lblk = new_node_start; 899 extent.e_pblk = new_node_pblk; 900 extent.e_len = new_node_length; 901 retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &extent); 902 if (retval) 903 goto done; 904 } 905 906 /* get handle back to our original position */ 907 retval = extent_goto(handle, orig_height, orig_lblk); 908 if (retval) 909 goto done; 910 911 /* new node hooked in, so update inode block count (do this here?) */ 912 handle->inode->i_blocks += handle->fs->blocksize / 512; 913 retval = ext2fs_write_inode_full(handle->fs, handle->ino, 914 handle->inode, EXT2_INODE_SIZE(handle->fs->super)); 915 if (retval) 916 goto done; 917 918done: 919 if (newpath) 920 ext2fs_free_mem(&newpath); 921 if (block_buf) 922 free(block_buf); 923 924 return retval; 925} 926 927errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags, 928 struct ext2fs_extent *extent) 929{ 930 struct extent_path *path; 931 struct ext3_extent_idx *ix; 932 struct ext3_extent_header *eh; 933 errcode_t retval; 934 935 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 936 937 if (!(handle->fs->flags & EXT2_FLAG_RW)) 938 return EXT2_ET_RO_FILSYS; 939 940 if (!handle->path) 941 return EXT2_ET_NO_CURRENT_NODE; 942 943 path = handle->path + handle->level; 944 945 if (path->entries >= path->max_entries) 946 return EXT2_ET_CANT_INSERT_EXTENT; 947 948 eh = (struct ext3_extent_header *) path->buf; 949 if (path->curr) { 950 ix = path->curr; 951 if (flags & EXT2_EXTENT_INSERT_AFTER) { 952 ix++; 953 path->left--; 954 } 955 } else 956 ix = EXT_FIRST_INDEX(eh); 957 958 path->curr = ix; 959 960 if (path->left >= 0) 961 memmove(ix + 1, ix, 962 (path->left+1) * sizeof(struct ext3_extent_idx)); 963 path->left++; 964 path->entries++; 965 966 eh = (struct ext3_extent_header *) path->buf; 967 eh->eh_entries = ext2fs_cpu_to_le16(path->entries); 968 969 retval = ext2fs_extent_replace(handle, 0, extent); 970 if (retval) 971 goto errout; 972 973 retval = update_path(handle); 974 if (retval) 975 goto errout; 976 977 return 0; 978 979errout: 980 ext2fs_extent_delete(handle, 0); 981 return retval; 982} 983 984errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, 985 int flags EXT2FS_ATTR((unused))) 986{ 987 struct extent_path *path; 988 char *cp; 989 struct ext3_extent_header *eh; 990 errcode_t retval; 991 992 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 993 994 if (!(handle->fs->flags & EXT2_FLAG_RW)) 995 return EXT2_ET_RO_FILSYS; 996 997 if (!handle->path) 998 return EXT2_ET_NO_CURRENT_NODE; 999 1000 path = handle->path + handle->level; 1001 if (!path->curr) 1002 return EXT2_ET_NO_CURRENT_NODE; 1003 1004 cp = path->curr; 1005 1006 if (path->left) { 1007 memmove(cp, cp + sizeof(struct ext3_extent_idx), 1008 path->left * sizeof(struct ext3_extent_idx)); 1009 path->left--; 1010 } else { 1011 struct ext3_extent_idx *ix = path->curr; 1012 ix--; 1013 path->curr = ix; 1014 } 1015 path->entries--; 1016 if (path->entries == 0) 1017 path->curr = 0; 1018 1019 eh = (struct ext3_extent_header *) path->buf; 1020 eh->eh_entries = ext2fs_cpu_to_le16(path->entries); 1021 1022 retval = update_path(handle); 1023 1024 return retval; 1025} 1026 1027errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle, 1028 struct ext2_extent_info *info) 1029{ 1030 struct extent_path *path; 1031 1032 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 1033 1034 memset(info, 0, sizeof(struct ext2_extent_info)); 1035 1036 path = handle->path + handle->level; 1037 if (path) { 1038 if (path->curr) 1039 info->curr_entry = ((char *) path->curr - path->buf) / 1040 sizeof(struct ext3_extent_idx); 1041 else 1042 info->curr_entry = 0; 1043 info->num_entries = path->entries; 1044 info->max_entries = path->max_entries; 1045 info->bytes_avail = (path->max_entries - path->entries) * 1046 sizeof(struct ext3_extent); 1047 } 1048 1049 info->curr_level = handle->level; 1050 info->max_depth = handle->max_depth; 1051 info->max_lblk = ((__u64) 1 << 32) - 1; 1052 info->max_pblk = ((__u64) 1 << 48) - 1; 1053 info->max_len = (1UL << 15); 1054 info->max_uninit_len = (1UL << 15) - 1; 1055 1056 return 0; 1057} 1058 1059#ifdef DEBUG 1060 1061#include "debugfs.h" 1062 1063/* 1064 * Hook in new commands into debugfs 1065 */ 1066const char *debug_prog_name = "tst_extents"; 1067extern ss_request_table extent_cmds; 1068ss_request_table *extra_cmds = &extent_cmds; 1069 1070ext2_ino_t current_ino = 0; 1071ext2_extent_handle_t current_handle; 1072 1073void do_inode(int argc, char *argv[]) 1074{ 1075 ext2_ino_t inode; 1076 int i; 1077 struct ext3_extent_header *eh; 1078 errcode_t retval; 1079 1080 if (check_fs_open(argv[0])) 1081 return; 1082 1083 if (argc == 1) { 1084 if (current_ino) 1085 printf("Current inode is %d\n", current_ino); 1086 else 1087 printf("No current inode\n"); 1088 return; 1089 } 1090 1091 if (common_inode_args_process(argc, argv, &inode, 0)) { 1092 return; 1093 } 1094 1095 current_ino = 0; 1096 1097 retval = ext2fs_extent_open(current_fs, inode, ¤t_handle); 1098 if (retval) { 1099 com_err(argv[1], retval, "while opening extent handle"); 1100 return; 1101 } 1102 1103 current_ino = inode; 1104 1105 printf("Loaded inode %d\n", current_ino); 1106 1107 return; 1108} 1109 1110void generic_goto_node(char *cmd_name, int op) 1111{ 1112 struct ext2fs_extent extent; 1113 errcode_t retval; 1114 1115 if (check_fs_open(cmd_name)) 1116 return; 1117 1118 if (!current_handle) { 1119 com_err(cmd_name, 0, "Extent handle not open"); 1120 return; 1121 } 1122 1123 retval = ext2fs_extent_get(current_handle, op, &extent); 1124 if (retval) { 1125 com_err(cmd_name, retval, 0); 1126 return; 1127 } 1128 dbg_print_extent(0, &extent); 1129} 1130 1131void do_current_node(int argc, char *argv[]) 1132{ 1133 generic_goto_node(argv[0], EXT2_EXTENT_CURRENT); 1134} 1135 1136void do_root_node(int argc, char *argv[]) 1137{ 1138 generic_goto_node(argv[0], EXT2_EXTENT_ROOT); 1139} 1140 1141void do_last_leaf(int argc, char *argv[]) 1142{ 1143 generic_goto_node(argv[0], EXT2_EXTENT_LAST_LEAF); 1144} 1145 1146void do_first_sib(int argc, char *argv[]) 1147{ 1148 generic_goto_node(argv[0], EXT2_EXTENT_FIRST_SIB); 1149} 1150 1151void do_last_sib(int argc, char *argv[]) 1152{ 1153 generic_goto_node(argv[0], EXT2_EXTENT_LAST_SIB); 1154} 1155 1156void do_next_sib(int argc, char *argv[]) 1157{ 1158 generic_goto_node(argv[0], EXT2_EXTENT_NEXT_SIB); 1159} 1160 1161void do_prev_sib(int argc, char *argv[]) 1162{ 1163 generic_goto_node(argv[0], EXT2_EXTENT_PREV_SIB); 1164} 1165 1166void do_next_leaf(int argc, char *argv[]) 1167{ 1168 generic_goto_node(argv[0], EXT2_EXTENT_NEXT_LEAF); 1169} 1170 1171void do_prev_leaf(int argc, char *argv[]) 1172{ 1173 generic_goto_node(argv[0], EXT2_EXTENT_PREV_LEAF); 1174} 1175 1176void do_next(int argc, char *argv[]) 1177{ 1178 generic_goto_node(argv[0], EXT2_EXTENT_NEXT); 1179} 1180 1181void do_prev(int argc, char *argv[]) 1182{ 1183 generic_goto_node(argv[0], EXT2_EXTENT_PREV); 1184} 1185 1186void do_up(int argc, char *argv[]) 1187{ 1188 generic_goto_node(argv[0], EXT2_EXTENT_UP); 1189} 1190 1191void do_down(int argc, char *argv[]) 1192{ 1193 generic_goto_node(argv[0], EXT2_EXTENT_DOWN); 1194} 1195 1196void do_delete_node(int argc, char *argv[]) 1197{ 1198 errcode_t retval; 1199 int err; 1200 1201 if (check_fs_read_write(argv[0])) 1202 return; 1203 1204 retval = ext2fs_extent_delete(current_handle, 0); 1205 if (retval) { 1206 com_err(argv[0], retval, 0); 1207 return; 1208 } 1209 if (current_handle->path && current_handle->path[0].curr) 1210 do_current_node(argc, argv); 1211} 1212 1213void do_replace_node(int argc, char *argv[]) 1214{ 1215 errcode_t retval; 1216 struct ext2fs_extent extent; 1217 int err; 1218 1219 if (check_fs_read_write(argv[0])) 1220 return; 1221 1222 extent.e_flags = 0; 1223 1224 if (!strcmp(argv[1], "--uninit")) { 1225 argc--; 1226 argv++; 1227 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; 1228 } 1229 1230 if (argc != 4) { 1231 fprintf(stderr, "usage: %s <lblk> <len> <pblk>\n", argv[0]); 1232 return; 1233 } 1234 1235 extent.e_lblk = parse_ulong(argv[1], argv[0], 1236 "logical block", &err); 1237 if (err) 1238 return; 1239 1240 extent.e_len = parse_ulong(argv[2], argv[0], 1241 "logical block", &err); 1242 if (err) 1243 return; 1244 1245 extent.e_pblk = parse_ulong(argv[3], argv[0], 1246 "logical block", &err); 1247 if (err) 1248 return; 1249 1250 retval = ext2fs_extent_replace(current_handle, 0, &extent); 1251 if (retval) { 1252 com_err(argv[0], retval, 0); 1253 return; 1254 } 1255 do_current_node(argc, argv); 1256} 1257 1258void do_split_node(int argc, char *argv[]) 1259{ 1260 errcode_t retval; 1261 struct ext2fs_extent extent; 1262 int err; 1263 int flags = 0; 1264 1265 if (check_fs_open(argv[0])) 1266 return; 1267 1268 if (check_fs_read_write(argv[0])) 1269 return; 1270 1271 if (!current_handle) { 1272 com_err(argv[0], 0, "Extent handle not open"); 1273 return; 1274 } 1275 1276 retval = extent_node_split(current_handle, flags); 1277 if (retval) { 1278 com_err(argv[0], retval, 0); 1279 return; 1280 } 1281 do_current_node(argc, argv); 1282} 1283 1284void do_insert_node(int argc, char *argv[]) 1285{ 1286 errcode_t retval; 1287 struct ext2fs_extent extent; 1288 char *cmd; 1289 int err; 1290 int flags = 0; 1291 1292 if (check_fs_read_write(argv[0])) 1293 return; 1294 1295 cmd = argv[0]; 1296 1297 extent.e_flags = 0; 1298 1299 while (argc > 2) { 1300 if (!strcmp(argv[1], "--after")) { 1301 argc--; 1302 argv++; 1303 flags |= EXT2_EXTENT_INSERT_AFTER; 1304 continue; 1305 } 1306 if (!strcmp(argv[1], "--uninit")) { 1307 argc--; 1308 argv++; 1309 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; 1310 continue; 1311 } 1312 break; 1313 } 1314 1315 if (argc != 4) { 1316 fprintf(stderr, "usage: %s <lblk> <len> <pblk>\n", cmd); 1317 return; 1318 } 1319 1320 extent.e_lblk = parse_ulong(argv[1], cmd, 1321 "logical block", &err); 1322 if (err) 1323 return; 1324 1325 extent.e_len = parse_ulong(argv[2], cmd, 1326 "length", &err); 1327 if (err) 1328 return; 1329 1330 extent.e_pblk = parse_ulong(argv[3], cmd, 1331 "pysical block", &err); 1332 if (err) 1333 return; 1334 1335 retval = ext2fs_extent_insert(current_handle, flags, &extent); 1336 if (retval) { 1337 com_err(cmd, retval, 0); 1338 return; 1339 } 1340 do_current_node(argc, argv); 1341} 1342 1343void do_print_all(int argc, char **argv) 1344{ 1345 struct ext2fs_extent extent; 1346 errcode_t retval; 1347 errcode_t end_err = EXT2_ET_EXTENT_NO_NEXT; 1348 int op = EXT2_EXTENT_NEXT; 1349 int first_op = EXT2_EXTENT_ROOT; 1350 1351 1352 if (check_fs_open(argv[0])) 1353 return; 1354 1355 if (!current_handle) { 1356 com_err(argv[0], 0, "Extent handle not open"); 1357 return; 1358 } 1359 1360 if (argc > 2) { 1361 print_usage: 1362 fprintf(stderr, 1363 "Usage: %s [--leaf-only|--reverse|--reverse-leaf]\n", 1364 argv[0]); 1365 return; 1366 } 1367 1368 if (argc == 2) { 1369 if (!strcmp(argv[1], "--leaf-only")) 1370 op = EXT2_EXTENT_NEXT_LEAF; 1371 else if (!strcmp(argv[1], "--reverse")) { 1372 op = EXT2_EXTENT_PREV; 1373 first_op = EXT2_EXTENT_LAST_LEAF; 1374 end_err = EXT2_ET_EXTENT_NO_PREV; 1375 } else if (!strcmp(argv[1], "--reverse-leaf")) { 1376 op = EXT2_EXTENT_PREV_LEAF; 1377 first_op = EXT2_EXTENT_LAST_LEAF; 1378 end_err = EXT2_ET_EXTENT_NO_PREV; 1379 } else 1380 goto print_usage; 1381 } 1382 1383 retval = ext2fs_extent_get(current_handle, first_op, &extent); 1384 if (retval) { 1385 com_err(argv[0], retval, 0); 1386 return; 1387 } 1388 dbg_print_extent(0, &extent); 1389 1390 while (1) { 1391 retval = ext2fs_extent_get(current_handle, op, &extent); 1392 if (retval == end_err) 1393 break; 1394 1395 if (retval) { 1396 com_err(argv[0], retval, 0); 1397 return; 1398 } 1399 dbg_print_extent(0, &extent); 1400 } 1401} 1402 1403void do_info(int argc, char **argv) 1404{ 1405 struct ext2fs_extent extent; 1406 struct ext2_extent_info info; 1407 errcode_t retval; 1408 1409 if (check_fs_open(argv[0])) 1410 return; 1411 1412 if (!current_handle) { 1413 com_err(argv[0], 0, "Extent handle not open"); 1414 return; 1415 } 1416 1417 retval = ext2fs_extent_get_info(current_handle, &info); 1418 if (retval) { 1419 com_err(argv[0], retval, 0); 1420 return; 1421 } 1422 1423 retval = ext2fs_extent_get(current_handle, 1424 EXT2_EXTENT_CURRENT, &extent); 1425 if (retval) { 1426 com_err(argv[0], retval, 0); 1427 return; 1428 } 1429 1430 dbg_print_extent(0, &extent); 1431 1432 printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n", 1433 info.curr_entry, info.num_entries, info.max_entries, 1434 info.bytes_avail, info.curr_level, info.max_depth); 1435 printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk, 1436 info.max_pblk); 1437 printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len, 1438 info.max_uninit_len); 1439} 1440 1441void do_goto_block(int argc, char **argv) 1442{ 1443 struct ext2fs_extent extent; 1444 errcode_t retval; 1445 int op = EXT2_EXTENT_NEXT_LEAF; 1446 blk_t blk; 1447 int level = 0; 1448 1449 if (check_fs_open(argv[0])) 1450 return; 1451 1452 if (!current_handle) { 1453 com_err(argv[0], 0, "Extent handle not open"); 1454 return; 1455 } 1456 1457 if (argc < 2 || argc > 3) { 1458 fprintf(stderr, "%s block [level]\n", argv[0]); 1459 return; 1460 } 1461 1462 if (strtoblk(argv[0], argv[1], &blk)) 1463 return; 1464 1465 if (argc == 3) 1466 if (strtoblk(argv[0], argv[2], &level)) 1467 return; 1468 1469 retval = extent_goto(current_handle, level, (blk64_t) blk); 1470 1471 if (retval) { 1472 com_err(argv[0], retval, "while trying to go to block %lu, level %d", 1473 blk, level); 1474 return; 1475 } 1476 1477 generic_goto_node(argv[0], EXT2_EXTENT_CURRENT); 1478} 1479#endif 1480 1481