blob: f64c0af30576931b089554376d52f8f1b9c3f83f [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'oa78926e2001-05-03 04:02:29 +000062 if (ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) {
63 ctx->errcode = 0;
64 memset(ctx->ind_buf, 0, ctx->fs->blocksize);
65 } else
66 ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block,
67 1, ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +000068 if (ctx->errcode) {
69 ret |= BLOCK_ERROR;
70 return ret;
71 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +000072#ifdef EXT2FS_ENABLE_SWAPFS
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 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +000079#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +000080 block_nr = (blk_t *) ctx->ind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000081 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000082 if (ctx->flags & BLOCK_FLAG_APPEND) {
83 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
Theodore Ts'o3839e651997-04-26 13:21:57 +000084 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000085 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000086 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000087 changed |= flags;
88 if (flags & BLOCK_ABORT) {
89 ret |= BLOCK_ABORT;
90 break;
91 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +000092 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000093 }
94 } else {
95 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
96 if (*block_nr == 0)
97 continue;
98 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000099 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000100 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000101 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000102 if (flags & BLOCK_ABORT) {
103 ret |= BLOCK_ABORT;
104 break;
105 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000106 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000107 }
108 }
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000109 if (!(ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
110 (changed & BLOCK_CHANGED)) {
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000111#ifdef EXT2FS_ENABLE_SWAPFS
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000112 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
113 EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000114 block_nr = (blk_t *) ctx->ind_buf;
115 for (i = 0; i < limit; i++, block_nr++)
116 *block_nr = ext2fs_swab32(*block_nr);
117 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000118#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000119 ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block,
120 1, ctx->ind_buf);
121 if (ctx->errcode)
122 ret |= BLOCK_ERROR | BLOCK_ABORT;
123 }
124 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000125 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000126 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000127 ret |= (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000128 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000129 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000130 return ret;
131}
132
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000133static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
134 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000135{
136 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000137 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000138 blk_t *block_nr;
139
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000140 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000141 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
142 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000143 ret = (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000144 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000145 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000146 if (!*dind_block || (ret & BLOCK_ABORT)) {
147 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000148 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000149 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000150 if (*dind_block >= ctx->fs->super->s_blocks_count ||
151 *dind_block < ctx->fs->super->s_first_data_block) {
152 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
153 ret |= BLOCK_ERROR;
154 return ret;
155 }
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000156 if (ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) {
157 ctx->errcode = 0;
158 memset(ctx->dind_buf, 0, ctx->fs->blocksize);
159 } else
160 ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block,
161 1, ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000162 if (ctx->errcode) {
163 ret |= BLOCK_ERROR;
164 return ret;
165 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000166#ifdef EXT2FS_ENABLE_SWAPFS
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000167 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
168 EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000169 block_nr = (blk_t *) ctx->dind_buf;
170 for (i = 0; i < limit; i++, block_nr++)
171 *block_nr = ext2fs_swab32(*block_nr);
172 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000173#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000174 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000175 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000176 if (ctx->flags & BLOCK_FLAG_APPEND) {
177 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000178 flags = block_iterate_ind(block_nr,
179 *dind_block, offset,
180 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000181 changed |= flags;
182 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
183 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
184 break;
185 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000186 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000187 }
188 } else {
189 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000190 if (*block_nr == 0) {
191 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000192 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000193 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000194 flags = block_iterate_ind(block_nr,
195 *dind_block, offset,
196 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000197 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000198 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
199 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
200 break;
201 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000202 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000203 }
204 }
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000205 if (!(ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
206 (changed & BLOCK_CHANGED)) {
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000207#ifdef EXT2FS_ENABLE_SWAPFS
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000208 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
209 EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000210 block_nr = (blk_t *) ctx->dind_buf;
211 for (i = 0; i < limit; i++, block_nr++)
212 *block_nr = ext2fs_swab32(*block_nr);
213 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000214#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000215 ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block,
216 1, ctx->dind_buf);
217 if (ctx->errcode)
218 ret |= BLOCK_ERROR | BLOCK_ABORT;
219 }
220 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000221 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000222 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000223 ret |= (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000224 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000225 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000226 return ret;
227}
228
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000229static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
230 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000231{
232 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000233 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000234 blk_t *block_nr;
235
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000236 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000237 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
238 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000239 ret = (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000240 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000241 ref_offset, ctx->priv_data);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000242 if (!*tind_block || (ret & BLOCK_ABORT)) {
243 ctx->bcount += limit*limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000244 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000245 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000246 if (*tind_block >= ctx->fs->super->s_blocks_count ||
247 *tind_block < ctx->fs->super->s_first_data_block) {
248 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
249 ret |= BLOCK_ERROR;
250 return ret;
251 }
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000252 if (ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) {
253 ctx->errcode = 0;
254 memset(ctx->tind_buf, 0, ctx->fs->blocksize);
255 } else
256 ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block,
257 1, ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000258 if (ctx->errcode) {
259 ret |= BLOCK_ERROR;
260 return ret;
261 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000262#ifdef EXT2FS_ENABLE_SWAPFS
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000263 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
264 EXT2_FLAG_SWAP_BYTES_READ)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000265 block_nr = (blk_t *) ctx->tind_buf;
266 for (i = 0; i < limit; i++, block_nr++)
267 *block_nr = ext2fs_swab32(*block_nr);
268 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000269#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000270 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000271 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000272 if (ctx->flags & BLOCK_FLAG_APPEND) {
273 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000274 flags = block_iterate_dind(block_nr,
275 *tind_block,
276 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000277 changed |= flags;
278 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
279 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
280 break;
281 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000282 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000283 }
284 } else {
285 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000286 if (*block_nr == 0) {
287 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000288 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000289 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000290 flags = block_iterate_dind(block_nr,
291 *tind_block,
292 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000293 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000294 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
295 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
296 break;
297 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000298 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000299 }
300 }
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000301 if (!(ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
302 (changed & BLOCK_CHANGED)) {
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000303#ifdef EXT2FS_ENABLE_SWAPFS
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000304 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES |
305 EXT2_FLAG_SWAP_BYTES_WRITE)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000306 block_nr = (blk_t *) ctx->tind_buf;
307 for (i = 0; i < limit; i++, block_nr++)
308 *block_nr = ext2fs_swab32(*block_nr);
309 }
Theodore Ts'o5df55d72001-06-11 07:00:04 +0000310#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000311 ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block,
312 1, ctx->tind_buf);
313 if (ctx->errcode)
314 ret |= BLOCK_ERROR | BLOCK_ABORT;
315 }
316 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000317 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000318 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000319 ret |= (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000320 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000321 ref_offset, ctx->priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000322
323 return ret;
324}
325
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000326errcode_t ext2fs_block_iterate2(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000327 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000328 int flags,
329 char *block_buf,
330 int (*func)(ext2_filsys fs,
331 blk_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +0000332 e2_blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000333 blk_t ref_blk,
334 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000335 void *priv_data),
336 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000337{
338 int i;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000339 int got_inode = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000340 int ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000341 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
342 struct ext2_inode inode;
343 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000344 struct block_context ctx;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000345 int limit;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000346
Theodore Ts'of3db3561997-04-26 13:34:30 +0000347 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
348
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000349 /*
350 * Check to see if we need to limit large files
351 */
352 if (flags & BLOCK_FLAG_NO_LARGE) {
353 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
354 if (ctx.errcode)
Theodore Ts'o2eb374c1998-09-03 01:22:57 +0000355 return ctx.errcode;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000356 got_inode = 1;
357 if (!LINUX_S_ISDIR(inode.i_mode) &&
358 (inode.i_size_high != 0))
359 return EXT2_ET_FILE_TOO_BIG;
360 }
361
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +0000362 retval = ext2fs_get_blocks(fs, ino, blocks);
363 if (retval)
364 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000365
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000366 limit = fs->blocksize >> 2;
367
Theodore Ts'o3839e651997-04-26 13:21:57 +0000368 ctx.fs = fs;
369 ctx.func = func;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000370 ctx.priv_data = priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000371 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000372 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000373 if (block_buf) {
374 ctx.ind_buf = block_buf;
375 } else {
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400376 retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000377 if (retval)
378 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000379 }
380 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
381 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000382
383 /*
384 * Iterate over the HURD translator block (if present)
385 */
386 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000387 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000388 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
389 if (ctx.errcode)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000390 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000391 got_inode = 1;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000392 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000393 ret |= (*ctx.func)(fs,
394 &inode.osd1.hurd1.h_i_translator,
395 BLOCK_COUNT_TRANSLATOR,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000396 0, 0, priv_data);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000397 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000398 goto abort_exit;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000399 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000400 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000401
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000402 /*
403 * Iterate over normal data blocks
404 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000405 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
406 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000407 ret |= (*ctx.func)(fs, &blocks[i],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000408 ctx.bcount, 0, i, priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000409 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000410 goto abort_exit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000411 }
412 }
413 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000414 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000415 0, EXT2_IND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000416 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000417 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000418 } else
419 ctx.bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000420 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000421 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000422 0, EXT2_DIND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000423 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000424 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000425 } else
426 ctx.bcount += limit * limit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000427 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000428 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000429 0, EXT2_TIND_BLOCK, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000430 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000431 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000432 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000433
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000434abort_exit:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000435 if (ret & BLOCK_CHANGED) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000436 if (!got_inode) {
437 retval = ext2fs_read_inode(fs, ino, &inode);
438 if (retval)
439 return retval;
440 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000441 for (i=0; i < EXT2_N_BLOCKS; i++)
442 inode.i_block[i] = blocks[i];
443 retval = ext2fs_write_inode(fs, ino, &inode);
444 if (retval)
445 return retval;
446 }
447
448 if (!block_buf)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400449 ext2fs_free_mem(&ctx.ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000450
451 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
452}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000453
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000454/*
455 * Emulate the old ext2fs_block_iterate function!
456 */
457
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000458struct xlate {
459 int (*func)(ext2_filsys fs,
460 blk_t *blocknr,
461 int bcount,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000462 void *priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000463 void *real_private;
464};
465
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000466#ifdef __TURBOC__
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000467 #pragma argsused
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000468#endif
Theodore Ts'o03673db1998-06-10 20:39:43 +0000469static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
Theodore Ts'o54434922003-12-07 01:28:50 -0500470 blk_t ref_block EXT2FS_ATTR((unused)),
471 int ref_offset EXT2FS_ATTR((unused)),
472 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000473{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000474 struct xlate *xl = (struct xlate *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000475
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000476 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000477}
478
479errcode_t ext2fs_block_iterate(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000480 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000481 int flags,
482 char *block_buf,
483 int (*func)(ext2_filsys fs,
484 blk_t *blocknr,
485 int blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000486 void *priv_data),
487 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000488{
489 struct xlate xl;
490
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000491 xl.real_private = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000492 xl.func = func;
493
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000494 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000495 block_buf, xlate_func, &xl);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000496}
497