scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
scan->fs = fs;
+ scan->inode_size = EXT2_INODE_SIZE(fs->super);
+ scan->bytes_left = 0;
scan->current_group = -1;
scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
scan->groups_left = fs->group_desc_count;
free(scan);
return ENOMEM;
}
+ scan->temp_buffer = malloc(scan->inode_size);
+ if (!scan->temp_buffer) {
+ free(scan->inode_buffer);
+ free(scan);
+ return ENOMEM;
+ }
*ret_scan = scan;
return 0;
}
free(scan->inode_buffer);
scan->inode_buffer = NULL;
+ free(scan->temp_buffer);
+ scan->temp_buffer = NULL;
free(scan);
return;
}
{
errcode_t retval;
int num_blocks;
+ int extra_bytes = 0;
EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
+ /*
+ * Do we need to start reading a new block group?
+ */
if (scan->inodes_left <= 0) {
- if (scan->blocks_left <= 0) {
- if (scan->done_group) {
- retval = (scan->done_group)
- (scan->fs, scan,
- scan->current_group,
- scan->done_group_data);
- if (retval)
- return retval;
- }
- do {
- if (scan->groups_left <= 0) {
- *ino = 0;
- return 0;
- }
- scan->current_group++;
- scan->groups_left--;
-
- scan->current_block =
- scan->fs->group_desc[scan->current_group].bg_inode_table;
- scan->blocks_left = (EXT2_INODES_PER_GROUP(scan->fs->super) /
- EXT2_INODES_PER_BLOCK(scan->fs->super));
- } while (scan->current_block == 0);
- } else {
- scan->current_block += scan->inode_buffer_blocks;
+ if (scan->done_group) {
+ retval = (scan->done_group)
+ (scan->fs, scan,
+ scan->current_group,
+ scan->done_group_data);
+ if (retval)
+ return retval;
+ }
+ if (scan->groups_left <= 0) {
+ *ino = 0;
+ return 0;
}
+ scan->current_group++;
+ scan->groups_left--;
+
+ scan->current_block = scan->fs->
+ group_desc[scan->current_group].bg_inode_table;
+
+ if (scan->current_block == 0)
+ return EXT2_ET_MISSING_INODE_TABLE;
+ scan->bytes_left = 0;
+ scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
+ scan->blocks_left = scan->fs->inode_blocks_per_group;
+ }
+
+ /*
+ * Have we run out of space in the inode buffer? If so, we
+ * need to read in more blocks.
+ */
+ if (scan->bytes_left < scan->inode_size) {
+ memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
+ extra_bytes = scan->bytes_left;
+
scan->blocks_left -= scan->inode_buffer_blocks;
num_blocks = scan->inode_buffer_blocks;
if (scan->blocks_left < 0)
num_blocks += scan->blocks_left;
- scan->inodes_left = EXT2_INODES_PER_BLOCK(scan->fs->super) *
- num_blocks;
-
retval = io_channel_read_blk(scan->fs->io, scan->current_block,
num_blocks, scan->inode_buffer);
if (retval)
return EXT2_ET_NEXT_INODE_READ;
- scan->inode_scan_ptr = (struct ext2_inode *) scan->inode_buffer;
+ scan->ptr = scan->inode_buffer;
+ scan->bytes_left = num_blocks * scan->fs->blocksize;
+
+ scan->current_block += scan->inode_buffer_blocks;
+ }
+
+ if (extra_bytes) {
+ memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
+ scan->inode_size - extra_bytes);
+ scan->ptr += scan->inode_size - extra_bytes;
+ scan->bytes_left -= scan->inode_size - extra_bytes;
+
+ if (scan->fs->flags & EXT2_SWAP_BYTES)
+ inocpy_with_swap(inode, (struct ext2_inode *)
+ scan->temp_buffer);
+ else
+ *inode = *((struct ext2_inode *) scan->temp_buffer);
+ } else {
+ if (scan->fs->flags & EXT2_SWAP_BYTES)
+ inocpy_with_swap(inode, (struct ext2_inode *)
+ scan->ptr);
+ else
+ *inode = *((struct ext2_inode *) scan->ptr);
+ scan->ptr += scan->inode_size;
+ scan->bytes_left -= scan->inode_size;
}
- if (scan->fs->flags & EXT2_SWAP_BYTES)
- inocpy_with_swap(inode, scan->inode_scan_ptr++);
- else
- *inode = *scan->inode_scan_ptr++;
scan->inodes_left--;
scan->current_inode++;
* Functions to read and write a single inode.
*/
static char *inode_buffer = 0;
-static blk_t inode_buffer_block;
+static blk_t inode_buffer_block = 0;
static int inode_buffer_size = 0;
errcode_t ext2fs_read_inode (ext2_filsys fs, unsigned long ino,
struct ext2_inode * inode)
{
- unsigned long group;
- unsigned long block;
- unsigned long block_nr;
+ unsigned long group, block, block_nr, offset;
+ char *ptr;
errcode_t retval;
- int i;
+ int clen, length;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
}
group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
- block = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) /
- EXT2_INODES_PER_BLOCK(fs->super);
- i = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) %
- EXT2_INODES_PER_BLOCK(fs->super);
+ offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+ EXT2_INODE_SIZE(fs->super);
+ block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
block_nr = fs->group_desc[group].bg_inode_table + block;
if (block_nr != inode_buffer_block) {
retval = io_channel_read_blk(fs->io, block_nr, 1,
return retval;
inode_buffer_block = block_nr;
}
+ offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
+ ptr = ((char *) inode_buffer) + offset;
+
+ memset(inode, 0, sizeof(struct ext2_inode));
+ length = EXT2_INODE_SIZE(fs->super);
+ if (length > sizeof(struct ext2_inode))
+ length = sizeof(struct ext2_inode);
+
+ if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
+ clen = EXT2_BLOCK_SIZE(fs->super) - offset;
+ memcpy((char *) inode, ptr, clen);
+ length -= clen;
+
+ retval = io_channel_read_blk(fs->io, block_nr+1, 1,
+ inode_buffer);
+ if (retval)
+ return retval;
+ inode_buffer_block = block_nr+1;
+
+ memcpy(((char *) inode) + clen,
+ inode_buffer, length);
+ } else
+ memcpy((char *) inode, ptr, length);
+
if (fs->flags & EXT2_SWAP_BYTES)
- inocpy_with_swap(inode,
- (struct ext2_inode *) inode_buffer + i);
- else
- memcpy (inode, (struct ext2_inode *) inode_buffer + i,
- sizeof (struct ext2_inode));
+ inocpy_with_swap(inode, inode);
+
return 0;
}
errcode_t ext2fs_write_inode(ext2_filsys fs, unsigned long ino,
struct ext2_inode * inode)
{
- unsigned long group;
- unsigned long block;
- unsigned long block_nr;
+ unsigned long group, block, block_nr, offset;
errcode_t retval;
- int i;
+ struct ext2_inode temp_inode;
+ char *ptr;
+ int i, clen, length;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
inode_buffer_size = fs->blocksize;
inode_buffer_block = 0;
}
-
+ if (fs->flags & EXT2_SWAP_BYTES)
+ inocpy_with_swap(&temp_inode, inode);
+ else
+ memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
+
group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
- block = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) /
- EXT2_INODES_PER_BLOCK(fs->super);
- i = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) %
- EXT2_INODES_PER_BLOCK(fs->super);
+ offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+ EXT2_INODE_SIZE(fs->super);
+ block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
block_nr = fs->group_desc[group].bg_inode_table + block;
+ offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
+ ptr = (char *) inode_buffer + offset;
+
+ length = EXT2_INODE_SIZE(fs->super);
+ if (length > sizeof(struct ext2_inode))
+ length = sizeof(struct ext2_inode);
+
if (inode_buffer_block != block_nr) {
retval = io_channel_read_blk(fs->io, block_nr, 1,
inode_buffer);
return retval;
inode_buffer_block = block_nr;
}
- if (fs->flags & EXT2_SWAP_BYTES)
- inocpy_with_swap((struct ext2_inode *) inode_buffer + i,
- inode);
- else
- memcpy ((struct ext2_inode *) inode_buffer + i, inode,
- sizeof (struct ext2_inode));
+
+ if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
+ clen = EXT2_BLOCK_SIZE(fs->super) - offset;
+ memcpy(ptr, &temp_inode, clen);
+ length -= clen;
+ } else {
+ memcpy(ptr, &temp_inode, length);
+ length = 0;
+ }
retval = io_channel_write_blk(fs->io, block_nr, 1, inode_buffer);
if (retval)
return retval;
+
+ if (length) {
+ retval = io_channel_read_blk(fs->io, ++block_nr, 1,
+ inode_buffer);
+ if (retval) {
+ inode_buffer_block = 0;
+ return retval;
+ }
+ inode_buffer_block = block_nr;
+ memcpy(inode_buffer, ((char *) &temp_inode) + clen, length);
+
+ retval = io_channel_write_blk(fs->io, block_nr, 1,
+ inode_buffer);
+ if (retval)
+ return retval;
+ }
+
fs->flags |= EXT2_FLAG_CHANGED;
return 0;
}