blob: 03bf5f3609f7584977c709ebf8a220c6811911ca [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * block.c --- iterate over all blocks in an inode
3 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * 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 Public
8 * License.
9 * %End-Header%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 */
11
12#include <stdio.h>
13#include <string.h>
14#include <unistd.h>
15#include <stdlib.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000016#if HAVE_ERRNO_H
17#include <errno.h>
18#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000019
Theodore Ts'o3839e651997-04-26 13:21:57 +000020#include <linux/ext2_fs.h>
21
22#include "ext2fs.h"
23
24struct block_context {
25 ext2_filsys fs;
26 int (*func)(ext2_filsys fs,
27 blk_t *blocknr,
28 int bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000029 blk_t ref_blk,
30 int ref_offset,
Theodore Ts'o3839e651997-04-26 13:21:57 +000031 void *private);
32 int bcount;
33 int bsize;
34 int flags;
35 errcode_t errcode;
36 char *ind_buf;
37 char *dind_buf;
38 char *tind_buf;
39 void *private;
40};
41
Theodore Ts'o21c84b71997-04-29 16:15:03 +000042static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
43 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000044{
45 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000046 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +000047 blk_t *block_nr;
48
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000049 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000050 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
51 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
52 ret = (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000053 BLOCK_COUNT_IND, ref_block,
54 ref_offset, ctx->private);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000055 if (!*ind_block || (ret & BLOCK_ABORT)) {
56 ctx->bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +000057 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000058 }
Theodore Ts'of3db3561997-04-26 13:34:30 +000059 if (*ind_block >= ctx->fs->super->s_blocks_count ||
60 *ind_block < ctx->fs->super->s_first_data_block) {
61 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
62 ret |= BLOCK_ERROR;
63 return ret;
64 }
Theodore Ts'o3839e651997-04-26 13:21:57 +000065 ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block,
66 1, ctx->ind_buf);
67 if (ctx->errcode) {
68 ret |= BLOCK_ERROR;
69 return ret;
70 }
Theodore Ts'o5c576471997-04-29 15:29:49 +000071 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
72 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +000073 block_nr = (blk_t *) ctx->ind_buf;
74 for (i = 0; i < limit; i++, block_nr++)
75 *block_nr = ext2fs_swab32(*block_nr);
76 }
77 block_nr = (blk_t *) ctx->ind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000078 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000079 if (ctx->flags & BLOCK_FLAG_APPEND) {
80 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
Theodore Ts'o3839e651997-04-26 13:21:57 +000081 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000082 *ind_block, offset,
Theodore Ts'o3839e651997-04-26 13:21:57 +000083 ctx->private);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000084 changed |= flags;
85 if (flags & BLOCK_ABORT) {
86 ret |= BLOCK_ABORT;
87 break;
88 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +000089 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000090 }
91 } else {
92 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
93 if (*block_nr == 0)
94 continue;
95 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000096 *ind_block, offset,
Theodore Ts'o50e1e101997-04-26 13:58:21 +000097 ctx->private);
98 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +000099 if (flags & BLOCK_ABORT) {
100 ret |= BLOCK_ABORT;
101 break;
102 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000103 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000104 }
105 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000106 if (changed & BLOCK_CHANGED) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000107 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
108 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000109 block_nr = (blk_t *) ctx->ind_buf;
110 for (i = 0; i < limit; i++, block_nr++)
111 *block_nr = ext2fs_swab32(*block_nr);
112 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000113 ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block,
114 1, ctx->ind_buf);
115 if (ctx->errcode)
116 ret |= BLOCK_ERROR | BLOCK_ABORT;
117 }
118 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000119 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000120 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000121 ret |= (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000122 BLOCK_COUNT_IND, ref_block,
123 ref_offset, ctx->private);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000124 return ret;
125}
126
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000127static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
128 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000129{
130 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000131 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000132 blk_t *block_nr;
133
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000134 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000135 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
136 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
137 ret = (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000138 BLOCK_COUNT_DIND, ref_block,
139 ref_offset, ctx->private);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000140 if (!*dind_block || (ret & BLOCK_ABORT)) {
141 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000142 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000143 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000144 if (*dind_block >= ctx->fs->super->s_blocks_count ||
145 *dind_block < ctx->fs->super->s_first_data_block) {
146 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
147 ret |= BLOCK_ERROR;
148 return ret;
149 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000150 ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block,
151 1, ctx->dind_buf);
152 if (ctx->errcode) {
153 ret |= BLOCK_ERROR;
154 return ret;
155 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000156 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
157 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000158 block_nr = (blk_t *) ctx->dind_buf;
159 for (i = 0; i < limit; i++, block_nr++)
160 *block_nr = ext2fs_swab32(*block_nr);
161 }
162 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000163 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000164 if (ctx->flags & BLOCK_FLAG_APPEND) {
165 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000166 flags = block_iterate_ind(block_nr,
167 *dind_block, offset,
168 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000169 changed |= flags;
170 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
171 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
172 break;
173 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000174 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000175 }
176 } else {
177 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000178 if (*block_nr == 0) {
179 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000180 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000181 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000182 flags = block_iterate_ind(block_nr,
183 *dind_block, offset,
184 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000185 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000186 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
187 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
188 break;
189 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000190 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000191 }
192 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000193 if (changed & BLOCK_CHANGED) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000194 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
195 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000196 block_nr = (blk_t *) ctx->dind_buf;
197 for (i = 0; i < limit; i++, block_nr++)
198 *block_nr = ext2fs_swab32(*block_nr);
199 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000200 ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block,
201 1, ctx->dind_buf);
202 if (ctx->errcode)
203 ret |= BLOCK_ERROR | BLOCK_ABORT;
204 }
205 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000206 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000207 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000208 ret |= (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000209 BLOCK_COUNT_DIND, ref_block,
210 ref_offset, ctx->private);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000211 return ret;
212}
213
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000214static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
215 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000216{
217 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000218 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000219 blk_t *block_nr;
220
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000221 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000222 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
223 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
224 ret = (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000225 BLOCK_COUNT_TIND, ref_block,
226 ref_offset, ctx->private);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000227 if (!*tind_block || (ret & BLOCK_ABORT)) {
228 ctx->bcount += limit*limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000229 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000230 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000231 if (*tind_block >= ctx->fs->super->s_blocks_count ||
232 *tind_block < ctx->fs->super->s_first_data_block) {
233 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
234 ret |= BLOCK_ERROR;
235 return ret;
236 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000237 ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block,
238 1, ctx->tind_buf);
239 if (ctx->errcode) {
240 ret |= BLOCK_ERROR;
241 return ret;
242 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000243 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
244 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000245 block_nr = (blk_t *) ctx->tind_buf;
246 for (i = 0; i < limit; i++, block_nr++)
247 *block_nr = ext2fs_swab32(*block_nr);
248 }
249 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000250 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000251 if (ctx->flags & BLOCK_FLAG_APPEND) {
252 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000253 flags = block_iterate_dind(block_nr,
254 *tind_block,
255 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000256 changed |= flags;
257 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
258 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
259 break;
260 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000261 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000262 }
263 } else {
264 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000265 if (*block_nr == 0) {
266 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000267 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000268 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000269 flags = block_iterate_dind(block_nr,
270 *tind_block,
271 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000272 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000273 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
274 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
275 break;
276 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000277 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000278 }
279 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000280 if (changed & BLOCK_CHANGED) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000281 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
282 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000283 block_nr = (blk_t *) ctx->tind_buf;
284 for (i = 0; i < limit; i++, block_nr++)
285 *block_nr = ext2fs_swab32(*block_nr);
286 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000287 ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block,
288 1, ctx->tind_buf);
289 if (ctx->errcode)
290 ret |= BLOCK_ERROR | BLOCK_ABORT;
291 }
292 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000293 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000294 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000295 ret |= (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000296 BLOCK_COUNT_TIND, ref_block,
297 ref_offset, ctx->private);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000298
299 return ret;
300}
301
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000302errcode_t ext2fs_block_iterate2(ext2_filsys fs,
303 ino_t ino,
304 int flags,
305 char *block_buf,
306 int (*func)(ext2_filsys fs,
307 blk_t *blocknr,
308 int blockcnt,
309 blk_t ref_blk,
310 int ref_offset,
311 void *private),
312 void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000313{
314 int i;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000315 int got_inode = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000316 int ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000317 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
318 struct ext2_inode inode;
319 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000320 struct block_context ctx;
321
Theodore Ts'of3db3561997-04-26 13:34:30 +0000322 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
323
Theodore Ts'o3839e651997-04-26 13:21:57 +0000324 ret = ext2fs_get_blocks(fs, ino, blocks);
325 if (ret)
326 return ret;
327
328 ctx.fs = fs;
329 ctx.func = func;
330 ctx.private = private;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000331 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000332 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000333 if (block_buf) {
334 ctx.ind_buf = block_buf;
335 } else {
336 ctx.ind_buf = malloc(fs->blocksize * 3);
337 if (!ctx.ind_buf)
338 return ENOMEM;
339 }
340 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
341 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000342
343 /*
344 * Iterate over the HURD translator block (if present)
345 */
346 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000347 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000348 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
349 if (ctx.errcode)
350 goto abort;
351 got_inode = 1;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000352 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000353 ret |= (*ctx.func)(fs,
354 &inode.osd1.hurd1.h_i_translator,
355 BLOCK_COUNT_TRANSLATOR,
356 0, 0, private);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000357 if (ret & BLOCK_ABORT)
358 goto abort;
359 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000360 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000361
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000362 /*
363 * Iterate over normal data blocks
364 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000365 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
366 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000367 ret |= (*ctx.func)(fs, &blocks[i],
368 ctx.bcount, 0, 0, private);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000369 if (ret & BLOCK_ABORT)
370 goto abort;
371 }
372 }
373 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000374 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
375 0, 0, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000376 if (ret & BLOCK_ABORT)
377 goto abort;
378 }
379 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000380 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
381 0, 0, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000382 if (ret & BLOCK_ABORT)
383 goto abort;
384 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000385 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000386 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
387 0, 0, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000388 if (ret & BLOCK_ABORT)
389 goto abort;
390 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000391
392abort:
393 if (ret & BLOCK_CHANGED) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000394 if (!got_inode) {
395 retval = ext2fs_read_inode(fs, ino, &inode);
396 if (retval)
397 return retval;
398 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000399 for (i=0; i < EXT2_N_BLOCKS; i++)
400 inode.i_block[i] = blocks[i];
401 retval = ext2fs_write_inode(fs, ino, &inode);
402 if (retval)
403 return retval;
404 }
405
406 if (!block_buf)
407 free(ctx.ind_buf);
408
409 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
410}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000411
412struct xlate {
413 int (*func)(ext2_filsys fs,
414 blk_t *blocknr,
415 int bcount,
416 void *private);
417 void *real_private;
418};
419
420static int xlate_func(ext2_filsys fs, blk_t *blocknr, int blockcnt,
421 blk_t ref_block, int ref_offset, void *private)
422{
423 struct xlate *xl = private;
424
425 return (*xl->func)(fs, blocknr, blockcnt, xl->real_private);
426}
427
428errcode_t ext2fs_block_iterate(ext2_filsys fs,
429 ino_t ino,
430 int flags,
431 char *block_buf,
432 int (*func)(ext2_filsys fs,
433 blk_t *blocknr,
434 int blockcnt,
435 void *private),
436 void *private)
437{
438 struct xlate xl;
439
440 xl.real_private = private;
441 xl.func = func;
442
443 return ext2fs_block_iterate2(fs, ino, flags, block_buf,
444 xlate_func, &xl);
445}
446
447