+
+ if (inode.i_flags & EXT4_EXTENTS_FL) {
+ ext2_extent_handle_t handle;
+ struct ext2fs_extent extent, next;
+ e2_blkcnt_t blockcnt = 0;
+ blk64_t blk, new_blk;
+ int op = EXT2_EXTENT_ROOT;
+ int uninit;
+ unsigned int j;
+
+ ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
+ if (ctx.errcode)
+ goto abort_exit;
+
+ while (1) {
+ if (op == EXT2_EXTENT_CURRENT)
+ ctx.errcode = 0;
+ else
+ ctx.errcode = ext2fs_extent_get(handle, op,
+ &extent);
+ if (ctx.errcode) {
+ if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
+ break;
+ ctx.errcode = 0;
+ if (!(flags & BLOCK_FLAG_APPEND))
+ break;
+ next_block_set:
+ blk = 0;
+ r = (*ctx.func)(fs, &blk, blockcnt,
+ 0, 0, priv_data);
+ ret |= r;
+ check_for_ro_violation_goto(&ctx, ret,
+ extent_done);
+ if (r & BLOCK_CHANGED) {
+ ctx.errcode =
+ ext2fs_extent_set_bmap(handle,
+ (blk64_t) blockcnt++,
+ (blk64_t) blk, 0);
+ if (ctx.errcode || (ret & BLOCK_ABORT))
+ break;
+ if (blk)
+ goto next_block_set;
+ }
+ break;
+ }
+
+ op = EXT2_EXTENT_NEXT;
+ blk = extent.e_pblk;
+ if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
+ if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
+ continue;
+ if ((!(extent.e_flags &
+ EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
+ !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
+ ((extent.e_flags &
+ EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
+ (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
+ ret |= (*ctx.func)(fs, &blk,
+ -1, 0, 0, priv_data);
+ if (ret & BLOCK_CHANGED) {
+ extent.e_pblk = blk;
+ ctx.errcode =
+ ext2fs_extent_replace(handle, 0, &extent);
+ if (ctx.errcode)
+ break;
+ }
+ if (ret & BLOCK_ABORT)
+ break;
+ }
+ continue;
+ }
+ uninit = 0;
+ if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
+ uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
+
+ /*
+ * Get the next extent before we start messing
+ * with the current extent
+ */
+ retval = ext2fs_extent_get(handle, op, &next);
+
+#if 0
+ printf("lblk %llu pblk %llu len %d blockcnt %llu\n",
+ extent.e_lblk, extent.e_pblk,
+ extent.e_len, blockcnt);
+#endif
+ if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt)
+ continue;
+ if (extent.e_lblk > (blk64_t) blockcnt)
+ blockcnt = extent.e_lblk;
+ j = blockcnt - extent.e_lblk;
+ blk += j;
+ for (blockcnt = extent.e_lblk, j = 0;
+ j < extent.e_len;
+ blk++, blockcnt++, j++) {
+ new_blk = blk;
+ r = (*ctx.func)(fs, &new_blk, blockcnt,
+ 0, 0, priv_data);
+ ret |= r;
+ check_for_ro_violation_goto(&ctx, ret,
+ extent_done);
+ if (r & BLOCK_CHANGED) {
+ ctx.errcode =
+ ext2fs_extent_set_bmap(handle,
+ (blk64_t) blockcnt,
+ new_blk, uninit);
+ if (ctx.errcode)
+ goto extent_done;
+ }
+ if (ret & BLOCK_ABORT)
+ goto extent_done;
+ }
+ if (retval == 0) {
+ extent = next;
+ op = EXT2_EXTENT_CURRENT;
+ }
+ }
+
+ extent_done:
+ ext2fs_extent_free(handle);
+ ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */
+ goto errout;
+ }
+