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