1 /*
2 * block.c --- iterate over all blocks in an inode
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
9 * %End-Header%
10 */
11
12 #include "config.h"
13 #include <stdio.h>
14 #include <string.h>
15 #if HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18
19 #include "ext2_fs.h"
20 #include "ext2fs.h"
21
22 struct block_context {
23 ext2_filsys fs;
24 int (*func)(ext2_filsys fs,
25 blk64_t *blocknr,
26 e2_blkcnt_t bcount,
27 blk64_t ref_blk,
28 int ref_offset,
29 void *priv_data);
30 e2_blkcnt_t bcount;
31 int bsize;
32 int flags;
33 errcode_t errcode;
34 char *ind_buf;
35 char *dind_buf;
36 char *tind_buf;
37 void *priv_data;
38 };
39
40 #define check_for_ro_violation_return(ctx, ret) \
41 do { \
42 if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
43 ((ret) & BLOCK_CHANGED)) { \
44 (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
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; \
57 } \
58 } while (0)
59
block_iterate_ind(blk_t * ind_block,blk_t ref_block,int ref_offset,struct block_context * ctx)60 static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
61 int ref_offset, struct block_context *ctx)
62 {
63 int ret = 0, changed = 0;
64 int i, flags, limit, offset;
65 blk_t *block_nr;
66 blk64_t blk64;
67
68 limit = ctx->fs->blocksize >> 2;
69 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
70 !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
71 blk64 = *ind_block;
72 ret = (*ctx->func)(ctx->fs, &blk64,
73 BLOCK_COUNT_IND, ref_block,
74 ref_offset, ctx->priv_data);
75 *ind_block = blk64;
76 }
77 check_for_ro_violation_return(ctx, ret);
78 if (!*ind_block || (ret & BLOCK_ABORT)) {
79 ctx->bcount += limit;
80 return ret;
81 }
82 if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) ||
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 }
88 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
89 ctx->ind_buf);
90 if (ctx->errcode) {
91 ret |= BLOCK_ERROR;
92 return ret;
93 }
94
95 block_nr = (blk_t *) ctx->ind_buf;
96 offset = 0;
97 if (ctx->flags & BLOCK_FLAG_APPEND) {
98 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
99 blk64 = *block_nr;
100 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
101 *ind_block, offset,
102 ctx->priv_data);
103 *block_nr = blk64;
104 changed |= flags;
105 if (flags & BLOCK_ABORT) {
106 ret |= BLOCK_ABORT;
107 break;
108 }
109 offset += sizeof(blk_t);
110 }
111 } else {
112 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
113 if (*block_nr == 0)
114 goto skip_sparse;
115 blk64 = *block_nr;
116 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
117 *ind_block, offset,
118 ctx->priv_data);
119 *block_nr = blk64;
120 changed |= flags;
121 if (flags & BLOCK_ABORT) {
122 ret |= BLOCK_ABORT;
123 break;
124 }
125 skip_sparse:
126 offset += sizeof(blk_t);
127 }
128 }
129 check_for_ro_violation_return(ctx, changed);
130 if (changed & BLOCK_CHANGED) {
131 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
132 ctx->ind_buf);
133 if (ctx->errcode)
134 ret |= BLOCK_ERROR | BLOCK_ABORT;
135 }
136 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
137 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
138 !(ret & BLOCK_ABORT)) {
139 blk64 = *ind_block;
140 ret |= (*ctx->func)(ctx->fs, &blk64,
141 BLOCK_COUNT_IND, ref_block,
142 ref_offset, ctx->priv_data);
143 *ind_block = blk64;
144 }
145 check_for_ro_violation_return(ctx, ret);
146 return ret;
147 }
148
block_iterate_dind(blk_t * dind_block,blk_t ref_block,int ref_offset,struct block_context * ctx)149 static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
150 int ref_offset, struct block_context *ctx)
151 {
152 int ret = 0, changed = 0;
153 int i, flags, limit, offset;
154 blk_t *block_nr;
155 blk64_t blk64;
156
157 limit = ctx->fs->blocksize >> 2;
158 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
159 BLOCK_FLAG_DATA_ONLY))) {
160 blk64 = *dind_block;
161 ret = (*ctx->func)(ctx->fs, &blk64,
162 BLOCK_COUNT_DIND, ref_block,
163 ref_offset, ctx->priv_data);
164 *dind_block = blk64;
165 }
166 check_for_ro_violation_return(ctx, ret);
167 if (!*dind_block || (ret & BLOCK_ABORT)) {
168 ctx->bcount += limit*limit;
169 return ret;
170 }
171 if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) ||
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 }
177 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
178 ctx->dind_buf);
179 if (ctx->errcode) {
180 ret |= BLOCK_ERROR;
181 return ret;
182 }
183
184 block_nr = (blk_t *) ctx->dind_buf;
185 offset = 0;
186 if (ctx->flags & BLOCK_FLAG_APPEND) {
187 for (i = 0; i < limit; i++, block_nr++) {
188 flags = block_iterate_ind(block_nr,
189 *dind_block, offset,
190 ctx);
191 changed |= flags;
192 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
193 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
194 break;
195 }
196 offset += sizeof(blk_t);
197 }
198 } else {
199 for (i = 0; i < limit; i++, block_nr++) {
200 if (*block_nr == 0) {
201 ctx->bcount += limit;
202 continue;
203 }
204 flags = block_iterate_ind(block_nr,
205 *dind_block, offset,
206 ctx);
207 changed |= flags;
208 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
209 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
210 break;
211 }
212 offset += sizeof(blk_t);
213 }
214 }
215 check_for_ro_violation_return(ctx, changed);
216 if (changed & BLOCK_CHANGED) {
217 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
218 ctx->dind_buf);
219 if (ctx->errcode)
220 ret |= BLOCK_ERROR | BLOCK_ABORT;
221 }
222 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
223 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
224 !(ret & BLOCK_ABORT)) {
225 blk64 = *dind_block;
226 ret |= (*ctx->func)(ctx->fs, &blk64,
227 BLOCK_COUNT_DIND, ref_block,
228 ref_offset, ctx->priv_data);
229 *dind_block = blk64;
230 }
231 check_for_ro_violation_return(ctx, ret);
232 return ret;
233 }
234
block_iterate_tind(blk_t * tind_block,blk_t ref_block,int ref_offset,struct block_context * ctx)235 static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
236 int ref_offset, struct block_context *ctx)
237 {
238 int ret = 0, changed = 0;
239 int i, flags, limit, offset;
240 blk_t *block_nr;
241 blk64_t blk64;
242
243 limit = ctx->fs->blocksize >> 2;
244 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
245 BLOCK_FLAG_DATA_ONLY))) {
246 blk64 = *tind_block;
247 ret = (*ctx->func)(ctx->fs, &blk64,
248 BLOCK_COUNT_TIND, ref_block,
249 ref_offset, ctx->priv_data);
250 *tind_block = blk64;
251 }
252 check_for_ro_violation_return(ctx, ret);
253 if (!*tind_block || (ret & BLOCK_ABORT)) {
254 ctx->bcount += ((unsigned long long) limit)*limit*limit;
255 return ret;
256 }
257 if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) ||
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 }
263 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
264 ctx->tind_buf);
265 if (ctx->errcode) {
266 ret |= BLOCK_ERROR;
267 return ret;
268 }
269
270 block_nr = (blk_t *) ctx->tind_buf;
271 offset = 0;
272 if (ctx->flags & BLOCK_FLAG_APPEND) {
273 for (i = 0; i < limit; i++, block_nr++) {
274 flags = block_iterate_dind(block_nr,
275 *tind_block,
276 offset, ctx);
277 changed |= flags;
278 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
279 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
280 break;
281 }
282 offset += sizeof(blk_t);
283 }
284 } else {
285 for (i = 0; i < limit; i++, block_nr++) {
286 if (*block_nr == 0) {
287 ctx->bcount += limit*limit;
288 continue;
289 }
290 flags = block_iterate_dind(block_nr,
291 *tind_block,
292 offset, ctx);
293 changed |= flags;
294 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
295 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
296 break;
297 }
298 offset += sizeof(blk_t);
299 }
300 }
301 check_for_ro_violation_return(ctx, changed);
302 if (changed & BLOCK_CHANGED) {
303 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
304 ctx->tind_buf);
305 if (ctx->errcode)
306 ret |= BLOCK_ERROR | BLOCK_ABORT;
307 }
308 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
309 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
310 !(ret & BLOCK_ABORT)) {
311 blk64 = *tind_block;
312 ret |= (*ctx->func)(ctx->fs, &blk64,
313 BLOCK_COUNT_TIND, ref_block,
314 ref_offset, ctx->priv_data);
315 *tind_block = blk64;
316 }
317 check_for_ro_violation_return(ctx, ret);
318 return ret;
319 }
320
ext2fs_block_iterate3(ext2_filsys fs,ext2_ino_t ino,int flags,char * block_buf,int (* func)(ext2_filsys fs,blk64_t * blocknr,e2_blkcnt_t blockcnt,blk64_t ref_blk,int ref_offset,void * priv_data),void * priv_data)321 errcode_t ext2fs_block_iterate3(ext2_filsys fs,
322 ext2_ino_t ino,
323 int flags,
324 char *block_buf,
325 int (*func)(ext2_filsys fs,
326 blk64_t *blocknr,
327 e2_blkcnt_t blockcnt,
328 blk64_t ref_blk,
329 int ref_offset,
330 void *priv_data),
331 void *priv_data)
332 {
333 int i;
334 int r, ret = 0;
335 struct ext2_inode inode;
336 errcode_t retval;
337 struct block_context ctx;
338 int limit;
339 blk64_t blk64;
340
341 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
342
343 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
344 if (ctx.errcode)
345 return ctx.errcode;
346
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
354 /*
355 * Check to see if we need to limit large files
356 */
357 if (flags & BLOCK_FLAG_NO_LARGE) {
358 if (!LINUX_S_ISDIR(inode.i_mode) &&
359 (inode.i_size_high != 0))
360 return EXT2_ET_FILE_TOO_BIG;
361 }
362
363 limit = fs->blocksize >> 2;
364
365 ctx.fs = fs;
366 ctx.func = func;
367 ctx.priv_data = priv_data;
368 ctx.flags = flags;
369 ctx.bcount = 0;
370 if (block_buf) {
371 ctx.ind_buf = block_buf;
372 } else {
373 retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
374 if (retval)
375 return retval;
376 }
377 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
378 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
379
380 /*
381 * Iterate over the HURD translator block (if present)
382 */
383 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
384 !(flags & BLOCK_FLAG_DATA_ONLY)) {
385 if (inode.osd1.hurd1.h_i_translator) {
386 blk64 = inode.osd1.hurd1.h_i_translator;
387 ret |= (*ctx.func)(fs, &blk64,
388 BLOCK_COUNT_TRANSLATOR,
389 0, 0, priv_data);
390 inode.osd1.hurd1.h_i_translator = (blk_t) blk64;
391 if (ret & BLOCK_ABORT)
392 goto abort_exit;
393 check_for_ro_violation_goto(&ctx, ret, abort_exit);
394 }
395 }
396
397 if (inode.i_flags & EXT4_EXTENTS_FL) {
398 ext2_extent_handle_t handle;
399 struct ext2fs_extent extent, next;
400 e2_blkcnt_t blockcnt = 0;
401 blk64_t blk, new_blk;
402 int op = EXT2_EXTENT_ROOT;
403 int uninit;
404 unsigned int j;
405
406 ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
407 if (ctx.errcode)
408 goto abort_exit;
409
410 while (1) {
411 if (op == EXT2_EXTENT_CURRENT)
412 ctx.errcode = 0;
413 else
414 ctx.errcode = ext2fs_extent_get(handle, op,
415 &extent);
416 if (ctx.errcode) {
417 if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
418 break;
419 ctx.errcode = 0;
420 if (!(flags & BLOCK_FLAG_APPEND))
421 break;
422 next_block_set:
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,
428 extent_done);
429 if (r & BLOCK_CHANGED) {
430 ctx.errcode =
431 ext2fs_extent_set_bmap(handle,
432 (blk64_t) blockcnt++,
433 (blk64_t) blk, 0);
434 if (ctx.errcode || (ret & BLOCK_ABORT))
435 break;
436 if (blk)
437 goto next_block_set;
438 }
439 break;
440 }
441
442 op = EXT2_EXTENT_NEXT;
443 blk = extent.e_pblk;
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) {
456 extent.e_pblk = blk;
457 ctx.errcode =
458 ext2fs_extent_replace(handle, 0, &extent);
459 if (ctx.errcode)
460 break;
461 }
462 if (ret & BLOCK_ABORT)
463 break;
464 }
465 continue;
466 }
467 uninit = 0;
468 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
469 uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
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
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
482 if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt)
483 continue;
484 if (extent.e_lblk > (blk64_t) blockcnt)
485 blockcnt = extent.e_lblk;
486 j = blockcnt - extent.e_lblk;
487 blk += j;
488 for (blockcnt = extent.e_lblk, j = 0;
489 j < extent.e_len;
490 blk++, blockcnt++, j++) {
491 new_blk = blk;
492 r = (*ctx.func)(fs, &new_blk, blockcnt,
493 0, 0, priv_data);
494 ret |= r;
495 check_for_ro_violation_goto(&ctx, ret,
496 extent_done);
497 if (r & BLOCK_CHANGED) {
498 ctx.errcode =
499 ext2fs_extent_set_bmap(handle,
500 (blk64_t) blockcnt,
501 new_blk, uninit);
502 if (ctx.errcode)
503 goto extent_done;
504 }
505 if (ret & BLOCK_ABORT)
506 goto extent_done;
507 }
508 if (retval == 0) {
509 extent = next;
510 op = EXT2_EXTENT_CURRENT;
511 }
512 }
513
514 extent_done:
515 ext2fs_extent_free(handle);
516 ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */
517 goto errout;
518 }
519
520 /*
521 * Iterate over normal data blocks
522 */
523 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
524 if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
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;
529 if (ret & BLOCK_ABORT)
530 goto abort_exit;
531 }
532 }
533 check_for_ro_violation_goto(&ctx, ret, abort_exit);
534 if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
535 ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
536 0, EXT2_IND_BLOCK, &ctx);
537 if (ret & BLOCK_ABORT)
538 goto abort_exit;
539 } else
540 ctx.bcount += limit;
541 if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
542 ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
543 0, EXT2_DIND_BLOCK, &ctx);
544 if (ret & BLOCK_ABORT)
545 goto abort_exit;
546 } else
547 ctx.bcount += limit * limit;
548 if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
549 ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
550 0, EXT2_TIND_BLOCK, &ctx);
551 if (ret & BLOCK_ABORT)
552 goto abort_exit;
553 }
554
555 abort_exit:
556 if (ret & BLOCK_CHANGED) {
557 retval = ext2fs_write_inode(fs, ino, &inode);
558 if (retval) {
559 ret |= BLOCK_ERROR;
560 ctx.errcode = retval;
561 }
562 }
563 errout:
564 if (!block_buf)
565 ext2fs_free_mem(&ctx.ind_buf);
566
567 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
568 }
569
570 /*
571 * Emulate the old ext2fs_block_iterate function!
572 */
573
574 struct 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
xlate64_func(ext2_filsys fs,blk64_t * blocknr,e2_blkcnt_t blockcnt,blk64_t ref_blk,int ref_offset,void * priv_data)584 static 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
ext2fs_block_iterate2(ext2_filsys fs,ext2_ino_t ino,int flags,char * block_buf,int (* func)(ext2_filsys fs,blk_t * blocknr,e2_blkcnt_t blockcnt,blk_t ref_blk,int ref_offset,void * priv_data),void * priv_data)598 errcode_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
620 struct xlate {
621 int (*func)(ext2_filsys fs,
622 blk_t *blocknr,
623 int bcount,
624 void *priv_data);
625 void *real_private;
626 };
627
628 #ifdef __TURBOC__
629 #pragma argsused
630 #endif
xlate_func(ext2_filsys fs,blk_t * blocknr,e2_blkcnt_t blockcnt,blk_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data)631 static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
632 blk_t ref_block EXT2FS_ATTR((unused)),
633 int ref_offset EXT2FS_ATTR((unused)),
634 void *priv_data)
635 {
636 struct xlate *xl = (struct xlate *) priv_data;
637
638 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
639 }
640
ext2fs_block_iterate(ext2_filsys fs,ext2_ino_t ino,int flags,char * block_buf,int (* func)(ext2_filsys fs,blk_t * blocknr,int blockcnt,void * priv_data),void * priv_data)641 errcode_t ext2fs_block_iterate(ext2_filsys fs,
642 ext2_ino_t ino,
643 int flags,
644 char *block_buf,
645 int (*func)(ext2_filsys fs,
646 blk_t *blocknr,
647 int blockcnt,
648 void *priv_data),
649 void *priv_data)
650 {
651 struct xlate xl;
652
653 xl.real_private = priv_data;
654 xl.func = func;
655
656 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
657 block_buf, xlate_func, &xl);
658 }
659
660