• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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