extent.c revision 01229db57ee71518f81d87d6bf900c62fe1de100
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 if (flags & EXT2_EXTENT_INSERT_NOSPLIT) { 947 return EXT2_ET_CANT_INSERT_EXTENT; 948 } else { 949 dbg_printf("node full - splitting\n"); 950 retval = extent_node_split(handle, 0); 951 if (retval) 952 goto errout; 953 path = handle->path + handle->level; 954 } 955 } 956 957 eh = (struct ext3_extent_header *) path->buf; 958 if (path->curr) { 959 ix = path->curr; 960 if (flags & EXT2_EXTENT_INSERT_AFTER) { 961 ix++; 962 path->left--; 963 } 964 } else 965 ix = EXT_FIRST_INDEX(eh); 966 967 path->curr = ix; 968 969 if (path->left >= 0) 970 memmove(ix + 1, ix, 971 (path->left+1) * sizeof(struct ext3_extent_idx)); 972 path->left++; 973 path->entries++; 974 975 eh = (struct ext3_extent_header *) path->buf; 976 eh->eh_entries = ext2fs_cpu_to_le16(path->entries); 977 978 retval = ext2fs_extent_replace(handle, 0, extent); 979 if (retval) 980 goto errout; 981 982 retval = update_path(handle); 983 if (retval) 984 goto errout; 985 986 return 0; 987 988errout: 989 ext2fs_extent_delete(handle, 0); 990 return retval; 991} 992 993errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, 994 int flags EXT2FS_ATTR((unused))) 995{ 996 struct extent_path *path; 997 char *cp; 998 struct ext3_extent_header *eh; 999 errcode_t retval; 1000 1001 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 1002 1003 if (!(handle->fs->flags & EXT2_FLAG_RW)) 1004 return EXT2_ET_RO_FILSYS; 1005 1006 if (!handle->path) 1007 return EXT2_ET_NO_CURRENT_NODE; 1008 1009 path = handle->path + handle->level; 1010 if (!path->curr) 1011 return EXT2_ET_NO_CURRENT_NODE; 1012 1013 cp = path->curr; 1014 1015 if (path->left) { 1016 memmove(cp, cp + sizeof(struct ext3_extent_idx), 1017 path->left * sizeof(struct ext3_extent_idx)); 1018 path->left--; 1019 } else { 1020 struct ext3_extent_idx *ix = path->curr; 1021 ix--; 1022 path->curr = ix; 1023 } 1024 path->entries--; 1025 if (path->entries == 0) 1026 path->curr = 0; 1027 1028 eh = (struct ext3_extent_header *) path->buf; 1029 eh->eh_entries = ext2fs_cpu_to_le16(path->entries); 1030 1031 retval = update_path(handle); 1032 1033 return retval; 1034} 1035 1036errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle, 1037 struct ext2_extent_info *info) 1038{ 1039 struct extent_path *path; 1040 1041 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); 1042 1043 memset(info, 0, sizeof(struct ext2_extent_info)); 1044 1045 path = handle->path + handle->level; 1046 if (path) { 1047 if (path->curr) 1048 info->curr_entry = ((char *) path->curr - path->buf) / 1049 sizeof(struct ext3_extent_idx); 1050 else 1051 info->curr_entry = 0; 1052 info->num_entries = path->entries; 1053 info->max_entries = path->max_entries; 1054 info->bytes_avail = (path->max_entries - path->entries) * 1055 sizeof(struct ext3_extent); 1056 } 1057 1058 info->curr_level = handle->level; 1059 info->max_depth = handle->max_depth; 1060 info->max_lblk = ((__u64) 1 << 32) - 1; 1061 info->max_pblk = ((__u64) 1 << 48) - 1; 1062 info->max_len = (1UL << 15); 1063 info->max_uninit_len = (1UL << 15) - 1; 1064 1065 return 0; 1066} 1067 1068#ifdef DEBUG 1069 1070#include "debugfs.h" 1071 1072/* 1073 * Hook in new commands into debugfs 1074 */ 1075const char *debug_prog_name = "tst_extents"; 1076extern ss_request_table extent_cmds; 1077ss_request_table *extra_cmds = &extent_cmds; 1078 1079ext2_ino_t current_ino = 0; 1080ext2_extent_handle_t current_handle; 1081 1082void do_inode(int argc, char *argv[]) 1083{ 1084 ext2_ino_t inode; 1085 int i; 1086 struct ext3_extent_header *eh; 1087 errcode_t retval; 1088 1089 if (check_fs_open(argv[0])) 1090 return; 1091 1092 if (argc == 1) { 1093 if (current_ino) 1094 printf("Current inode is %d\n", current_ino); 1095 else 1096 printf("No current inode\n"); 1097 return; 1098 } 1099 1100 if (common_inode_args_process(argc, argv, &inode, 0)) { 1101 return; 1102 } 1103 1104 current_ino = 0; 1105 1106 retval = ext2fs_extent_open(current_fs, inode, ¤t_handle); 1107 if (retval) { 1108 com_err(argv[1], retval, "while opening extent handle"); 1109 return; 1110 } 1111 1112 current_ino = inode; 1113 1114 printf("Loaded inode %d\n", current_ino); 1115 1116 return; 1117} 1118 1119void generic_goto_node(char *cmd_name, int op) 1120{ 1121 struct ext2fs_extent extent; 1122 errcode_t retval; 1123 1124 if (check_fs_open(cmd_name)) 1125 return; 1126 1127 if (!current_handle) { 1128 com_err(cmd_name, 0, "Extent handle not open"); 1129 return; 1130 } 1131 1132 retval = ext2fs_extent_get(current_handle, op, &extent); 1133 if (retval) { 1134 com_err(cmd_name, retval, 0); 1135 return; 1136 } 1137 dbg_print_extent(0, &extent); 1138} 1139 1140void do_current_node(int argc, char *argv[]) 1141{ 1142 generic_goto_node(argv[0], EXT2_EXTENT_CURRENT); 1143} 1144 1145void do_root_node(int argc, char *argv[]) 1146{ 1147 generic_goto_node(argv[0], EXT2_EXTENT_ROOT); 1148} 1149 1150void do_last_leaf(int argc, char *argv[]) 1151{ 1152 generic_goto_node(argv[0], EXT2_EXTENT_LAST_LEAF); 1153} 1154 1155void do_first_sib(int argc, char *argv[]) 1156{ 1157 generic_goto_node(argv[0], EXT2_EXTENT_FIRST_SIB); 1158} 1159 1160void do_last_sib(int argc, char *argv[]) 1161{ 1162 generic_goto_node(argv[0], EXT2_EXTENT_LAST_SIB); 1163} 1164 1165void do_next_sib(int argc, char *argv[]) 1166{ 1167 generic_goto_node(argv[0], EXT2_EXTENT_NEXT_SIB); 1168} 1169 1170void do_prev_sib(int argc, char *argv[]) 1171{ 1172 generic_goto_node(argv[0], EXT2_EXTENT_PREV_SIB); 1173} 1174 1175void do_next_leaf(int argc, char *argv[]) 1176{ 1177 generic_goto_node(argv[0], EXT2_EXTENT_NEXT_LEAF); 1178} 1179 1180void do_prev_leaf(int argc, char *argv[]) 1181{ 1182 generic_goto_node(argv[0], EXT2_EXTENT_PREV_LEAF); 1183} 1184 1185void do_next(int argc, char *argv[]) 1186{ 1187 generic_goto_node(argv[0], EXT2_EXTENT_NEXT); 1188} 1189 1190void do_prev(int argc, char *argv[]) 1191{ 1192 generic_goto_node(argv[0], EXT2_EXTENT_PREV); 1193} 1194 1195void do_up(int argc, char *argv[]) 1196{ 1197 generic_goto_node(argv[0], EXT2_EXTENT_UP); 1198} 1199 1200void do_down(int argc, char *argv[]) 1201{ 1202 generic_goto_node(argv[0], EXT2_EXTENT_DOWN); 1203} 1204 1205void do_delete_node(int argc, char *argv[]) 1206{ 1207 errcode_t retval; 1208 int err; 1209 1210 if (check_fs_read_write(argv[0])) 1211 return; 1212 1213 retval = ext2fs_extent_delete(current_handle, 0); 1214 if (retval) { 1215 com_err(argv[0], retval, 0); 1216 return; 1217 } 1218 if (current_handle->path && current_handle->path[0].curr) 1219 do_current_node(argc, argv); 1220} 1221 1222void do_replace_node(int argc, char *argv[]) 1223{ 1224 errcode_t retval; 1225 struct ext2fs_extent extent; 1226 int err; 1227 1228 if (check_fs_read_write(argv[0])) 1229 return; 1230 1231 extent.e_flags = 0; 1232 1233 if (!strcmp(argv[1], "--uninit")) { 1234 argc--; 1235 argv++; 1236 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; 1237 } 1238 1239 if (argc != 4) { 1240 fprintf(stderr, "usage: %s <lblk> <len> <pblk>\n", argv[0]); 1241 return; 1242 } 1243 1244 extent.e_lblk = parse_ulong(argv[1], argv[0], 1245 "logical block", &err); 1246 if (err) 1247 return; 1248 1249 extent.e_len = parse_ulong(argv[2], argv[0], 1250 "logical block", &err); 1251 if (err) 1252 return; 1253 1254 extent.e_pblk = parse_ulong(argv[3], argv[0], 1255 "logical block", &err); 1256 if (err) 1257 return; 1258 1259 retval = ext2fs_extent_replace(current_handle, 0, &extent); 1260 if (retval) { 1261 com_err(argv[0], retval, 0); 1262 return; 1263 } 1264 do_current_node(argc, argv); 1265} 1266 1267void do_split_node(int argc, char *argv[]) 1268{ 1269 errcode_t retval; 1270 struct ext2fs_extent extent; 1271 int err; 1272 int flags = 0; 1273 1274 if (check_fs_open(argv[0])) 1275 return; 1276 1277 if (check_fs_read_write(argv[0])) 1278 return; 1279 1280 if (!current_handle) { 1281 com_err(argv[0], 0, "Extent handle not open"); 1282 return; 1283 } 1284 1285 retval = extent_node_split(current_handle, flags); 1286 if (retval) { 1287 com_err(argv[0], retval, 0); 1288 return; 1289 } 1290 do_current_node(argc, argv); 1291} 1292 1293void do_insert_node(int argc, char *argv[]) 1294{ 1295 errcode_t retval; 1296 struct ext2fs_extent extent; 1297 char *cmd; 1298 int err; 1299 int flags = 0; 1300 1301 if (check_fs_read_write(argv[0])) 1302 return; 1303 1304 cmd = argv[0]; 1305 1306 extent.e_flags = 0; 1307 1308 while (argc > 2) { 1309 if (!strcmp(argv[1], "--after")) { 1310 argc--; 1311 argv++; 1312 flags |= EXT2_EXTENT_INSERT_AFTER; 1313 continue; 1314 } 1315 if (!strcmp(argv[1], "--uninit")) { 1316 argc--; 1317 argv++; 1318 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; 1319 continue; 1320 } 1321 break; 1322 } 1323 1324 if (argc != 4) { 1325 fprintf(stderr, "usage: %s [--after] <lblk> <len> <pblk>\n", cmd); 1326 return; 1327 } 1328 1329 extent.e_lblk = parse_ulong(argv[1], cmd, 1330 "logical block", &err); 1331 if (err) 1332 return; 1333 1334 extent.e_len = parse_ulong(argv[2], cmd, 1335 "length", &err); 1336 if (err) 1337 return; 1338 1339 extent.e_pblk = parse_ulong(argv[3], cmd, 1340 "pysical block", &err); 1341 if (err) 1342 return; 1343 1344 retval = ext2fs_extent_insert(current_handle, flags, &extent); 1345 if (retval) { 1346 com_err(cmd, retval, 0); 1347 return; 1348 } 1349 do_current_node(argc, argv); 1350} 1351 1352void do_print_all(int argc, char **argv) 1353{ 1354 struct ext2fs_extent extent; 1355 errcode_t retval; 1356 errcode_t end_err = EXT2_ET_EXTENT_NO_NEXT; 1357 int op = EXT2_EXTENT_NEXT; 1358 int first_op = EXT2_EXTENT_ROOT; 1359 1360 1361 if (check_fs_open(argv[0])) 1362 return; 1363 1364 if (!current_handle) { 1365 com_err(argv[0], 0, "Extent handle not open"); 1366 return; 1367 } 1368 1369 if (argc > 2) { 1370 print_usage: 1371 fprintf(stderr, 1372 "Usage: %s [--leaf-only|--reverse|--reverse-leaf]\n", 1373 argv[0]); 1374 return; 1375 } 1376 1377 if (argc == 2) { 1378 if (!strcmp(argv[1], "--leaf-only")) 1379 op = EXT2_EXTENT_NEXT_LEAF; 1380 else if (!strcmp(argv[1], "--reverse")) { 1381 op = EXT2_EXTENT_PREV; 1382 first_op = EXT2_EXTENT_LAST_LEAF; 1383 end_err = EXT2_ET_EXTENT_NO_PREV; 1384 } else if (!strcmp(argv[1], "--reverse-leaf")) { 1385 op = EXT2_EXTENT_PREV_LEAF; 1386 first_op = EXT2_EXTENT_LAST_LEAF; 1387 end_err = EXT2_ET_EXTENT_NO_PREV; 1388 } else 1389 goto print_usage; 1390 } 1391 1392 retval = ext2fs_extent_get(current_handle, first_op, &extent); 1393 if (retval) { 1394 com_err(argv[0], retval, 0); 1395 return; 1396 } 1397 dbg_print_extent(0, &extent); 1398 1399 while (1) { 1400 retval = ext2fs_extent_get(current_handle, op, &extent); 1401 if (retval == end_err) 1402 break; 1403 1404 if (retval) { 1405 com_err(argv[0], retval, 0); 1406 return; 1407 } 1408 dbg_print_extent(0, &extent); 1409 } 1410} 1411 1412void do_info(int argc, char **argv) 1413{ 1414 struct ext2fs_extent extent; 1415 struct ext2_extent_info info; 1416 errcode_t retval; 1417 1418 if (check_fs_open(argv[0])) 1419 return; 1420 1421 if (!current_handle) { 1422 com_err(argv[0], 0, "Extent handle not open"); 1423 return; 1424 } 1425 1426 retval = ext2fs_extent_get_info(current_handle, &info); 1427 if (retval) { 1428 com_err(argv[0], retval, 0); 1429 return; 1430 } 1431 1432 retval = ext2fs_extent_get(current_handle, 1433 EXT2_EXTENT_CURRENT, &extent); 1434 if (retval) { 1435 com_err(argv[0], retval, 0); 1436 return; 1437 } 1438 1439 dbg_print_extent(0, &extent); 1440 1441 printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n", 1442 info.curr_entry, info.num_entries, info.max_entries, 1443 info.bytes_avail, info.curr_level, info.max_depth); 1444 printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk, 1445 info.max_pblk); 1446 printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len, 1447 info.max_uninit_len); 1448} 1449 1450void do_goto_block(int argc, char **argv) 1451{ 1452 struct ext2fs_extent extent; 1453 errcode_t retval; 1454 int op = EXT2_EXTENT_NEXT_LEAF; 1455 blk_t blk; 1456 int level = 0; 1457 1458 if (check_fs_open(argv[0])) 1459 return; 1460 1461 if (!current_handle) { 1462 com_err(argv[0], 0, "Extent handle not open"); 1463 return; 1464 } 1465 1466 if (argc < 2 || argc > 3) { 1467 fprintf(stderr, "%s block [level]\n", argv[0]); 1468 return; 1469 } 1470 1471 if (strtoblk(argv[0], argv[1], &blk)) 1472 return; 1473 1474 if (argc == 3) 1475 if (strtoblk(argv[0], argv[2], &level)) 1476 return; 1477 1478 retval = extent_goto(current_handle, level, (blk64_t) blk); 1479 1480 if (retval) { 1481 com_err(argv[0], retval, "while trying to go to block %lu, level %d", 1482 blk, level); 1483 return; 1484 } 1485 1486 generic_goto_node(argv[0], EXT2_EXTENT_CURRENT); 1487} 1488#endif 1489 1490