1 /*
   2     ext2_resize.c -- ext2 resizer
   3     Copyright (C) 1998-2000, 2007 Free Software Foundation, Inc.
   4 
   5     This program is free software; you can redistribute it and/or modify
   6     it under the terms of the GNU General Public License as published by
   7     the Free Software Foundation; either version 3 of the License, or
   8     (at your option) any later version.
   9 
  10     This program is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13     GNU General Public License for more details.
  14 
  15     You should have received a copy of the GNU General Public License
  16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18 
  19 #include <config.h>
  20 
  21 #ifndef DISCOVER_ONLY
  22 
  23 #include <stdio.h>
  24 #include <stdlib.h>
  25 #include "ext2.h"
  26 
  27 static int ext2_add_group(struct ext2_fs *fs, blk_t groupsize)
  28 {
  29         blk_t admin;
  30         int   group;
  31         blk_t groupstart;
  32         blk_t newgdblocks;
  33         int   sparse;
  34 
  35         if (fs->opt_verbose)
  36                 fputs ("ext2_add_group\n", stderr);
  37 
  38         if (!ped_realloc ((void*) &fs->gd,
  39                           (fs->numgroups+1) * sizeof(struct ext2_group_desc)
  40                               + fs->blocksize))
  41                 return 0;
  42 
  43         if (fs->opt_debug)
  44         {
  45                 if (EXT2_SUPER_BLOCKS_COUNT(fs->sb) !=
  46                     EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
  47                     + fs->numgroups * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
  48                 {
  49                         fputs ("ext2_add_group: last (existing) group "
  50                                "isn't complete!\n", stderr);
  51 
  52                         return 0;
  53                 }
  54         }
  55 
  56         group = fs->numgroups;
  57         sparse = ext2_is_group_sparse(fs, group);
  58         groupstart = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
  59                      + group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
  60 
  61         admin = fs->adminblocks;
  62         if (!sparse)
  63                 admin -= fs->gdblocks + 1;
  64 
  65         if (fs->opt_debug)
  66         {
  67                 if (groupsize < fs->adminblocks ||
  68                     groupsize > EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
  69                 {
  70                         fprintf(stderr,
  71                                 "ext2_add_group: groups of %i blocks are "
  72                                 "impossible!\n", groupsize);
  73 
  74                         return 0;
  75                 }
  76         }
  77 
  78         newgdblocks = ped_div_round_up((fs->numgroups + 1)
  79                                         * sizeof(struct ext2_group_desc),
  80                               fs->blocksize);
  81         if (newgdblocks != fs->gdblocks)
  82         {
  83                 int i;
  84 
  85                 for (i=0;i<fs->numgroups;i++)
  86                         if (ext2_is_group_sparse(fs, i))
  87                         {
  88                                 blk_t start;
  89 
  90                                 start = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
  91                                       + i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
  92                                 ext2_set_block_state(fs,
  93                                                 start + fs->gdblocks + 1, 1, 1);
  94                         }
  95 
  96                 fs->gdblocks++;
  97                 fs->adminblocks++;
  98                 if (sparse)
  99                         admin++;
 100         }
 101 
 102         fs->numgroups++;
 103 
 104         fs->sb.s_inodes_count = PED_CPU_TO_LE32(
 105                 EXT2_SUPER_INODES_COUNT(fs->sb)
 106                 + EXT2_SUPER_INODES_PER_GROUP(fs->sb));
 107         fs->sb.s_blocks_count = PED_CPU_TO_LE32(
 108                 EXT2_SUPER_BLOCKS_COUNT(fs->sb) + groupsize);
 109         fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
 110                 EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) + groupsize - admin);
 111         fs->sb.s_free_inodes_count = PED_CPU_TO_LE32(
 112                 EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
 113                 + EXT2_SUPER_INODES_PER_GROUP(fs->sb));
 114         fs->metadirty |= EXT2_META_SB;
 115 
 116         {
 117                 blk_t off;
 118                 blk_t sparseoff;
 119 
 120                 off = groupstart;
 121                 sparseoff = off + fs->itoffset - 2;
 122 
 123                 if (sparse)
 124                 {
 125                         fs->gd[group].bg_block_bitmap
 126                                 = PED_CPU_TO_LE32(sparseoff);
 127                         fs->gd[group].bg_inode_bitmap
 128                                 = PED_CPU_TO_LE32(sparseoff + 1);
 129                 }
 130                 else
 131                 {
 132                         fs->gd[group].bg_block_bitmap
 133                                 = PED_CPU_TO_LE32(off);
 134                         fs->gd[group].bg_inode_bitmap
 135                                 = PED_CPU_TO_LE32(off + 1);
 136                 }
 137 
 138                 /* Hey, I don't know _why_ either */
 139                 fs->gd[group].bg_inode_table = PED_CPU_TO_LE32(sparseoff + 2);
 140         }
 141 
 142         fs->gd[group].bg_free_blocks_count = PED_CPU_TO_LE16(groupsize - admin);
 143         fs->gd[group].bg_free_inodes_count = PED_CPU_TO_LE16(
 144                 EXT2_SUPER_INODES_PER_GROUP(fs->sb));
 145         fs->gd[group].bg_used_dirs_count = 0;
 146         fs->metadirty |= EXT2_META_SB | EXT2_META_GD;
 147 
 148         {
 149                 struct ext2_buffer_head *bh;
 150                 blk_t i;
 151 
 152                 bh = ext2_bcreate(fs, EXT2_GROUP_BLOCK_BITMAP(fs->gd[group]));
 153                 if (!bh)
 154                         return 0;
 155 
 156                 if (sparse)
 157                 {
 158                         bh->data[0] |= _bitmap[0];
 159                         for (i=1;i<=fs->gdblocks;i++)
 160                                 bh->data[i>>3] |= _bitmap[i&7];
 161                 }
 162 
 163                 i = EXT2_GROUP_BLOCK_BITMAP(fs->gd[group]) - groupstart;
 164                 bh->data[i>>3] |= _bitmap[i&7];
 165 
 166                 i = EXT2_GROUP_INODE_BITMAP(fs->gd[group]) - groupstart;
 167                 bh->data[i>>3] |= _bitmap[i&7];
 168 
 169                 for (i=0;i<fs->inodeblocks;i++)
 170                 {
 171                         blk_t j;
 172 
 173                         j = EXT2_GROUP_INODE_TABLE(fs->gd[group])
 174                             - groupstart + i;
 175                         bh->data[j>>3] |= _bitmap[j&7];
 176                 }
 177 
 178                 for (i=groupsize;i<EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);i++)
 179                         bh->data[i>>3] |= _bitmap[i&7];
 180 
 181                 ext2_brelse(bh, 0);         /* this is a block bitmap */
 182         }
 183 
 184         if (!ext2_zero_blocks(fs, EXT2_GROUP_INODE_BITMAP(fs->gd[group]), 1))
 185                 return 0;
 186         if (!ext2_zero_blocks(fs, EXT2_GROUP_INODE_TABLE(fs->gd[group]),
 187                               fs->inodeblocks))
 188                 return 0;
 189 
 190         if (fs->opt_safe)
 191                 if (!ext2_sync(fs))
 192                         return 0;
 193 
 194         return 1;
 195 }
 196 
 197 static int ext2_del_group(struct ext2_fs *fs)
 198 {
 199         blk_t admin;
 200         int   group;
 201         blk_t groupsize;
 202         blk_t newgdblocks;
 203         int   sparse;
 204 
 205         if (fs->opt_verbose)
 206                 fputs ("ext2_del_group\n", stderr);
 207 
 208         group = fs->numgroups - 1;
 209         sparse = ext2_is_group_sparse(fs, group);
 210 
 211         admin = fs->adminblocks;
 212         if (!sparse)
 213                 admin -= fs->gdblocks + 1;
 214 
 215         groupsize = EXT2_SUPER_BLOCKS_COUNT(fs->sb)
 216                   - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
 217                   - group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 218 
 219         if (EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) < groupsize - admin)
 220         {
 221                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 222                         _("File system is too full to remove a group!"));
 223 
 224                 return 0;
 225         }
 226 
 227         if (EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
 228                 < EXT2_SUPER_INODES_PER_GROUP(fs->sb))
 229         {
 230                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 231                         _("File system has too many allocated inodes to "
 232                           "remove a group!"));
 233                 return 0;
 234         }
 235 
 236         if (fs->opt_debug)
 237         {
 238                 if (EXT2_GROUP_FREE_INODES_COUNT(fs->gd[group]) !=
 239                     EXT2_SUPER_INODES_PER_GROUP(fs->sb))
 240                 {
 241                         fputs ("ext2_del_group: this should not "
 242                                "happen anymore!\n", stderr);
 243 
 244                         return 0;
 245                 }
 246         }
 247 
 248         newgdblocks = ped_div_round_up((fs->numgroups - 1) *
 249                               sizeof(struct ext2_group_desc), fs->blocksize);
 250 
 251         if (newgdblocks != fs->gdblocks)
 252         {
 253                 int i;
 254 
 255                 for (i=0;i<fs->numgroups;i++)
 256                         if (ext2_is_group_sparse(fs, i))
 257                         {
 258                                 blk_t start;
 259 
 260                                 start = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb) +
 261                                         i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 262                                 ext2_set_block_state(fs,
 263                                                      start + fs->gdblocks,
 264                                                      0, 1);
 265                         }
 266 
 267                 fs->gdblocks--;
 268                 fs->adminblocks--;
 269                 if (sparse)
 270                         admin--;
 271         }
 272 
 273         if (fs->opt_debug)
 274         {
 275                 if (EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[group])
 276                                 != groupsize - admin)
 277                 {
 278                         blk_t i;
 279                         blk_t num;
 280                         blk_t offset;
 281 
 282                         offset = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb) +
 283                                 group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 284                         num = EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 285 
 286                         for (i=0;i<num;i++)
 287                                 if (ext2_is_data_block(fs, offset+i) &&
 288                                     ext2_get_block_state(fs, offset+i))
 289                                 {
 290                                         fprintf(stderr,
 291                                                 "error: block relocator "
 292                                                 "should have relocated "
 293                                                 "%i\n",
 294                                                 offset+i);
 295 
 296                                         return 0;
 297                                 }
 298                 }
 299         }
 300 
 301         fs->numgroups--;
 302 
 303         fs->sb.s_inodes_count = PED_CPU_TO_LE32(
 304                 EXT2_SUPER_INODES_COUNT(fs->sb)
 305                 - EXT2_SUPER_INODES_PER_GROUP(fs->sb));
 306         fs->sb.s_blocks_count = PED_CPU_TO_LE32(
 307                 EXT2_SUPER_BLOCKS_COUNT(fs->sb) - groupsize);
 308         fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
 309                 EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) - (groupsize - admin));
 310         fs->sb.s_free_inodes_count = PED_CPU_TO_LE32(
 311                 EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
 312                 - EXT2_SUPER_INODES_PER_GROUP(fs->sb));
 313         fs->metadirty |= EXT2_META_SB;
 314 
 315         if (fs->opt_safe)
 316                 ext2_sync(fs);
 317 
 318         ped_realloc ((void*) &fs->gd,
 319                      fs->numgroups * sizeof(struct ext2_group_desc)
 320                               + fs->blocksize);
 321 
 322         return 1;
 323 }
 324 
 325 static int ext2_grow_group(struct ext2_fs *fs, blk_t newsize)
 326 {
 327         int   group;
 328         blk_t groupoff;
 329         blk_t gblocks;
 330         blk_t i;
 331 
 332         if (fs->opt_verbose)
 333                 fputs ("ext2_grow_group\n", stderr);
 334 
 335         group = fs->numgroups - 1;
 336         groupoff = group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb)
 337                    + EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
 338         gblocks = EXT2_SUPER_BLOCKS_COUNT(fs->sb) - groupoff;
 339 
 340         if (fs->opt_debug)
 341         {
 342                 if (newsize < gblocks)
 343                 {
 344                         fputs ("ext2_grow_group: called to shrink group!\n",
 345                                stderr);
 346 
 347                         return 0;
 348                 }
 349 
 350                 if (gblocks == newsize)
 351                 {
 352                         fputs ("ext2_grow_group: nothing to do!\n", stderr);
 353                         return 0;
 354                 }
 355         }
 356 
 357         for (i=gblocks;i<newsize;i++)
 358                 ext2_set_block_state(fs, groupoff + i, 0, 1);
 359 
 360         fs->sb.s_blocks_count = PED_CPU_TO_LE32(
 361                 EXT2_SUPER_BLOCKS_COUNT(fs->sb) + newsize - gblocks);
 362         fs->metadirty |= EXT2_META_SB;
 363 
 364         if (fs->opt_safe)
 365                 ext2_sync(fs);
 366 
 367         return 1;
 368 }
 369 
 370 static int ext2_shrink_group(struct ext2_fs *fs, blk_t newsize)
 371 {
 372         blk_t admin;
 373         int   group;
 374         blk_t groupoff;
 375         blk_t gblocks;
 376         blk_t i;
 377 
 378         if (fs->opt_verbose)
 379                 fputs ("ext2_shrink_group\n", stderr);
 380 
 381         group = fs->numgroups - 1;
 382 
 383         admin = fs->adminblocks;
 384         if (!ext2_is_group_sparse(fs, group))
 385                 admin -= fs->gdblocks + 1;
 386 
 387         groupoff = group * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb)
 388                    + EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
 389         gblocks = EXT2_SUPER_BLOCKS_COUNT(fs->sb) - groupoff;
 390 
 391         if (fs->opt_debug)
 392         {
 393                 if (newsize < admin)
 394                 {
 395                         fprintf(stderr,
 396                                 "ext2_shrink_group: cant shrink a group "
 397                                 "to %i blocks\n", newsize);
 398 
 399                         return 0;
 400                 }
 401 
 402                 if (newsize > gblocks)
 403                 {
 404                         fputs ("ext2_shrink_group: called to grow group!\n",
 405                                stderr);
 406 
 407                         return 0;
 408                 }
 409 
 410                 if (gblocks == newsize)
 411                 {
 412                         fputs ("ext2_shrink_group: nothing to do!\n",
 413                                stderr);
 414 
 415                         return 0;
 416                 }
 417         }
 418 
 419         for (i=newsize;i<gblocks;i++)
 420         {
 421                 if (fs->opt_debug && ext2_get_block_state(fs, groupoff + i))
 422                 {
 423                         fprintf(stderr,
 424                                 "error: block relocator should have relocated "
 425                                 "%i\n",
 426                                 groupoff + i);
 427 
 428                         return 0;
 429                 }
 430 
 431                 ext2_set_block_state(fs, groupoff + i, 1, 0);
 432         }
 433 
 434         i = gblocks - newsize;
 435         fs->sb.s_blocks_count = PED_CPU_TO_LE32(
 436                 EXT2_SUPER_BLOCKS_COUNT(fs->sb) - i);
 437         fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
 438                 EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) - i);
 439         fs->gd[group].bg_free_blocks_count = PED_CPU_TO_LE16(
 440                 EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[group]) - i);
 441 
 442         fs->metadirty |= EXT2_META_SB | EXT2_META_GD;
 443 
 444         if (fs->opt_safe)
 445                 ext2_sync(fs);
 446 
 447         return 1;
 448 }
 449 
 450 
 451 
 452 
 453 
 454 
 455 static int ext2_grow_fs(struct ext2_fs *fs, blk_t newsize, PedTimer* timer)
 456 {
 457         blk_t diff;
 458         blk_t sizelast;
 459         blk_t origsize = EXT2_SUPER_BLOCKS_COUNT(fs->sb);
 460 
 461         if (fs->opt_verbose)
 462                 fputs ("ext2_grow_fs\n", stderr);
 463 
 464         if (!ext2_block_relocate(fs, newsize))
 465                 return 0;
 466 
 467         if (!ext2_metadata_push(fs, newsize))
 468                 return 0;
 469 
 470         diff = newsize - EXT2_SUPER_BLOCKS_COUNT(fs->sb);
 471         sizelast = EXT2_SUPER_BLOCKS_COUNT(fs->sb)
 472                    - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
 473                    - (fs->numgroups-1) * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 474 
 475         if (sizelast != EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
 476         {
 477                 blk_t growto;
 478 
 479                 growto = sizelast + diff;
 480                 if (growto > EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
 481                         growto = EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 482 
 483                 if (!ext2_grow_group(fs, growto))
 484                         return 0;
 485 
 486                 diff -= growto - sizelast;
 487         }
 488 
 489         ped_timer_reset (timer);
 490         ped_timer_set_state_name (timer, _("adding groups"));
 491 
 492         while (diff)
 493         {
 494                 ped_timer_update (timer,
 495                                   1.0 - 1.0 * diff / (newsize - origsize));
 496 
 497                 sizelast = PED_MIN(diff, EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
 498                 if (!ext2_add_group(fs, sizelast))
 499                         return 0;
 500 
 501                 diff -= sizelast;
 502         }
 503 
 504         ped_timer_update (timer, 1.0);
 505 
 506         return 1;
 507 }
 508 
 509 static int ext2_shrink_fs(struct ext2_fs *fs, blk_t newsize,
 510                           PedTimer* timer)
 511 {
 512         blk_t origsize = EXT2_SUPER_BLOCKS_COUNT (fs->sb);
 513         blk_t diff;
 514         int newgroups;
 515         blk_t sizelast;
 516 
 517         if (fs->opt_verbose)
 518                 fputs ("ext2_shrink_fs\n", stderr);
 519 
 520         newgroups = ped_div_round_up (newsize
 521                                 - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb),
 522                         EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
 523         if (EXT2_SUPER_BLOCKS_COUNT(fs->sb)
 524             - EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) > newsize)
 525         {
 526                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 527                         _("Your file system is too full to resize it to %i "
 528                           "blocks.  Sorry."), newsize);
 529                 return 0;
 530         }
 531 
 532         if (EXT2_SUPER_INODES_COUNT(fs->sb)
 533             - EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
 534                         > newgroups * EXT2_SUPER_INODES_PER_GROUP(fs->sb))
 535         {
 536                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 537                         _("Your file system has too many occupied inodes to "
 538                           "resize it to %i blocks.  Sorry."), newsize);
 539                 return 0;
 540         }
 541 
 542         if (!ext2_inode_relocate(fs, newgroups))
 543                 return 0;
 544 
 545         if (!ext2_block_relocate(fs, newsize))
 546                 return 0;
 547 
 548         diff = EXT2_SUPER_BLOCKS_COUNT(fs->sb) - newsize;
 549 
 550         ped_timer_reset (timer);
 551         ped_timer_set_state_name (timer, _("shrinking"));
 552 
 553         while (diff > 0)
 554         {
 555                 ped_timer_update (timer,
 556                                   1.0 - 1.0 * diff / (origsize - newsize));
 557 
 558                 sizelast = EXT2_SUPER_BLOCKS_COUNT(fs->sb)
 559                            - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb) -
 560                            (fs->numgroups - 1)
 561                                 * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 562 
 563                 if (diff < sizelast)
 564                 {
 565                         if (!ext2_shrink_group(fs, sizelast - diff))
 566                                 return 0;
 567 
 568                         diff = 0;
 569                 }
 570                 else
 571                 {
 572                         if (!ext2_del_group(fs))
 573                                 return 0;
 574 
 575                         diff -= sizelast;
 576                 }
 577         }
 578         
 579         ped_timer_update (timer, 1.0);
 580 
 581         return 1;
 582 }
 583 
 584 int ext2_determine_itoffset(struct ext2_fs *fs)
 585 {
 586         int i;
 587 
 588         fs->itoffset = EXT2_GROUP_INODE_TABLE(fs->gd[0])
 589                        - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
 590 
 591         /*PED_DEBUG (0x20, "itoffset is %d", fs->itoffset);
 592         
 593         PED_DEBUG (0x20, "walking %d groups", fs->numgroups);*/
 594 
 595         for (i=0;i<fs->numgroups;i++)
 596         {
 597                 blk_t start;
 598                 blk_t bb;
 599                 blk_t ib;
 600                 blk_t it;
 601 
 602                 start = EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb)
 603                         + (i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
 604                 it = start + fs->itoffset;
 605 
 606                 /*PED_DEBUG (0x21, "start = %d, it = %d", start, it);*/
 607 
 608                 if (ext2_is_group_sparse(fs, i))
 609                 {
 610                         /*PED_DEBUG (0x21, "%d has a superblock copy", i);*/
 611                         bb = it - 2;
 612                         ib = it - 1;
 613                 }
 614                 else
 615                 {
 616                         /*PED_DEBUG (0x21, "%d doesn't have a superblock copy",
 617                             i);*/
 618                         bb = start;
 619                         ib = start + 1;
 620                 }
 621 
 622                 if (EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]) != bb ||
 623                     EXT2_GROUP_INODE_BITMAP(fs->gd[i]) != ib ||
 624                     EXT2_GROUP_INODE_TABLE(fs->gd[i]) != it)
 625                 {
 626                 /*      ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
 627                                 PED_EXCEPTION_CANCEL,
 628                         _("This ext2 file system has a rather strange layout!  "
 629                           "Parted can't resize this (yet)."));*/
 630 
 631                  /*       PED_DEBUG (0x21, "calculated block bitmap to be %d, "
 632                                          "but fs says %d.", bb,
 633                                          EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]));
 634                         PED_DEBUG (0x21, "calculated inode bitmap to be %d, "
 635                                          "but fs says %d.", ib,
 636                                          EXT2_GROUP_INODE_BITMAP(fs->gd[i]));
 637                         PED_DEBUG (0x21, "calculated inode table to be %d, "
 638                                          "but fs says %d.", it,
 639                                          EXT2_GROUP_INODE_TABLE(fs->gd[i]));*/
 640                         
 641                         return 0;
 642                 }
 643         }
 644 
 645         return 1;
 646 }
 647 
 648 int ext2_resize_fs(struct ext2_fs *fs, blk_t newsize, PedTimer* timer)
 649 {
 650         blk_t residue;
 651         int status;
 652 
 653         if (EXT2_SUPER_STATE(fs->sb) & EXT2_ERROR_FS)
 654         {
 655                 ped_exception_throw (
 656                         PED_EXCEPTION_WARNING, PED_EXCEPTION_CANCEL,
 657                         _("File system has errors!  You should run e2fsck."));
 658                 return 0;
 659         }
 660 
 661         if (!(EXT2_SUPER_STATE(fs->sb) & EXT2_VALID_FS))
 662         {
 663                 ped_exception_throw (
 664                         PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 665                         _("File system was not cleanly unmounted!  "
 666                           "You should run e2fsck."));
 667                 return 0;
 668         }
 669 
 670         if (EXT2_SUPER_FEATURE_COMPAT(fs->sb)
 671                         & EXT2_FEATURE_COMPAT_HAS_DIR_INDEX) {
 672                 if (ped_exception_throw (
 673                         PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL,
 674                         _("The file system has the 'dir_index' feature "
 675                           "enabled.  Parted can only resize the file system "
 676                           "if it disables this feature.  You can enable it "
 677                           "later by running 'tune2fs -O dir_index DEVICE' "
 678                           "and then 'e2fsck -fD DEVICE'."))
 679                                 != PED_EXCEPTION_IGNORE)
 680                         return 0;
 681                 fs->sb.s_feature_compat
 682                         = PED_CPU_TO_LE32(EXT2_SUPER_FEATURE_COMPAT(fs->sb)
 683                                           & ~EXT2_FEATURE_COMPAT_HAS_DIR_INDEX);
 684                 fs->metadirty |= EXT2_META_SB;
 685         }
 686 
 687         if (!ext2_determine_itoffset(fs) && ped_exception_throw (
 688                         PED_EXCEPTION_WARNING,
 689                         PED_EXCEPTION_OK_CANCEL,
 690                         _("A resize operation on this file system will "
 691                           "use EXPERIMENTAL code\n"
 692                           "that MAY CORRUPT it (although no one has "
 693                           "reported any such damage yet).\n"
 694                           "You should at least backup your data first, "
 695                           "and run 'e2fsck -f' afterwards."))
 696                 == PED_EXCEPTION_CANCEL)
 697         {
 698                 return 0;
 699         }
 700 
 701         if (fs->opt_verbose)
 702                 fputs ("ext2_resize_fs\n", stderr);
 703 
 704         residue = (newsize - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb))
 705                    % EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb);
 706         if (residue && residue <= fs->adminblocks)
 707                 newsize -= residue;
 708 
 709         if (newsize == EXT2_SUPER_BLOCKS_COUNT(fs->sb))
 710                 return 1;
 711 
 712         fs->relocator_pool
 713                 = (unsigned char *)ped_malloc(ext2_relocator_pool_size << 10);
 714         if (!fs->relocator_pool)
 715                 return 0;
 716         fs->relocator_pool_end
 717                 = fs->relocator_pool + (ext2_relocator_pool_size << 10);
 718 
 719         if (newsize < EXT2_SUPER_BLOCKS_COUNT(fs->sb))
 720                 status = ext2_shrink_fs(fs, newsize, timer);
 721         else
 722                 status = ext2_grow_fs(fs, newsize, timer);
 723 
 724         ped_free(fs->relocator_pool);
 725         fs->relocator_pool = NULL;
 726         fs->relocator_pool_end = NULL;
 727 
 728         return status;
 729 }
 730 #endif /* !DISCOVER_ONLY */