blob: 07a64157e6f407b80543922d3ef1612a56474338 [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>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000014#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000015#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000016#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000017
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000018#include "ext2_fs.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000019#include "ext2fs.h"
20
21struct block_context {
22 ext2_filsys fs;
23 int (*func)(ext2_filsys fs,
24 blk_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +000025 e2_blkcnt_t bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000026 blk_t ref_blk,
27 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000028 void *priv_data);
Theodore Ts'o03673db1998-06-10 20:39:43 +000029 e2_blkcnt_t bcount;
Theodore Ts'o3839e651997-04-26 13:21:57 +000030 int bsize;
31 int flags;
32 errcode_t errcode;
33 char *ind_buf;
34 char *dind_buf;
35 char *tind_buf;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000036 void *priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +000037};
38
Theodore Ts'o21c84b71997-04-29 16:15:03 +000039static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
40 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000041{
42 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000043 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +000044 blk_t *block_nr;
45
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000046 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000047 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
48 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
49 ret = (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000050 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000051 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000052 if (!*ind_block || (ret & BLOCK_ABORT)) {
53 ctx->bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +000054 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000055 }
Theodore Ts'of3db3561997-04-26 13:34:30 +000056 if (*ind_block >= ctx->fs->super->s_blocks_count ||
57 *ind_block < ctx->fs->super->s_first_data_block) {
58 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
59 ret |= BLOCK_ERROR;
60 return ret;
61 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -050062 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
63 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +000064 if (ctx->errcode) {
65 ret |= BLOCK_ERROR;
66 return ret;
67 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -050068
Theodore Ts'o50e1e101997-04-26 13:58:21 +000069 block_nr = (blk_t *) ctx->ind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000070 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000071 if (ctx->flags & BLOCK_FLAG_APPEND) {
72 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
Theodore Ts'o3839e651997-04-26 13:21:57 +000073 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000074 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000075 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000076 changed |= flags;
77 if (flags & BLOCK_ABORT) {
78 ret |= BLOCK_ABORT;
79 break;
80 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +000081 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000082 }
83 } else {
84 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
85 if (*block_nr == 0)
86 continue;
87 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000088 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000089 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000090 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +000091 if (flags & BLOCK_ABORT) {
92 ret |= BLOCK_ABORT;
93 break;
94 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +000095 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +000096 }
97 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -050098 if (changed & BLOCK_CHANGED) {
99 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
100 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000101 if (ctx->errcode)
102 ret |= BLOCK_ERROR | BLOCK_ABORT;
103 }
104 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000105 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000106 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000107 ret |= (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000108 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000109 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000110 return ret;
111}
112
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000113static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
114 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000115{
116 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000117 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000118 blk_t *block_nr;
119
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000120 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000121 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
122 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000123 ret = (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000124 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000125 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000126 if (!*dind_block || (ret & BLOCK_ABORT)) {
127 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000128 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000129 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000130 if (*dind_block >= ctx->fs->super->s_blocks_count ||
131 *dind_block < ctx->fs->super->s_first_data_block) {
132 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
133 ret |= BLOCK_ERROR;
134 return ret;
135 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500136 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
137 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000138 if (ctx->errcode) {
139 ret |= BLOCK_ERROR;
140 return ret;
141 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500142
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000143 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000144 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000145 if (ctx->flags & BLOCK_FLAG_APPEND) {
146 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000147 flags = block_iterate_ind(block_nr,
148 *dind_block, offset,
149 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000150 changed |= flags;
151 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
152 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
153 break;
154 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000155 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000156 }
157 } else {
158 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000159 if (*block_nr == 0) {
160 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000161 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000162 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000163 flags = block_iterate_ind(block_nr,
164 *dind_block, offset,
165 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000166 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000167 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
168 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
169 break;
170 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000171 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000172 }
173 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500174 if (changed & BLOCK_CHANGED) {
175 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
176 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000177 if (ctx->errcode)
178 ret |= BLOCK_ERROR | BLOCK_ABORT;
179 }
180 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000181 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000182 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000183 ret |= (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000184 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000185 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000186 return ret;
187}
188
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000189static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
190 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000191{
192 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000193 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000194 blk_t *block_nr;
195
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000196 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000197 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
198 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000199 ret = (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000200 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000201 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000202 if (!*tind_block || (ret & BLOCK_ABORT)) {
203 ctx->bcount += limit*limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000204 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000205 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000206 if (*tind_block >= ctx->fs->super->s_blocks_count ||
207 *tind_block < ctx->fs->super->s_first_data_block) {
208 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
209 ret |= BLOCK_ERROR;
210 return ret;
211 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500212 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
213 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000214 if (ctx->errcode) {
215 ret |= BLOCK_ERROR;
216 return ret;
217 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500218
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000219 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000220 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000221 if (ctx->flags & BLOCK_FLAG_APPEND) {
222 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000223 flags = block_iterate_dind(block_nr,
224 *tind_block,
225 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000226 changed |= flags;
227 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
228 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
229 break;
230 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000231 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000232 }
233 } else {
234 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000235 if (*block_nr == 0) {
236 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000237 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000238 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000239 flags = block_iterate_dind(block_nr,
240 *tind_block,
241 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000242 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000243 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
244 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
245 break;
246 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000247 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000248 }
249 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500250 if (changed & BLOCK_CHANGED) {
251 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
252 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000253 if (ctx->errcode)
254 ret |= BLOCK_ERROR | BLOCK_ABORT;
255 }
256 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000257 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000258 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000259 ret |= (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000260 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000261 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000262
263 return ret;
264}
265
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000266errcode_t ext2fs_block_iterate2(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000267 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000268 int flags,
269 char *block_buf,
270 int (*func)(ext2_filsys fs,
271 blk_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +0000272 e2_blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000273 blk_t ref_blk,
274 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000275 void *priv_data),
276 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000277{
278 int i;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000279 int got_inode = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000280 int ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000281 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
282 struct ext2_inode inode;
283 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000284 struct block_context ctx;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000285 int limit;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000286
Theodore Ts'of3db3561997-04-26 13:34:30 +0000287 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
288
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000289 /*
290 * Check to see if we need to limit large files
291 */
292 if (flags & BLOCK_FLAG_NO_LARGE) {
293 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
294 if (ctx.errcode)
Theodore Ts'o2eb374c1998-09-03 01:22:57 +0000295 return ctx.errcode;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000296 got_inode = 1;
297 if (!LINUX_S_ISDIR(inode.i_mode) &&
298 (inode.i_size_high != 0))
299 return EXT2_ET_FILE_TOO_BIG;
300 }
301
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +0000302 retval = ext2fs_get_blocks(fs, ino, blocks);
303 if (retval)
304 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000305
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000306 limit = fs->blocksize >> 2;
307
Theodore Ts'o3839e651997-04-26 13:21:57 +0000308 ctx.fs = fs;
309 ctx.func = func;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000310 ctx.priv_data = priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000311 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000312 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000313 if (block_buf) {
314 ctx.ind_buf = block_buf;
315 } else {
Theodore Ts'oee010792007-11-09 19:01:06 -0500316 retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000317 if (retval)
318 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000319 }
320 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
321 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000322
323 /*
324 * Iterate over the HURD translator block (if present)
325 */
326 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000327 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000328 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
329 if (ctx.errcode)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000330 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000331 got_inode = 1;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000332 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000333 ret |= (*ctx.func)(fs,
334 &inode.osd1.hurd1.h_i_translator,
335 BLOCK_COUNT_TRANSLATOR,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000336 0, 0, priv_data);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000337 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000338 goto abort_exit;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000339 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000340 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000341
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000342 /*
343 * Iterate over normal data blocks
344 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000345 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
346 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000347 ret |= (*ctx.func)(fs, &blocks[i],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000348 ctx.bcount, 0, i, priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000349 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000350 goto abort_exit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000351 }
352 }
353 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000354 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000355 0, EXT2_IND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000356 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000357 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000358 } else
359 ctx.bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000360 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000361 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000362 0, EXT2_DIND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000363 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000364 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000365 } else
366 ctx.bcount += limit * limit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000367 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000368 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000369 0, EXT2_TIND_BLOCK, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000370 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000371 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000372 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000373
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000374abort_exit:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000375 if (ret & BLOCK_CHANGED) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000376 if (!got_inode) {
377 retval = ext2fs_read_inode(fs, ino, &inode);
378 if (retval)
379 return retval;
380 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000381 for (i=0; i < EXT2_N_BLOCKS; i++)
382 inode.i_block[i] = blocks[i];
383 retval = ext2fs_write_inode(fs, ino, &inode);
384 if (retval)
385 return retval;
386 }
387
388 if (!block_buf)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400389 ext2fs_free_mem(&ctx.ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000390
391 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
392}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000393
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000394/*
395 * Emulate the old ext2fs_block_iterate function!
396 */
397
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000398struct xlate {
399 int (*func)(ext2_filsys fs,
400 blk_t *blocknr,
401 int bcount,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000402 void *priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000403 void *real_private;
404};
405
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000406#ifdef __TURBOC__
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000407 #pragma argsused
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000408#endif
Theodore Ts'o03673db1998-06-10 20:39:43 +0000409static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
Theodore Ts'o54434922003-12-07 01:28:50 -0500410 blk_t ref_block EXT2FS_ATTR((unused)),
411 int ref_offset EXT2FS_ATTR((unused)),
412 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000413{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000414 struct xlate *xl = (struct xlate *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000415
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000416 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000417}
418
419errcode_t ext2fs_block_iterate(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000420 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000421 int flags,
422 char *block_buf,
423 int (*func)(ext2_filsys fs,
424 blk_t *blocknr,
425 int blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000426 void *priv_data),
427 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000428{
429 struct xlate xl;
430
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000431 xl.real_private = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000432 xl.func = func;
433
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000434 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000435 block_buf, xlate_func, &xl);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000436}
437