2 * block.c --- iterate over all blocks in an inode
4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
20 #include <linux/ext2_fs.h>
24 struct block_context {
26 int (*func)(ext2_filsys fs,
42 static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
43 int ref_offset, struct block_context *ctx)
45 int ret = 0, changed = 0;
46 int i, flags, limit, offset;
49 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
50 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
51 ret = (*ctx->func)(ctx->fs, ind_block,
52 BLOCK_COUNT_IND, ref_block,
53 ref_offset, ctx->private);
54 if (!*ind_block || (ret & BLOCK_ABORT))
56 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;
62 ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block,
68 limit = ctx->fs->blocksize >> 2;
69 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
70 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
71 block_nr = (blk_t *) ctx->ind_buf;
72 for (i = 0; i < limit; i++, block_nr++)
73 *block_nr = ext2fs_swab32(*block_nr);
75 block_nr = (blk_t *) ctx->ind_buf;
77 if (ctx->flags & BLOCK_FLAG_APPEND) {
78 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
79 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
83 if (flags & BLOCK_ABORT) {
87 offset += sizeof(blk_t);
90 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
93 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
97 if (flags & BLOCK_ABORT) {
101 offset += sizeof(blk_t);
104 if (changed & BLOCK_CHANGED) {
105 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
106 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
107 block_nr = (blk_t *) ctx->ind_buf;
108 for (i = 0; i < limit; i++, block_nr++)
109 *block_nr = ext2fs_swab32(*block_nr);
111 ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block,
114 ret |= BLOCK_ERROR | BLOCK_ABORT;
116 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
117 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
118 !(ret & BLOCK_ABORT))
119 ret |= (*ctx->func)(ctx->fs, ind_block,
120 BLOCK_COUNT_IND, ref_block,
121 ref_offset, ctx->private);
125 static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
126 int ref_offset, struct block_context *ctx)
128 int ret = 0, changed = 0;
129 int i, flags, limit, offset;
132 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
133 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
134 ret = (*ctx->func)(ctx->fs, dind_block,
135 BLOCK_COUNT_DIND, ref_block,
136 ref_offset, ctx->private);
137 if (!*dind_block || (ret & BLOCK_ABORT))
139 if (*dind_block >= ctx->fs->super->s_blocks_count ||
140 *dind_block < ctx->fs->super->s_first_data_block) {
141 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
145 ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block,
151 limit = ctx->fs->blocksize >> 2;
152 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
153 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
154 block_nr = (blk_t *) ctx->dind_buf;
155 for (i = 0; i < limit; i++, block_nr++)
156 *block_nr = ext2fs_swab32(*block_nr);
158 block_nr = (blk_t *) ctx->dind_buf;
160 if (ctx->flags & BLOCK_FLAG_APPEND) {
161 for (i = 0; i < limit; i++, block_nr++) {
162 flags = block_iterate_ind(block_nr,
166 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
167 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
170 offset += sizeof(blk_t);
173 for (i = 0; i < limit; i++, block_nr++) {
176 flags = block_iterate_ind(block_nr,
180 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
181 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
184 offset += sizeof(blk_t);
187 if (changed & BLOCK_CHANGED) {
188 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
189 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
190 block_nr = (blk_t *) ctx->dind_buf;
191 for (i = 0; i < limit; i++, block_nr++)
192 *block_nr = ext2fs_swab32(*block_nr);
194 ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block,
197 ret |= BLOCK_ERROR | BLOCK_ABORT;
199 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
200 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
201 !(ret & BLOCK_ABORT))
202 ret |= (*ctx->func)(ctx->fs, dind_block,
203 BLOCK_COUNT_DIND, ref_block,
204 ref_offset, ctx->private);
208 static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
209 int ref_offset, struct block_context *ctx)
211 int ret = 0, changed = 0;
212 int i, flags, limit, offset;
215 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
216 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
217 ret = (*ctx->func)(ctx->fs, tind_block,
218 BLOCK_COUNT_TIND, ref_block,
219 ref_offset, ctx->private);
220 if (!*tind_block || (ret & BLOCK_ABORT))
222 if (*tind_block >= ctx->fs->super->s_blocks_count ||
223 *tind_block < ctx->fs->super->s_first_data_block) {
224 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
228 ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block,
234 limit = ctx->fs->blocksize >> 2;
235 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
236 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
237 block_nr = (blk_t *) ctx->tind_buf;
238 for (i = 0; i < limit; i++, block_nr++)
239 *block_nr = ext2fs_swab32(*block_nr);
241 block_nr = (blk_t *) ctx->tind_buf;
243 if (ctx->flags & BLOCK_FLAG_APPEND) {
244 for (i = 0; i < limit; i++, block_nr++) {
245 flags = block_iterate_dind(block_nr,
249 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
250 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
253 offset += sizeof(blk_t);
256 for (i = 0; i < limit; i++, block_nr++) {
259 flags = block_iterate_dind(block_nr,
263 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
264 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
267 offset += sizeof(blk_t);
270 if (changed & BLOCK_CHANGED) {
271 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
272 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
273 block_nr = (blk_t *) ctx->tind_buf;
274 for (i = 0; i < limit; i++, block_nr++)
275 *block_nr = ext2fs_swab32(*block_nr);
277 ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block,
280 ret |= BLOCK_ERROR | BLOCK_ABORT;
282 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
283 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
284 !(ret & BLOCK_ABORT))
285 ret |= (*ctx->func)(ctx->fs, tind_block,
286 BLOCK_COUNT_TIND, ref_block,
287 ref_offset, ctx->private);
292 errcode_t ext2fs_block_iterate2(ext2_filsys fs,
296 int (*func)(ext2_filsys fs,
307 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
308 struct ext2_inode inode;
310 struct block_context ctx;
312 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
314 ret = ext2fs_get_blocks(fs, ino, blocks);
320 ctx.private = private;
324 ctx.ind_buf = block_buf;
326 ctx.ind_buf = malloc(fs->blocksize * 3);
330 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
331 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
334 * Iterate over the HURD translator block (if present)
336 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
337 !(flags & BLOCK_FLAG_DATA_ONLY)) {
338 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
342 if (inode.osd1.hurd1.h_i_translator) {
343 ret |= (*ctx.func)(fs,
344 &inode.osd1.hurd1.h_i_translator,
345 BLOCK_COUNT_TRANSLATOR,
347 if (ret & BLOCK_ABORT)
353 * Iterate over normal data blocks
355 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
356 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
357 ret |= (*ctx.func)(fs, &blocks[i],
358 ctx.bcount, 0, 0, private);
359 if (ret & BLOCK_ABORT)
363 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
364 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
366 if (ret & BLOCK_ABORT)
369 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
370 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
372 if (ret & BLOCK_ABORT)
375 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
376 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
378 if (ret & BLOCK_ABORT)
383 if (ret & BLOCK_CHANGED) {
385 retval = ext2fs_read_inode(fs, ino, &inode);
389 for (i=0; i < EXT2_N_BLOCKS; i++)
390 inode.i_block[i] = blocks[i];
391 retval = ext2fs_write_inode(fs, ino, &inode);
399 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
403 int (*func)(ext2_filsys fs,
410 static int xlate_func(ext2_filsys fs, blk_t *blocknr, int blockcnt,
411 blk_t ref_block, int ref_offset, void *private)
413 struct xlate *xl = private;
415 return (*xl->func)(fs, blocknr, blockcnt, xl->real_private);
418 errcode_t ext2fs_block_iterate(ext2_filsys fs,
422 int (*func)(ext2_filsys fs,
430 xl.real_private = private;
433 return ext2fs_block_iterate2(fs, ino, flags, block_buf,