]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * block.c --- iterate over all blocks in an inode | |
efc6f628 | 3 | * |
21c84b71 TT |
4 | * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. |
5 | * | |
6 | * %Begin-Header% | |
543547a5 TT |
7 | * This file may be redistributed under the terms of the GNU Library |
8 | * General Public License, version 2. | |
21c84b71 | 9 | * %End-Header% |
3839e657 TT |
10 | */ |
11 | ||
d1154eb4 | 12 | #include "config.h" |
3839e657 TT |
13 | #include <stdio.h> |
14 | #include <string.h> | |
4cbe8af4 | 15 | #if HAVE_UNISTD_H |
3839e657 | 16 | #include <unistd.h> |
4cbe8af4 | 17 | #endif |
f3db3566 | 18 | |
b5abe6fa | 19 | #include "ext2_fs.h" |
3839e657 TT |
20 | #include "ext2fs.h" |
21 | ||
22 | struct block_context { | |
23 | ext2_filsys fs; | |
24 | int (*func)(ext2_filsys fs, | |
272631e4 | 25 | blk64_t *blocknr, |
03673dbb | 26 | e2_blkcnt_t bcount, |
272631e4 | 27 | blk64_t ref_blk, |
21c84b71 | 28 | int ref_offset, |
b5abe6fa | 29 | void *priv_data); |
03673dbb | 30 | e2_blkcnt_t bcount; |
3839e657 TT |
31 | int bsize; |
32 | int flags; | |
33 | errcode_t errcode; | |
34 | char *ind_buf; | |
35 | char *dind_buf; | |
36 | char *tind_buf; | |
b5abe6fa | 37 | void *priv_data; |
3839e657 TT |
38 | }; |
39 | ||
206fea69 | 40 | #define check_for_ro_violation_return(ctx, ret) \ |
357d1863 TT |
41 | do { \ |
42 | if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \ | |
43 | ((ret) & BLOCK_CHANGED)) { \ | |
44 | (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \ | |
206fea69 TT |
45 | ret |= BLOCK_ABORT | BLOCK_ERROR; \ |
46 | return ret; \ | |
47 | } \ | |
48 | } while (0) | |
49 | ||
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; \ | |
357d1863 TT |
57 | } \ |
58 | } while (0) | |
357d1863 | 59 | |
21c84b71 TT |
60 | static int block_iterate_ind(blk_t *ind_block, blk_t ref_block, |
61 | int ref_offset, struct block_context *ctx) | |
3839e657 TT |
62 | { |
63 | int ret = 0, changed = 0; | |
21c84b71 | 64 | int i, flags, limit, offset; |
3839e657 | 65 | blk_t *block_nr; |
272631e4 | 66 | blk64_t blk64; |
3839e657 | 67 | |
a29f4d30 | 68 | limit = ctx->fs->blocksize >> 2; |
1e3472c5 | 69 | if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && |
272631e4 TT |
70 | !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) { |
71 | blk64 = *ind_block; | |
72 | ret = (*ctx->func)(ctx->fs, &blk64, | |
21c84b71 | 73 | BLOCK_COUNT_IND, ref_block, |
b5abe6fa | 74 | ref_offset, ctx->priv_data); |
272631e4 TT |
75 | *ind_block = blk64; |
76 | } | |
206fea69 | 77 | check_for_ro_violation_return(ctx, ret); |
a29f4d30 TT |
78 | if (!*ind_block || (ret & BLOCK_ABORT)) { |
79 | ctx->bcount += limit; | |
3839e657 | 80 | return ret; |
a29f4d30 | 81 | } |
4efbac6f | 82 | if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) || |
f3db3566 TT |
83 | *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 | } | |
efc6f628 | 88 | ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block, |
dc8ce346 | 89 | ctx->ind_buf); |
3839e657 TT |
90 | if (ctx->errcode) { |
91 | ret |= BLOCK_ERROR; | |
92 | return ret; | |
93 | } | |
dc8ce346 | 94 | |
50e1e10f | 95 | block_nr = (blk_t *) ctx->ind_buf; |
21c84b71 | 96 | offset = 0; |
50e1e10f TT |
97 | if (ctx->flags & BLOCK_FLAG_APPEND) { |
98 | for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { | |
272631e4 TT |
99 | blk64 = *block_nr; |
100 | flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount, | |
efc6f628 | 101 | *ind_block, offset, |
b5abe6fa | 102 | ctx->priv_data); |
272631e4 | 103 | *block_nr = blk64; |
50e1e10f TT |
104 | changed |= flags; |
105 | if (flags & BLOCK_ABORT) { | |
106 | ret |= BLOCK_ABORT; | |
107 | break; | |
108 | } | |
21c84b71 | 109 | offset += sizeof(blk_t); |
50e1e10f TT |
110 | } |
111 | } else { | |
112 | for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { | |
113 | if (*block_nr == 0) | |
94ded6c1 | 114 | goto skip_sparse; |
272631e4 TT |
115 | blk64 = *block_nr; |
116 | flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount, | |
efc6f628 | 117 | *ind_block, offset, |
b5abe6fa | 118 | ctx->priv_data); |
272631e4 | 119 | *block_nr = blk64; |
50e1e10f | 120 | changed |= flags; |
3839e657 TT |
121 | if (flags & BLOCK_ABORT) { |
122 | ret |= BLOCK_ABORT; | |
123 | break; | |
124 | } | |
94ded6c1 | 125 | skip_sparse: |
21c84b71 | 126 | offset += sizeof(blk_t); |
3839e657 TT |
127 | } |
128 | } | |
206fea69 | 129 | check_for_ro_violation_return(ctx, changed); |
dc8ce346 TT |
130 | if (changed & BLOCK_CHANGED) { |
131 | ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block, | |
132 | ctx->ind_buf); | |
3839e657 TT |
133 | if (ctx->errcode) |
134 | ret |= BLOCK_ERROR | BLOCK_ABORT; | |
135 | } | |
136 | if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && | |
1e3472c5 | 137 | !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && |
272631e4 TT |
138 | !(ret & BLOCK_ABORT)) { |
139 | blk64 = *ind_block; | |
140 | ret |= (*ctx->func)(ctx->fs, &blk64, | |
21c84b71 | 141 | BLOCK_COUNT_IND, ref_block, |
b5abe6fa | 142 | ref_offset, ctx->priv_data); |
272631e4 TT |
143 | *ind_block = blk64; |
144 | } | |
206fea69 | 145 | check_for_ro_violation_return(ctx, ret); |
3839e657 TT |
146 | return ret; |
147 | } | |
efc6f628 | 148 | |
21c84b71 TT |
149 | static int block_iterate_dind(blk_t *dind_block, blk_t ref_block, |
150 | int ref_offset, struct block_context *ctx) | |
3839e657 TT |
151 | { |
152 | int ret = 0, changed = 0; | |
21c84b71 | 153 | int i, flags, limit, offset; |
3839e657 | 154 | blk_t *block_nr; |
272631e4 | 155 | blk64_t blk64; |
3839e657 | 156 | |
a29f4d30 | 157 | limit = ctx->fs->blocksize >> 2; |
06af47f0 | 158 | if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | |
272631e4 TT |
159 | BLOCK_FLAG_DATA_ONLY))) { |
160 | blk64 = *dind_block; | |
161 | ret = (*ctx->func)(ctx->fs, &blk64, | |
21c84b71 | 162 | BLOCK_COUNT_DIND, ref_block, |
b5abe6fa | 163 | ref_offset, ctx->priv_data); |
272631e4 TT |
164 | *dind_block = blk64; |
165 | } | |
206fea69 | 166 | check_for_ro_violation_return(ctx, ret); |
a29f4d30 TT |
167 | if (!*dind_block || (ret & BLOCK_ABORT)) { |
168 | ctx->bcount += limit*limit; | |
3839e657 | 169 | return ret; |
a29f4d30 | 170 | } |
4efbac6f | 171 | if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) || |
f3db3566 TT |
172 | *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 | } | |
efc6f628 | 177 | ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block, |
dc8ce346 | 178 | ctx->dind_buf); |
3839e657 TT |
179 | if (ctx->errcode) { |
180 | ret |= BLOCK_ERROR; | |
181 | return ret; | |
182 | } | |
dc8ce346 | 183 | |
50e1e10f | 184 | block_nr = (blk_t *) ctx->dind_buf; |
21c84b71 | 185 | offset = 0; |
50e1e10f TT |
186 | if (ctx->flags & BLOCK_FLAG_APPEND) { |
187 | for (i = 0; i < limit; i++, block_nr++) { | |
21c84b71 TT |
188 | flags = block_iterate_ind(block_nr, |
189 | *dind_block, offset, | |
190 | ctx); | |
50e1e10f TT |
191 | changed |= flags; |
192 | if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { | |
193 | ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | |
194 | break; | |
195 | } | |
21c84b71 | 196 | offset += sizeof(blk_t); |
50e1e10f TT |
197 | } |
198 | } else { | |
199 | for (i = 0; i < limit; i++, block_nr++) { | |
a29f4d30 TT |
200 | if (*block_nr == 0) { |
201 | ctx->bcount += limit; | |
50e1e10f | 202 | continue; |
a29f4d30 | 203 | } |
21c84b71 TT |
204 | flags = block_iterate_ind(block_nr, |
205 | *dind_block, offset, | |
206 | ctx); | |
50e1e10f | 207 | changed |= flags; |
3839e657 TT |
208 | if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { |
209 | ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | |
210 | break; | |
211 | } | |
21c84b71 | 212 | offset += sizeof(blk_t); |
3839e657 TT |
213 | } |
214 | } | |
206fea69 | 215 | check_for_ro_violation_return(ctx, changed); |
dc8ce346 TT |
216 | if (changed & BLOCK_CHANGED) { |
217 | ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block, | |
218 | ctx->dind_buf); | |
3839e657 TT |
219 | if (ctx->errcode) |
220 | ret |= BLOCK_ERROR | BLOCK_ABORT; | |
221 | } | |
222 | if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && | |
1e3472c5 | 223 | !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && |
272631e4 TT |
224 | !(ret & BLOCK_ABORT)) { |
225 | blk64 = *dind_block; | |
226 | ret |= (*ctx->func)(ctx->fs, &blk64, | |
21c84b71 | 227 | BLOCK_COUNT_DIND, ref_block, |
b5abe6fa | 228 | ref_offset, ctx->priv_data); |
272631e4 TT |
229 | *dind_block = blk64; |
230 | } | |
206fea69 | 231 | check_for_ro_violation_return(ctx, ret); |
3839e657 TT |
232 | return ret; |
233 | } | |
efc6f628 | 234 | |
21c84b71 TT |
235 | static int block_iterate_tind(blk_t *tind_block, blk_t ref_block, |
236 | int ref_offset, struct block_context *ctx) | |
3839e657 TT |
237 | { |
238 | int ret = 0, changed = 0; | |
21c84b71 | 239 | int i, flags, limit, offset; |
3839e657 | 240 | blk_t *block_nr; |
272631e4 | 241 | blk64_t blk64; |
3839e657 | 242 | |
a29f4d30 | 243 | limit = ctx->fs->blocksize >> 2; |
06af47f0 | 244 | if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | |
272631e4 TT |
245 | BLOCK_FLAG_DATA_ONLY))) { |
246 | blk64 = *tind_block; | |
247 | ret = (*ctx->func)(ctx->fs, &blk64, | |
21c84b71 | 248 | BLOCK_COUNT_TIND, ref_block, |
b5abe6fa | 249 | ref_offset, ctx->priv_data); |
272631e4 TT |
250 | *tind_block = blk64; |
251 | } | |
206fea69 | 252 | check_for_ro_violation_return(ctx, ret); |
a29f4d30 | 253 | if (!*tind_block || (ret & BLOCK_ABORT)) { |
c8ca2397 | 254 | ctx->bcount += ((unsigned long long) limit)*limit*limit; |
3839e657 | 255 | return ret; |
a29f4d30 | 256 | } |
4efbac6f | 257 | if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) || |
f3db3566 TT |
258 | *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 | } | |
efc6f628 | 263 | ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block, |
dc8ce346 | 264 | ctx->tind_buf); |
3839e657 TT |
265 | if (ctx->errcode) { |
266 | ret |= BLOCK_ERROR; | |
267 | return ret; | |
268 | } | |
dc8ce346 | 269 | |
50e1e10f | 270 | block_nr = (blk_t *) ctx->tind_buf; |
21c84b71 | 271 | offset = 0; |
50e1e10f TT |
272 | if (ctx->flags & BLOCK_FLAG_APPEND) { |
273 | for (i = 0; i < limit; i++, block_nr++) { | |
21c84b71 TT |
274 | flags = block_iterate_dind(block_nr, |
275 | *tind_block, | |
276 | offset, ctx); | |
50e1e10f TT |
277 | changed |= flags; |
278 | if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { | |
279 | ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | |
280 | break; | |
281 | } | |
21c84b71 | 282 | offset += sizeof(blk_t); |
50e1e10f TT |
283 | } |
284 | } else { | |
285 | for (i = 0; i < limit; i++, block_nr++) { | |
a29f4d30 TT |
286 | if (*block_nr == 0) { |
287 | ctx->bcount += limit*limit; | |
50e1e10f | 288 | continue; |
a29f4d30 | 289 | } |
21c84b71 TT |
290 | flags = block_iterate_dind(block_nr, |
291 | *tind_block, | |
292 | offset, ctx); | |
50e1e10f | 293 | changed |= flags; |
3839e657 TT |
294 | if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { |
295 | ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); | |
296 | break; | |
297 | } | |
21c84b71 | 298 | offset += sizeof(blk_t); |
3839e657 TT |
299 | } |
300 | } | |
206fea69 | 301 | check_for_ro_violation_return(ctx, changed); |
dc8ce346 TT |
302 | if (changed & BLOCK_CHANGED) { |
303 | ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block, | |
304 | ctx->tind_buf); | |
3839e657 TT |
305 | if (ctx->errcode) |
306 | ret |= BLOCK_ERROR | BLOCK_ABORT; | |
307 | } | |
308 | if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && | |
1e3472c5 | 309 | !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && |
272631e4 TT |
310 | !(ret & BLOCK_ABORT)) { |
311 | blk64 = *tind_block; | |
312 | ret |= (*ctx->func)(ctx->fs, &blk64, | |
21c84b71 | 313 | BLOCK_COUNT_TIND, ref_block, |
b5abe6fa | 314 | ref_offset, ctx->priv_data); |
272631e4 TT |
315 | *tind_block = blk64; |
316 | } | |
206fea69 | 317 | check_for_ro_violation_return(ctx, ret); |
3839e657 TT |
318 | return ret; |
319 | } | |
efc6f628 | 320 | |
272631e4 | 321 | errcode_t ext2fs_block_iterate3(ext2_filsys fs, |
31dbecd4 | 322 | ext2_ino_t ino, |
21c84b71 TT |
323 | int flags, |
324 | char *block_buf, | |
325 | int (*func)(ext2_filsys fs, | |
272631e4 | 326 | blk64_t *blocknr, |
03673dbb | 327 | e2_blkcnt_t blockcnt, |
272631e4 | 328 | blk64_t ref_blk, |
21c84b71 | 329 | int ref_offset, |
b5abe6fa TT |
330 | void *priv_data), |
331 | void *priv_data) | |
3839e657 TT |
332 | { |
333 | int i; | |
d7b92206 | 334 | int r, ret = 0; |
3839e657 TT |
335 | struct ext2_inode inode; |
336 | errcode_t retval; | |
21c84b71 | 337 | struct block_context ctx; |
674a4ee1 | 338 | int limit; |
272631e4 | 339 | blk64_t blk64; |
21c84b71 | 340 | |
f3db3566 TT |
341 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
342 | ||
206fea69 TT |
343 | ctx.errcode = ext2fs_read_inode(fs, ino, &inode); |
344 | if (ctx.errcode) | |
345 | return ctx.errcode; | |
346 | ||
a7f4c635 TT |
347 | /* |
348 | * An inode with inline data has no blocks over which to | |
349 | * iterate, so return an error code indicating this fact. | |
350 | */ | |
351 | if (inode.i_flags & EXT4_INLINE_DATA_FL) | |
352 | return EXT2_ET_INLINE_DATA_CANT_ITERATE; | |
353 | ||
674a4ee1 TT |
354 | /* |
355 | * Check to see if we need to limit large files | |
356 | */ | |
357 | if (flags & BLOCK_FLAG_NO_LARGE) { | |
674a4ee1 TT |
358 | if (!LINUX_S_ISDIR(inode.i_mode) && |
359 | (inode.i_size_high != 0)) | |
360 | return EXT2_ET_FILE_TOO_BIG; | |
361 | } | |
362 | ||
674a4ee1 TT |
363 | limit = fs->blocksize >> 2; |
364 | ||
3839e657 TT |
365 | ctx.fs = fs; |
366 | ctx.func = func; | |
b5abe6fa | 367 | ctx.priv_data = priv_data; |
3839e657 | 368 | ctx.flags = flags; |
21c84b71 | 369 | ctx.bcount = 0; |
3839e657 TT |
370 | if (block_buf) { |
371 | ctx.ind_buf = block_buf; | |
372 | } else { | |
ee01079a | 373 | retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf); |
7b4e4534 TT |
374 | if (retval) |
375 | return retval; | |
3839e657 TT |
376 | } |
377 | ctx.dind_buf = ctx.ind_buf + fs->blocksize; | |
378 | ctx.tind_buf = ctx.dind_buf + fs->blocksize; | |
1e3472c5 TT |
379 | |
380 | /* | |
381 | * Iterate over the HURD translator block (if present) | |
382 | */ | |
383 | if ((fs->super->s_creator_os == EXT2_OS_HURD) && | |
5c576477 | 384 | !(flags & BLOCK_FLAG_DATA_ONLY)) { |
5c576477 | 385 | if (inode.osd1.hurd1.h_i_translator) { |
272631e4 TT |
386 | blk64 = inode.osd1.hurd1.h_i_translator; |
387 | ret |= (*ctx.func)(fs, &blk64, | |
21c84b71 | 388 | BLOCK_COUNT_TRANSLATOR, |
b5abe6fa | 389 | 0, 0, priv_data); |
272631e4 | 390 | inode.osd1.hurd1.h_i_translator = (blk_t) blk64; |
5c576477 | 391 | if (ret & BLOCK_ABORT) |
31dbecd4 | 392 | goto abort_exit; |
206fea69 | 393 | check_for_ro_violation_goto(&ctx, ret, abort_exit); |
5c576477 | 394 | } |
1e3472c5 | 395 | } |
efc6f628 | 396 | |
206fea69 TT |
397 | if (inode.i_flags & EXT4_EXTENTS_FL) { |
398 | ext2_extent_handle_t handle; | |
beb388a4 | 399 | struct ext2fs_extent extent, next; |
685d544e | 400 | e2_blkcnt_t blockcnt = 0; |
272631e4 | 401 | blk64_t blk, new_blk; |
206fea69 | 402 | int op = EXT2_EXTENT_ROOT; |
07f1a070 | 403 | int uninit; |
2d328bb7 | 404 | unsigned int j; |
206fea69 | 405 | |
84b239ae | 406 | ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle); |
206fea69 TT |
407 | if (ctx.errcode) |
408 | goto abort_exit; | |
409 | ||
410 | while (1) { | |
beb388a4 TT |
411 | if (op == EXT2_EXTENT_CURRENT) |
412 | ctx.errcode = 0; | |
413 | else | |
414 | ctx.errcode = ext2fs_extent_get(handle, op, | |
415 | &extent); | |
206fea69 | 416 | if (ctx.errcode) { |
685d544e TT |
417 | if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT) |
418 | break; | |
419 | ctx.errcode = 0; | |
420 | if (!(flags & BLOCK_FLAG_APPEND)) | |
421 | break; | |
8e2399d5 | 422 | next_block_set: |
685d544e TT |
423 | blk = 0; |
424 | r = (*ctx.func)(fs, &blk, blockcnt, | |
425 | 0, 0, priv_data); | |
426 | ret |= r; | |
427 | check_for_ro_violation_goto(&ctx, ret, | |
a204236e | 428 | extent_done); |
685d544e | 429 | if (r & BLOCK_CHANGED) { |
efc6f628 | 430 | ctx.errcode = |
685d544e TT |
431 | ext2fs_extent_set_bmap(handle, |
432 | (blk64_t) blockcnt++, | |
433 | (blk64_t) blk, 0); | |
434 | if (ctx.errcode || (ret & BLOCK_ABORT)) | |
64987c05 | 435 | break; |
8e2399d5 TT |
436 | if (blk) |
437 | goto next_block_set; | |
685d544e | 438 | } |
64987c05 | 439 | break; |
206fea69 TT |
440 | } |
441 | ||
442 | op = EXT2_EXTENT_NEXT; | |
443 | blk = extent.e_pblk; | |
d7b92206 TT |
444 | if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { |
445 | if (ctx.flags & BLOCK_FLAG_DATA_ONLY) | |
446 | continue; | |
447 | if ((!(extent.e_flags & | |
448 | EXT2_EXTENT_FLAGS_SECOND_VISIT) && | |
449 | !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) || | |
450 | ((extent.e_flags & | |
451 | EXT2_EXTENT_FLAGS_SECOND_VISIT) && | |
452 | (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) { | |
453 | ret |= (*ctx.func)(fs, &blk, | |
454 | -1, 0, 0, priv_data); | |
455 | if (ret & BLOCK_CHANGED) { | |
213fe928 TT |
456 | extent.e_pblk = blk; |
457 | ctx.errcode = | |
458 | ext2fs_extent_replace(handle, 0, &extent); | |
459 | if (ctx.errcode) | |
64987c05 | 460 | break; |
d7b92206 | 461 | } |
a204236e TT |
462 | if (ret & BLOCK_ABORT) |
463 | break; | |
d7b92206 | 464 | } |
206fea69 TT |
465 | continue; |
466 | } | |
07f1a070 TT |
467 | uninit = 0; |
468 | if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) | |
469 | uninit = EXT2_EXTENT_SET_BMAP_UNINIT; | |
beb388a4 TT |
470 | |
471 | /* | |
472 | * Get the next extent before we start messing | |
473 | * with the current extent | |
474 | */ | |
475 | retval = ext2fs_extent_get(handle, op, &next); | |
476 | ||
d8fae3cf TT |
477 | #if 0 |
478 | printf("lblk %llu pblk %llu len %d blockcnt %llu\n", | |
479 | extent.e_lblk, extent.e_pblk, | |
480 | extent.e_len, blockcnt); | |
481 | #endif | |
e48bf256 | 482 | if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt) |
d8fae3cf | 483 | continue; |
e48bf256 | 484 | if (extent.e_lblk > (blk64_t) blockcnt) |
d8fae3cf TT |
485 | blockcnt = extent.e_lblk; |
486 | j = blockcnt - extent.e_lblk; | |
487 | blk += j; | |
2d328bb7 TT |
488 | for (blockcnt = extent.e_lblk, j = 0; |
489 | j < extent.e_len; | |
490 | blk++, blockcnt++, j++) { | |
d7b92206 TT |
491 | new_blk = blk; |
492 | r = (*ctx.func)(fs, &new_blk, blockcnt, | |
493 | 0, 0, priv_data); | |
494 | ret |= r; | |
206fea69 | 495 | check_for_ro_violation_goto(&ctx, ret, |
a204236e | 496 | extent_done); |
d7b92206 TT |
497 | if (r & BLOCK_CHANGED) { |
498 | ctx.errcode = | |
499 | ext2fs_extent_set_bmap(handle, | |
500 | (blk64_t) blockcnt, | |
272631e4 | 501 | new_blk, uninit); |
d7b92206 | 502 | if (ctx.errcode) |
a204236e | 503 | goto extent_done; |
206fea69 | 504 | } |
64987c05 | 505 | if (ret & BLOCK_ABORT) |
a204236e | 506 | goto extent_done; |
206fea69 | 507 | } |
beb388a4 TT |
508 | if (retval == 0) { |
509 | extent = next; | |
510 | op = EXT2_EXTENT_CURRENT; | |
511 | } | |
206fea69 TT |
512 | } |
513 | ||
a204236e | 514 | extent_done: |
206fea69 | 515 | ext2fs_extent_free(handle); |
a204236e | 516 | ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */ |
d7b92206 | 517 | goto errout; |
206fea69 TT |
518 | } |
519 | ||
1e3472c5 TT |
520 | /* |
521 | * Iterate over normal data blocks | |
522 | */ | |
3839e657 | 523 | for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) { |
206fea69 | 524 | if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) { |
272631e4 TT |
525 | blk64 = inode.i_block[i]; |
526 | ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i, | |
527 | priv_data); | |
528 | inode.i_block[i] = (blk_t) blk64; | |
3839e657 | 529 | if (ret & BLOCK_ABORT) |
31dbecd4 | 530 | goto abort_exit; |
3839e657 TT |
531 | } |
532 | } | |
206fea69 TT |
533 | check_for_ro_violation_goto(&ctx, ret, abort_exit); |
534 | if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { | |
272631e4 | 535 | ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK], |
36a43d67 | 536 | 0, EXT2_IND_BLOCK, &ctx); |
3839e657 | 537 | if (ret & BLOCK_ABORT) |
31dbecd4 | 538 | goto abort_exit; |
674a4ee1 TT |
539 | } else |
540 | ctx.bcount += limit; | |
206fea69 TT |
541 | if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { |
542 | ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK], | |
36a43d67 | 543 | 0, EXT2_DIND_BLOCK, &ctx); |
3839e657 | 544 | if (ret & BLOCK_ABORT) |
31dbecd4 | 545 | goto abort_exit; |
674a4ee1 TT |
546 | } else |
547 | ctx.bcount += limit * limit; | |
206fea69 TT |
548 | if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { |
549 | ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK], | |
36a43d67 | 550 | 0, EXT2_TIND_BLOCK, &ctx); |
1e3472c5 | 551 | if (ret & BLOCK_ABORT) |
31dbecd4 | 552 | goto abort_exit; |
1e3472c5 | 553 | } |
3839e657 | 554 | |
31dbecd4 | 555 | abort_exit: |
3839e657 | 556 | if (ret & BLOCK_CHANGED) { |
3839e657 | 557 | retval = ext2fs_write_inode(fs, ino, &inode); |
9922c53a TT |
558 | if (retval) { |
559 | ret |= BLOCK_ERROR; | |
560 | ctx.errcode = retval; | |
561 | } | |
3839e657 | 562 | } |
d7b92206 | 563 | errout: |
3839e657 | 564 | if (!block_buf) |
c4e3d3f3 | 565 | ext2fs_free_mem(&ctx.ind_buf); |
3839e657 TT |
566 | |
567 | return (ret & BLOCK_ERROR) ? ctx.errcode : 0; | |
568 | } | |
21c84b71 | 569 | |
674a4ee1 TT |
570 | /* |
571 | * Emulate the old ext2fs_block_iterate function! | |
572 | */ | |
573 | ||
272631e4 TT |
574 | struct xlate64 { |
575 | int (*func)(ext2_filsys fs, | |
576 | blk_t *blocknr, | |
577 | e2_blkcnt_t blockcnt, | |
578 | blk_t ref_blk, | |
579 | int ref_offset, | |
580 | void *priv_data); | |
581 | void *real_private; | |
582 | }; | |
583 | ||
584 | static int xlate64_func(ext2_filsys fs, blk64_t *blocknr, | |
585 | e2_blkcnt_t blockcnt, blk64_t ref_blk, | |
586 | int ref_offset, void *priv_data) | |
587 | { | |
588 | struct xlate64 *xl = (struct xlate64 *) priv_data; | |
589 | int ret; | |
590 | blk_t block32 = *blocknr; | |
591 | ||
592 | ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset, | |
593 | xl->real_private); | |
594 | *blocknr = block32; | |
595 | return ret; | |
596 | } | |
597 | ||
598 | errcode_t ext2fs_block_iterate2(ext2_filsys fs, | |
599 | ext2_ino_t ino, | |
600 | int flags, | |
601 | char *block_buf, | |
602 | int (*func)(ext2_filsys fs, | |
603 | blk_t *blocknr, | |
604 | e2_blkcnt_t blockcnt, | |
605 | blk_t ref_blk, | |
606 | int ref_offset, | |
607 | void *priv_data), | |
608 | void *priv_data) | |
609 | { | |
610 | struct xlate64 xl; | |
611 | ||
612 | xl.real_private = priv_data; | |
613 | xl.func = func; | |
614 | ||
615 | return ext2fs_block_iterate3(fs, ino, flags, block_buf, | |
616 | xlate64_func, &xl); | |
617 | } | |
618 | ||
619 | ||
21c84b71 TT |
620 | struct xlate { |
621 | int (*func)(ext2_filsys fs, | |
622 | blk_t *blocknr, | |
623 | int bcount, | |
b5abe6fa | 624 | void *priv_data); |
21c84b71 TT |
625 | void *real_private; |
626 | }; | |
627 | ||
3cb6c502 | 628 | #ifdef __TURBOC__ |
31dbecd4 | 629 | #pragma argsused |
3cb6c502 | 630 | #endif |
03673dbb | 631 | static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, |
54434927 TT |
632 | blk_t ref_block EXT2FS_ATTR((unused)), |
633 | int ref_offset EXT2FS_ATTR((unused)), | |
634 | void *priv_data) | |
21c84b71 | 635 | { |
b5abe6fa | 636 | struct xlate *xl = (struct xlate *) priv_data; |
21c84b71 | 637 | |
674a4ee1 | 638 | return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private); |
21c84b71 TT |
639 | } |
640 | ||
641 | errcode_t ext2fs_block_iterate(ext2_filsys fs, | |
31dbecd4 | 642 | ext2_ino_t ino, |
21c84b71 TT |
643 | int flags, |
644 | char *block_buf, | |
645 | int (*func)(ext2_filsys fs, | |
646 | blk_t *blocknr, | |
647 | int blockcnt, | |
b5abe6fa TT |
648 | void *priv_data), |
649 | void *priv_data) | |
21c84b71 TT |
650 | { |
651 | struct xlate xl; | |
efc6f628 | 652 | |
b5abe6fa | 653 | xl.real_private = priv_data; |
21c84b71 TT |
654 | xl.func = func; |
655 | ||
36a43d67 | 656 | return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags, |
674a4ee1 TT |
657 | block_buf, xlate_func, &xl); |
658 | } | |
659 |