]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - lib/ext2fs/block.c
Merge remote-tracking branch 'josch/libarchive' into josch-libarchive
[thirdparty/e2fsprogs.git] / lib / ext2fs / block.c
CommitLineData
3839e657
TT
1/*
2 * block.c --- iterate over all blocks in an inode
efc6f628 3 *
21c84b71
TT
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
543547a5
TT
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
21c84b71 9 * %End-Header%
3839e657
TT
10 */
11
d1154eb4 12#include "config.h"
3839e657
TT
13#include <stdio.h>
14#include <string.h>
4cbe8af4 15#if HAVE_UNISTD_H
3839e657 16#include <unistd.h>
4cbe8af4 17#endif
f3db3566 18
b5abe6fa 19#include "ext2_fs.h"
3839e657
TT
20#include "ext2fs.h"
21
22struct block_context {
23 ext2_filsys fs;
24 int (*func)(ext2_filsys fs,
272631e4 25 blk64_t *blocknr,
03673dbb 26 e2_blkcnt_t bcount,
272631e4 27 blk64_t ref_blk,
21c84b71 28 int ref_offset,
b5abe6fa 29 void *priv_data);
03673dbb 30 e2_blkcnt_t bcount;
3839e657
TT
31 int bsize;
32 int flags;
33 errcode_t errcode;
34 char *ind_buf;
35 char *dind_buf;
36 char *tind_buf;
b5abe6fa 37 void *priv_data;
3839e657
TT
38};
39
206fea69 40#define check_for_ro_violation_return(ctx, ret) \
357d1863
TT
41 do { \
42 if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
43 ((ret) & BLOCK_CHANGED)) { \
44 (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
206fea69
TT
45 ret |= BLOCK_ABORT | BLOCK_ERROR; \
46 return ret; \
47 } \
48 } while (0)
49
50#define check_for_ro_violation_goto(ctx, ret, label) \
51 do { \
52 if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
53 ((ret) & BLOCK_CHANGED)) { \
54 (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
55 ret |= BLOCK_ABORT | BLOCK_ERROR; \
56 goto label; \
357d1863
TT
57 } \
58 } while (0)
357d1863 59
21c84b71
TT
60static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
61 int ref_offset, struct block_context *ctx)
3839e657
TT
62{
63 int ret = 0, changed = 0;
21c84b71 64 int i, flags, limit, offset;
3839e657 65 blk_t *block_nr;
272631e4 66 blk64_t blk64;
3839e657 67
a29f4d30 68 limit = ctx->fs->blocksize >> 2;
1e3472c5 69 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
272631e4
TT
70 !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
71 blk64 = *ind_block;
72 ret = (*ctx->func)(ctx->fs, &blk64,
21c84b71 73 BLOCK_COUNT_IND, ref_block,
b5abe6fa 74 ref_offset, ctx->priv_data);
272631e4
TT
75 *ind_block = blk64;
76 }
206fea69 77 check_for_ro_violation_return(ctx, ret);
a29f4d30
TT
78 if (!*ind_block || (ret & BLOCK_ABORT)) {
79 ctx->bcount += limit;
3839e657 80 return ret;
a29f4d30 81 }
4efbac6f 82 if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) ||
f3db3566
TT
83 *ind_block < ctx->fs->super->s_first_data_block) {
84 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
85 ret |= BLOCK_ERROR;
86 return ret;
87 }
efc6f628 88 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
dc8ce346 89 ctx->ind_buf);
3839e657
TT
90 if (ctx->errcode) {
91 ret |= BLOCK_ERROR;
92 return ret;
93 }
dc8ce346 94
50e1e10f 95 block_nr = (blk_t *) ctx->ind_buf;
21c84b71 96 offset = 0;
50e1e10f
TT
97 if (ctx->flags & BLOCK_FLAG_APPEND) {
98 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
272631e4
TT
99 blk64 = *block_nr;
100 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
efc6f628 101 *ind_block, offset,
b5abe6fa 102 ctx->priv_data);
272631e4 103 *block_nr = blk64;
50e1e10f
TT
104 changed |= flags;
105 if (flags & BLOCK_ABORT) {
106 ret |= BLOCK_ABORT;
107 break;
108 }
21c84b71 109 offset += sizeof(blk_t);
50e1e10f
TT
110 }
111 } else {
112 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
113 if (*block_nr == 0)
94ded6c1 114 goto skip_sparse;
272631e4
TT
115 blk64 = *block_nr;
116 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
efc6f628 117 *ind_block, offset,
b5abe6fa 118 ctx->priv_data);
272631e4 119 *block_nr = blk64;
50e1e10f 120 changed |= flags;
3839e657
TT
121 if (flags & BLOCK_ABORT) {
122 ret |= BLOCK_ABORT;
123 break;
124 }
94ded6c1 125 skip_sparse:
21c84b71 126 offset += sizeof(blk_t);
3839e657
TT
127 }
128 }
206fea69 129 check_for_ro_violation_return(ctx, changed);
dc8ce346
TT
130 if (changed & BLOCK_CHANGED) {
131 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
132 ctx->ind_buf);
3839e657
TT
133 if (ctx->errcode)
134 ret |= BLOCK_ERROR | BLOCK_ABORT;
135 }
136 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
1e3472c5 137 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
272631e4
TT
138 !(ret & BLOCK_ABORT)) {
139 blk64 = *ind_block;
140 ret |= (*ctx->func)(ctx->fs, &blk64,
21c84b71 141 BLOCK_COUNT_IND, ref_block,
b5abe6fa 142 ref_offset, ctx->priv_data);
272631e4
TT
143 *ind_block = blk64;
144 }
206fea69 145 check_for_ro_violation_return(ctx, ret);
3839e657
TT
146 return ret;
147}
efc6f628 148
21c84b71
TT
149static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
150 int ref_offset, struct block_context *ctx)
3839e657
TT
151{
152 int ret = 0, changed = 0;
21c84b71 153 int i, flags, limit, offset;
3839e657 154 blk_t *block_nr;
272631e4 155 blk64_t blk64;
3839e657 156
a29f4d30 157 limit = ctx->fs->blocksize >> 2;
06af47f0 158 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
272631e4
TT
159 BLOCK_FLAG_DATA_ONLY))) {
160 blk64 = *dind_block;
161 ret = (*ctx->func)(ctx->fs, &blk64,
21c84b71 162 BLOCK_COUNT_DIND, ref_block,
b5abe6fa 163 ref_offset, ctx->priv_data);
272631e4
TT
164 *dind_block = blk64;
165 }
206fea69 166 check_for_ro_violation_return(ctx, ret);
a29f4d30
TT
167 if (!*dind_block || (ret & BLOCK_ABORT)) {
168 ctx->bcount += limit*limit;
3839e657 169 return ret;
a29f4d30 170 }
4efbac6f 171 if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) ||
f3db3566
TT
172 *dind_block < ctx->fs->super->s_first_data_block) {
173 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
174 ret |= BLOCK_ERROR;
175 return ret;
176 }
efc6f628 177 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
dc8ce346 178 ctx->dind_buf);
3839e657
TT
179 if (ctx->errcode) {
180 ret |= BLOCK_ERROR;
181 return ret;
182 }
dc8ce346 183
50e1e10f 184 block_nr = (blk_t *) ctx->dind_buf;
21c84b71 185 offset = 0;
50e1e10f
TT
186 if (ctx->flags & BLOCK_FLAG_APPEND) {
187 for (i = 0; i < limit; i++, block_nr++) {
21c84b71
TT
188 flags = block_iterate_ind(block_nr,
189 *dind_block, offset,
190 ctx);
50e1e10f
TT
191 changed |= flags;
192 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
193 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
194 break;
195 }
21c84b71 196 offset += sizeof(blk_t);
50e1e10f
TT
197 }
198 } else {
199 for (i = 0; i < limit; i++, block_nr++) {
a29f4d30
TT
200 if (*block_nr == 0) {
201 ctx->bcount += limit;
50e1e10f 202 continue;
a29f4d30 203 }
21c84b71
TT
204 flags = block_iterate_ind(block_nr,
205 *dind_block, offset,
206 ctx);
50e1e10f 207 changed |= flags;
3839e657
TT
208 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
209 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
210 break;
211 }
21c84b71 212 offset += sizeof(blk_t);
3839e657
TT
213 }
214 }
206fea69 215 check_for_ro_violation_return(ctx, changed);
dc8ce346
TT
216 if (changed & BLOCK_CHANGED) {
217 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
218 ctx->dind_buf);
3839e657
TT
219 if (ctx->errcode)
220 ret |= BLOCK_ERROR | BLOCK_ABORT;
221 }
222 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
1e3472c5 223 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
272631e4
TT
224 !(ret & BLOCK_ABORT)) {
225 blk64 = *dind_block;
226 ret |= (*ctx->func)(ctx->fs, &blk64,
21c84b71 227 BLOCK_COUNT_DIND, ref_block,
b5abe6fa 228 ref_offset, ctx->priv_data);
272631e4
TT
229 *dind_block = blk64;
230 }
206fea69 231 check_for_ro_violation_return(ctx, ret);
3839e657
TT
232 return ret;
233}
efc6f628 234
21c84b71
TT
235static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
236 int ref_offset, struct block_context *ctx)
3839e657
TT
237{
238 int ret = 0, changed = 0;
21c84b71 239 int i, flags, limit, offset;
3839e657 240 blk_t *block_nr;
272631e4 241 blk64_t blk64;
3839e657 242
a29f4d30 243 limit = ctx->fs->blocksize >> 2;
06af47f0 244 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
272631e4
TT
245 BLOCK_FLAG_DATA_ONLY))) {
246 blk64 = *tind_block;
247 ret = (*ctx->func)(ctx->fs, &blk64,
21c84b71 248 BLOCK_COUNT_TIND, ref_block,
b5abe6fa 249 ref_offset, ctx->priv_data);
272631e4
TT
250 *tind_block = blk64;
251 }
206fea69 252 check_for_ro_violation_return(ctx, ret);
a29f4d30 253 if (!*tind_block || (ret & BLOCK_ABORT)) {
c8ca2397 254 ctx->bcount += ((unsigned long long) limit)*limit*limit;
3839e657 255 return ret;
a29f4d30 256 }
4efbac6f 257 if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) ||
f3db3566
TT
258 *tind_block < ctx->fs->super->s_first_data_block) {
259 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
260 ret |= BLOCK_ERROR;
261 return ret;
262 }
efc6f628 263 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
dc8ce346 264 ctx->tind_buf);
3839e657
TT
265 if (ctx->errcode) {
266 ret |= BLOCK_ERROR;
267 return ret;
268 }
dc8ce346 269
50e1e10f 270 block_nr = (blk_t *) ctx->tind_buf;
21c84b71 271 offset = 0;
50e1e10f
TT
272 if (ctx->flags & BLOCK_FLAG_APPEND) {
273 for (i = 0; i < limit; i++, block_nr++) {
21c84b71
TT
274 flags = block_iterate_dind(block_nr,
275 *tind_block,
276 offset, ctx);
50e1e10f
TT
277 changed |= flags;
278 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
279 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
280 break;
281 }
21c84b71 282 offset += sizeof(blk_t);
50e1e10f
TT
283 }
284 } else {
285 for (i = 0; i < limit; i++, block_nr++) {
a29f4d30
TT
286 if (*block_nr == 0) {
287 ctx->bcount += limit*limit;
50e1e10f 288 continue;
a29f4d30 289 }
21c84b71
TT
290 flags = block_iterate_dind(block_nr,
291 *tind_block,
292 offset, ctx);
50e1e10f 293 changed |= flags;
3839e657
TT
294 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
295 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
296 break;
297 }
21c84b71 298 offset += sizeof(blk_t);
3839e657
TT
299 }
300 }
206fea69 301 check_for_ro_violation_return(ctx, changed);
dc8ce346
TT
302 if (changed & BLOCK_CHANGED) {
303 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
304 ctx->tind_buf);
3839e657
TT
305 if (ctx->errcode)
306 ret |= BLOCK_ERROR | BLOCK_ABORT;
307 }
308 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
1e3472c5 309 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
272631e4
TT
310 !(ret & BLOCK_ABORT)) {
311 blk64 = *tind_block;
312 ret |= (*ctx->func)(ctx->fs, &blk64,
21c84b71 313 BLOCK_COUNT_TIND, ref_block,
b5abe6fa 314 ref_offset, ctx->priv_data);
272631e4
TT
315 *tind_block = blk64;
316 }
206fea69 317 check_for_ro_violation_return(ctx, ret);
3839e657
TT
318 return ret;
319}
efc6f628 320
272631e4 321errcode_t ext2fs_block_iterate3(ext2_filsys fs,
31dbecd4 322 ext2_ino_t ino,
21c84b71
TT
323 int flags,
324 char *block_buf,
325 int (*func)(ext2_filsys fs,
272631e4 326 blk64_t *blocknr,
03673dbb 327 e2_blkcnt_t blockcnt,
272631e4 328 blk64_t ref_blk,
21c84b71 329 int ref_offset,
b5abe6fa
TT
330 void *priv_data),
331 void *priv_data)
3839e657
TT
332{
333 int i;
d7b92206 334 int r, ret = 0;
3839e657
TT
335 struct ext2_inode inode;
336 errcode_t retval;
21c84b71 337 struct block_context ctx;
674a4ee1 338 int limit;
272631e4 339 blk64_t blk64;
21c84b71 340
f3db3566
TT
341 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
342
206fea69
TT
343 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
344 if (ctx.errcode)
345 return ctx.errcode;
346
a7f4c635
TT
347 /*
348 * An inode with inline data has no blocks over which to
349 * iterate, so return an error code indicating this fact.
350 */
351 if (inode.i_flags & EXT4_INLINE_DATA_FL)
352 return EXT2_ET_INLINE_DATA_CANT_ITERATE;
353
674a4ee1
TT
354 /*
355 * Check to see if we need to limit large files
356 */
357 if (flags & BLOCK_FLAG_NO_LARGE) {
674a4ee1
TT
358 if (!LINUX_S_ISDIR(inode.i_mode) &&
359 (inode.i_size_high != 0))
360 return EXT2_ET_FILE_TOO_BIG;
361 }
362
674a4ee1
TT
363 limit = fs->blocksize >> 2;
364
3839e657
TT
365 ctx.fs = fs;
366 ctx.func = func;
b5abe6fa 367 ctx.priv_data = priv_data;
3839e657 368 ctx.flags = flags;
21c84b71 369 ctx.bcount = 0;
3839e657
TT
370 if (block_buf) {
371 ctx.ind_buf = block_buf;
372 } else {
ee01079a 373 retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
7b4e4534
TT
374 if (retval)
375 return retval;
3839e657
TT
376 }
377 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
378 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
1e3472c5
TT
379
380 /*
381 * Iterate over the HURD translator block (if present)
382 */
383 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
5c576477 384 !(flags & BLOCK_FLAG_DATA_ONLY)) {
5c576477 385 if (inode.osd1.hurd1.h_i_translator) {
272631e4
TT
386 blk64 = inode.osd1.hurd1.h_i_translator;
387 ret |= (*ctx.func)(fs, &blk64,
21c84b71 388 BLOCK_COUNT_TRANSLATOR,
b5abe6fa 389 0, 0, priv_data);
272631e4 390 inode.osd1.hurd1.h_i_translator = (blk_t) blk64;
5c576477 391 if (ret & BLOCK_ABORT)
31dbecd4 392 goto abort_exit;
206fea69 393 check_for_ro_violation_goto(&ctx, ret, abort_exit);
5c576477 394 }
1e3472c5 395 }
efc6f628 396
206fea69
TT
397 if (inode.i_flags & EXT4_EXTENTS_FL) {
398 ext2_extent_handle_t handle;
beb388a4 399 struct ext2fs_extent extent, next;
685d544e 400 e2_blkcnt_t blockcnt = 0;
272631e4 401 blk64_t blk, new_blk;
206fea69 402 int op = EXT2_EXTENT_ROOT;
07f1a070 403 int uninit;
2d328bb7 404 unsigned int j;
206fea69 405
84b239ae 406 ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
206fea69
TT
407 if (ctx.errcode)
408 goto abort_exit;
409
410 while (1) {
beb388a4
TT
411 if (op == EXT2_EXTENT_CURRENT)
412 ctx.errcode = 0;
413 else
414 ctx.errcode = ext2fs_extent_get(handle, op,
415 &extent);
206fea69 416 if (ctx.errcode) {
685d544e
TT
417 if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
418 break;
419 ctx.errcode = 0;
420 if (!(flags & BLOCK_FLAG_APPEND))
421 break;
8e2399d5 422 next_block_set:
685d544e
TT
423 blk = 0;
424 r = (*ctx.func)(fs, &blk, blockcnt,
425 0, 0, priv_data);
426 ret |= r;
427 check_for_ro_violation_goto(&ctx, ret,
a204236e 428 extent_done);
685d544e 429 if (r & BLOCK_CHANGED) {
efc6f628 430 ctx.errcode =
685d544e
TT
431 ext2fs_extent_set_bmap(handle,
432 (blk64_t) blockcnt++,
433 (blk64_t) blk, 0);
434 if (ctx.errcode || (ret & BLOCK_ABORT))
64987c05 435 break;
8e2399d5
TT
436 if (blk)
437 goto next_block_set;
685d544e 438 }
64987c05 439 break;
206fea69
TT
440 }
441
442 op = EXT2_EXTENT_NEXT;
443 blk = extent.e_pblk;
d7b92206
TT
444 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
445 if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
446 continue;
447 if ((!(extent.e_flags &
448 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
449 !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
450 ((extent.e_flags &
451 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
452 (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
453 ret |= (*ctx.func)(fs, &blk,
454 -1, 0, 0, priv_data);
455 if (ret & BLOCK_CHANGED) {
213fe928
TT
456 extent.e_pblk = blk;
457 ctx.errcode =
458 ext2fs_extent_replace(handle, 0, &extent);
459 if (ctx.errcode)
64987c05 460 break;
d7b92206 461 }
a204236e
TT
462 if (ret & BLOCK_ABORT)
463 break;
d7b92206 464 }
206fea69
TT
465 continue;
466 }
07f1a070
TT
467 uninit = 0;
468 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
469 uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
beb388a4
TT
470
471 /*
472 * Get the next extent before we start messing
473 * with the current extent
474 */
475 retval = ext2fs_extent_get(handle, op, &next);
476
d8fae3cf
TT
477#if 0
478 printf("lblk %llu pblk %llu len %d blockcnt %llu\n",
479 extent.e_lblk, extent.e_pblk,
480 extent.e_len, blockcnt);
481#endif
e48bf256 482 if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt)
d8fae3cf 483 continue;
e48bf256 484 if (extent.e_lblk > (blk64_t) blockcnt)
d8fae3cf
TT
485 blockcnt = extent.e_lblk;
486 j = blockcnt - extent.e_lblk;
487 blk += j;
2d328bb7
TT
488 for (blockcnt = extent.e_lblk, j = 0;
489 j < extent.e_len;
490 blk++, blockcnt++, j++) {
d7b92206
TT
491 new_blk = blk;
492 r = (*ctx.func)(fs, &new_blk, blockcnt,
493 0, 0, priv_data);
494 ret |= r;
206fea69 495 check_for_ro_violation_goto(&ctx, ret,
a204236e 496 extent_done);
d7b92206
TT
497 if (r & BLOCK_CHANGED) {
498 ctx.errcode =
499 ext2fs_extent_set_bmap(handle,
500 (blk64_t) blockcnt,
272631e4 501 new_blk, uninit);
d7b92206 502 if (ctx.errcode)
a204236e 503 goto extent_done;
206fea69 504 }
64987c05 505 if (ret & BLOCK_ABORT)
a204236e 506 goto extent_done;
206fea69 507 }
beb388a4
TT
508 if (retval == 0) {
509 extent = next;
510 op = EXT2_EXTENT_CURRENT;
511 }
206fea69
TT
512 }
513
a204236e 514 extent_done:
206fea69 515 ext2fs_extent_free(handle);
a204236e 516 ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */
d7b92206 517 goto errout;
206fea69
TT
518 }
519
1e3472c5
TT
520 /*
521 * Iterate over normal data blocks
522 */
3839e657 523 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
206fea69 524 if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
272631e4
TT
525 blk64 = inode.i_block[i];
526 ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i,
527 priv_data);
528 inode.i_block[i] = (blk_t) blk64;
3839e657 529 if (ret & BLOCK_ABORT)
31dbecd4 530 goto abort_exit;
3839e657
TT
531 }
532 }
206fea69
TT
533 check_for_ro_violation_goto(&ctx, ret, abort_exit);
534 if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
272631e4 535 ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
36a43d67 536 0, EXT2_IND_BLOCK, &ctx);
3839e657 537 if (ret & BLOCK_ABORT)
31dbecd4 538 goto abort_exit;
674a4ee1
TT
539 } else
540 ctx.bcount += limit;
206fea69
TT
541 if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
542 ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
36a43d67 543 0, EXT2_DIND_BLOCK, &ctx);
3839e657 544 if (ret & BLOCK_ABORT)
31dbecd4 545 goto abort_exit;
674a4ee1
TT
546 } else
547 ctx.bcount += limit * limit;
206fea69
TT
548 if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
549 ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
36a43d67 550 0, EXT2_TIND_BLOCK, &ctx);
1e3472c5 551 if (ret & BLOCK_ABORT)
31dbecd4 552 goto abort_exit;
1e3472c5 553 }
3839e657 554
31dbecd4 555abort_exit:
3839e657 556 if (ret & BLOCK_CHANGED) {
3839e657 557 retval = ext2fs_write_inode(fs, ino, &inode);
9922c53a
TT
558 if (retval) {
559 ret |= BLOCK_ERROR;
560 ctx.errcode = retval;
561 }
3839e657 562 }
d7b92206 563errout:
3839e657 564 if (!block_buf)
c4e3d3f3 565 ext2fs_free_mem(&ctx.ind_buf);
3839e657
TT
566
567 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
568}
21c84b71 569
674a4ee1
TT
570/*
571 * Emulate the old ext2fs_block_iterate function!
572 */
573
272631e4
TT
574struct xlate64 {
575 int (*func)(ext2_filsys fs,
576 blk_t *blocknr,
577 e2_blkcnt_t blockcnt,
578 blk_t ref_blk,
579 int ref_offset,
580 void *priv_data);
581 void *real_private;
582};
583
584static int xlate64_func(ext2_filsys fs, blk64_t *blocknr,
585 e2_blkcnt_t blockcnt, blk64_t ref_blk,
586 int ref_offset, void *priv_data)
587{
588 struct xlate64 *xl = (struct xlate64 *) priv_data;
589 int ret;
590 blk_t block32 = *blocknr;
591
592 ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset,
593 xl->real_private);
594 *blocknr = block32;
595 return ret;
596}
597
598errcode_t ext2fs_block_iterate2(ext2_filsys fs,
599 ext2_ino_t ino,
600 int flags,
601 char *block_buf,
602 int (*func)(ext2_filsys fs,
603 blk_t *blocknr,
604 e2_blkcnt_t blockcnt,
605 blk_t ref_blk,
606 int ref_offset,
607 void *priv_data),
608 void *priv_data)
609{
610 struct xlate64 xl;
611
612 xl.real_private = priv_data;
613 xl.func = func;
614
615 return ext2fs_block_iterate3(fs, ino, flags, block_buf,
616 xlate64_func, &xl);
617}
618
619
21c84b71
TT
620struct xlate {
621 int (*func)(ext2_filsys fs,
622 blk_t *blocknr,
623 int bcount,
b5abe6fa 624 void *priv_data);
21c84b71
TT
625 void *real_private;
626};
627
3cb6c502 628#ifdef __TURBOC__
31dbecd4 629 #pragma argsused
3cb6c502 630#endif
03673dbb 631static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
54434927
TT
632 blk_t ref_block EXT2FS_ATTR((unused)),
633 int ref_offset EXT2FS_ATTR((unused)),
634 void *priv_data)
21c84b71 635{
b5abe6fa 636 struct xlate *xl = (struct xlate *) priv_data;
21c84b71 637
674a4ee1 638 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
21c84b71
TT
639}
640
641errcode_t ext2fs_block_iterate(ext2_filsys fs,
31dbecd4 642 ext2_ino_t ino,
21c84b71
TT
643 int flags,
644 char *block_buf,
645 int (*func)(ext2_filsys fs,
646 blk_t *blocknr,
647 int blockcnt,
b5abe6fa
TT
648 void *priv_data),
649 void *priv_data)
21c84b71
TT
650{
651 struct xlate xl;
efc6f628 652
b5abe6fa 653 xl.real_private = priv_data;
21c84b71
TT
654 xl.func = func;
655
36a43d67 656 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
674a4ee1
TT
657 block_buf, xlate_func, &xl);
658}
659