OSDN Git Service

maint: update copyright year ranges to include 2011
[android-x86/external-parted.git] / libparted / fs / ext2 / ext2_resize.c
1 /*
2     ext2_resize.c -- ext2 resizer
3     Copyright (C) 1998-2000, 2007, 2009-2011 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         free(fs->relocator_pool);
725         fs->relocator_pool = NULL;
726         fs->relocator_pool_end = NULL;
727
728         return status;
729 }
730 #endif /* !DISCOVER_ONLY */