inode.c revision a78926effb15bbabb1c0ed3e438b03be25c4d48c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * inode.c --- utility routines to read and write inodes 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %Begin-Header% 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This file may be redistributed under the terms of the GNU Public 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %End-Header% 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <string.h> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if HAVE_UNISTD_H 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <unistd.h> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if HAVE_SYS_STAT_H 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h> 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if HAVE_SYS_TYPES_H 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h> 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if EXT2_FLAT_INCLUDES 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ext2_fs.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/ext2_fs.h> 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ext2fsP.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "e2image.h" 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)struct ext2_struct_inode_scan { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errcode_t magic; 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ext2_filsys fs; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2_ino_t current_inode; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk_t current_block; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dgrp_t current_group; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2_ino_t inodes_left; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk_t blocks_left; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dgrp_t groups_left; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk_t inode_buffer_blocks; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char * inode_buffer; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int inode_size; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char * ptr; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bytes_left; 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) char *temp_buffer; 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) errcode_t (*done_group)(ext2_filsys fs, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2_inode_scan scan, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dgrp_t group, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void * priv_data); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void * done_group_data; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bad_block_ptr; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int scan_flags; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int reserved[6]; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This routine flushes the icache, if it exists. 607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) */ 617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)errcode_t ext2fs_flush_icache(ext2_filsys fs) 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles){ 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int i; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!fs->icache) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i < fs->icache->cache_size; i++) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fs->icache->cache[i].ino = 0; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t create_icache(ext2_filsys fs) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) errcode_t retval; 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fs->icache) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void **) &fs->icache); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) memset(fs->icache, 0, sizeof(struct ext2_inode_cache)); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_get_mem(fs->blocksize, (void **) &fs->icache->buffer); 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (retval) { 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ext2fs_free_mem((void **) &fs->icache); 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return retval; 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fs->icache->buffer_blk = 0; 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fs->icache->cache_last = -1; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fs->icache->cache_size = 4; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fs->icache->refcount = 1; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * fs->icache->cache_size, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void **) &fs->icache->cache); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &fs->icache->buffer); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &fs->icache); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_flush_icache(fs); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2_inode_scan *ret_scan) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2_inode_scan scan; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errcode_t retval; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If fs->badblocks isn't set, then set it --- since the inode 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * scanning functions require it. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 120c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (fs->badblocks == 0) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Temporarly save fs->get_blocks and set it to zero, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for compatibility with old e2fsck's. 124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch */ 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_get_blocks = fs->get_blocks; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fs->get_blocks = 0; 127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch retval = ext2fs_read_bb_inode(fs, &fs->badblocks); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval && fs->badblocks) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) badblocks_list_free(fs->badblocks); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fs->badblocks = 0; 131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fs->get_blocks = save_get_blocks; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void **) &scan); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(scan, 0, sizeof(struct ext2_struct_inode_scan)); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->magic = EXT2_ET_MAGIC_INODE_SCAN; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->fs = fs; 143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scan->inode_size = EXT2_INODE_SIZE(fs->super); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->bytes_left = 0; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_group = 0; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->groups_left = fs->group_desc_count - 1; 147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_block = scan->fs-> 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group_desc[scan->current_group].bg_inode_table; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->blocks_left = scan->fs->inode_blocks_per_group; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks * 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) fs->blocksize), 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void **) &scan->inode_buffer); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->done_group = 0; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->done_group_data = 0; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->bad_block_ptr = 0; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &scan); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = ext2fs_get_mem(scan->inode_size, 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void **) &scan->temp_buffer); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &scan->inode_buffer); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &scan); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->fs->badblocks && scan->fs->badblocks->num) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ret_scan = scan; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ext2fs_close_inode_scan(ext2_inode_scan scan) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &scan->inode_buffer); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->inode_buffer = NULL; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &scan->temp_buffer); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->temp_buffer = NULL; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2fs_free_mem((void **) &scan); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ext2fs_set_inode_callback(ext2_inode_scan scan, 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errcode_t (*done_group)(ext2_filsys fs, 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ext2_inode_scan scan, 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dgrp_t group, 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void * priv_data), 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *done_group_data) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->done_group = done_group; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->done_group_data = done_group_data; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int clear_flags) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_flags; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 207e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) 20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_flags = scan->scan_flags; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->scan_flags &= ~clear_flags; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->scan_flags |= set_flags; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return old_flags; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function is called by ext2fs_get_next_inode when it needs to 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * get ready to read in a new blockgroup. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t get_next_blockgroup(ext2_inode_scan scan) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_group++; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->groups_left--; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_block = scan->fs-> 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group_desc[scan->current_group].bg_inode_table; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_inode = scan->current_group * 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXT2_INODES_PER_GROUP(scan->fs->super); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->bytes_left = 0; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->blocks_left = scan->fs->inode_blocks_per_group; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int group) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_group = group - 1; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->groups_left = scan->fs->group_desc_count - group; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return get_next_blockgroup(scan); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function is called by get_next_blocks() to check for bad 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * blocks in the inode table. 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function assumes that badblocks_list->list is sorted in 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * increasing order. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk_t *num_blocks) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk_t blk = scan->current_block; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) badblocks_list bb = scan->fs->badblocks; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If the inode table is missing, then obviously there are no 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * bad blocks. :-) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (blk == 0) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If the current block is greater than the bad block listed 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the bad block list, then advance the pointer until this 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * is no longer the case. If we run out of bad blocks, then 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * we don't need to do any more checking! 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (blk > bb->list[scan->bad_block_ptr]) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (++scan->bad_block_ptr >= bb->num) { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /* 2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * If the current block is equal to the bad block listed in 2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * the bad block list, then handle that one block specially. 2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * (We could try to handle runs of bad blocks, but that 2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * only increases CPU efficiency by a small amount, at the 2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * expense of a huge expense of code complexity, and for an 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * uncommon case at that.) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (blk == bb->list[scan->bad_block_ptr]) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->scan_flags |= EXT2_SF_BAD_INODE_BLK; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *num_blocks = 1; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (++scan->bad_block_ptr >= bb->num) 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch /* 295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * If there is a bad block in the range that we're about to 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read in, adjust the number of blocks to read so that we we 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * don't read in the bad block. (Then the next block to read 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * will be the bad block, which is handled in the above case.) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr]) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function is called by ext2fs_get_next_inode when it needs to 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read in more blocks from the current blockgroup's inode table. 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t get_next_blocks(ext2_inode_scan scan) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blk_t num_blocks; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errcode_t retval; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Figure out how many blocks to read; we read at most 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * inode_buffer_blocks, and perhaps less if there aren't that 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * many blocks left to read. 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_blocks = scan->inode_buffer_blocks; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_blocks > scan->blocks_left) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_blocks = scan->blocks_left; 32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If the past block "read" was a bad block, then mark the 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * left-over extra bytes as also being bad. 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->bytes_left) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Do inode bad block processing, if necessary. 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) { 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = check_for_inode_bad_blocks(scan, &num_blocks); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) || 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (scan->current_block == 0)) { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(scan->inode_buffer, 0, 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (size_t) num_blocks * scan->fs->blocksize); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = io_channel_read_blk(scan->fs->io, 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_block, 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (int) num_blocks, 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->inode_buffer); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return EXT2_ET_NEXT_INODE_READ; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->ptr = scan->inode_buffer; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->bytes_left = num_blocks * scan->fs->blocksize; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->blocks_left -= num_blocks; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->current_block) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->current_block += num_blocks; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns 1 if the entire inode_buffer has a non-zero size and 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contains all zeros. (Not just deleted inodes, since that means 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * that part of the inode table was used at one point; we want all 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * zeros, which means that the inode table is pristine.) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline int is_empty_scan(ext2_inode_scan scan) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->bytes_left == 0) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i < scan->bytes_left; i++) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->ptr[i]) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ext2_inode *inode) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errcode_t retval; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int extra_bytes = 0; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Do we need to start reading a new block group? 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->inodes_left <= 0) { 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) force_new_group: 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->done_group) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = (scan->done_group) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (scan->fs, scan, scan->current_group, 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scan->done_group_data); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->groups_left <= 0) { 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ino = 0; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) retval = get_next_blockgroup(scan); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (retval) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return retval; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is done outside the above if statement so that the 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * check can be done for block group #0. 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->current_block == 0) { 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) { 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto force_new_group; 420 } else 421 return EXT2_ET_MISSING_INODE_TABLE; 422 } 423 424 425 /* 426 * Have we run out of space in the inode buffer? If so, we 427 * need to read in more blocks. 428 */ 429 if (scan->bytes_left < scan->inode_size) { 430 memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left); 431 extra_bytes = scan->bytes_left; 432 433 retval = get_next_blocks(scan); 434 if (retval) 435 return retval; 436#if 0 437 /* 438 * XXX test Need check for used inode somehow. 439 * (Note: this is hard.) 440 */ 441 if (is_empty_scan(scan)) 442 goto force_new_group; 443#endif 444 } 445 446 retval = 0; 447 if (extra_bytes) { 448 memcpy(scan->temp_buffer+extra_bytes, scan->ptr, 449 scan->inode_size - extra_bytes); 450 scan->ptr += scan->inode_size - extra_bytes; 451 scan->bytes_left -= scan->inode_size - extra_bytes; 452 453 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || 454 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) 455 ext2fs_swap_inode(scan->fs, inode, 456 (struct ext2_inode *) scan->temp_buffer, 0); 457 else 458 *inode = *((struct ext2_inode *) scan->temp_buffer); 459 if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES) 460 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; 461 scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES; 462 } else { 463 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || 464 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) 465 ext2fs_swap_inode(scan->fs, inode, 466 (struct ext2_inode *) scan->ptr, 0); 467 else 468 *inode = *((struct ext2_inode *) scan->ptr); 469 scan->ptr += scan->inode_size; 470 scan->bytes_left -= scan->inode_size; 471 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) 472 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; 473 } 474 475 scan->inodes_left--; 476 scan->current_inode++; 477 *ino = scan->current_inode; 478 return retval; 479} 480 481/* 482 * Functions to read and write a single inode. 483 */ 484errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, 485 struct ext2_inode * inode) 486{ 487 unsigned long group, block, block_nr, offset; 488 char *ptr; 489 errcode_t retval; 490 int clen, length, i, inodes_per_block; 491 492 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 493 494 /* Check to see if user has an override function */ 495 if (fs->read_inode) { 496 retval = (fs->read_inode)(fs, ino, inode); 497 if (retval != EXT2_ET_CALLBACK_NOTHANDLED) 498 return retval; 499 } 500 /* Create inode cache if not present */ 501 if (!fs->icache) { 502 retval = create_icache(fs); 503 if (retval) 504 return retval; 505 } 506 /* Check to see if it's in the inode cache */ 507 for (i=0; i < fs->icache->cache_size; i++) { 508 if (fs->icache->cache[i].ino == ino) { 509 *inode = fs->icache->cache[i].inode; 510 return 0; 511 } 512 } 513 if ((ino == 0) || (ino > fs->super->s_inodes_count)) 514 return EXT2_ET_BAD_INODE_NUM; 515 if (fs->flags & EXT2_FLAG_IMAGE_FILE) { 516 inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super); 517 block_nr = fs->image_header->offset_inode / fs->blocksize; 518 block_nr += (ino - 1) / inodes_per_block; 519 offset = ((ino - 1) % inodes_per_block) * 520 EXT2_INODE_SIZE(fs->super); 521 } else { 522 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); 523 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * 524 EXT2_INODE_SIZE(fs->super); 525 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); 526 if (!fs->group_desc[(unsigned)group].bg_inode_table) 527 return EXT2_ET_MISSING_INODE_TABLE; 528 block_nr = fs->group_desc[(unsigned)group].bg_inode_table + 529 block; 530 } 531 if (block_nr != fs->icache->buffer_blk) { 532 retval = io_channel_read_blk(fs->io, block_nr, 1, 533 fs->icache->buffer); 534 if (retval) 535 return retval; 536 fs->icache->buffer_blk = block_nr; 537 } 538 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); 539 ptr = ((char *) fs->icache->buffer) + (unsigned) offset; 540 541 memset(inode, 0, sizeof(struct ext2_inode)); 542 length = EXT2_INODE_SIZE(fs->super); 543 if (length > sizeof(struct ext2_inode)) 544 length = sizeof(struct ext2_inode); 545 546 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) { 547 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset); 548 memcpy((char *) inode, ptr, clen); 549 length -= clen; 550 551 retval = io_channel_read_blk(fs->io, block_nr+1, 1, 552 fs->icache->buffer); 553 if (retval) { 554 fs->icache->buffer_blk = 0; 555 return retval; 556 } 557 fs->icache->buffer_blk = block_nr+1; 558 559 memcpy(((char *) inode) + clen, 560 fs->icache->buffer, length); 561 } else 562 memcpy((char *) inode, ptr, length); 563 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 568 /* Update the inode cache */ 569 fs->icache->cache_last = (fs->icache->cache_last + 1) % 570 fs->icache->cache_size; 571 fs->icache->cache[fs->icache->cache_last].ino = ino; 572 fs->icache->cache[fs->icache->cache_last].inode = *inode; 573 574 return 0; 575} 576 577errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, 578 struct ext2_inode * inode) 579{ 580 unsigned long group, block, block_nr, offset; 581 errcode_t retval; 582 struct ext2_inode temp_inode; 583 char *ptr; 584 int clen, length, i; 585 586 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 587 588 /* Check to see if user provided an override function */ 589 if (fs->write_inode) { 590 retval = (fs->write_inode)(fs, ino, inode); 591 if (retval != EXT2_ET_CALLBACK_NOTHANDLED) 592 return retval; 593 } 594 595 /* Check to see if the inode cache needs to be updated */ 596 if (fs->icache) { 597 for (i=0; i < fs->icache->cache_size; i++) { 598 if (fs->icache->cache[i].ino == ino) { 599 fs->icache->cache[i].inode = *inode; 600 break; 601 } 602 } 603 } else { 604 retval = create_icache(fs); 605 if (retval) 606 return retval; 607 } 608 609 if (!(fs->flags & EXT2_FLAG_RW)) 610 return EXT2_ET_RO_FILSYS; 611 612 if ((ino == 0) || (ino > fs->super->s_inodes_count)) 613 return EXT2_ET_BAD_INODE_NUM; 614 615 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || 616 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) 617 ext2fs_swap_inode(fs, &temp_inode, inode, 1); 618 else 619 memcpy(&temp_inode, inode, sizeof(struct ext2_inode)); 620 621 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); 622 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * 623 EXT2_INODE_SIZE(fs->super); 624 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); 625 if (!fs->group_desc[(unsigned) group].bg_inode_table) 626 return EXT2_ET_MISSING_INODE_TABLE; 627 block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block; 628 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); 629 ptr = (char *) fs->icache->buffer + (unsigned) offset; 630 631 length = EXT2_INODE_SIZE(fs->super); 632 clen = length; 633 if (length > sizeof(struct ext2_inode)) 634 length = sizeof(struct ext2_inode); 635 636 if (fs->icache->buffer_blk != block_nr) { 637 retval = io_channel_read_blk(fs->io, block_nr, 1, 638 fs->icache->buffer); 639 if (retval) 640 return retval; 641 fs->icache->buffer_blk = block_nr; 642 } 643 644 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) { 645 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset); 646 length -= clen; 647 } else { 648 length = 0; 649 } 650 memcpy(ptr, &temp_inode, clen); 651 retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer); 652 if (retval) 653 return retval; 654 655 if (length) { 656 retval = io_channel_read_blk(fs->io, ++block_nr, 1, 657 fs->icache->buffer); 658 if (retval) { 659 fs->icache->buffer_blk = 0; 660 return retval; 661 } 662 fs->icache->buffer_blk = block_nr; 663 memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen, 664 length); 665 666 retval = io_channel_write_blk(fs->io, block_nr, 1, 667 fs->icache->buffer); 668 if (retval) 669 return retval; 670 } 671 672 fs->flags |= EXT2_FLAG_CHANGED; 673 return 0; 674} 675 676errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks) 677{ 678 struct ext2_inode inode; 679 int i; 680 errcode_t retval; 681 682 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 683 684 if (ino > fs->super->s_inodes_count) 685 return EXT2_ET_BAD_INODE_NUM; 686 687 if (fs->get_blocks) { 688 if (!(*fs->get_blocks)(fs, ino, blocks)) 689 return 0; 690 } 691 retval = ext2fs_read_inode(fs, ino, &inode); 692 if (retval) 693 return retval; 694 for (i=0; i < EXT2_N_BLOCKS; i++) 695 blocks[i] = inode.i_block[i]; 696 return 0; 697} 698 699errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino) 700{ 701 struct ext2_inode inode; 702 errcode_t retval; 703 704 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 705 706 if (ino > fs->super->s_inodes_count) 707 return EXT2_ET_BAD_INODE_NUM; 708 709 if (fs->check_directory) { 710 retval = (fs->check_directory)(fs, ino); 711 if (retval != EXT2_ET_CALLBACK_NOTHANDLED) 712 return retval; 713 } 714 retval = ext2fs_read_inode(fs, ino, &inode); 715 if (retval) 716 return retval; 717 if (!LINUX_S_ISDIR(inode.i_mode)) 718 return EXT2_ET_NO_DIRECTORY; 719 return 0; 720} 721 722