int type;
int level;
int max_depth;
+ int max_paths;
struct extent_path *path;
};
return;
if (handle->path) {
- for (i=1; i <= handle->max_depth; i++) {
+ for (i = 1; i < handle->max_paths; i++) {
if (handle->path[i].buf)
ext2fs_free_mem(&handle->path[i].buf);
}
handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth);
handle->type = ext2fs_le16_to_cpu(eh->eh_magic);
- retval = ext2fs_get_mem(((handle->max_depth+1) *
- sizeof(struct extent_path)),
- &handle->path);
- memset(handle->path, 0,
- (handle->max_depth+1) * sizeof(struct extent_path));
+ handle->max_paths = handle->max_depth + 1;
+ retval = ext2fs_get_memzero(handle->max_paths *
+ sizeof(struct extent_path),
+ &handle->path);
handle->path[0].buf = (char *) handle->inode->i_block;
handle->path[0].left = handle->path[0].entries =
return retval;
}
+ if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+ !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
+ eh)) {
+ handle->level--;
+ return EXT2_ET_EXTENT_CSUM_INVALID;
+ }
+
newpath->left = newpath->entries =
ext2fs_le16_to_cpu(eh->eh_entries);
newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
blk64_t blk;
errcode_t retval;
struct ext3_extent_idx *ix;
+ struct ext3_extent_header *eh;
if (handle->level == 0) {
retval = ext2fs_write_inode(handle->fs, handle->ino,
blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
+ /* then update the checksum */
+ eh = (struct ext3_extent_header *)
+ handle->path[handle->level].buf;
+ retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino,
+ eh);
+ if (retval)
+ return retval;
+
retval = io_channel_write_blk64(handle->fs->io,
blk, 1, handle->path[handle->level].buf);
}
* and so on.
*
* Safe to call for any position in node; if not at the first entry,
- * will simply return.
+ * it will simply return.
+ *
+ * Note a subtlety of this function -- if there happen to be two extents
+ * mapping the same lblk and someone calls fix_parents on the second of the two
+ * extents, the position of the extent handle after the call will be the second
+ * extent if nothing happened, or the first extent if something did. A caller
+ * in this situation must use ext2fs_extent_goto() after calling this function.
+ * Or simply don't map the same lblk with two extents, ever.
*/
errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
{
if (handle->level == 0) {
new_root = 1;
tocopy = ext2fs_le16_to_cpu(eh->eh_entries);
- retval = ext2fs_get_mem(((handle->max_depth+2) *
- sizeof(struct extent_path)),
- &newpath);
+ retval = ext2fs_get_memzero((handle->max_paths + 1) *
+ sizeof(struct extent_path),
+ &newpath);
if (retval)
goto done;
- memset(newpath, 0,
- ((handle->max_depth+2) * sizeof(struct extent_path)));
} else {
if (no_balance)
tocopy = 1;
new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
+ /* then update the checksum */
+ retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, neweh);
+ if (retval)
+ goto done;
+
/* ...and write the new node block out to disk. */
retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
block_buf);
/* current path now has fewer active entries, we copied some out */
if (handle->level == 0) {
memcpy(newpath, path,
- sizeof(struct extent_path) * (handle->max_depth+1));
+ sizeof(struct extent_path) * handle->max_paths);
handle->path = newpath;
newpath = path;
path = handle->path;
path->entries = 1;
path->left = path->max_entries - 1;
handle->max_depth++;
+ handle->max_paths++;
eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth);
} else {
path->entries -= tocopy;
&next_extent);
if (retval)
goto done;
- retval = ext2fs_extent_fix_parents(handle);
- if (retval)
- goto done;
} else
retval = ext2fs_extent_insert(handle,
EXT2_EXTENT_INSERT_AFTER, &newextent);
if (retval)
goto done;
- /* Now pointing at inserted extent; move back to prev */
+ retval = ext2fs_extent_fix_parents(handle);
+ if (retval)
+ goto done;
+ /*
+ * Now pointing at inserted extent; move back to prev.
+ *
+ * We cannot use EXT2_EXTENT_PREV to go back; note the
+ * subtlety in the comment for fix_parents().
+ */
+ retval = ext2fs_extent_goto(handle, logical);
+ if (retval)
+ goto done;
retval = ext2fs_extent_get(handle,
- EXT2_EXTENT_PREV_LEAF,
+ EXT2_EXTENT_CURRENT,
&extent);
if (retval)
goto done;
0, &newextent);
if (retval)
goto done;
+ retval = ext2fs_extent_fix_parents(handle);
+ if (retval)
+ goto done;
retval = ext2fs_extent_get(handle,
EXT2_EXTENT_NEXT_LEAF,
&extent);
if (retval) {
r2 = ext2fs_extent_goto(handle, orig_lblk);
if (r2 == 0)
- ext2fs_extent_replace(handle, 0,
+ (void)ext2fs_extent_replace(handle, 0,
&orig_extent);
goto done;
}
r2 = ext2fs_extent_goto(handle,
newextent.e_lblk);
if (r2 == 0)
- ext2fs_extent_delete(handle, 0);
+ (void)ext2fs_extent_delete(handle, 0);
}
r2 = ext2fs_extent_goto(handle, orig_lblk);
if (r2 == 0)
- ext2fs_extent_replace(handle, 0, &orig_extent);
+ (void)ext2fs_extent_replace(handle, 0,
+ &orig_extent);
goto done;
}
}