blob: 4575cf392cdf881a8b86d0871a30854eb65f9567 [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'o206fea62008-02-03 22:29:16 -050039#define check_for_ro_violation_return(ctx, ret) \
Theodore Ts'o357d1862008-02-02 21:26:54 -050040 do { \
41 if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
42 ((ret) & BLOCK_CHANGED)) { \
43 (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
Theodore Ts'o206fea62008-02-03 22:29:16 -050044 ret |= BLOCK_ABORT | BLOCK_ERROR; \
45 return ret; \
Theodore Ts'o357d1862008-02-02 21:26:54 -050046 } \
47 } while (0)
Theodore Ts'o206fea62008-02-03 22:29:16 -050048
49#define check_for_ro_violation_goto(ctx, ret, label) \
50 do { \
51 if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
52 ((ret) & BLOCK_CHANGED)) { \
53 (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
54 ret |= BLOCK_ABORT | BLOCK_ERROR; \
55 goto label; \
56 } \
57 } while (0)
Theodore Ts'o357d1862008-02-02 21:26:54 -050058
Theodore Ts'o21c84b71997-04-29 16:15:03 +000059static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
60 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000061{
62 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000063 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +000064 blk_t *block_nr;
65
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000066 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000067 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
68 !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
69 ret = (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000070 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000071 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -050072 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000073 if (!*ind_block || (ret & BLOCK_ABORT)) {
74 ctx->bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +000075 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000076 }
Theodore Ts'of3db3561997-04-26 13:34:30 +000077 if (*ind_block >= ctx->fs->super->s_blocks_count ||
78 *ind_block < ctx->fs->super->s_first_data_block) {
79 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
80 ret |= BLOCK_ERROR;
81 return ret;
82 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -050083 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
84 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +000085 if (ctx->errcode) {
86 ret |= BLOCK_ERROR;
87 return ret;
88 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -050089
Theodore Ts'o50e1e101997-04-26 13:58:21 +000090 block_nr = (blk_t *) ctx->ind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000091 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000092 if (ctx->flags & BLOCK_FLAG_APPEND) {
93 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
Theodore Ts'o3839e651997-04-26 13:21:57 +000094 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000095 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000096 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000097 changed |= flags;
98 if (flags & BLOCK_ABORT) {
99 ret |= BLOCK_ABORT;
100 break;
101 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000102 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000103 }
104 } else {
105 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
106 if (*block_nr == 0)
107 continue;
108 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000109 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000110 ctx->priv_data);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000111 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000112 if (flags & BLOCK_ABORT) {
113 ret |= BLOCK_ABORT;
114 break;
115 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000116 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000117 }
118 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500119 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500120 if (changed & BLOCK_CHANGED) {
121 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
122 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000123 if (ctx->errcode)
124 ret |= BLOCK_ERROR | BLOCK_ABORT;
125 }
126 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000127 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000128 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000129 ret |= (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000130 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000131 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500132 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000133 return ret;
134}
135
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000136static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
137 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000138{
139 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000140 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000141 blk_t *block_nr;
142
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000143 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000144 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
145 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000146 ret = (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000147 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000148 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500149 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000150 if (!*dind_block || (ret & BLOCK_ABORT)) {
151 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000152 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000153 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000154 if (*dind_block >= ctx->fs->super->s_blocks_count ||
155 *dind_block < ctx->fs->super->s_first_data_block) {
156 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
157 ret |= BLOCK_ERROR;
158 return ret;
159 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500160 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
161 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'odc8ce342005-01-06 00:04:24 -0500166
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000167 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000168 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000169 if (ctx->flags & BLOCK_FLAG_APPEND) {
170 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000171 flags = block_iterate_ind(block_nr,
172 *dind_block, offset,
173 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000174 changed |= flags;
175 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
176 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
177 break;
178 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000179 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000180 }
181 } else {
182 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000183 if (*block_nr == 0) {
184 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000185 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000186 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000187 flags = block_iterate_ind(block_nr,
188 *dind_block, offset,
189 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000190 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000191 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
192 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
193 break;
194 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000195 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000196 }
197 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500198 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500199 if (changed & BLOCK_CHANGED) {
200 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
201 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000202 if (ctx->errcode)
203 ret |= BLOCK_ERROR | BLOCK_ABORT;
204 }
205 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000206 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000207 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000208 ret |= (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000209 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000210 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500211 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000212 return ret;
213}
214
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000215static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
216 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000217{
218 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000219 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000220 blk_t *block_nr;
221
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000222 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000223 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
224 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000225 ret = (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000226 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000227 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500228 check_for_ro_violation_return(ctx, ret);
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'odc8ce342005-01-06 00:04:24 -0500239 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
240 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000241 if (ctx->errcode) {
242 ret |= BLOCK_ERROR;
243 return ret;
244 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500245
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000246 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000247 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000248 if (ctx->flags & BLOCK_FLAG_APPEND) {
249 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000250 flags = block_iterate_dind(block_nr,
251 *tind_block,
252 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000253 changed |= flags;
254 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
255 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
256 break;
257 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000258 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000259 }
260 } else {
261 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000262 if (*block_nr == 0) {
263 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000264 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000265 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000266 flags = block_iterate_dind(block_nr,
267 *tind_block,
268 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000269 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000270 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
271 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
272 break;
273 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000274 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000275 }
276 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500277 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500278 if (changed & BLOCK_CHANGED) {
279 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
280 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000281 if (ctx->errcode)
282 ret |= BLOCK_ERROR | BLOCK_ABORT;
283 }
284 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000285 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000286 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000287 ret |= (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000288 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000289 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500290 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000291 return ret;
292}
293
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000294errcode_t ext2fs_block_iterate2(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000295 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000296 int flags,
297 char *block_buf,
298 int (*func)(ext2_filsys fs,
299 blk_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +0000300 e2_blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000301 blk_t ref_blk,
302 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000303 void *priv_data),
304 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000305{
306 int i;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400307 int r, ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000308 struct ext2_inode inode;
309 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000310 struct block_context ctx;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000311 int limit;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000312
Theodore Ts'of3db3561997-04-26 13:34:30 +0000313 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
314
Theodore Ts'o206fea62008-02-03 22:29:16 -0500315 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
316 if (ctx.errcode)
317 return ctx.errcode;
318
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000319 /*
320 * Check to see if we need to limit large files
321 */
322 if (flags & BLOCK_FLAG_NO_LARGE) {
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000323 if (!LINUX_S_ISDIR(inode.i_mode) &&
324 (inode.i_size_high != 0))
325 return EXT2_ET_FILE_TOO_BIG;
326 }
327
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000328 limit = fs->blocksize >> 2;
329
Theodore Ts'o3839e651997-04-26 13:21:57 +0000330 ctx.fs = fs;
331 ctx.func = func;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000332 ctx.priv_data = priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000333 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000334 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000335 if (block_buf) {
336 ctx.ind_buf = block_buf;
337 } else {
Theodore Ts'oee010792007-11-09 19:01:06 -0500338 retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000339 if (retval)
340 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000341 }
342 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
343 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000344
345 /*
346 * Iterate over the HURD translator block (if present)
347 */
348 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000349 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000350 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000351 ret |= (*ctx.func)(fs,
352 &inode.osd1.hurd1.h_i_translator,
353 BLOCK_COUNT_TRANSLATOR,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000354 0, 0, priv_data);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000355 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000356 goto abort_exit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500357 check_for_ro_violation_goto(&ctx, ret, abort_exit);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000358 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000359 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000360
Theodore Ts'o206fea62008-02-03 22:29:16 -0500361 if (inode.i_flags & EXT4_EXTENTS_FL) {
362 ext2_extent_handle_t handle;
363 struct ext2fs_extent extent;
364 e2_blkcnt_t blockcnt;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400365 blk_t blk, new_blk;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500366 int op = EXT2_EXTENT_ROOT;
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400367 unsigned int j;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500368
Theodore Ts'o206fea62008-02-03 22:29:16 -0500369 ctx.errcode = ext2fs_extent_open(fs, ino, &handle);
370 if (ctx.errcode)
371 goto abort_exit;
372
373 while (1) {
374 ctx.errcode = ext2fs_extent_get(handle, op, &extent);
375 if (ctx.errcode) {
376 if (ctx.errcode == EXT2_ET_EXTENT_NO_NEXT)
377 ctx.errcode = 0;
378 break;
379 }
380
381 op = EXT2_EXTENT_NEXT;
382 blk = extent.e_pblk;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400383 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
384 if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
385 continue;
386 if ((!(extent.e_flags &
387 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
388 !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
389 ((extent.e_flags &
390 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
391 (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
392 ret |= (*ctx.func)(fs, &blk,
393 -1, 0, 0, priv_data);
394 if (ret & BLOCK_CHANGED) {
395 ctx.errcode = EXT2_ET_EXTENT_NOT_SUPPORTED;
396 goto errout;
397 }
398 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500399 continue;
400 }
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400401 for (blockcnt = extent.e_lblk, j = 0;
402 j < extent.e_len;
403 blk++, blockcnt++, j++) {
Theodore Ts'od7b92202008-05-27 06:59:32 -0400404 new_blk = blk;
405 r = (*ctx.func)(fs, &new_blk, blockcnt,
406 0, 0, priv_data);
407 ret |= r;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500408 check_for_ro_violation_goto(&ctx, ret,
409 extent_errout);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400410 if (r & BLOCK_CHANGED) {
411 ctx.errcode =
412 ext2fs_extent_set_bmap(handle,
413 (blk64_t) blockcnt,
414 (blk64_t) new_blk, 0);
415 if (ctx.errcode)
416 goto errout;
417 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500418 if (ret & BLOCK_ABORT) {
419 ext2fs_extent_free(handle);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400420 goto errout;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500421 }
422 }
423 }
424
425 extent_errout:
426 ext2fs_extent_free(handle);
427 ret |= BLOCK_ERROR | BLOCK_ABORT;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400428 goto errout;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500429 }
430
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000431 /*
432 * Iterate over normal data blocks
433 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000434 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
Theodore Ts'o206fea62008-02-03 22:29:16 -0500435 if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
436 ret |= (*ctx.func)(fs, &inode.i_block[i],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000437 ctx.bcount, 0, i, priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000438 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000439 goto abort_exit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000440 }
441 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500442 check_for_ro_violation_goto(&ctx, ret, abort_exit);
443 if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
444 ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000445 0, EXT2_IND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000446 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000447 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000448 } else
449 ctx.bcount += limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500450 if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
451 ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000452 0, EXT2_DIND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000453 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000454 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000455 } else
456 ctx.bcount += limit * limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500457 if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
458 ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000459 0, EXT2_TIND_BLOCK, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000460 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000461 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000462 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000463
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000464abort_exit:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000465 if (ret & BLOCK_CHANGED) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000466 retval = ext2fs_write_inode(fs, ino, &inode);
467 if (retval)
468 return retval;
469 }
Theodore Ts'od7b92202008-05-27 06:59:32 -0400470errout:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000471 if (!block_buf)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400472 ext2fs_free_mem(&ctx.ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000473
474 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
475}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000476
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000477/*
478 * Emulate the old ext2fs_block_iterate function!
479 */
480
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000481struct xlate {
482 int (*func)(ext2_filsys fs,
483 blk_t *blocknr,
484 int bcount,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000485 void *priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000486 void *real_private;
487};
488
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000489#ifdef __TURBOC__
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000490 #pragma argsused
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000491#endif
Theodore Ts'o03673db1998-06-10 20:39:43 +0000492static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
Theodore Ts'o54434922003-12-07 01:28:50 -0500493 blk_t ref_block EXT2FS_ATTR((unused)),
494 int ref_offset EXT2FS_ATTR((unused)),
495 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000496{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000497 struct xlate *xl = (struct xlate *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000498
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000499 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000500}
501
502errcode_t ext2fs_block_iterate(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000503 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000504 int flags,
505 char *block_buf,
506 int (*func)(ext2_filsys fs,
507 blk_t *blocknr,
508 int blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000509 void *priv_data),
510 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000511{
512 struct xlate xl;
513
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000514 xl.real_private = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000515 xl.func = func;
516
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000517 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000518 block_buf, xlate_func, &xl);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000519}
520