blob: 4054a07b3fc28f492ff8862bf921b9324b775fc4 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * block.c --- iterate over all blocks in an inode
Theodore Ts'oefc6f622008-08-27 23:07:54 -04003 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5 *
6 * %Begin-Header%
Theodore Ts'o543547a2010-05-17 21:31:56 -04007 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
Theodore Ts'o21c84b71997-04-29 16:15:03 +00009 * %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'oefc6f622008-08-27 23:07:54 -040083 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -050084 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'oefc6f622008-08-27 23:07:54 -040095 *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)
Theodore Ts'o94ded6c2010-12-16 19:34:24 -0500107 goto skip_sparse;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000108 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400109 *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'o94ded6c2010-12-16 19:34:24 -0500116 skip_sparse:
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000117 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000118 }
119 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500120 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500121 if (changed & BLOCK_CHANGED) {
122 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
123 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000124 if (ctx->errcode)
125 ret |= BLOCK_ERROR | BLOCK_ABORT;
126 }
127 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000128 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000129 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000130 ret |= (*ctx->func)(ctx->fs, ind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000131 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000132 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500133 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000134 return ret;
135}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400136
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000137static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
138 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000139{
140 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000141 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000142 blk_t *block_nr;
143
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000144 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000145 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
146 BLOCK_FLAG_DATA_ONLY)))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000147 ret = (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000148 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000149 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500150 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000151 if (!*dind_block || (ret & BLOCK_ABORT)) {
152 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000153 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000154 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000155 if (*dind_block >= ctx->fs->super->s_blocks_count ||
156 *dind_block < ctx->fs->super->s_first_data_block) {
157 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
158 ret |= BLOCK_ERROR;
159 return ret;
160 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400161 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500162 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000163 if (ctx->errcode) {
164 ret |= BLOCK_ERROR;
165 return ret;
166 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500167
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000168 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000169 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000170 if (ctx->flags & BLOCK_FLAG_APPEND) {
171 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000172 flags = block_iterate_ind(block_nr,
173 *dind_block, offset,
174 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000175 changed |= flags;
176 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
177 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
178 break;
179 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000180 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000181 }
182 } else {
183 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000184 if (*block_nr == 0) {
185 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000186 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000187 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000188 flags = block_iterate_ind(block_nr,
189 *dind_block, offset,
190 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000191 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000192 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
193 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
194 break;
195 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000196 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000197 }
198 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500199 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500200 if (changed & BLOCK_CHANGED) {
201 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
202 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000203 if (ctx->errcode)
204 ret |= BLOCK_ERROR | BLOCK_ABORT;
205 }
206 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000207 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000208 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000209 ret |= (*ctx->func)(ctx->fs, dind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000210 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000211 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500212 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000213 return ret;
214}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400215
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'o206fea62008-02-03 22:29:16 -0500229 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000230 if (!*tind_block || (ret & BLOCK_ABORT)) {
231 ctx->bcount += limit*limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000232 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000233 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000234 if (*tind_block >= ctx->fs->super->s_blocks_count ||
235 *tind_block < ctx->fs->super->s_first_data_block) {
236 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
237 ret |= BLOCK_ERROR;
238 return ret;
239 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400240 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500241 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000242 if (ctx->errcode) {
243 ret |= BLOCK_ERROR;
244 return ret;
245 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500246
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000247 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000248 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000249 if (ctx->flags & BLOCK_FLAG_APPEND) {
250 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000251 flags = block_iterate_dind(block_nr,
252 *tind_block,
253 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000254 changed |= flags;
255 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
256 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
257 break;
258 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000259 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000260 }
261 } else {
262 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000263 if (*block_nr == 0) {
264 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000265 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000266 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000267 flags = block_iterate_dind(block_nr,
268 *tind_block,
269 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000270 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000271 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
272 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
273 break;
274 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000275 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000276 }
277 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500278 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500279 if (changed & BLOCK_CHANGED) {
280 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
281 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000282 if (ctx->errcode)
283 ret |= BLOCK_ERROR | BLOCK_ABORT;
284 }
285 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000286 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o3839e651997-04-26 13:21:57 +0000287 !(ret & BLOCK_ABORT))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000288 ret |= (*ctx->func)(ctx->fs, tind_block,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000289 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000290 ref_offset, ctx->priv_data);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500291 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000292 return ret;
293}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400294
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000295errcode_t ext2fs_block_iterate2(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000296 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000297 int flags,
298 char *block_buf,
299 int (*func)(ext2_filsys fs,
300 blk_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +0000301 e2_blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000302 blk_t ref_blk,
303 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000304 void *priv_data),
305 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000306{
307 int i;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400308 int r, ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000309 struct ext2_inode inode;
310 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000311 struct block_context ctx;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000312 int limit;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000313
Theodore Ts'of3db3561997-04-26 13:34:30 +0000314 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
315
Theodore Ts'o206fea62008-02-03 22:29:16 -0500316 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
317 if (ctx.errcode)
318 return ctx.errcode;
319
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000320 /*
321 * Check to see if we need to limit large files
322 */
323 if (flags & BLOCK_FLAG_NO_LARGE) {
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000324 if (!LINUX_S_ISDIR(inode.i_mode) &&
325 (inode.i_size_high != 0))
326 return EXT2_ET_FILE_TOO_BIG;
327 }
328
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000329 limit = fs->blocksize >> 2;
330
Theodore Ts'o3839e651997-04-26 13:21:57 +0000331 ctx.fs = fs;
332 ctx.func = func;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000333 ctx.priv_data = priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000334 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000335 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000336 if (block_buf) {
337 ctx.ind_buf = block_buf;
338 } else {
Theodore Ts'oee010792007-11-09 19:01:06 -0500339 retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000340 if (retval)
341 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000342 }
343 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
344 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000345
346 /*
347 * Iterate over the HURD translator block (if present)
348 */
349 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000350 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000351 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000352 ret |= (*ctx.func)(fs,
353 &inode.osd1.hurd1.h_i_translator,
354 BLOCK_COUNT_TRANSLATOR,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000355 0, 0, priv_data);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000356 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000357 goto abort_exit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500358 check_for_ro_violation_goto(&ctx, ret, abort_exit);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000359 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000360 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400361
Theodore Ts'o206fea62008-02-03 22:29:16 -0500362 if (inode.i_flags & EXT4_EXTENTS_FL) {
363 ext2_extent_handle_t handle;
364 struct ext2fs_extent extent;
Theodore Ts'o685d5442008-08-27 15:17:36 -0400365 e2_blkcnt_t blockcnt = 0;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400366 blk_t blk, new_blk;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500367 int op = EXT2_EXTENT_ROOT;
Theodore Ts'o07f1a072009-01-19 19:30:59 -0500368 int uninit;
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400369 unsigned int j;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500370
number965284b239a2009-05-19 13:34:12 -0700371 ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500372 if (ctx.errcode)
373 goto abort_exit;
374
375 while (1) {
376 ctx.errcode = ext2fs_extent_get(handle, op, &extent);
377 if (ctx.errcode) {
Theodore Ts'o685d5442008-08-27 15:17:36 -0400378 if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
379 break;
380 ctx.errcode = 0;
381 if (!(flags & BLOCK_FLAG_APPEND))
382 break;
Theodore Ts'o8e2399d2010-03-11 12:47:41 -0500383 next_block_set:
Theodore Ts'o685d5442008-08-27 15:17:36 -0400384 blk = 0;
385 r = (*ctx.func)(fs, &blk, blockcnt,
386 0, 0, priv_data);
387 ret |= r;
388 check_for_ro_violation_goto(&ctx, ret,
389 extent_errout);
390 if (r & BLOCK_CHANGED) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400391 ctx.errcode =
Theodore Ts'o685d5442008-08-27 15:17:36 -0400392 ext2fs_extent_set_bmap(handle,
393 (blk64_t) blockcnt++,
394 (blk64_t) blk, 0);
395 if (ctx.errcode || (ret & BLOCK_ABORT))
Theodore Ts'o64987c02008-08-27 17:50:14 -0400396 break;
Theodore Ts'o8e2399d2010-03-11 12:47:41 -0500397 if (blk)
398 goto next_block_set;
Theodore Ts'o685d5442008-08-27 15:17:36 -0400399 }
Theodore Ts'o64987c02008-08-27 17:50:14 -0400400 break;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500401 }
402
403 op = EXT2_EXTENT_NEXT;
404 blk = extent.e_pblk;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400405 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
406 if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
407 continue;
408 if ((!(extent.e_flags &
409 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
410 !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
411 ((extent.e_flags &
412 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
413 (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
414 ret |= (*ctx.func)(fs, &blk,
415 -1, 0, 0, priv_data);
416 if (ret & BLOCK_CHANGED) {
Theodore Ts'o213fe922008-08-22 02:50:02 -0400417 extent.e_pblk = blk;
418 ctx.errcode =
419 ext2fs_extent_replace(handle, 0, &extent);
420 if (ctx.errcode)
Theodore Ts'o64987c02008-08-27 17:50:14 -0400421 break;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400422 }
423 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500424 continue;
425 }
Theodore Ts'o07f1a072009-01-19 19:30:59 -0500426 uninit = 0;
427 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
428 uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400429 for (blockcnt = extent.e_lblk, j = 0;
430 j < extent.e_len;
431 blk++, blockcnt++, j++) {
Theodore Ts'od7b92202008-05-27 06:59:32 -0400432 new_blk = blk;
433 r = (*ctx.func)(fs, &new_blk, blockcnt,
434 0, 0, priv_data);
435 ret |= r;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500436 check_for_ro_violation_goto(&ctx, ret,
437 extent_errout);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400438 if (r & BLOCK_CHANGED) {
439 ctx.errcode =
440 ext2fs_extent_set_bmap(handle,
441 (blk64_t) blockcnt,
Theodore Ts'o07f1a072009-01-19 19:30:59 -0500442 (blk64_t) new_blk,
443 uninit);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400444 if (ctx.errcode)
Theodore Ts'od3a8fc52009-01-19 14:22:52 -0500445 goto extent_errout;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400446 }
Theodore Ts'o64987c02008-08-27 17:50:14 -0400447 if (ret & BLOCK_ABORT)
448 break;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500449 }
450 }
451
452 extent_errout:
453 ext2fs_extent_free(handle);
454 ret |= BLOCK_ERROR | BLOCK_ABORT;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400455 goto errout;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500456 }
457
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000458 /*
459 * Iterate over normal data blocks
460 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000461 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
Theodore Ts'o206fea62008-02-03 22:29:16 -0500462 if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
463 ret |= (*ctx.func)(fs, &inode.i_block[i],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000464 ctx.bcount, 0, i, priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000465 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000466 goto abort_exit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000467 }
468 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500469 check_for_ro_violation_goto(&ctx, ret, abort_exit);
470 if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
471 ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000472 0, EXT2_IND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000473 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000474 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000475 } else
476 ctx.bcount += limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500477 if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
478 ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000479 0, EXT2_DIND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000480 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000481 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000482 } else
483 ctx.bcount += limit * limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500484 if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
485 ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000486 0, EXT2_TIND_BLOCK, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000487 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000488 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000489 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000490
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000491abort_exit:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000492 if (ret & BLOCK_CHANGED) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000493 retval = ext2fs_write_inode(fs, ino, &inode);
Theodore Ts'o9922c532009-07-18 10:02:41 -0400494 if (retval) {
495 ret |= BLOCK_ERROR;
496 ctx.errcode = retval;
497 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000498 }
Theodore Ts'od7b92202008-05-27 06:59:32 -0400499errout:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000500 if (!block_buf)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400501 ext2fs_free_mem(&ctx.ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000502
503 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
504}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000505
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000506/*
507 * Emulate the old ext2fs_block_iterate function!
508 */
509
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000510struct xlate {
511 int (*func)(ext2_filsys fs,
512 blk_t *blocknr,
513 int bcount,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000514 void *priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000515 void *real_private;
516};
517
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000518#ifdef __TURBOC__
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000519 #pragma argsused
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000520#endif
Theodore Ts'o03673db1998-06-10 20:39:43 +0000521static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
Theodore Ts'o54434922003-12-07 01:28:50 -0500522 blk_t ref_block EXT2FS_ATTR((unused)),
523 int ref_offset EXT2FS_ATTR((unused)),
524 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000525{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000526 struct xlate *xl = (struct xlate *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000527
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000528 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000529}
530
531errcode_t ext2fs_block_iterate(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000532 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000533 int flags,
534 char *block_buf,
535 int (*func)(ext2_filsys fs,
536 blk_t *blocknr,
537 int blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000538 void *priv_data),
539 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000540{
541 struct xlate xl;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400542
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000543 xl.real_private = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000544 xl.func = func;
545
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000546 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000547 block_buf, xlate_func, &xl);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000548}
549