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