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 limit = ctx->fs->blocksize >> 2;
50 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
51 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
52 ret = (*ctx->func)(ctx->fs, ind_block,
53 BLOCK_COUNT_IND, ref_block,
54 ref_offset, ctx->private);
55 if (!*ind_block || (ret & BLOCK_ABORT)) {
59 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;
65 ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block,
71 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
72 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
73 block_nr = (blk_t *) ctx->ind_buf;
74 for (i = 0; i < limit; i++, block_nr++)
75 *block_nr = ext2fs_swab32(*block_nr);
77 block_nr = (blk_t *) ctx->ind_buf;
79 if (ctx->flags & BLOCK_FLAG_APPEND) {
80 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
81 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
85 if (flags & BLOCK_ABORT) {
89 offset += sizeof(blk_t);
92 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
95 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
99 if (flags & BLOCK_ABORT) {
103 offset += sizeof(blk_t);
106 if (changed & BLOCK_CHANGED) {
107 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
108 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
109 block_nr = (blk_t *) ctx->ind_buf;
110 for (i = 0; i < limit; i++, block_nr++)
111 *block_nr = ext2fs_swab32(*block_nr);
113 ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block,
116 ret |= BLOCK_ERROR | BLOCK_ABORT;
118 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
119 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
120 !(ret & BLOCK_ABORT))
121 ret |= (*ctx->func)(ctx->fs, ind_block,
122 BLOCK_COUNT_IND, ref_block,
123 ref_offset, ctx->private);
127 static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
128 int ref_offset, struct block_context *ctx)
130 int ret = 0, changed = 0;
131 int i, flags, limit, offset;
134 limit = ctx->fs->blocksize >> 2;
135 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
136 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
137 ret = (*ctx->func)(ctx->fs, dind_block,
138 BLOCK_COUNT_DIND, ref_block,
139 ref_offset, ctx->private);
140 if (!*dind_block || (ret & BLOCK_ABORT)) {
141 ctx->bcount += limit*limit;
144 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;
150 ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block,
156 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
157 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
158 block_nr = (blk_t *) ctx->dind_buf;
159 for (i = 0; i < limit; i++, block_nr++)
160 *block_nr = ext2fs_swab32(*block_nr);
162 block_nr = (blk_t *) ctx->dind_buf;
164 if (ctx->flags & BLOCK_FLAG_APPEND) {
165 for (i = 0; i < limit; i++, block_nr++) {
166 flags = block_iterate_ind(block_nr,
170 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
171 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
174 offset += sizeof(blk_t);
177 for (i = 0; i < limit; i++, block_nr++) {
178 if (*block_nr == 0) {
179 ctx->bcount += limit;
182 flags = block_iterate_ind(block_nr,
186 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
187 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
190 offset += sizeof(blk_t);
193 if (changed & BLOCK_CHANGED) {
194 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
195 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
196 block_nr = (blk_t *) ctx->dind_buf;
197 for (i = 0; i < limit; i++, block_nr++)
198 *block_nr = ext2fs_swab32(*block_nr);
200 ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block,
203 ret |= BLOCK_ERROR | BLOCK_ABORT;
205 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
206 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
207 !(ret & BLOCK_ABORT))
208 ret |= (*ctx->func)(ctx->fs, dind_block,
209 BLOCK_COUNT_DIND, ref_block,
210 ref_offset, ctx->private);
214 static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
215 int ref_offset, struct block_context *ctx)
217 int ret = 0, changed = 0;
218 int i, flags, limit, offset;
221 limit = ctx->fs->blocksize >> 2;
222 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
223 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
224 ret = (*ctx->func)(ctx->fs, tind_block,
225 BLOCK_COUNT_TIND, ref_block,
226 ref_offset, ctx->private);
227 if (!*tind_block || (ret & BLOCK_ABORT)) {
228 ctx->bcount += limit*limit*limit;
231 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;
237 ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block,
243 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
244 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) {
245 block_nr = (blk_t *) ctx->tind_buf;
246 for (i = 0; i < limit; i++, block_nr++)
247 *block_nr = ext2fs_swab32(*block_nr);
249 block_nr = (blk_t *) ctx->tind_buf;
251 if (ctx->flags & BLOCK_FLAG_APPEND) {
252 for (i = 0; i < limit; i++, block_nr++) {
253 flags = block_iterate_dind(block_nr,
257 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
258 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
261 offset += sizeof(blk_t);
264 for (i = 0; i < limit; i++, block_nr++) {
265 if (*block_nr == 0) {
266 ctx->bcount += limit*limit;
269 flags = block_iterate_dind(block_nr,
273 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
274 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
277 offset += sizeof(blk_t);
280 if (changed & BLOCK_CHANGED) {
281 if ((ctx->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
282 (ctx->fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
283 block_nr = (blk_t *) ctx->tind_buf;
284 for (i = 0; i < limit; i++, block_nr++)
285 *block_nr = ext2fs_swab32(*block_nr);
287 ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block,
290 ret |= BLOCK_ERROR | BLOCK_ABORT;
292 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
293 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
294 !(ret & BLOCK_ABORT))
295 ret |= (*ctx->func)(ctx->fs, tind_block,
296 BLOCK_COUNT_TIND, ref_block,
297 ref_offset, ctx->private);
302 errcode_t ext2fs_block_iterate2(ext2_filsys fs,
306 int (*func)(ext2_filsys fs,
317 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
318 struct ext2_inode inode;
320 struct block_context ctx;
322 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
324 ret = ext2fs_get_blocks(fs, ino, blocks);
330 ctx.private = private;
334 ctx.ind_buf = block_buf;
336 ctx.ind_buf = malloc(fs->blocksize * 3);
340 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
341 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
344 * Iterate over the HURD translator block (if present)
346 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
347 !(flags & BLOCK_FLAG_DATA_ONLY)) {
348 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
352 if (inode.osd1.hurd1.h_i_translator) {
353 ret |= (*ctx.func)(fs,
354 &inode.osd1.hurd1.h_i_translator,
355 BLOCK_COUNT_TRANSLATOR,
357 if (ret & BLOCK_ABORT)
363 * Iterate over normal data blocks
365 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
366 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
367 ret |= (*ctx.func)(fs, &blocks[i],
368 ctx.bcount, 0, 0, private);
369 if (ret & BLOCK_ABORT)
373 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
374 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
376 if (ret & BLOCK_ABORT)
379 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
380 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
382 if (ret & BLOCK_ABORT)
385 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
386 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
388 if (ret & BLOCK_ABORT)
393 if (ret & BLOCK_CHANGED) {
395 retval = ext2fs_read_inode(fs, ino, &inode);
399 for (i=0; i < EXT2_N_BLOCKS; i++)
400 inode.i_block[i] = blocks[i];
401 retval = ext2fs_write_inode(fs, ino, &inode);
409 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
413 int (*func)(ext2_filsys fs,
420 static int xlate_func(ext2_filsys fs, blk_t *blocknr, int blockcnt,
421 blk_t ref_block, int ref_offset, void *private)
423 struct xlate *xl = private;
425 return (*xl->func)(fs, blocknr, blockcnt, xl->real_private);
428 errcode_t ext2fs_block_iterate(ext2_filsys fs,
432 int (*func)(ext2_filsys fs,
440 xl.real_private = private;
443 return ext2fs_block_iterate2(fs, ino, flags, block_buf,