Logo Search packages:      
Sourcecode: parted version File versions

ext2_meta.c

/*
    ext2_meta.c -- ext2 metadata mover
    Copyright (C) 1998-2000 Free Software Foundation, Inc.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "config.h"

#ifndef DISCOVER_ONLY

#include <stdio.h>
#include <stdlib.h>
#include "ext2.h"

int ext2_metadata_push(struct ext2_fs *fs, blk_t newsize)
{
      int   i;
      int   newgdblocks;
      blk_t newitoffset;

      newgdblocks = howmany(newsize - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb),
                        EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
      newgdblocks = howmany(newgdblocks * sizeof(struct ext2_group_desc),
                        fs->blocksize);
      newitoffset = newgdblocks + 3;

      if (newitoffset <= fs->itoffset)
            return 1;

      for (i=0;i<fs->numgroups;i++)
      {
            blk_t diff;
            blk_t j;
            blk_t fromblock;
            blk_t start;

            start = (i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
                  + EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);

            if (EXT2_GROUP_INODE_TABLE(fs->gd[i]) >= start + newitoffset
                && EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]) >= start + newitoffset - 2
                && EXT2_GROUP_INODE_BITMAP(fs->gd[i]) >= start + newitoffset - 1)
                  continue;

            diff = newitoffset - (EXT2_GROUP_INODE_TABLE(fs->gd[i]) - start);

            /* inode table */
            fromblock = EXT2_GROUP_INODE_TABLE(fs->gd[i]) + fs->inodeblocks;

            if (fs->opt_debug)
            {
                  for (j=0;j<diff;j++)
                        if (ext2_get_block_state(fs, fromblock+j))
                        {
                              fprintf(stderr,
                                    "error: block relocator "
                                    "should have relocated "
                                    "%i\n",
                                    fromblock);

                              return 0;
                        }
            }

            for (j=0;j<diff;j++)
                  if (!ext2_set_block_state(fs, fromblock+j, 1, 0))
                        return 0;

            if (!ext2_move_blocks(fs,
                              EXT2_GROUP_INODE_TABLE(fs->gd[i]),
                              fs->inodeblocks,
                              EXT2_GROUP_INODE_TABLE(fs->gd[i]) + diff))
                  return 0;
            fs->gd[i].bg_inode_table = PED_CPU_TO_LE32 (
                  EXT2_GROUP_INODE_TABLE(fs->gd[i]) + diff);
            fs->metadirty |= EXT2_META_GD;

            if (fs->opt_safe)
                  if (!ext2_sync(fs))
                        return 0;

            /* block bitmap and inode bitmap */
            fromblock = EXT2_GROUP_INODE_TABLE(fs->gd[i]);
            if (ext2_is_group_sparse(fs, i))
            {
                  if (!ext2_copy_block(fs,
                        EXT2_GROUP_INODE_BITMAP(fs->gd[i]),
                        EXT2_GROUP_INODE_BITMAP(fs->gd[i]) + diff))
                        return 0;
                  fs->gd[i].bg_inode_bitmap = PED_CPU_TO_LE32 (
                        EXT2_GROUP_INODE_BITMAP(fs->gd[i]) + diff);
                        fs->metadirty |= EXT2_META_GD;

                  if (fs->opt_safe)
                        if (!ext2_sync(fs))
                              return 0;

                  if (!ext2_copy_block(fs,
                        EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]),
                        EXT2_GROUP_BLOCK_BITMAP(fs->gd[i])+diff))
                        return 0;
                  fs->gd[i].bg_block_bitmap = PED_CPU_TO_LE32 (
                        EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]) + diff);
                  fs->metadirty |= EXT2_META_GD;

                  if (fs->opt_safe)
                        if (!ext2_sync(fs))
                              return 0;

                  fromblock = EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]);
            }

            ext2_zero_blocks(fs, fromblock-diff, diff);
            for (j=0;j<diff;j++)
                  if (!ext2_set_block_state(fs, fromblock+j-diff, 0, 0))
                        return 0;

            if (fs->opt_verbose)
                  fprintf(stderr,
                        "ext2_metadata_push: group %i/%i\r",
                        i+1, fs->numgroups);
      }

      fs->itoffset = newitoffset;

      if (fs->opt_verbose)
            fprintf(stderr, "\n");

      return 1;
}
#endif /* !DISCOVER_ONLY */

Generated by  Doxygen 1.6.0   Back to index