*/
errcode_t ext2fs_flush_icache(ext2_filsys fs)
{
- int i;
+ unsigned i;
if (!fs->icache)
return 0;
*/
void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
{
- int i;
+ unsigned i;
if (--icache->refcount)
return;
errcode_t ext2fs_create_inode_cache(ext2_filsys fs, unsigned int cache_size)
{
- int i;
+ unsigned i;
errcode_t retval;
if (fs->icache)
*/
if (fs->badblocks == 0) {
/*
- * Temporarly save fs->get_blocks and set it to zero,
+ * Temporarily save fs->get_blocks and set it to zero,
* for compatibility with old e2fsck's.
*/
save_get_blocks = fs->get_blocks;
scan->bytes_left = 0;
scan->current_group = 0;
scan->groups_left = fs->group_desc_count - 1;
- scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
+ scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks :
+ EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS;
scan->current_block = ext2fs_inode_table_loc(scan->fs,
scan->current_group);
+ if (scan->current_block &&
+ ((scan->current_block < fs->super->s_first_data_block) ||
+ (scan->current_block + fs->inode_blocks_per_group - 1 >=
+ ext2fs_blocks_count(fs->super)))) {
+ ext2fs_free_mem(&scan);
+ return EXT2_ET_GDESC_BAD_INODE_TABLE;
+ }
+
scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
scan->blocks_left = scan->fs->inode_blocks_per_group;
if (ext2fs_has_group_desc_csum(fs)) {
- scan->inodes_left -=
- ext2fs_bg_itable_unused(fs, scan->current_group);
+ __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
+ if (scan->inodes_left > unused)
+ scan->inodes_left -= unused;
+ else
+ scan->inodes_left = 0;
scan->blocks_left =
(scan->inodes_left +
(fs->blocksize / scan->inode_size - 1)) *
scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
scan->blocks_left = fs->inode_blocks_per_group;
if (ext2fs_has_group_desc_csum(fs)) {
- scan->inodes_left -=
- ext2fs_bg_itable_unused(fs, scan->current_group);
+ __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
+ if (scan->inodes_left > unused)
+ scan->inodes_left -= unused;
+ else
+ scan->inodes_left = 0;
scan->blocks_left =
(scan->inodes_left +
(fs->blocksize / scan->inode_size - 1)) *
scan->inode_size / fs->blocksize;
}
-
+ if (scan->current_block &&
+ ((scan->current_block < fs->super->s_first_data_block) ||
+ (scan->current_block + fs->inode_blocks_per_group - 1 >=
+ ext2fs_blocks_count(fs->super))))
+ return EXT2_ET_GDESC_BAD_INODE_TABLE;
return 0;
}
{
scan->current_group = group - 1;
scan->groups_left = scan->fs->group_desc_count - group;
+ scan->bad_block_ptr = 0;
return get_next_blockgroup(scan);
}
if (blk == 0)
return 0;
+ /* Make sure bad_block_ptr is still valid */
+ if (scan->bad_block_ptr >= bb->num) {
+ scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
+ return 0;
+ }
+
/*
* If the current block is greater than the bad block listed
* in the bad block list, then advance the pointer until this
ext2_ino_t ino, inodes_to_scan;
unsigned int badness, checksum_failures;
unsigned int inodes_in_buf, inodes_per_block;
- void *p;
+ char *p;
struct ext2_inode_large *inode;
char *block_status;
- unsigned int blk;
+ unsigned int blk, bad_csum;
if (!(scan->scan_flags & EXT2_SF_WARN_GARBAGE_INODES))
return;
if (inodes_to_scan > inodes_in_buf)
inodes_to_scan = inodes_in_buf;
- p = scan->inode_buffer;
+ p = (char *) scan->inode_buffer;
ino = scan->current_inode + 1;
checksum_failures = badness = 0;
block_status = SCAN_BLOCK_STATUS(scan);
memset(block_status, 0, scan->inode_buffer_blocks);
inodes_per_block = EXT2_INODES_PER_BLOCK(scan->fs->super);
+ if (inodes_per_block < 2)
+ return;
+
+#ifdef WORDS_BIGENDIAN
+ if (ext2fs_get_mem(EXT2_INODE_SIZE(scan->fs->super), &inode))
+ return;
+#endif
+
while (inodes_to_scan > 0) {
- blk = (p - (void *)scan->inode_buffer) / scan->fs->blocksize;
- inode = p;
+ blk = (p - (char *)scan->inode_buffer) / scan->fs->blocksize;
+ bad_csum = ext2fs_inode_csum_verify(scan->fs, ino,
+ (struct ext2_inode_large *) p) == 0;
+
+#ifdef WORDS_BIGENDIAN
+ ext2fs_swap_inode_full(scan->fs,
+ (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) p,
+ 0, EXT2_INODE_SIZE(scan->fs->super));
+#else
+ inode = (struct ext2_inode_large *) p;
+#endif
/* Is this inode insane? */
- if (!ext2fs_inode_csum_verify(scan->fs, ino, inode)) {
+ if (bad_csum) {
checksum_failures++;
badness++;
} else if (extent_head_looks_insane(inode) ||
p += scan->inode_size;
ino++;
};
+
+#ifdef WORDS_BIGENDIAN
+ ext2fs_free_mem(&inode);
+#endif
}
/*
* need to read in more blocks.
*/
if (scan->bytes_left < scan->inode_size) {
- memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
+ if (scan->bytes_left)
+ memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
extra_bytes = scan->bytes_left;
retval = get_next_blocks(scan);
/*
* Functions to read and write a single inode.
*/
-errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
- struct ext2_inode * inode, int bufsize)
+errcode_t ext2fs_read_inode2(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize,
+ int flags)
{
blk64_t block_nr;
- unsigned long group, block, offset;
+ dgrp_t group;
+ unsigned long block, offset;
char *ptr;
errcode_t retval;
- int clen, i, inodes_per_block;
+ unsigned i;
+ int clen, inodes_per_block;
io_channel io;
int length = EXT2_INODE_SIZE(fs->super);
struct ext2_inode_large *iptr;
- int cache_slot;
+ int cache_slot, fail_csum;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
}
if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
- block_nr = fs->image_header->offset_inode / fs->blocksize;
+ block_nr = ext2fs_le32_to_cpu(fs->image_header->offset_inode) / fs->blocksize;
block_nr += (ino - 1) / inodes_per_block;
offset = ((ino - 1) % inodes_per_block) *
EXT2_INODE_SIZE(fs->super);
offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
EXT2_INODE_SIZE(fs->super);
block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
- if (!ext2fs_inode_table_loc(fs, (unsigned) group))
+ block_nr = ext2fs_inode_table_loc(fs, group);
+ if (!block_nr)
return EXT2_ET_MISSING_INODE_TABLE;
- block_nr = ext2fs_inode_table_loc(fs, group) +
- block;
+ if ((block_nr < fs->super->s_first_data_block) ||
+ (block_nr + fs->inode_blocks_per_group - 1 >=
+ ext2fs_blocks_count(fs->super)))
+ return EXT2_ET_GDESC_BAD_INODE_TABLE;
+ block_nr += block;
io = fs->io;
}
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
length = EXT2_INODE_SIZE(fs->super);
/* Verify the inode checksum. */
- if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
- !ext2fs_inode_csum_verify(fs, ino, iptr))
- return EXT2_ET_INODE_CSUM_INVALID;
+ fail_csum = !ext2fs_inode_csum_verify(fs, ino, iptr);
#ifdef WORDS_BIGENDIAN
ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) iptr,
#endif
/* Update the inode cache bookkeeping */
- fs->icache->cache_last = cache_slot;
- fs->icache->cache[cache_slot].ino = ino;
+ if (!fail_csum) {
+ fs->icache->cache_last = cache_slot;
+ fs->icache->cache[cache_slot].ino = ino;
+ }
memcpy(inode, iptr, (bufsize > length) ? length : bufsize);
+ if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+ !(flags & READ_INODE_NOCSUM) && fail_csum)
+ return EXT2_ET_INODE_CSUM_INVALID;
+
return 0;
}
+errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize)
+{
+ return ext2fs_read_inode2(fs, ino, inode, bufsize, 0);
+}
+
errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode * inode)
{
- return ext2fs_read_inode_full(fs, ino, inode,
- sizeof(struct ext2_inode));
+ return ext2fs_read_inode2(fs, ino, inode,
+ sizeof(struct ext2_inode), 0);
}
-errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
- struct ext2_inode * inode, int bufsize)
+errcode_t ext2fs_write_inode2(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize,
+ int flags)
{
blk64_t block_nr;
- unsigned long group, block, offset;
+ dgrp_t group;
+ unsigned long block, offset;
errcode_t retval = 0;
struct ext2_inode_large *w_inode;
char *ptr;
- int clen, i;
+ unsigned i;
+ int clen;
int length = EXT2_INODE_SIZE(fs->super);
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
return retval;
if (bufsize < length) {
- int old_flags = fs->flags;
- fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
- retval = ext2fs_read_inode_full(fs, ino,
- (struct ext2_inode *)w_inode,
- length);
- fs->flags = old_flags;
+ retval = ext2fs_read_inode2(fs, ino,
+ (struct ext2_inode *)w_inode,
+ length, READ_INODE_NOCSUM);
if (retval)
goto errout;
}
ext2fs_swap_inode_full(fs, w_inode, w_inode, 1, length);
#endif
- retval = ext2fs_inode_csum_set(fs, ino, w_inode);
- if (retval)
- goto errout;
+ if ((flags & WRITE_INODE_NOCSUM) == 0) {
+ retval = ext2fs_inode_csum_set(fs, ino, w_inode);
+ if (retval)
+ goto errout;
+ }
group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
EXT2_INODE_SIZE(fs->super);
block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
- if (!ext2fs_inode_table_loc(fs, (unsigned) group)) {
+ block_nr = ext2fs_inode_table_loc(fs, (unsigned) group);
+ if (!block_nr) {
retval = EXT2_ET_MISSING_INODE_TABLE;
goto errout;
}
- block_nr = ext2fs_inode_table_loc(fs, (unsigned) group) + block;
+ if ((block_nr < fs->super->s_first_data_block) ||
+ (block_nr + fs->inode_blocks_per_group - 1 >=
+ ext2fs_blocks_count(fs->super))) {
+ retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
+ goto errout;
+ }
+ block_nr += block;
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
return retval;
}
+errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize)
+{
+ return ext2fs_write_inode2(fs, ino, inode, bufsize, 0);
+}
+
errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode)
{
- return ext2fs_write_inode_full(fs, ino, inode,
- sizeof(struct ext2_inode));
+ return ext2fs_write_inode2(fs, ino, inode,
+ sizeof(struct ext2_inode), 0);
}
/*