blob: 95ad31e2bd47aaa24429ce80173f249f78e371be [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,
Theodore Ts'o272631e2009-06-01 16:15:40 -040024 blk64_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +000025 e2_blkcnt_t bcount,
Theodore Ts'o272631e2009-06-01 16:15:40 -040026 blk64_t ref_blk,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000027 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;
Theodore Ts'o272631e2009-06-01 16:15:40 -040065 blk64_t blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +000066
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000067 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000068 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -040069 !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
70 blk64 = *ind_block;
71 ret = (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000072 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000073 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -040074 *ind_block = blk64;
75 }
Theodore Ts'o206fea62008-02-03 22:29:16 -050076 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000077 if (!*ind_block || (ret & BLOCK_ABORT)) {
78 ctx->bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +000079 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000080 }
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -040081 if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) ||
Theodore Ts'of3db3561997-04-26 13:34:30 +000082 *ind_block < ctx->fs->super->s_first_data_block) {
83 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
84 ret |= BLOCK_ERROR;
85 return ret;
86 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -040087 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -050088 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +000089 if (ctx->errcode) {
90 ret |= BLOCK_ERROR;
91 return ret;
92 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -050093
Theodore Ts'o50e1e101997-04-26 13:58:21 +000094 block_nr = (blk_t *) ctx->ind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000095 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000096 if (ctx->flags & BLOCK_FLAG_APPEND) {
97 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
Theodore Ts'o272631e2009-06-01 16:15:40 -040098 blk64 = *block_nr;
99 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400100 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000101 ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400102 *block_nr = blk64;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000103 changed |= flags;
104 if (flags & BLOCK_ABORT) {
105 ret |= BLOCK_ABORT;
106 break;
107 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000108 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000109 }
110 } else {
111 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
112 if (*block_nr == 0)
Theodore Ts'o94ded6c2010-12-16 19:34:24 -0500113 goto skip_sparse;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400114 blk64 = *block_nr;
115 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400116 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000117 ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400118 *block_nr = blk64;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000119 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000120 if (flags & BLOCK_ABORT) {
121 ret |= BLOCK_ABORT;
122 break;
123 }
Theodore Ts'o94ded6c2010-12-16 19:34:24 -0500124 skip_sparse:
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000125 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000126 }
127 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500128 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500129 if (changed & BLOCK_CHANGED) {
130 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
131 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000132 if (ctx->errcode)
133 ret |= BLOCK_ERROR | BLOCK_ABORT;
134 }
135 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000136 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -0400137 !(ret & BLOCK_ABORT)) {
138 blk64 = *ind_block;
139 ret |= (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000140 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000141 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400142 *ind_block = blk64;
143 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500144 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000145 return ret;
146}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400147
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000148static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
149 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000150{
151 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000152 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000153 blk_t *block_nr;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400154 blk64_t blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000155
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000156 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000157 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
Theodore Ts'o272631e2009-06-01 16:15:40 -0400158 BLOCK_FLAG_DATA_ONLY))) {
159 blk64 = *dind_block;
160 ret = (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000161 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000162 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400163 *dind_block = blk64;
164 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500165 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000166 if (!*dind_block || (ret & BLOCK_ABORT)) {
167 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000168 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000169 }
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400170 if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) ||
Theodore Ts'of3db3561997-04-26 13:34:30 +0000171 *dind_block < ctx->fs->super->s_first_data_block) {
172 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
173 ret |= BLOCK_ERROR;
174 return ret;
175 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400176 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500177 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000178 if (ctx->errcode) {
179 ret |= BLOCK_ERROR;
180 return ret;
181 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500182
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000183 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000184 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000185 if (ctx->flags & BLOCK_FLAG_APPEND) {
186 for (i = 0; i < limit; i++, block_nr++) {
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;
191 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'o50e1e101997-04-26 13:58:21 +0000196 }
197 } else {
198 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000199 if (*block_nr == 0) {
200 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000201 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000202 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000203 flags = block_iterate_ind(block_nr,
204 *dind_block, offset,
205 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000206 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000207 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
208 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
209 break;
210 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000211 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000212 }
213 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500214 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500215 if (changed & BLOCK_CHANGED) {
216 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
217 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000218 if (ctx->errcode)
219 ret |= BLOCK_ERROR | BLOCK_ABORT;
220 }
221 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000222 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -0400223 !(ret & BLOCK_ABORT)) {
224 blk64 = *dind_block;
225 ret |= (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000226 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000227 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400228 *dind_block = blk64;
229 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500230 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000231 return ret;
232}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400233
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000234static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
235 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000236{
237 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000238 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000239 blk_t *block_nr;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400240 blk64_t blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000241
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000242 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000243 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
Theodore Ts'o272631e2009-06-01 16:15:40 -0400244 BLOCK_FLAG_DATA_ONLY))) {
245 blk64 = *tind_block;
246 ret = (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000247 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000248 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400249 *tind_block = blk64;
250 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500251 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000252 if (!*tind_block || (ret & BLOCK_ABORT)) {
253 ctx->bcount += limit*limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000254 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000255 }
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400256 if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) ||
Theodore Ts'of3db3561997-04-26 13:34:30 +0000257 *tind_block < ctx->fs->super->s_first_data_block) {
258 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
259 ret |= BLOCK_ERROR;
260 return ret;
261 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400262 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500263 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000264 if (ctx->errcode) {
265 ret |= BLOCK_ERROR;
266 return ret;
267 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500268
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000269 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000270 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000271 if (ctx->flags & BLOCK_FLAG_APPEND) {
272 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000273 flags = block_iterate_dind(block_nr,
274 *tind_block,
275 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000276 changed |= flags;
277 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
278 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
279 break;
280 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000281 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000282 }
283 } else {
284 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000285 if (*block_nr == 0) {
286 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000287 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000288 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000289 flags = block_iterate_dind(block_nr,
290 *tind_block,
291 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000292 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000293 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
294 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
295 break;
296 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000297 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000298 }
299 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500300 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500301 if (changed & BLOCK_CHANGED) {
302 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
303 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000304 if (ctx->errcode)
305 ret |= BLOCK_ERROR | BLOCK_ABORT;
306 }
307 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000308 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -0400309 !(ret & BLOCK_ABORT)) {
310 blk64 = *tind_block;
311 ret |= (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000312 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000313 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400314 *tind_block = blk64;
315 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500316 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000317 return ret;
318}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400319
Theodore Ts'o272631e2009-06-01 16:15:40 -0400320errcode_t ext2fs_block_iterate3(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000321 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000322 int flags,
323 char *block_buf,
324 int (*func)(ext2_filsys fs,
Theodore Ts'o272631e2009-06-01 16:15:40 -0400325 blk64_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +0000326 e2_blkcnt_t blockcnt,
Theodore Ts'o272631e2009-06-01 16:15:40 -0400327 blk64_t ref_blk,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000328 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000329 void *priv_data),
330 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000331{
332 int i;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400333 int r, ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000334 struct ext2_inode inode;
335 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000336 struct block_context ctx;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000337 int limit;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400338 blk64_t blk64;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000339
Theodore Ts'of3db3561997-04-26 13:34:30 +0000340 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
341
Theodore Ts'o206fea62008-02-03 22:29:16 -0500342 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
343 if (ctx.errcode)
344 return ctx.errcode;
345
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000346 /*
347 * Check to see if we need to limit large files
348 */
349 if (flags & BLOCK_FLAG_NO_LARGE) {
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000350 if (!LINUX_S_ISDIR(inode.i_mode) &&
351 (inode.i_size_high != 0))
352 return EXT2_ET_FILE_TOO_BIG;
353 }
354
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000355 limit = fs->blocksize >> 2;
356
Theodore Ts'o3839e651997-04-26 13:21:57 +0000357 ctx.fs = fs;
358 ctx.func = func;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000359 ctx.priv_data = priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000360 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000361 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000362 if (block_buf) {
363 ctx.ind_buf = block_buf;
364 } else {
Theodore Ts'oee010792007-11-09 19:01:06 -0500365 retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000366 if (retval)
367 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000368 }
369 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
370 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000371
372 /*
373 * Iterate over the HURD translator block (if present)
374 */
375 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000376 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000377 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o272631e2009-06-01 16:15:40 -0400378 blk64 = inode.osd1.hurd1.h_i_translator;
379 ret |= (*ctx.func)(fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000380 BLOCK_COUNT_TRANSLATOR,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000381 0, 0, priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400382 inode.osd1.hurd1.h_i_translator = (blk_t) blk64;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000383 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000384 goto abort_exit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500385 check_for_ro_violation_goto(&ctx, ret, abort_exit);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000386 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000387 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400388
Theodore Ts'o206fea62008-02-03 22:29:16 -0500389 if (inode.i_flags & EXT4_EXTENTS_FL) {
390 ext2_extent_handle_t handle;
391 struct ext2fs_extent extent;
Theodore Ts'o685d5442008-08-27 15:17:36 -0400392 e2_blkcnt_t blockcnt = 0;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400393 blk64_t blk, new_blk;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500394 int op = EXT2_EXTENT_ROOT;
Theodore Ts'o07f1a072009-01-19 19:30:59 -0500395 int uninit;
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400396 unsigned int j;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500397
number965284b239a2009-05-19 13:34:12 -0700398 ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500399 if (ctx.errcode)
400 goto abort_exit;
401
402 while (1) {
403 ctx.errcode = ext2fs_extent_get(handle, op, &extent);
404 if (ctx.errcode) {
Theodore Ts'o685d5442008-08-27 15:17:36 -0400405 if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
406 break;
407 ctx.errcode = 0;
408 if (!(flags & BLOCK_FLAG_APPEND))
409 break;
Theodore Ts'o8e2399d2010-03-11 12:47:41 -0500410 next_block_set:
Theodore Ts'o685d5442008-08-27 15:17:36 -0400411 blk = 0;
412 r = (*ctx.func)(fs, &blk, blockcnt,
413 0, 0, priv_data);
414 ret |= r;
415 check_for_ro_violation_goto(&ctx, ret,
416 extent_errout);
417 if (r & BLOCK_CHANGED) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400418 ctx.errcode =
Theodore Ts'o685d5442008-08-27 15:17:36 -0400419 ext2fs_extent_set_bmap(handle,
420 (blk64_t) blockcnt++,
421 (blk64_t) blk, 0);
422 if (ctx.errcode || (ret & BLOCK_ABORT))
Theodore Ts'o64987c02008-08-27 17:50:14 -0400423 break;
Theodore Ts'o8e2399d2010-03-11 12:47:41 -0500424 if (blk)
425 goto next_block_set;
Theodore Ts'o685d5442008-08-27 15:17:36 -0400426 }
Theodore Ts'o64987c02008-08-27 17:50:14 -0400427 break;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500428 }
429
430 op = EXT2_EXTENT_NEXT;
431 blk = extent.e_pblk;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400432 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
433 if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
434 continue;
435 if ((!(extent.e_flags &
436 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
437 !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
438 ((extent.e_flags &
439 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
440 (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
441 ret |= (*ctx.func)(fs, &blk,
442 -1, 0, 0, priv_data);
443 if (ret & BLOCK_CHANGED) {
Theodore Ts'o213fe922008-08-22 02:50:02 -0400444 extent.e_pblk = blk;
445 ctx.errcode =
446 ext2fs_extent_replace(handle, 0, &extent);
447 if (ctx.errcode)
Theodore Ts'o64987c02008-08-27 17:50:14 -0400448 break;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400449 }
450 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500451 continue;
452 }
Theodore Ts'o07f1a072009-01-19 19:30:59 -0500453 uninit = 0;
454 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
455 uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
Theodore Ts'od8fae3c2011-07-09 22:25:52 -0400456#if 0
457 printf("lblk %llu pblk %llu len %d blockcnt %llu\n",
458 extent.e_lblk, extent.e_pblk,
459 extent.e_len, blockcnt);
460#endif
461 if (extent.e_lblk + extent.e_len <= blockcnt)
462 continue;
463 if (extent.e_lblk > blockcnt)
464 blockcnt = extent.e_lblk;
465 j = blockcnt - extent.e_lblk;
466 blk += j;
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400467 for (blockcnt = extent.e_lblk, j = 0;
468 j < extent.e_len;
469 blk++, blockcnt++, j++) {
Theodore Ts'od7b92202008-05-27 06:59:32 -0400470 new_blk = blk;
471 r = (*ctx.func)(fs, &new_blk, blockcnt,
472 0, 0, priv_data);
473 ret |= r;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500474 check_for_ro_violation_goto(&ctx, ret,
475 extent_errout);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400476 if (r & BLOCK_CHANGED) {
477 ctx.errcode =
478 ext2fs_extent_set_bmap(handle,
479 (blk64_t) blockcnt,
Theodore Ts'o272631e2009-06-01 16:15:40 -0400480 new_blk, uninit);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400481 if (ctx.errcode)
Theodore Ts'od3a8fc52009-01-19 14:22:52 -0500482 goto extent_errout;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400483 }
Theodore Ts'o64987c02008-08-27 17:50:14 -0400484 if (ret & BLOCK_ABORT)
485 break;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500486 }
487 }
488
489 extent_errout:
490 ext2fs_extent_free(handle);
491 ret |= BLOCK_ERROR | BLOCK_ABORT;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400492 goto errout;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500493 }
494
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000495 /*
496 * Iterate over normal data blocks
497 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000498 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
Theodore Ts'o206fea62008-02-03 22:29:16 -0500499 if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o272631e2009-06-01 16:15:40 -0400500 blk64 = inode.i_block[i];
501 ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i,
502 priv_data);
503 inode.i_block[i] = (blk_t) blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000504 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000505 goto abort_exit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000506 }
507 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500508 check_for_ro_violation_goto(&ctx, ret, abort_exit);
509 if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o272631e2009-06-01 16:15:40 -0400510 ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000511 0, EXT2_IND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000512 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000513 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000514 } else
515 ctx.bcount += limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500516 if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
517 ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000518 0, EXT2_DIND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000519 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000520 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000521 } else
522 ctx.bcount += limit * limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500523 if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
524 ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000525 0, EXT2_TIND_BLOCK, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000526 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000527 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000528 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000529
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000530abort_exit:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000531 if (ret & BLOCK_CHANGED) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000532 retval = ext2fs_write_inode(fs, ino, &inode);
Theodore Ts'o9922c532009-07-18 10:02:41 -0400533 if (retval) {
534 ret |= BLOCK_ERROR;
535 ctx.errcode = retval;
536 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000537 }
Theodore Ts'od7b92202008-05-27 06:59:32 -0400538errout:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000539 if (!block_buf)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400540 ext2fs_free_mem(&ctx.ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000541
542 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
543}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000544
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000545/*
546 * Emulate the old ext2fs_block_iterate function!
547 */
548
Theodore Ts'o272631e2009-06-01 16:15:40 -0400549struct xlate64 {
550 int (*func)(ext2_filsys fs,
551 blk_t *blocknr,
552 e2_blkcnt_t blockcnt,
553 blk_t ref_blk,
554 int ref_offset,
555 void *priv_data);
556 void *real_private;
557};
558
559static int xlate64_func(ext2_filsys fs, blk64_t *blocknr,
560 e2_blkcnt_t blockcnt, blk64_t ref_blk,
561 int ref_offset, void *priv_data)
562{
563 struct xlate64 *xl = (struct xlate64 *) priv_data;
564 int ret;
565 blk_t block32 = *blocknr;
566
567 ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset,
568 xl->real_private);
569 *blocknr = block32;
570 return ret;
571}
572
573errcode_t ext2fs_block_iterate2(ext2_filsys fs,
574 ext2_ino_t ino,
575 int flags,
576 char *block_buf,
577 int (*func)(ext2_filsys fs,
578 blk_t *blocknr,
579 e2_blkcnt_t blockcnt,
580 blk_t ref_blk,
581 int ref_offset,
582 void *priv_data),
583 void *priv_data)
584{
585 struct xlate64 xl;
586
587 xl.real_private = priv_data;
588 xl.func = func;
589
590 return ext2fs_block_iterate3(fs, ino, flags, block_buf,
591 xlate64_func, &xl);
592}
593
594
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000595struct xlate {
596 int (*func)(ext2_filsys fs,
597 blk_t *blocknr,
598 int bcount,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000599 void *priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000600 void *real_private;
601};
602
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000603#ifdef __TURBOC__
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000604 #pragma argsused
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000605#endif
Theodore Ts'o03673db1998-06-10 20:39:43 +0000606static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
Theodore Ts'o54434922003-12-07 01:28:50 -0500607 blk_t ref_block EXT2FS_ATTR((unused)),
608 int ref_offset EXT2FS_ATTR((unused)),
609 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000610{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000611 struct xlate *xl = (struct xlate *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000612
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000613 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000614}
615
616errcode_t ext2fs_block_iterate(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000617 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000618 int flags,
619 char *block_buf,
620 int (*func)(ext2_filsys fs,
621 blk_t *blocknr,
622 int blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000623 void *priv_data),
624 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000625{
626 struct xlate xl;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400627
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000628 xl.real_private = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000629 xl.func = func;
630
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000631 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000632 block_buf, xlate_func, &xl);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000633}
634