return 0;
}
+/*
+ * Free the inode cache structure
+ */
+void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
+{
+ int i;
+
+ if (--icache->refcount)
+ return;
+ if (icache->buffer)
+ ext2fs_free_mem(&icache->buffer);
+ for (i = 0; i < icache->cache_size; i++)
+ ext2fs_free_mem(&icache->cache[i].inode);
+ if (icache->cache)
+ ext2fs_free_mem(&icache->cache);
+ icache->buffer_blk = 0;
+ ext2fs_free_mem(&icache);
+}
+
static errcode_t create_icache(ext2_filsys fs)
{
+ int i;
errcode_t retval;
if (fs->icache)
memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
- if (retval) {
- ext2fs_free_mem(&fs->icache);
- return retval;
- }
+ if (retval)
+ goto errout;
+
fs->icache->buffer_blk = 0;
fs->icache->cache_last = -1;
fs->icache->cache_size = 4;
retval = ext2fs_get_array(fs->icache->cache_size,
sizeof(struct ext2_inode_cache_ent),
&fs->icache->cache);
- if (retval) {
- ext2fs_free_mem(&fs->icache->buffer);
- ext2fs_free_mem(&fs->icache);
- return retval;
+ if (retval)
+ goto errout;
+
+ for (i = 0; i < fs->icache->cache_size; i++) {
+ retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super),
+ &fs->icache->cache[i].inode);
+ if (retval)
+ goto errout;
}
+
ext2fs_flush_icache(fs);
return 0;
+errout:
+ ext2fs_free_inode_cache(fs->icache);
+ fs->icache = 0;
+ return retval;
}
errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
scan->current_group);
scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
scan->blocks_left = scan->fs->inode_blocks_per_group;
- if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+ if (ext2fs_has_group_desc_csum(fs)) {
scan->inodes_left -=
ext2fs_bg_itable_unused(fs, scan->current_group);
scan->blocks_left =
}
if (scan->fs->badblocks && scan->fs->badblocks->num)
scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
- if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+ if (ext2fs_has_group_desc_csum(fs))
scan->scan_flags |= EXT2_SF_DO_LAZY;
*ret_scan = scan;
return 0;
scan->bytes_left = 0;
scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
scan->blocks_left = fs->inode_blocks_per_group;
- if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+ if (ext2fs_has_group_desc_csum(fs)) {
scan->inodes_left -=
ext2fs_bg_itable_unused(fs, scan->current_group);
scan->blocks_left =
{
errcode_t retval;
int extra_bytes = 0;
+ const int length = EXT2_INODE_SIZE(scan->fs->super);
+ struct ext2_inode_large *iptr = (struct ext2_inode_large *)inode;
EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
#endif
}
+ if (bufsize < length) {
+ retval = ext2fs_get_mem(length, &iptr);
+ if (retval)
+ return retval;
+ }
+
retval = 0;
if (extra_bytes) {
memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
scan->ptr += scan->inode_size - extra_bytes;
scan->bytes_left -= scan->inode_size - extra_bytes;
+ /* Verify the inode checksum. */
+ if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+ !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1,
+ (struct ext2_inode_large *)scan->temp_buffer))
+ retval = EXT2_ET_INODE_CSUM_INVALID;
+
#ifdef WORDS_BIGENDIAN
- memset(inode, 0, bufsize);
+ memset(iptr, 0, length);
ext2fs_swap_inode_full(scan->fs,
- (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) iptr,
(struct ext2_inode_large *) scan->temp_buffer,
- 0, bufsize);
+ 0, length);
#else
- *inode = *((struct ext2_inode *) scan->temp_buffer);
+ memcpy(iptr, scan->temp_buffer, length);
#endif
if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
} else {
+ /* Verify the inode checksum. */
+ if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+ !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1,
+ (struct ext2_inode_large *)scan->ptr))
+ retval = EXT2_ET_INODE_CSUM_INVALID;
+
#ifdef WORDS_BIGENDIAN
- memset(inode, 0, bufsize);
+ memset(iptr, 0, length);
ext2fs_swap_inode_full(scan->fs,
- (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) iptr,
(struct ext2_inode_large *) scan->ptr,
- 0, bufsize);
+ 0, length);
#else
- memcpy(inode, scan->ptr, bufsize);
+ memcpy(iptr, scan->ptr, length);
#endif
scan->ptr += scan->inode_size;
scan->bytes_left -= scan->inode_size;
scan->inodes_left--;
scan->current_inode++;
*ino = scan->current_inode;
+ if (iptr != (struct ext2_inode_large *)inode) {
+ memcpy(inode, iptr, bufsize);
+ ext2fs_free_mem(&iptr);
+ }
return retval;
}
unsigned long group, block, offset;
char *ptr;
errcode_t retval;
- int clen, i, inodes_per_block, length;
+ int clen, i, inodes_per_block;
io_channel io;
+ int length = EXT2_INODE_SIZE(fs->super);
+ struct ext2_inode_large *iptr;
+ int cache_slot;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
return retval;
}
/* Check to see if it's in the inode cache */
- if (bufsize == sizeof(struct ext2_inode)) {
- /* only old good inode can be retrieved from the cache */
- for (i=0; i < fs->icache->cache_size; i++) {
- if (fs->icache->cache[i].ino == ino) {
- *inode = fs->icache->cache[i].inode;
- return 0;
- }
+ for (i = 0; i < fs->icache->cache_size; i++) {
+ if (fs->icache->cache[i].ino == ino) {
+ memcpy(inode, fs->icache->cache[i].inode,
+ (bufsize > length) ? length : bufsize);
+ return 0;
}
}
if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
}
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
- length = EXT2_INODE_SIZE(fs->super);
- if (bufsize < length)
- length = bufsize;
+ cache_slot = (fs->icache->cache_last + 1) % fs->icache->cache_size;
+ iptr = (struct ext2_inode_large *)fs->icache->cache[cache_slot].inode;
- ptr = (char *) inode;
+ ptr = (char *) iptr;
while (length) {
clen = length;
if ((offset + length) > fs->blocksize)
ptr += clen;
block_nr++;
}
+ 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;
#ifdef WORDS_BIGENDIAN
- ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
- (struct ext2_inode_large *) inode,
- 0, bufsize);
+ ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) iptr,
+ (struct ext2_inode_large *) iptr,
+ 0, length);
#endif
- /* Update the inode cache */
- fs->icache->cache_last = (fs->icache->cache_last + 1) %
- fs->icache->cache_size;
- fs->icache->cache[fs->icache->cache_last].ino = ino;
- fs->icache->cache[fs->icache->cache_last].inode = *inode;
+ /* Update the inode cache bookkeeping */
+ fs->icache->cache_last = cache_slot;
+ fs->icache->cache[cache_slot].ino = ino;
+ memcpy(inode, iptr, (bufsize > length) ? length : bufsize);
return 0;
}
blk64_t block_nr;
unsigned long group, block, offset;
errcode_t retval = 0;
- struct ext2_inode_large temp_inode, *w_inode;
+ struct ext2_inode_large *w_inode;
char *ptr;
- int clen, i, length;
+ int clen, i;
+ int length = EXT2_INODE_SIZE(fs->super);
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
return retval;
}
+ if ((ino == 0) || (ino > fs->super->s_inodes_count))
+ return EXT2_ET_BAD_INODE_NUM;
+
+ /* Prepare our shadow buffer for read/modify/byteswap/write */
+ retval = ext2fs_get_mem(length, &w_inode);
+ if (retval)
+ 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;
+ if (retval)
+ goto errout;
+ }
+
/* Check to see if the inode cache needs to be updated */
if (fs->icache) {
for (i=0; i < fs->icache->cache_size; i++) {
if (fs->icache->cache[i].ino == ino) {
- fs->icache->cache[i].inode = *inode;
+ memcpy(fs->icache->cache[i].inode, inode,
+ (bufsize > length) ? length : bufsize);
break;
}
}
} else {
retval = create_icache(fs);
if (retval)
- return retval;
+ goto errout;
}
+ memcpy(w_inode, inode, (bufsize > length) ? length : bufsize);
- if (!(fs->flags & EXT2_FLAG_RW))
- return EXT2_ET_RO_FILSYS;
-
- if ((ino == 0) || (ino > fs->super->s_inodes_count))
- return EXT2_ET_BAD_INODE_NUM;
-
- length = bufsize;
- if (length < EXT2_INODE_SIZE(fs->super))
- length = EXT2_INODE_SIZE(fs->super);
-
- if (length > (int) sizeof(struct ext2_inode_large)) {
- w_inode = malloc(length);
- if (!w_inode) {
- retval = ENOMEM;
- goto errout;
- }
- } else
- w_inode = &temp_inode;
- memset(w_inode, 0, length);
+ if (!(fs->flags & EXT2_FLAG_RW)) {
+ retval = EXT2_ET_RO_FILSYS;
+ goto errout;
+ }
#ifdef WORDS_BIGENDIAN
- ext2fs_swap_inode_full(fs, w_inode,
- (struct ext2_inode_large *) inode,
- 1, bufsize);
-#else
- memcpy(w_inode, inode, bufsize);
+ 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;
+
group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
EXT2_INODE_SIZE(fs->super);
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
- length = EXT2_INODE_SIZE(fs->super);
- if (length > bufsize)
- length = bufsize;
-
ptr = (char *) w_inode;
while (length) {
fs->flags |= EXT2_FLAG_CHANGED;
errout:
- if (w_inode && w_inode != &temp_inode)
- free(w_inode);
+ ext2fs_free_mem(&w_inode);
return retval;
}