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