block.c revision 1ad54a940c499a66241f624882f1ffa03ce56d90
1/* 2 * block.c --- iterate over all blocks in an inode 3 * 4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#include <stdio.h> 13#include <string.h> 14#if HAVE_UNISTD_H 15#include <unistd.h> 16#endif 17 18#include "ext2_fs.h" 19#include "ext2fs.h" 20 21struct block_context { 22 ext2_filsys fs; 23 int (*func)(ext2_filsys fs, 24 blk_t *blocknr, 25 e2_blkcnt_t bcount, 26 blk_t ref_blk, 27 int ref_offset, 28 void *priv_data); 29 e2_blkcnt_t bcount; 30 int bsize; 31 int flags; 32 errcode_t errcode; 33 char *ind_buf; 34 char *dind_buf; 35 char *tind_buf; 36 void *priv_data; 37}; 38 39static int block_iterate_ind(blk_t *ind_block, blk_t ref_block, 40 int ref_offset, struct block_context *ctx) 41{ 42 int ret = 0, changed = 0; 43 int i, flags, limit, offset; 44 blk_t *block_nr; 45 46 limit = ctx->fs->blocksize >> 2; 47 if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && 48 !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) 49 ret = (*ctx->func)(ctx->fs, ind_block, 50 BLOCK_COUNT_IND, ref_block, 51 ref_offset, ctx->priv_data); 52 if (!*ind_block || (ret & BLOCK_ABORT)) { 53 ctx->bcount += limit; 54 return ret; 55 } 56 if (*ind_block >= ctx->fs->super->s_blocks_count || 57 *ind_block < ctx->fs->super->s_first_data_block) { 58 ctx->errcode = EXT2_ET_BAD_IND_BLOCK; 59 ret |= BLOCK_ERROR; 60 return ret; 61 } 62 if ((ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && 63 (ctx->fs->io != ctx->fs->image_io)) { 64 ctx->errcode = 0; 65 memset(ctx->ind_buf, 0, ctx->fs->blocksize); 66 } else 67 ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block, 68 1, ctx->ind_buf); 69 if (ctx->errcode) { 70 ret |= BLOCK_ERROR; 71 return ret; 72 } 73#ifdef EXT2FS_ENABLE_SWAPFS 74 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES | 75 EXT2_FLAG_SWAP_BYTES_READ)) { 76 block_nr = (blk_t *) ctx->ind_buf; 77 for (i = 0; i < limit; i++, block_nr++) 78 *block_nr = ext2fs_swab32(*block_nr); 79 } 80#endif 81 block_nr = (blk_t *) ctx->ind_buf; 82 offset = 0; 83 if (ctx->flags & BLOCK_FLAG_APPEND) { 84 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { 85 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount, 86 *ind_block, offset, 87 ctx->priv_data); 88 changed |= flags; 89 if (flags & BLOCK_ABORT) { 90 ret |= BLOCK_ABORT; 91 break; 92 } 93 offset += sizeof(blk_t); 94 } 95 } else { 96 for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { 97 if (*block_nr == 0) 98 continue; 99 flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount, 100 *ind_block, offset, 101 ctx->priv_data); 102 changed |= flags; 103 if (flags & BLOCK_ABORT) { 104 ret |= BLOCK_ABORT; 105 break; 106 } 107 offset += sizeof(blk_t); 108 } 109 } 110 if (!(ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && 111 (changed & BLOCK_CHANGED)) { 112#ifdef EXT2FS_ENABLE_SWAPFS 113 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES | 114 EXT2_FLAG_SWAP_BYTES_WRITE)) { 115 block_nr = (blk_t *) ctx->ind_buf; 116 for (i = 0; i < limit; i++, block_nr++) 117 *block_nr = ext2fs_swab32(*block_nr); 118 } 119#endif 120 ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block, 121 1, ctx->ind_buf); 122 if (ctx->errcode) 123 ret |= BLOCK_ERROR | BLOCK_ABORT; 124 } 125 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && 126 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && 127 !(ret & BLOCK_ABORT)) 128 ret |= (*ctx->func)(ctx->fs, ind_block, 129 BLOCK_COUNT_IND, ref_block, 130 ref_offset, ctx->priv_data); 131 return ret; 132} 133 134static int block_iterate_dind(blk_t *dind_block, blk_t ref_block, 135 int ref_offset, struct block_context *ctx) 136{ 137 int ret = 0, changed = 0; 138 int i, flags, limit, offset; 139 blk_t *block_nr; 140 141 limit = ctx->fs->blocksize >> 2; 142 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | 143 BLOCK_FLAG_DATA_ONLY))) 144 ret = (*ctx->func)(ctx->fs, dind_block, 145 BLOCK_COUNT_DIND, ref_block, 146 ref_offset, ctx->priv_data); 147 if (!*dind_block || (ret & BLOCK_ABORT)) { 148 ctx->bcount += limit*limit; 149 return ret; 150 } 151 if (*dind_block >= ctx->fs->super->s_blocks_count || 152 *dind_block < ctx->fs->super->s_first_data_block) { 153 ctx->errcode = EXT2_ET_BAD_DIND_BLOCK; 154 ret |= BLOCK_ERROR; 155 return ret; 156 } 157 if ((ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && 158 (ctx->fs->io != ctx->fs->image_io)) { 159 ctx->errcode = 0; 160 memset(ctx->dind_buf, 0, ctx->fs->blocksize); 161 } else 162 ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block, 163 1, ctx->dind_buf); 164 if (ctx->errcode) { 165 ret |= BLOCK_ERROR; 166 return ret; 167 } 168#ifdef EXT2FS_ENABLE_SWAPFS 169 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES | 170 EXT2_FLAG_SWAP_BYTES_READ)) { 171 block_nr = (blk_t *) ctx->dind_buf; 172 for (i = 0; i < limit; i++, block_nr++) 173 *block_nr = ext2fs_swab32(*block_nr); 174 } 175#endif 176 block_nr = (blk_t *) ctx->dind_buf; 177 offset = 0; 178 if (ctx->flags & BLOCK_FLAG_APPEND) { 179 for (i = 0; i < limit; i++, block_nr++) { 180 flags = block_iterate_ind(block_nr, 181 *dind_block, offset, 182 ctx); 183 changed |= flags; 184 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { 185 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); 186 break; 187 } 188 offset += sizeof(blk_t); 189 } 190 } else { 191 for (i = 0; i < limit; i++, block_nr++) { 192 if (*block_nr == 0) { 193 ctx->bcount += limit; 194 continue; 195 } 196 flags = block_iterate_ind(block_nr, 197 *dind_block, offset, 198 ctx); 199 changed |= flags; 200 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { 201 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); 202 break; 203 } 204 offset += sizeof(blk_t); 205 } 206 } 207 if (!(ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && 208 (changed & BLOCK_CHANGED)) { 209#ifdef EXT2FS_ENABLE_SWAPFS 210 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES | 211 EXT2_FLAG_SWAP_BYTES_WRITE)) { 212 block_nr = (blk_t *) ctx->dind_buf; 213 for (i = 0; i < limit; i++, block_nr++) 214 *block_nr = ext2fs_swab32(*block_nr); 215 } 216#endif 217 ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block, 218 1, ctx->dind_buf); 219 if (ctx->errcode) 220 ret |= BLOCK_ERROR | BLOCK_ABORT; 221 } 222 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && 223 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && 224 !(ret & BLOCK_ABORT)) 225 ret |= (*ctx->func)(ctx->fs, dind_block, 226 BLOCK_COUNT_DIND, ref_block, 227 ref_offset, ctx->priv_data); 228 return ret; 229} 230 231static int block_iterate_tind(blk_t *tind_block, blk_t ref_block, 232 int ref_offset, struct block_context *ctx) 233{ 234 int ret = 0, changed = 0; 235 int i, flags, limit, offset; 236 blk_t *block_nr; 237 238 limit = ctx->fs->blocksize >> 2; 239 if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | 240 BLOCK_FLAG_DATA_ONLY))) 241 ret = (*ctx->func)(ctx->fs, tind_block, 242 BLOCK_COUNT_TIND, ref_block, 243 ref_offset, ctx->priv_data); 244 if (!*tind_block || (ret & BLOCK_ABORT)) { 245 ctx->bcount += limit*limit*limit; 246 return ret; 247 } 248 if (*tind_block >= ctx->fs->super->s_blocks_count || 249 *tind_block < ctx->fs->super->s_first_data_block) { 250 ctx->errcode = EXT2_ET_BAD_TIND_BLOCK; 251 ret |= BLOCK_ERROR; 252 return ret; 253 } 254 if ((ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && 255 (ctx->fs->io != ctx->fs->image_io)) { 256 ctx->errcode = 0; 257 memset(ctx->tind_buf, 0, ctx->fs->blocksize); 258 } else 259 ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block, 260 1, ctx->tind_buf); 261 if (ctx->errcode) { 262 ret |= BLOCK_ERROR; 263 return ret; 264 } 265#ifdef EXT2FS_ENABLE_SWAPFS 266 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES | 267 EXT2_FLAG_SWAP_BYTES_READ)) { 268 block_nr = (blk_t *) ctx->tind_buf; 269 for (i = 0; i < limit; i++, block_nr++) 270 *block_nr = ext2fs_swab32(*block_nr); 271 } 272#endif 273 block_nr = (blk_t *) ctx->tind_buf; 274 offset = 0; 275 if (ctx->flags & BLOCK_FLAG_APPEND) { 276 for (i = 0; i < limit; i++, block_nr++) { 277 flags = block_iterate_dind(block_nr, 278 *tind_block, 279 offset, ctx); 280 changed |= flags; 281 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { 282 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); 283 break; 284 } 285 offset += sizeof(blk_t); 286 } 287 } else { 288 for (i = 0; i < limit; i++, block_nr++) { 289 if (*block_nr == 0) { 290 ctx->bcount += limit*limit; 291 continue; 292 } 293 flags = block_iterate_dind(block_nr, 294 *tind_block, 295 offset, ctx); 296 changed |= flags; 297 if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { 298 ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); 299 break; 300 } 301 offset += sizeof(blk_t); 302 } 303 } 304 if (!(ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && 305 (changed & BLOCK_CHANGED)) { 306#ifdef EXT2FS_ENABLE_SWAPFS 307 if (ctx->fs->flags & (EXT2_FLAG_SWAP_BYTES | 308 EXT2_FLAG_SWAP_BYTES_WRITE)) { 309 block_nr = (blk_t *) ctx->tind_buf; 310 for (i = 0; i < limit; i++, block_nr++) 311 *block_nr = ext2fs_swab32(*block_nr); 312 } 313#endif 314 ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block, 315 1, ctx->tind_buf); 316 if (ctx->errcode) 317 ret |= BLOCK_ERROR | BLOCK_ABORT; 318 } 319 if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && 320 !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && 321 !(ret & BLOCK_ABORT)) 322 ret |= (*ctx->func)(ctx->fs, tind_block, 323 BLOCK_COUNT_TIND, ref_block, 324 ref_offset, ctx->priv_data); 325 326 return ret; 327} 328 329errcode_t ext2fs_block_iterate2(ext2_filsys fs, 330 ext2_ino_t ino, 331 int flags, 332 char *block_buf, 333 int (*func)(ext2_filsys fs, 334 blk_t *blocknr, 335 e2_blkcnt_t blockcnt, 336 blk_t ref_blk, 337 int ref_offset, 338 void *priv_data), 339 void *priv_data) 340{ 341 int i; 342 int got_inode = 0; 343 int ret = 0; 344 blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */ 345 struct ext2_inode inode; 346 errcode_t retval; 347 struct block_context ctx; 348 int limit; 349 350 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 351 352 /* 353 * Check to see if we need to limit large files 354 */ 355 if (flags & BLOCK_FLAG_NO_LARGE) { 356 ctx.errcode = ext2fs_read_inode(fs, ino, &inode); 357 if (ctx.errcode) 358 return ctx.errcode; 359 got_inode = 1; 360 if (!LINUX_S_ISDIR(inode.i_mode) && 361 (inode.i_size_high != 0)) 362 return EXT2_ET_FILE_TOO_BIG; 363 } 364 365 retval = ext2fs_get_blocks(fs, ino, blocks); 366 if (retval) 367 return retval; 368 369 limit = fs->blocksize >> 2; 370 371 ctx.fs = fs; 372 ctx.func = func; 373 ctx.priv_data = priv_data; 374 ctx.flags = flags; 375 ctx.bcount = 0; 376 if (block_buf) { 377 ctx.ind_buf = block_buf; 378 } else { 379 retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf); 380 if (retval) 381 return retval; 382 } 383 ctx.dind_buf = ctx.ind_buf + fs->blocksize; 384 ctx.tind_buf = ctx.dind_buf + fs->blocksize; 385 386 /* 387 * Iterate over the HURD translator block (if present) 388 */ 389 if ((fs->super->s_creator_os == EXT2_OS_HURD) && 390 !(flags & BLOCK_FLAG_DATA_ONLY)) { 391 ctx.errcode = ext2fs_read_inode(fs, ino, &inode); 392 if (ctx.errcode) 393 goto abort_exit; 394 got_inode = 1; 395 if (inode.osd1.hurd1.h_i_translator) { 396 ret |= (*ctx.func)(fs, 397 &inode.osd1.hurd1.h_i_translator, 398 BLOCK_COUNT_TRANSLATOR, 399 0, 0, priv_data); 400 if (ret & BLOCK_ABORT) 401 goto abort_exit; 402 } 403 } 404 405 /* 406 * Iterate over normal data blocks 407 */ 408 for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) { 409 if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) { 410 ret |= (*ctx.func)(fs, &blocks[i], 411 ctx.bcount, 0, i, priv_data); 412 if (ret & BLOCK_ABORT) 413 goto abort_exit; 414 } 415 } 416 if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { 417 ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK, 418 0, EXT2_IND_BLOCK, &ctx); 419 if (ret & BLOCK_ABORT) 420 goto abort_exit; 421 } else 422 ctx.bcount += limit; 423 if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { 424 ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK, 425 0, EXT2_DIND_BLOCK, &ctx); 426 if (ret & BLOCK_ABORT) 427 goto abort_exit; 428 } else 429 ctx.bcount += limit * limit; 430 if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) { 431 ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK, 432 0, EXT2_TIND_BLOCK, &ctx); 433 if (ret & BLOCK_ABORT) 434 goto abort_exit; 435 } 436 437abort_exit: 438 if (ret & BLOCK_CHANGED) { 439 if (!got_inode) { 440 retval = ext2fs_read_inode(fs, ino, &inode); 441 if (retval) 442 return retval; 443 } 444 for (i=0; i < EXT2_N_BLOCKS; i++) 445 inode.i_block[i] = blocks[i]; 446 retval = ext2fs_write_inode(fs, ino, &inode); 447 if (retval) 448 return retval; 449 } 450 451 if (!block_buf) 452 ext2fs_free_mem(&ctx.ind_buf); 453 454 return (ret & BLOCK_ERROR) ? ctx.errcode : 0; 455} 456 457/* 458 * Emulate the old ext2fs_block_iterate function! 459 */ 460 461struct xlate { 462 int (*func)(ext2_filsys fs, 463 blk_t *blocknr, 464 int bcount, 465 void *priv_data); 466 void *real_private; 467}; 468 469#ifdef __TURBOC__ 470 #pragma argsused 471#endif 472static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, 473 blk_t ref_block EXT2FS_ATTR((unused)), 474 int ref_offset EXT2FS_ATTR((unused)), 475 void *priv_data) 476{ 477 struct xlate *xl = (struct xlate *) priv_data; 478 479 return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private); 480} 481 482errcode_t ext2fs_block_iterate(ext2_filsys fs, 483 ext2_ino_t ino, 484 int flags, 485 char *block_buf, 486 int (*func)(ext2_filsys fs, 487 blk_t *blocknr, 488 int blockcnt, 489 void *priv_data), 490 void *priv_data) 491{ 492 struct xlate xl; 493 494 xl.real_private = priv_data; 495 xl.func = func; 496 497 return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags, 498 block_buf, xlate_func, &xl); 499} 500 501