blob: 03357b10e64203ea5f2f4007e1ba5f235a12f1be [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#if EXT2_FLAT_INCLUDES
19#include "ext2_fs.h"
20#else
Theodore Ts'o3839e651997-04-26 13:21:57 +000021#include <linux/ext2_fs.h>
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000022#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000023
24#include "ext2fs.h"
25
26struct block_context {
27 ext2_filsys fs;
28 int (*func)(ext2_filsys fs,
29 blk_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +000030 e2_blkcnt_t bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000031 blk_t ref_blk,
32 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000033 void *priv_data);
Theodore Ts'o03673db1998-06-10 20:39:43 +000034 e2_blkcnt_t bcount;
Theodore Ts'o3839e651997-04-26 13:21:57 +000035 int bsize;
36 int flags;
37 errcode_t errcode;
38 char *ind_buf;
39 char *dind_buf;
40 char *tind_buf;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000041 void *priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +000042};
43
Theodore Ts'o21c84b71997-04-29 16:15:03 +000044static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
45 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000046{
47 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000048 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +000049 blk_t *block_nr;
50
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000051 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000052 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
53 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
54 ret = (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000055 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000056 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000057 if (!*ind_block || (ret & BLOCK_ABORT)) {
58 ctx->bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +000059 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000060 }
Theodore Ts'of3db3561997-04-26 13:34:30 +000061 if (*ind_block >= ctx->fs->super->s_blocks_count ||
62 *ind_block < ctx->fs->super->s_first_data_block) {
63 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
64 ret |= BLOCK_ERROR;
65 return ret;
66 }
Theodore Ts'o3839e651997-04-26 13:21:57 +000067 ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block,
68 1, ctx->ind_buf);
69 if (ctx->errcode) {
70 ret |= BLOCK_ERROR;
71 return ret;
72 }
Theodore Ts'o06af47f2000-04-03 13:51:00 +000073 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
74 EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +000075 block_nr = (blk_t *) ctx->ind_buf;
76 for (i = 0; i < limit; i++, block_nr++)
77 *block_nr = ext2fs_swab32(*block_nr);
78 }
79 block_nr = (blk_t *) ctx->ind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000080 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000081 if (ctx->flags & BLOCK_FLAG_APPEND) {
82 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
Theodore Ts'o3839e651997-04-26 13:21:57 +000083 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000084 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000085 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000086 changed |= flags;
87 if (flags & BLOCK_ABORT) {
88 ret |= BLOCK_ABORT;
89 break;
90 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +000091 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000092 }
93 } else {
94 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
95 if (*block_nr == 0)
96 continue;
97 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000098 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000099 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000100 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000101 if (flags & BLOCK_ABORT) {
102 ret |= BLOCK_ABORT;
103 break;
104 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000105 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000106 }
107 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000108 if (changed & BLOCK_CHANGED) {
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000109 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
110 EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000111 block_nr = (blk_t *) ctx->ind_buf;
112 for (i = 0; i < limit; i++, block_nr++)
113 *block_nr = ext2fs_swab32(*block_nr);
114 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000115 ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block,
116 1, ctx->ind_buf);
117 if (ctx->errcode)
118 ret |= BLOCK_ERROR | BLOCK_ABORT;
119 }
120 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000121 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000122 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000123 ret |= (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000124 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000125 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000126 return ret;
127}
128
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000129static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
130 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000131{
132 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000133 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000134 blk_t *block_nr;
135
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000136 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000137 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
138 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000139 ret = (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000140 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000141 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000142 if (!*dind_block || (ret & BLOCK_ABORT)) {
143 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000144 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000145 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000146 if (*dind_block >= ctx->fs->super->s_blocks_count ||
147 *dind_block < ctx->fs->super->s_first_data_block) {
148 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
149 ret |= BLOCK_ERROR;
150 return ret;
151 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000152 ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block,
153 1, ctx->dind_buf);
154 if (ctx->errcode) {
155 ret |= BLOCK_ERROR;
156 return ret;
157 }
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000158 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
159 EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000160 block_nr = (blk_t *) ctx->dind_buf;
161 for (i = 0; i < limit; i++, block_nr++)
162 *block_nr = ext2fs_swab32(*block_nr);
163 }
164 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000165 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000166 if (ctx->flags & BLOCK_FLAG_APPEND) {
167 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000168 flags = block_iterate_ind(block_nr,
169 *dind_block, offset,
170 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000171 changed |= flags;
172 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
173 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
174 break;
175 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000176 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000177 }
178 } else {
179 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000180 if (*block_nr == 0) {
181 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000182 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000183 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000184 flags = block_iterate_ind(block_nr,
185 *dind_block, offset,
186 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000187 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000188 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
189 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
190 break;
191 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000192 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000193 }
194 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000195 if (changed & BLOCK_CHANGED) {
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000196 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
197 EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000198 block_nr = (blk_t *) ctx->dind_buf;
199 for (i = 0; i < limit; i++, block_nr++)
200 *block_nr = ext2fs_swab32(*block_nr);
201 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000202 ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block,
203 1, ctx->dind_buf);
204 if (ctx->errcode)
205 ret |= BLOCK_ERROR | BLOCK_ABORT;
206 }
207 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000208 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000209 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000210 ret |= (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000211 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000212 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000213 return ret;
214}
215
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000216static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
217 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000218{
219 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000220 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000221 blk_t *block_nr;
222
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000223 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000224 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
225 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000226 ret = (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000227 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000228 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000229 if (!*tind_block || (ret & BLOCK_ABORT)) {
230 ctx->bcount += limit*limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000231 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000232 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000233 if (*tind_block >= ctx->fs->super->s_blocks_count ||
234 *tind_block < ctx->fs->super->s_first_data_block) {
235 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
236 ret |= BLOCK_ERROR;
237 return ret;
238 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000239 ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block,
240 1, ctx->tind_buf);
241 if (ctx->errcode) {
242 ret |= BLOCK_ERROR;
243 return ret;
244 }
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000245 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
246 EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000247 block_nr = (blk_t *) ctx->tind_buf;
248 for (i = 0; i < limit; i++, block_nr++)
249 *block_nr = ext2fs_swab32(*block_nr);
250 }
251 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000252 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000253 if (ctx->flags & BLOCK_FLAG_APPEND) {
254 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000255 flags = block_iterate_dind(block_nr,
256 *tind_block,
257 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000258 changed |= flags;
259 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
260 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
261 break;
262 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000263 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000264 }
265 } else {
266 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000267 if (*block_nr == 0) {
268 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000269 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000270 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000271 flags = block_iterate_dind(block_nr,
272 *tind_block,
273 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000274 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000275 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
276 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
277 break;
278 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000279 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000280 }
281 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000282 if (changed & BLOCK_CHANGED) {
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000283 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
284 EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000285 block_nr = (blk_t *) ctx->tind_buf;
286 for (i = 0; i < limit; i++, block_nr++)
287 *block_nr = ext2fs_swab32(*block_nr);
288 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000289 ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block,
290 1, ctx->tind_buf);
291 if (ctx->errcode)
292 ret |= BLOCK_ERROR | BLOCK_ABORT;
293 }
294 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000295 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000296 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000297 ret |= (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000298 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000299 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000300
301 return ret;
302}
303
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000304errcode_t ext2fs_block_iterate2(ext2_filsys fs,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000305 ino_t ino,
306 int flags,
307 char *block_buf,
308 int (*func)(ext2_filsys fs,
309 blk_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +0000310 e2_blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000311 blk_t ref_blk,
312 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000313 void *priv_data),
314 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000315{
316 int i;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000317 int got_inode = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000318 int ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000319 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
320 struct ext2_inode inode;
321 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000322 struct block_context ctx;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000323 int limit;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000324
Theodore Ts'of3db3561997-04-26 13:34:30 +0000325 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
326
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000327 /*
328 * Check to see if we need to limit large files
329 */
330 if (flags & BLOCK_FLAG_NO_LARGE) {
331 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
332 if (ctx.errcode)
Theodore Ts'o2eb374c1998-09-03 01:22:57 +0000333 return ctx.errcode;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000334 got_inode = 1;
335 if (!LINUX_S_ISDIR(inode.i_mode) &&
336 (inode.i_size_high != 0))
337 return EXT2_ET_FILE_TOO_BIG;
338 }
339
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +0000340 retval = ext2fs_get_blocks(fs, ino, blocks);
341 if (retval)
342 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000343
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000344 limit = fs->blocksize >> 2;
345
Theodore Ts'o3839e651997-04-26 13:21:57 +0000346 ctx.fs = fs;
347 ctx.func = func;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000348 ctx.priv_data = priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000349 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000350 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000351 if (block_buf) {
352 ctx.ind_buf = block_buf;
353 } else {
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000354 retval = ext2fs_get_mem(fs->blocksize * 3,
355 (void **) &ctx.ind_buf);
356 if (retval)
357 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000358 }
359 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
360 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000361
362 /*
363 * Iterate over the HURD translator block (if present)
364 */
365 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000366 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000367 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
368 if (ctx.errcode)
369 goto abort;
370 got_inode = 1;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000371 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000372 ret |= (*ctx.func)(fs,
373 &inode.osd1.hurd1.h_i_translator,
374 BLOCK_COUNT_TRANSLATOR,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000375 0, 0, priv_data);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000376 if (ret & BLOCK_ABORT)
377 goto abort;
378 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000379 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000380
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000381 /*
382 * Iterate over normal data blocks
383 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000384 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
385 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000386 ret |= (*ctx.func)(fs, &blocks[i],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000387 ctx.bcount, 0, i, priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000388 if (ret & BLOCK_ABORT)
389 goto abort;
390 }
391 }
392 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000393 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000394 0, EXT2_IND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000395 if (ret & BLOCK_ABORT)
396 goto abort;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000397 } else
398 ctx.bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000399 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000400 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000401 0, EXT2_DIND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000402 if (ret & BLOCK_ABORT)
403 goto abort;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000404 } else
405 ctx.bcount += limit * limit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000406 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000407 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000408 0, EXT2_TIND_BLOCK, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000409 if (ret & BLOCK_ABORT)
410 goto abort;
411 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000412
413abort:
414 if (ret & BLOCK_CHANGED) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000415 if (!got_inode) {
416 retval = ext2fs_read_inode(fs, ino, &inode);
417 if (retval)
418 return retval;
419 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000420 for (i=0; i < EXT2_N_BLOCKS; i++)
421 inode.i_block[i] = blocks[i];
422 retval = ext2fs_write_inode(fs, ino, &inode);
423 if (retval)
424 return retval;
425 }
426
427 if (!block_buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000428 ext2fs_free_mem((void **) &ctx.ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000429
430 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
431}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000432
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000433/*
434 * Emulate the old ext2fs_block_iterate function!
435 */
436
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000437struct xlate {
438 int (*func)(ext2_filsys fs,
439 blk_t *blocknr,
440 int bcount,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000441 void *priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000442 void *real_private;
443};
444
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000445#ifdef __TURBOC__
446#pragma argsused
447#endif
Theodore Ts'o03673db1998-06-10 20:39:43 +0000448static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000449 blk_t ref_block, int ref_offset, void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000450{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000451 struct xlate *xl = (struct xlate *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000452
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000453 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000454}
455
456errcode_t ext2fs_block_iterate(ext2_filsys fs,
457 ino_t ino,
458 int flags,
459 char *block_buf,
460 int (*func)(ext2_filsys fs,
461 blk_t *blocknr,
462 int blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000463 void *priv_data),
464 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000465{
466 struct xlate xl;
467
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000468 xl.real_private = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000469 xl.func = func;
470
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000471 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000472 block_buf, xlate_func, &xl);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000473}
474