inode.c revision 5df55d7f847e29d23227592a0bb23daad1a61500
1/* 2 * inode.c --- utility routines to read and write inodes 3 * 4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 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_SYS_STAT_H 18#include <sys/stat.h> 19#endif 20#if HAVE_SYS_TYPES_H 21#include <sys/types.h> 22#endif 23 24#include "ext2_fs.h" 25#include "ext2fsP.h" 26#include "e2image.h" 27 28struct ext2_struct_inode_scan { 29 errcode_t magic; 30 ext2_filsys fs; 31 ext2_ino_t current_inode; 32 blk_t current_block; 33 dgrp_t current_group; 34 ext2_ino_t inodes_left; 35 blk_t blocks_left; 36 dgrp_t groups_left; 37 blk_t inode_buffer_blocks; 38 char * inode_buffer; 39 int inode_size; 40 char * ptr; 41 int bytes_left; 42 char *temp_buffer; 43 errcode_t (*done_group)(ext2_filsys fs, 44 ext2_inode_scan scan, 45 dgrp_t group, 46 void * priv_data); 47 void * done_group_data; 48 int bad_block_ptr; 49 int scan_flags; 50 int reserved[6]; 51}; 52 53/* 54 * This routine flushes the icache, if it exists. 55 */ 56errcode_t ext2fs_flush_icache(ext2_filsys fs) 57{ 58 int i; 59 60 if (!fs->icache) 61 return 0; 62 63 for (i=0; i < fs->icache->cache_size; i++) 64 fs->icache->cache[i].ino = 0; 65 66 return 0; 67} 68 69static errcode_t create_icache(ext2_filsys fs) 70{ 71 errcode_t retval; 72 73 if (fs->icache) 74 return 0; 75 retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), 76 (void **) &fs->icache); 77 if (retval) 78 return retval; 79 80 memset(fs->icache, 0, sizeof(struct ext2_inode_cache)); 81 retval = ext2fs_get_mem(fs->blocksize, (void **) &fs->icache->buffer); 82 if (retval) { 83 ext2fs_free_mem((void **) &fs->icache); 84 return retval; 85 } 86 fs->icache->buffer_blk = 0; 87 fs->icache->cache_last = -1; 88 fs->icache->cache_size = 4; 89 fs->icache->refcount = 1; 90 retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent) 91 * fs->icache->cache_size, 92 (void **) &fs->icache->cache); 93 if (retval) { 94 ext2fs_free_mem((void **) &fs->icache->buffer); 95 ext2fs_free_mem((void **) &fs->icache); 96 return retval; 97 } 98 ext2fs_flush_icache(fs); 99 return 0; 100} 101 102errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, 103 ext2_inode_scan *ret_scan) 104{ 105 ext2_inode_scan scan; 106 errcode_t retval; 107 errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks); 108 109 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 110 111 /* 112 * If fs->badblocks isn't set, then set it --- since the inode 113 * scanning functions require it. 114 */ 115 if (fs->badblocks == 0) { 116 /* 117 * Temporarly save fs->get_blocks and set it to zero, 118 * for compatibility with old e2fsck's. 119 */ 120 save_get_blocks = fs->get_blocks; 121 fs->get_blocks = 0; 122 retval = ext2fs_read_bb_inode(fs, &fs->badblocks); 123 if (retval && fs->badblocks) { 124 badblocks_list_free(fs->badblocks); 125 fs->badblocks = 0; 126 } 127 fs->get_blocks = save_get_blocks; 128 } 129 130 retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), 131 (void **) &scan); 132 if (retval) 133 return retval; 134 memset(scan, 0, sizeof(struct ext2_struct_inode_scan)); 135 136 scan->magic = EXT2_ET_MAGIC_INODE_SCAN; 137 scan->fs = fs; 138 scan->inode_size = EXT2_INODE_SIZE(fs->super); 139 scan->bytes_left = 0; 140 scan->current_group = 0; 141 scan->groups_left = fs->group_desc_count - 1; 142 scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8; 143 scan->current_block = scan->fs-> 144 group_desc[scan->current_group].bg_inode_table; 145 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); 146 scan->blocks_left = scan->fs->inode_blocks_per_group; 147 retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks * 148 fs->blocksize), 149 (void **) &scan->inode_buffer); 150 scan->done_group = 0; 151 scan->done_group_data = 0; 152 scan->bad_block_ptr = 0; 153 if (retval) { 154 ext2fs_free_mem((void **) &scan); 155 return retval; 156 } 157 retval = ext2fs_get_mem(scan->inode_size, 158 (void **) &scan->temp_buffer); 159 if (retval) { 160 ext2fs_free_mem((void **) &scan->inode_buffer); 161 ext2fs_free_mem((void **) &scan); 162 return retval; 163 } 164 if (scan->fs->badblocks && scan->fs->badblocks->num) 165 scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS; 166 *ret_scan = scan; 167 return 0; 168} 169 170void ext2fs_close_inode_scan(ext2_inode_scan scan) 171{ 172 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) 173 return; 174 175 ext2fs_free_mem((void **) &scan->inode_buffer); 176 scan->inode_buffer = NULL; 177 ext2fs_free_mem((void **) &scan->temp_buffer); 178 scan->temp_buffer = NULL; 179 ext2fs_free_mem((void **) &scan); 180 return; 181} 182 183void ext2fs_set_inode_callback(ext2_inode_scan scan, 184 errcode_t (*done_group)(ext2_filsys fs, 185 ext2_inode_scan scan, 186 dgrp_t group, 187 void * priv_data), 188 void *done_group_data) 189{ 190 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) 191 return; 192 193 scan->done_group = done_group; 194 scan->done_group_data = done_group_data; 195} 196 197int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, 198 int clear_flags) 199{ 200 int old_flags; 201 202 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) 203 return 0; 204 205 old_flags = scan->scan_flags; 206 scan->scan_flags &= ~clear_flags; 207 scan->scan_flags |= set_flags; 208 return old_flags; 209} 210 211/* 212 * This function is called by ext2fs_get_next_inode when it needs to 213 * get ready to read in a new blockgroup. 214 */ 215static errcode_t get_next_blockgroup(ext2_inode_scan scan) 216{ 217 scan->current_group++; 218 scan->groups_left--; 219 220 scan->current_block = scan->fs-> 221 group_desc[scan->current_group].bg_inode_table; 222 223 scan->current_inode = scan->current_group * 224 EXT2_INODES_PER_GROUP(scan->fs->super); 225 226 scan->bytes_left = 0; 227 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); 228 scan->blocks_left = scan->fs->inode_blocks_per_group; 229 return 0; 230} 231 232errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, 233 int group) 234{ 235 scan->current_group = group - 1; 236 scan->groups_left = scan->fs->group_desc_count - group; 237 return get_next_blockgroup(scan); 238} 239 240/* 241 * This function is called by get_next_blocks() to check for bad 242 * blocks in the inode table. 243 * 244 * This function assumes that badblocks_list->list is sorted in 245 * increasing order. 246 */ 247static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, 248 blk_t *num_blocks) 249{ 250 blk_t blk = scan->current_block; 251 badblocks_list bb = scan->fs->badblocks; 252 253 /* 254 * If the inode table is missing, then obviously there are no 255 * bad blocks. :-) 256 */ 257 if (blk == 0) 258 return 0; 259 260 /* 261 * If the current block is greater than the bad block listed 262 * in the bad block list, then advance the pointer until this 263 * is no longer the case. If we run out of bad blocks, then 264 * we don't need to do any more checking! 265 */ 266 while (blk > bb->list[scan->bad_block_ptr]) { 267 if (++scan->bad_block_ptr >= bb->num) { 268 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; 269 return 0; 270 } 271 } 272 273 /* 274 * If the current block is equal to the bad block listed in 275 * the bad block list, then handle that one block specially. 276 * (We could try to handle runs of bad blocks, but that 277 * only increases CPU efficiency by a small amount, at the 278 * expense of a huge expense of code complexity, and for an 279 * uncommon case at that.) 280 */ 281 if (blk == bb->list[scan->bad_block_ptr]) { 282 scan->scan_flags |= EXT2_SF_BAD_INODE_BLK; 283 *num_blocks = 1; 284 if (++scan->bad_block_ptr >= bb->num) 285 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; 286 return 0; 287 } 288 289 /* 290 * If there is a bad block in the range that we're about to 291 * read in, adjust the number of blocks to read so that we we 292 * don't read in the bad block. (Then the next block to read 293 * will be the bad block, which is handled in the above case.) 294 */ 295 if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr]) 296 *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk); 297 298 return 0; 299} 300 301/* 302 * This function is called by ext2fs_get_next_inode when it needs to 303 * read in more blocks from the current blockgroup's inode table. 304 */ 305static errcode_t get_next_blocks(ext2_inode_scan scan) 306{ 307 blk_t num_blocks; 308 errcode_t retval; 309 310 /* 311 * Figure out how many blocks to read; we read at most 312 * inode_buffer_blocks, and perhaps less if there aren't that 313 * many blocks left to read. 314 */ 315 num_blocks = scan->inode_buffer_blocks; 316 if (num_blocks > scan->blocks_left) 317 num_blocks = scan->blocks_left; 318 319 /* 320 * If the past block "read" was a bad block, then mark the 321 * left-over extra bytes as also being bad. 322 */ 323 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) { 324 if (scan->bytes_left) 325 scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES; 326 scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK; 327 } 328 329 /* 330 * Do inode bad block processing, if necessary. 331 */ 332 if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) { 333 retval = check_for_inode_bad_blocks(scan, &num_blocks); 334 if (retval) 335 return retval; 336 } 337 338 if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) || 339 (scan->current_block == 0)) { 340 memset(scan->inode_buffer, 0, 341 (size_t) num_blocks * scan->fs->blocksize); 342 } else { 343 retval = io_channel_read_blk(scan->fs->io, 344 scan->current_block, 345 (int) num_blocks, 346 scan->inode_buffer); 347 if (retval) 348 return EXT2_ET_NEXT_INODE_READ; 349 } 350 scan->ptr = scan->inode_buffer; 351 scan->bytes_left = num_blocks * scan->fs->blocksize; 352 353 scan->blocks_left -= num_blocks; 354 if (scan->current_block) 355 scan->current_block += num_blocks; 356 return 0; 357} 358 359#if 0 360/* 361 * Returns 1 if the entire inode_buffer has a non-zero size and 362 * contains all zeros. (Not just deleted inodes, since that means 363 * that part of the inode table was used at one point; we want all 364 * zeros, which means that the inode table is pristine.) 365 */ 366static inline int is_empty_scan(ext2_inode_scan scan) 367{ 368 int i; 369 370 if (scan->bytes_left == 0) 371 return 0; 372 373 for (i=0; i < scan->bytes_left; i++) 374 if (scan->ptr[i]) 375 return 0; 376 return 1; 377} 378#endif 379 380errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, 381 struct ext2_inode *inode) 382{ 383 errcode_t retval; 384 int extra_bytes = 0; 385 386 EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN); 387 388 /* 389 * Do we need to start reading a new block group? 390 */ 391 if (scan->inodes_left <= 0) { 392 force_new_group: 393 if (scan->done_group) { 394 retval = (scan->done_group) 395 (scan->fs, scan, scan->current_group, 396 scan->done_group_data); 397 if (retval) 398 return retval; 399 } 400 if (scan->groups_left <= 0) { 401 *ino = 0; 402 return 0; 403 } 404 retval = get_next_blockgroup(scan); 405 if (retval) 406 return retval; 407 } 408 /* 409 * This is done outside the above if statement so that the 410 * check can be done for block group #0. 411 */ 412 if (scan->current_block == 0) { 413 if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) { 414 goto force_new_group; 415 } else 416 return EXT2_ET_MISSING_INODE_TABLE; 417 } 418 419 420 /* 421 * Have we run out of space in the inode buffer? If so, we 422 * need to read in more blocks. 423 */ 424 if (scan->bytes_left < scan->inode_size) { 425 memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left); 426 extra_bytes = scan->bytes_left; 427 428 retval = get_next_blocks(scan); 429 if (retval) 430 return retval; 431#if 0 432 /* 433 * XXX test Need check for used inode somehow. 434 * (Note: this is hard.) 435 */ 436 if (is_empty_scan(scan)) 437 goto force_new_group; 438#endif 439 } 440 441 retval = 0; 442 if (extra_bytes) { 443 memcpy(scan->temp_buffer+extra_bytes, scan->ptr, 444 scan->inode_size - extra_bytes); 445 scan->ptr += scan->inode_size - extra_bytes; 446 scan->bytes_left -= scan->inode_size - extra_bytes; 447 448#ifdef EXT2FS_ENABLE_SWAPFS 449 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || 450 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) 451 ext2fs_swap_inode(scan->fs, inode, 452 (struct ext2_inode *) scan->temp_buffer, 0); 453 else 454#endif 455 *inode = *((struct ext2_inode *) scan->temp_buffer); 456 if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES) 457 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; 458 scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES; 459 } else { 460#ifdef EXT2FS_ENABLE_SWAPFS 461 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || 462 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) 463 ext2fs_swap_inode(scan->fs, inode, 464 (struct ext2_inode *) scan->ptr, 0); 465 else 466#endif 467 *inode = *((struct ext2_inode *) scan->ptr); 468 scan->ptr += scan->inode_size; 469 scan->bytes_left -= scan->inode_size; 470 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) 471 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; 472 } 473 474 scan->inodes_left--; 475 scan->current_inode++; 476 *ino = scan->current_inode; 477 return retval; 478} 479 480/* 481 * Functions to read and write a single inode. 482 */ 483errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, 484 struct ext2_inode * inode) 485{ 486 unsigned long group, block, block_nr, offset; 487 char *ptr; 488 errcode_t retval; 489 int clen, length, i, inodes_per_block; 490 491 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 492 493 /* Check to see if user has an override function */ 494 if (fs->read_inode) { 495 retval = (fs->read_inode)(fs, ino, inode); 496 if (retval != EXT2_ET_CALLBACK_NOTHANDLED) 497 return retval; 498 } 499 /* Create inode cache if not present */ 500 if (!fs->icache) { 501 retval = create_icache(fs); 502 if (retval) 503 return retval; 504 } 505 /* Check to see if it's in the inode cache */ 506 for (i=0; i < fs->icache->cache_size; i++) { 507 if (fs->icache->cache[i].ino == ino) { 508 *inode = fs->icache->cache[i].inode; 509 return 0; 510 } 511 } 512 if ((ino == 0) || (ino > fs->super->s_inodes_count)) 513 return EXT2_ET_BAD_INODE_NUM; 514 if (fs->flags & EXT2_FLAG_IMAGE_FILE) { 515 inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super); 516 block_nr = fs->image_header->offset_inode / fs->blocksize; 517 block_nr += (ino - 1) / inodes_per_block; 518 offset = ((ino - 1) % inodes_per_block) * 519 EXT2_INODE_SIZE(fs->super); 520 } else { 521 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); 522 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * 523 EXT2_INODE_SIZE(fs->super); 524 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); 525 if (!fs->group_desc[(unsigned)group].bg_inode_table) 526 return EXT2_ET_MISSING_INODE_TABLE; 527 block_nr = fs->group_desc[(unsigned)group].bg_inode_table + 528 block; 529 } 530 if (block_nr != fs->icache->buffer_blk) { 531 retval = io_channel_read_blk(fs->io, block_nr, 1, 532 fs->icache->buffer); 533 if (retval) 534 return retval; 535 fs->icache->buffer_blk = block_nr; 536 } 537 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); 538 ptr = ((char *) fs->icache->buffer) + (unsigned) offset; 539 540 memset(inode, 0, sizeof(struct ext2_inode)); 541 length = EXT2_INODE_SIZE(fs->super); 542 if (length > sizeof(struct ext2_inode)) 543 length = sizeof(struct ext2_inode); 544 545 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) { 546 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset); 547 memcpy((char *) inode, ptr, clen); 548 length -= clen; 549 550 retval = io_channel_read_blk(fs->io, block_nr+1, 1, 551 fs->icache->buffer); 552 if (retval) { 553 fs->icache->buffer_blk = 0; 554 return retval; 555 } 556 fs->icache->buffer_blk = block_nr+1; 557 558 memcpy(((char *) inode) + clen, 559 fs->icache->buffer, length); 560 } else 561 memcpy((char *) inode, ptr, length); 562 563#ifdef EXT2FS_ENABLE_SWAPFS 564 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || 565 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) 566 ext2fs_swap_inode(fs, inode, inode, 0); 567#endif 568 569 /* Update the inode cache */ 570 fs->icache->cache_last = (fs->icache->cache_last + 1) % 571 fs->icache->cache_size; 572 fs->icache->cache[fs->icache->cache_last].ino = ino; 573 fs->icache->cache[fs->icache->cache_last].inode = *inode; 574 575 return 0; 576} 577 578errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, 579 struct ext2_inode * inode) 580{ 581 unsigned long group, block, block_nr, offset; 582 errcode_t retval; 583 struct ext2_inode temp_inode; 584 char *ptr; 585 int clen, length, i; 586 587 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 588 589 /* Check to see if user provided an override function */ 590 if (fs->write_inode) { 591 retval = (fs->write_inode)(fs, ino, inode); 592 if (retval != EXT2_ET_CALLBACK_NOTHANDLED) 593 return retval; 594 } 595 596 /* Check to see if the inode cache needs to be updated */ 597 if (fs->icache) { 598 for (i=0; i < fs->icache->cache_size; i++) { 599 if (fs->icache->cache[i].ino == ino) { 600 fs->icache->cache[i].inode = *inode; 601 break; 602 } 603 } 604 } else { 605 retval = create_icache(fs); 606 if (retval) 607 return retval; 608 } 609 610 if (!(fs->flags & EXT2_FLAG_RW)) 611 return EXT2_ET_RO_FILSYS; 612 613 if ((ino == 0) || (ino > fs->super->s_inodes_count)) 614 return EXT2_ET_BAD_INODE_NUM; 615 616#ifdef EXT2FS_ENABLE_SWAPFS 617 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || 618 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) 619 ext2fs_swap_inode(fs, &temp_inode, inode, 1); 620 else 621#endif 622 memcpy(&temp_inode, inode, sizeof(struct ext2_inode)); 623 624 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); 625 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * 626 EXT2_INODE_SIZE(fs->super); 627 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); 628 if (!fs->group_desc[(unsigned) group].bg_inode_table) 629 return EXT2_ET_MISSING_INODE_TABLE; 630 block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block; 631 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); 632 ptr = (char *) fs->icache->buffer + (unsigned) offset; 633 634 length = EXT2_INODE_SIZE(fs->super); 635 clen = length; 636 if (length > sizeof(struct ext2_inode)) 637 length = sizeof(struct ext2_inode); 638 639 if (fs->icache->buffer_blk != block_nr) { 640 retval = io_channel_read_blk(fs->io, block_nr, 1, 641 fs->icache->buffer); 642 if (retval) 643 return retval; 644 fs->icache->buffer_blk = block_nr; 645 } 646 647 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) { 648 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset); 649 length -= clen; 650 } else { 651 length = 0; 652 } 653 memcpy(ptr, &temp_inode, clen); 654 retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer); 655 if (retval) 656 return retval; 657 658 if (length) { 659 retval = io_channel_read_blk(fs->io, ++block_nr, 1, 660 fs->icache->buffer); 661 if (retval) { 662 fs->icache->buffer_blk = 0; 663 return retval; 664 } 665 fs->icache->buffer_blk = block_nr; 666 memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen, 667 length); 668 669 retval = io_channel_write_blk(fs->io, block_nr, 1, 670 fs->icache->buffer); 671 if (retval) 672 return retval; 673 } 674 675 fs->flags |= EXT2_FLAG_CHANGED; 676 return 0; 677} 678 679errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks) 680{ 681 struct ext2_inode inode; 682 int i; 683 errcode_t retval; 684 685 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 686 687 if (ino > fs->super->s_inodes_count) 688 return EXT2_ET_BAD_INODE_NUM; 689 690 if (fs->get_blocks) { 691 if (!(*fs->get_blocks)(fs, ino, blocks)) 692 return 0; 693 } 694 retval = ext2fs_read_inode(fs, ino, &inode); 695 if (retval) 696 return retval; 697 for (i=0; i < EXT2_N_BLOCKS; i++) 698 blocks[i] = inode.i_block[i]; 699 return 0; 700} 701 702errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino) 703{ 704 struct ext2_inode inode; 705 errcode_t retval; 706 707 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 708 709 if (ino > fs->super->s_inodes_count) 710 return EXT2_ET_BAD_INODE_NUM; 711 712 if (fs->check_directory) { 713 retval = (fs->check_directory)(fs, ino); 714 if (retval != EXT2_ET_CALLBACK_NOTHANDLED) 715 return retval; 716 } 717 retval = ext2fs_read_inode(fs, ino, &inode); 718 if (retval) 719 return retval; 720 if (!LINUX_S_ISDIR(inode.i_mode)) 721 return EXT2_ET_NO_DIRECTORY; 722 return 0; 723} 724 725