blob: b8c68798bd6c74ff1c3785c7b976f0082fac1086 [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
Theodore Ts'od1154eb2011-09-18 17:34:37 -040012#include "config.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000013#include <stdio.h>
14#include <string.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000015#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000016#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000017#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000018
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000019#include "ext2_fs.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000020#include "ext2fs.h"
21
22struct block_context {
23 ext2_filsys fs;
24 int (*func)(ext2_filsys fs,
Theodore Ts'o272631e2009-06-01 16:15:40 -040025 blk64_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +000026 e2_blkcnt_t bcount,
Theodore Ts'o272631e2009-06-01 16:15:40 -040027 blk64_t ref_blk,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000028 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000029 void *priv_data);
Theodore Ts'o03673db1998-06-10 20:39:43 +000030 e2_blkcnt_t bcount;
Theodore Ts'o3839e651997-04-26 13:21:57 +000031 int bsize;
32 int flags;
33 errcode_t errcode;
34 char *ind_buf;
35 char *dind_buf;
36 char *tind_buf;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000037 void *priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +000038};
39
Theodore Ts'o206fea62008-02-03 22:29:16 -050040#define check_for_ro_violation_return(ctx, ret) \
Theodore Ts'o357d1862008-02-02 21:26:54 -050041 do { \
42 if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
43 ((ret) & BLOCK_CHANGED)) { \
44 (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
Theodore Ts'o206fea62008-02-03 22:29:16 -050045 ret |= BLOCK_ABORT | BLOCK_ERROR; \
46 return ret; \
Theodore Ts'o357d1862008-02-02 21:26:54 -050047 } \
48 } while (0)
Theodore Ts'o206fea62008-02-03 22:29:16 -050049
50#define check_for_ro_violation_goto(ctx, ret, label) \
51 do { \
52 if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
53 ((ret) & BLOCK_CHANGED)) { \
54 (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
55 ret |= BLOCK_ABORT | BLOCK_ERROR; \
56 goto label; \
57 } \
58 } while (0)
Theodore Ts'o357d1862008-02-02 21:26:54 -050059
Theodore Ts'o21c84b71997-04-29 16:15:03 +000060static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
61 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000062{
63 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000064 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +000065 blk_t *block_nr;
Theodore Ts'o272631e2009-06-01 16:15:40 -040066 blk64_t blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +000067
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000068 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000069 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -040070 !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
71 blk64 = *ind_block;
72 ret = (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000073 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000074 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -040075 *ind_block = blk64;
76 }
Theodore Ts'o206fea62008-02-03 22:29:16 -050077 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000078 if (!*ind_block || (ret & BLOCK_ABORT)) {
79 ctx->bcount += limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +000080 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000081 }
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -040082 if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) ||
Theodore Ts'of3db3561997-04-26 13:34:30 +000083 *ind_block < ctx->fs->super->s_first_data_block) {
84 ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
85 ret |= BLOCK_ERROR;
86 return ret;
87 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -040088 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -050089 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +000090 if (ctx->errcode) {
91 ret |= BLOCK_ERROR;
92 return ret;
93 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -050094
Theodore Ts'o50e1e101997-04-26 13:58:21 +000095 block_nr = (blk_t *) ctx->ind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000096 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000097 if (ctx->flags & BLOCK_FLAG_APPEND) {
98 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
Theodore Ts'o272631e2009-06-01 16:15:40 -040099 blk64 = *block_nr;
100 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400101 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000102 ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400103 *block_nr = blk64;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000104 changed |= flags;
105 if (flags & BLOCK_ABORT) {
106 ret |= BLOCK_ABORT;
107 break;
108 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000109 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000110 }
111 } else {
112 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
113 if (*block_nr == 0)
Theodore Ts'o94ded6c2010-12-16 19:34:24 -0500114 goto skip_sparse;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400115 blk64 = *block_nr;
116 flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400117 *ind_block, offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000118 ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400119 *block_nr = blk64;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000120 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000121 if (flags & BLOCK_ABORT) {
122 ret |= BLOCK_ABORT;
123 break;
124 }
Theodore Ts'o94ded6c2010-12-16 19:34:24 -0500125 skip_sparse:
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000126 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000127 }
128 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500129 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500130 if (changed & BLOCK_CHANGED) {
131 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
132 ctx->ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000133 if (ctx->errcode)
134 ret |= BLOCK_ERROR | BLOCK_ABORT;
135 }
136 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000137 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -0400138 !(ret & BLOCK_ABORT)) {
139 blk64 = *ind_block;
140 ret |= (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000141 BLOCK_COUNT_IND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000142 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400143 *ind_block = blk64;
144 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500145 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000146 return ret;
147}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400148
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000149static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
150 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000151{
152 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000153 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000154 blk_t *block_nr;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400155 blk64_t blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000156
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000157 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000158 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
Theodore Ts'o272631e2009-06-01 16:15:40 -0400159 BLOCK_FLAG_DATA_ONLY))) {
160 blk64 = *dind_block;
161 ret = (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000162 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000163 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400164 *dind_block = blk64;
165 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500166 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000167 if (!*dind_block || (ret & BLOCK_ABORT)) {
168 ctx->bcount += limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000169 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000170 }
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400171 if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) ||
Theodore Ts'of3db3561997-04-26 13:34:30 +0000172 *dind_block < ctx->fs->super->s_first_data_block) {
173 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
174 ret |= BLOCK_ERROR;
175 return ret;
176 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400177 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500178 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000179 if (ctx->errcode) {
180 ret |= BLOCK_ERROR;
181 return ret;
182 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500183
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000184 block_nr = (blk_t *) ctx->dind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000185 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000186 if (ctx->flags & BLOCK_FLAG_APPEND) {
187 for (i = 0; i < limit; i++, block_nr++) {
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;
192 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'o50e1e101997-04-26 13:58:21 +0000197 }
198 } else {
199 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000200 if (*block_nr == 0) {
201 ctx->bcount += limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000202 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000203 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000204 flags = block_iterate_ind(block_nr,
205 *dind_block, offset,
206 ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000207 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000208 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
209 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
210 break;
211 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000212 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000213 }
214 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500215 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500216 if (changed & BLOCK_CHANGED) {
217 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
218 ctx->dind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000219 if (ctx->errcode)
220 ret |= BLOCK_ERROR | BLOCK_ABORT;
221 }
222 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000223 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -0400224 !(ret & BLOCK_ABORT)) {
225 blk64 = *dind_block;
226 ret |= (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000227 BLOCK_COUNT_DIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000228 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400229 *dind_block = blk64;
230 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500231 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000232 return ret;
233}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400234
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000235static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
236 int ref_offset, struct block_context *ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000237{
238 int ret = 0, changed = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000239 int i, flags, limit, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000240 blk_t *block_nr;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400241 blk64_t blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000242
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000243 limit = ctx->fs->blocksize >> 2;
Theodore Ts'o06af47f2000-04-03 13:51:00 +0000244 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
Theodore Ts'o272631e2009-06-01 16:15:40 -0400245 BLOCK_FLAG_DATA_ONLY))) {
246 blk64 = *tind_block;
247 ret = (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000248 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000249 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400250 *tind_block = blk64;
251 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500252 check_for_ro_violation_return(ctx, ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000253 if (!*tind_block || (ret & BLOCK_ABORT)) {
254 ctx->bcount += limit*limit*limit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000255 return ret;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000256 }
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400257 if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) ||
Theodore Ts'of3db3561997-04-26 13:34:30 +0000258 *tind_block < ctx->fs->super->s_first_data_block) {
259 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
260 ret |= BLOCK_ERROR;
261 return ret;
262 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400263 ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500264 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000265 if (ctx->errcode) {
266 ret |= BLOCK_ERROR;
267 return ret;
268 }
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500269
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000270 block_nr = (blk_t *) ctx->tind_buf;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000271 offset = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000272 if (ctx->flags & BLOCK_FLAG_APPEND) {
273 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000274 flags = block_iterate_dind(block_nr,
275 *tind_block,
276 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000277 changed |= flags;
278 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
279 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
280 break;
281 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000282 offset += sizeof(blk_t);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000283 }
284 } else {
285 for (i = 0; i < limit; i++, block_nr++) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000286 if (*block_nr == 0) {
287 ctx->bcount += limit*limit;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000288 continue;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000289 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000290 flags = block_iterate_dind(block_nr,
291 *tind_block,
292 offset, ctx);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000293 changed |= flags;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000294 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
295 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
296 break;
297 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000298 offset += sizeof(blk_t);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000299 }
300 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500301 check_for_ro_violation_return(ctx, changed);
Theodore Ts'odc8ce342005-01-06 00:04:24 -0500302 if (changed & BLOCK_CHANGED) {
303 ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
304 ctx->tind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000305 if (ctx->errcode)
306 ret |= BLOCK_ERROR | BLOCK_ABORT;
307 }
308 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000309 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
Theodore Ts'o272631e2009-06-01 16:15:40 -0400310 !(ret & BLOCK_ABORT)) {
311 blk64 = *tind_block;
312 ret |= (*ctx->func)(ctx->fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000313 BLOCK_COUNT_TIND, ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000314 ref_offset, ctx->priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400315 *tind_block = blk64;
316 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500317 check_for_ro_violation_return(ctx, ret);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000318 return ret;
319}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400320
Theodore Ts'o272631e2009-06-01 16:15:40 -0400321errcode_t ext2fs_block_iterate3(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000322 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000323 int flags,
324 char *block_buf,
325 int (*func)(ext2_filsys fs,
Theodore Ts'o272631e2009-06-01 16:15:40 -0400326 blk64_t *blocknr,
Theodore Ts'o03673db1998-06-10 20:39:43 +0000327 e2_blkcnt_t blockcnt,
Theodore Ts'o272631e2009-06-01 16:15:40 -0400328 blk64_t ref_blk,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000329 int ref_offset,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000330 void *priv_data),
331 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000332{
333 int i;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400334 int r, ret = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000335 struct ext2_inode inode;
336 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000337 struct block_context ctx;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000338 int limit;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400339 blk64_t blk64;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000340
Theodore Ts'of3db3561997-04-26 13:34:30 +0000341 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
342
Theodore Ts'o206fea62008-02-03 22:29:16 -0500343 ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
344 if (ctx.errcode)
345 return ctx.errcode;
346
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000347 /*
348 * Check to see if we need to limit large files
349 */
350 if (flags & BLOCK_FLAG_NO_LARGE) {
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000351 if (!LINUX_S_ISDIR(inode.i_mode) &&
352 (inode.i_size_high != 0))
353 return EXT2_ET_FILE_TOO_BIG;
354 }
355
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000356 limit = fs->blocksize >> 2;
357
Theodore Ts'o3839e651997-04-26 13:21:57 +0000358 ctx.fs = fs;
359 ctx.func = func;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000360 ctx.priv_data = priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000361 ctx.flags = flags;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000362 ctx.bcount = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000363 if (block_buf) {
364 ctx.ind_buf = block_buf;
365 } else {
Theodore Ts'oee010792007-11-09 19:01:06 -0500366 retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000367 if (retval)
368 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000369 }
370 ctx.dind_buf = ctx.ind_buf + fs->blocksize;
371 ctx.tind_buf = ctx.dind_buf + fs->blocksize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000372
373 /*
374 * Iterate over the HURD translator block (if present)
375 */
376 if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
Theodore Ts'o5c576471997-04-29 15:29:49 +0000377 !(flags & BLOCK_FLAG_DATA_ONLY)) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000378 if (inode.osd1.hurd1.h_i_translator) {
Theodore Ts'o272631e2009-06-01 16:15:40 -0400379 blk64 = inode.osd1.hurd1.h_i_translator;
380 ret |= (*ctx.func)(fs, &blk64,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000381 BLOCK_COUNT_TRANSLATOR,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000382 0, 0, priv_data);
Theodore Ts'o272631e2009-06-01 16:15:40 -0400383 inode.osd1.hurd1.h_i_translator = (blk_t) blk64;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000384 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000385 goto abort_exit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500386 check_for_ro_violation_goto(&ctx, ret, abort_exit);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000387 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000388 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400389
Theodore Ts'o206fea62008-02-03 22:29:16 -0500390 if (inode.i_flags & EXT4_EXTENTS_FL) {
391 ext2_extent_handle_t handle;
Theodore Ts'obeb388a2012-06-12 00:27:39 -0400392 struct ext2fs_extent extent, next;
Theodore Ts'o685d5442008-08-27 15:17:36 -0400393 e2_blkcnt_t blockcnt = 0;
Theodore Ts'o272631e2009-06-01 16:15:40 -0400394 blk64_t blk, new_blk;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500395 int op = EXT2_EXTENT_ROOT;
Theodore Ts'o07f1a072009-01-19 19:30:59 -0500396 int uninit;
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400397 unsigned int j;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500398
number965284b239a2009-05-19 13:34:12 -0700399 ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500400 if (ctx.errcode)
401 goto abort_exit;
402
403 while (1) {
Theodore Ts'obeb388a2012-06-12 00:27:39 -0400404 if (op == EXT2_EXTENT_CURRENT)
405 ctx.errcode = 0;
406 else
407 ctx.errcode = ext2fs_extent_get(handle, op,
408 &extent);
Theodore Ts'o206fea62008-02-03 22:29:16 -0500409 if (ctx.errcode) {
Theodore Ts'o685d5442008-08-27 15:17:36 -0400410 if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
411 break;
412 ctx.errcode = 0;
413 if (!(flags & BLOCK_FLAG_APPEND))
414 break;
Theodore Ts'o8e2399d2010-03-11 12:47:41 -0500415 next_block_set:
Theodore Ts'o685d5442008-08-27 15:17:36 -0400416 blk = 0;
417 r = (*ctx.func)(fs, &blk, blockcnt,
418 0, 0, priv_data);
419 ret |= r;
420 check_for_ro_violation_goto(&ctx, ret,
Theodore Ts'oa2042362012-02-15 17:25:32 -0500421 extent_done);
Theodore Ts'o685d5442008-08-27 15:17:36 -0400422 if (r & BLOCK_CHANGED) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400423 ctx.errcode =
Theodore Ts'o685d5442008-08-27 15:17:36 -0400424 ext2fs_extent_set_bmap(handle,
425 (blk64_t) blockcnt++,
426 (blk64_t) blk, 0);
427 if (ctx.errcode || (ret & BLOCK_ABORT))
Theodore Ts'o64987c02008-08-27 17:50:14 -0400428 break;
Theodore Ts'o8e2399d2010-03-11 12:47:41 -0500429 if (blk)
430 goto next_block_set;
Theodore Ts'o685d5442008-08-27 15:17:36 -0400431 }
Theodore Ts'o64987c02008-08-27 17:50:14 -0400432 break;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500433 }
434
435 op = EXT2_EXTENT_NEXT;
436 blk = extent.e_pblk;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400437 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
438 if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
439 continue;
440 if ((!(extent.e_flags &
441 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
442 !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
443 ((extent.e_flags &
444 EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
445 (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
446 ret |= (*ctx.func)(fs, &blk,
447 -1, 0, 0, priv_data);
448 if (ret & BLOCK_CHANGED) {
Theodore Ts'o213fe922008-08-22 02:50:02 -0400449 extent.e_pblk = blk;
450 ctx.errcode =
451 ext2fs_extent_replace(handle, 0, &extent);
452 if (ctx.errcode)
Theodore Ts'o64987c02008-08-27 17:50:14 -0400453 break;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400454 }
Theodore Ts'oa2042362012-02-15 17:25:32 -0500455 if (ret & BLOCK_ABORT)
456 break;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400457 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500458 continue;
459 }
Theodore Ts'o07f1a072009-01-19 19:30:59 -0500460 uninit = 0;
461 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
462 uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
Theodore Ts'obeb388a2012-06-12 00:27:39 -0400463
464 /*
465 * Get the next extent before we start messing
466 * with the current extent
467 */
468 retval = ext2fs_extent_get(handle, op, &next);
469
Theodore Ts'od8fae3c2011-07-09 22:25:52 -0400470#if 0
471 printf("lblk %llu pblk %llu len %d blockcnt %llu\n",
472 extent.e_lblk, extent.e_pblk,
473 extent.e_len, blockcnt);
474#endif
Theodore Ts'oe48bf252013-05-19 18:50:10 -0400475 if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt)
Theodore Ts'od8fae3c2011-07-09 22:25:52 -0400476 continue;
Theodore Ts'oe48bf252013-05-19 18:50:10 -0400477 if (extent.e_lblk > (blk64_t) blockcnt)
Theodore Ts'od8fae3c2011-07-09 22:25:52 -0400478 blockcnt = extent.e_lblk;
479 j = blockcnt - extent.e_lblk;
480 blk += j;
Theodore Ts'o2d328bb2008-03-17 23:17:13 -0400481 for (blockcnt = extent.e_lblk, j = 0;
482 j < extent.e_len;
483 blk++, blockcnt++, j++) {
Theodore Ts'od7b92202008-05-27 06:59:32 -0400484 new_blk = blk;
485 r = (*ctx.func)(fs, &new_blk, blockcnt,
486 0, 0, priv_data);
487 ret |= r;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500488 check_for_ro_violation_goto(&ctx, ret,
Theodore Ts'oa2042362012-02-15 17:25:32 -0500489 extent_done);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400490 if (r & BLOCK_CHANGED) {
491 ctx.errcode =
492 ext2fs_extent_set_bmap(handle,
493 (blk64_t) blockcnt,
Theodore Ts'o272631e2009-06-01 16:15:40 -0400494 new_blk, uninit);
Theodore Ts'od7b92202008-05-27 06:59:32 -0400495 if (ctx.errcode)
Theodore Ts'oa2042362012-02-15 17:25:32 -0500496 goto extent_done;
Theodore Ts'od7b92202008-05-27 06:59:32 -0400497 }
Theodore Ts'o64987c02008-08-27 17:50:14 -0400498 if (ret & BLOCK_ABORT)
Theodore Ts'oa2042362012-02-15 17:25:32 -0500499 goto extent_done;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500500 }
Theodore Ts'obeb388a2012-06-12 00:27:39 -0400501 if (retval == 0) {
502 extent = next;
503 op = EXT2_EXTENT_CURRENT;
504 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500505 }
506
Theodore Ts'oa2042362012-02-15 17:25:32 -0500507 extent_done:
Theodore Ts'o206fea62008-02-03 22:29:16 -0500508 ext2fs_extent_free(handle);
Theodore Ts'oa2042362012-02-15 17:25:32 -0500509 ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */
Theodore Ts'od7b92202008-05-27 06:59:32 -0400510 goto errout;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500511 }
512
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000513 /*
514 * Iterate over normal data blocks
515 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000516 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
Theodore Ts'o206fea62008-02-03 22:29:16 -0500517 if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o272631e2009-06-01 16:15:40 -0400518 blk64 = inode.i_block[i];
519 ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i,
520 priv_data);
521 inode.i_block[i] = (blk_t) blk64;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000522 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000523 goto abort_exit;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000524 }
525 }
Theodore Ts'o206fea62008-02-03 22:29:16 -0500526 check_for_ro_violation_goto(&ctx, ret, abort_exit);
527 if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
Theodore Ts'o272631e2009-06-01 16:15:40 -0400528 ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000529 0, EXT2_IND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000530 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000531 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000532 } else
533 ctx.bcount += limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500534 if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
535 ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000536 0, EXT2_DIND_BLOCK, &ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000537 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000538 goto abort_exit;
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000539 } else
540 ctx.bcount += limit * limit;
Theodore Ts'o206fea62008-02-03 22:29:16 -0500541 if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
542 ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000543 0, EXT2_TIND_BLOCK, &ctx);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000544 if (ret & BLOCK_ABORT)
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000545 goto abort_exit;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000546 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000547
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000548abort_exit:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000549 if (ret & BLOCK_CHANGED) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000550 retval = ext2fs_write_inode(fs, ino, &inode);
Theodore Ts'o9922c532009-07-18 10:02:41 -0400551 if (retval) {
552 ret |= BLOCK_ERROR;
553 ctx.errcode = retval;
554 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000555 }
Theodore Ts'od7b92202008-05-27 06:59:32 -0400556errout:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000557 if (!block_buf)
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400558 ext2fs_free_mem(&ctx.ind_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000559
560 return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
561}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000562
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000563/*
564 * Emulate the old ext2fs_block_iterate function!
565 */
566
Theodore Ts'o272631e2009-06-01 16:15:40 -0400567struct xlate64 {
568 int (*func)(ext2_filsys fs,
569 blk_t *blocknr,
570 e2_blkcnt_t blockcnt,
571 blk_t ref_blk,
572 int ref_offset,
573 void *priv_data);
574 void *real_private;
575};
576
577static int xlate64_func(ext2_filsys fs, blk64_t *blocknr,
578 e2_blkcnt_t blockcnt, blk64_t ref_blk,
579 int ref_offset, void *priv_data)
580{
581 struct xlate64 *xl = (struct xlate64 *) priv_data;
582 int ret;
583 blk_t block32 = *blocknr;
584
585 ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset,
586 xl->real_private);
587 *blocknr = block32;
588 return ret;
589}
590
591errcode_t ext2fs_block_iterate2(ext2_filsys fs,
592 ext2_ino_t ino,
593 int flags,
594 char *block_buf,
595 int (*func)(ext2_filsys fs,
596 blk_t *blocknr,
597 e2_blkcnt_t blockcnt,
598 blk_t ref_blk,
599 int ref_offset,
600 void *priv_data),
601 void *priv_data)
602{
603 struct xlate64 xl;
604
605 xl.real_private = priv_data;
606 xl.func = func;
607
608 return ext2fs_block_iterate3(fs, ino, flags, block_buf,
609 xlate64_func, &xl);
610}
611
612
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000613struct xlate {
614 int (*func)(ext2_filsys fs,
615 blk_t *blocknr,
616 int bcount,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000617 void *priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000618 void *real_private;
619};
620
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000621#ifdef __TURBOC__
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000622 #pragma argsused
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000623#endif
Theodore Ts'o03673db1998-06-10 20:39:43 +0000624static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
Theodore Ts'o54434922003-12-07 01:28:50 -0500625 blk_t ref_block EXT2FS_ATTR((unused)),
626 int ref_offset EXT2FS_ATTR((unused)),
627 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000628{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000629 struct xlate *xl = (struct xlate *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000630
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000631 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000632}
633
634errcode_t ext2fs_block_iterate(ext2_filsys fs,
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000635 ext2_ino_t ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000636 int flags,
637 char *block_buf,
638 int (*func)(ext2_filsys fs,
639 blk_t *blocknr,
640 int blockcnt,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000641 void *priv_data),
642 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000643{
644 struct xlate xl;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400645
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000646 xl.real_private = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000647 xl.func = func;
648
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000649 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000650 block_buf, xlate_func, &xl);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000651}
652