1 /*
   2     interface.c -- parted binding glue to libext2resize
   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 /* VERSION: libext2resize 1.1.6 (by Lennert)
  20  * merged 1.1.11 changes (by Andrew)
  21  */
  22 
  23 #include <config.h>
  24 
  25 #include <parted/parted.h>
  26 #include "ext2.h"
  27 #include "parted_io.h"
  28 
  29 static PedFileSystemType _ext2_type;
  30 static PedFileSystemType _ext3_type;
  31 
  32 struct ext2_dev_handle* ext2_make_dev_handle_from_parted_geometry(PedGeometry* geom);
  33 
  34 static PedGeometry*
  35 _ext2_generic_probe (PedGeometry* geom, int expect_ext3)
  36 {
  37         struct ext2_super_block sb;
  38 
  39         if (!ped_geometry_read(geom, &sb, 2, 2))
  40                 return NULL;
  41 
  42         if (EXT2_SUPER_MAGIC(sb) == EXT2_SUPER_MAGIC_CONST) {
  43                 PedSector block_size = 1 << (EXT2_SUPER_LOG_BLOCK_SIZE(sb) + 1);
  44                 PedSector block_count = EXT2_SUPER_BLOCKS_COUNT(sb);
  45                 PedSector group_blocks = EXT2_SUPER_BLOCKS_PER_GROUP(sb);
  46                 PedSector group_nr = EXT2_SUPER_BLOCK_GROUP_NR(sb);
  47                 PedSector first_data_block = EXT2_SUPER_FIRST_DATA_BLOCK(sb);
  48                 int version = EXT2_SUPER_REV_LEVEL(sb);
  49                 int is_ext3 = (EXT2_SUPER_FEATURE_COMPAT(sb) 
  50                                 & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0;
  51 
  52                 if (expect_ext3 != is_ext3)
  53                         return NULL;
  54 
  55                 if (version > 0 && group_nr > 0) {
  56                         PedSector start;
  57                         PedGeometry probe_geom;
  58 
  59                         start = geom->start
  60                                         - group_blocks * group_nr
  61                                         - first_data_block;
  62 
  63                         if (start < 0)
  64                                 return NULL;
  65                         ped_geometry_init (&probe_geom, geom->dev,
  66                                            start, block_count * block_size);
  67                         return _ext2_generic_probe (&probe_geom, expect_ext3);
  68                 } else {
  69                         return ped_geometry_new (geom->dev, geom->start,
  70                                                  block_count * block_size);
  71                 }
  72         }
  73         return NULL;
  74 }
  75 
  76 static PedGeometry*
  77 _ext2_probe (PedGeometry* geom)
  78 {
  79         return _ext2_generic_probe (geom, 0);
  80 }
  81 
  82 static PedGeometry*
  83 _ext3_probe (PedGeometry* geom)
  84 {
  85         return _ext2_generic_probe (geom, 1);
  86 }
  87 
  88 #ifndef DISCOVER_ONLY
  89 static int
  90 _ext2_clobber (PedGeometry* geom)
  91 {
  92         struct ext2_super_block sb;
  93 
  94         if (!ped_geometry_read(geom, &sb, 2, 2))
  95                 return 0;
  96         if (EXT2_SUPER_MAGIC(sb) != EXT2_SUPER_MAGIC_CONST)
  97                 return 1;
  98 
  99         sb.s_magic = 0;
 100         return ped_geometry_write(geom, &sb, 2, 2);
 101 }
 102 
 103 static PedFileSystem*
 104 _ext2_open (PedGeometry* geom)
 105 {
 106         PedFileSystem*          fs;
 107         struct ext2_fs*         fs_info;
 108         struct ext2_dev_handle* handle;
 109 
 110         fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
 111         if (!fs) goto error;
 112 
 113         fs->type = &_ext2_type;
 114         fs->geom = ped_geometry_duplicate (geom);
 115         fs->checked = 1;
 116 
 117         handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
 118         if (!handle) goto error_free_fs;
 119 
 120         fs_info = (struct ext2_fs*) ext2_open(handle, 0);
 121         if (!fs_info) goto error_free_handle;
 122 
 123         fs->type_specific = (void*) fs_info;
 124         fs_info->opt_verbose = 0;
 125 
 126         return fs;
 127 
 128 error_free_handle:
 129         ext2_destroy_dev_handle(handle);
 130 error_free_fs:
 131         ped_free(fs);
 132 error:
 133         return NULL;
 134 }
 135 
 136 static PedFileSystem*
 137 _ext2_create (PedGeometry* geom, PedTimer* timer)
 138 {
 139         PedFileSystem*          fs;
 140         struct ext2_fs*         fs_info;
 141         struct ext2_dev_handle* handle;
 142 
 143         fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
 144         if (!fs) goto error;
 145 
 146         fs->type = &_ext2_type;
 147         fs->geom = ped_geometry_duplicate (geom);
 148 
 149         handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
 150         if (!handle) goto error_free_fs;
 151 
 152         fs_info = ext2_mkfs (handle, 0, 0, 0, 0, -1, -1, timer);
 153         if (!fs_info) goto error_free_handle;
 154 
 155         fs->type_specific = (void*) fs_info;
 156         fs_info->opt_verbose = 0;
 157 
 158         return fs;
 159 
 160 error_free_handle:
 161         ext2_destroy_dev_handle(handle);
 162 error_free_fs:
 163         ped_free(fs);
 164 error:
 165         return NULL;
 166 }
 167 
 168 static int
 169 _ext2_close (PedFileSystem *fs)
 170 {
 171         struct ext2_dev_handle* handle;
 172 
 173         handle = ((struct ext2_fs*)fs->type_specific)->devhandle;
 174         ext2_close(fs->type_specific);
 175         ext2_destroy_dev_handle(handle);
 176 
 177         ped_free(fs);
 178         return 1;
 179 }
 180 
 181 static int
 182 _ext2_check (PedFileSystem *fs, PedTimer* timer)
 183 {
 184         ped_exception_throw (PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
 185                 _("The ext2 file system passed a basic check.  For a more "
 186                   "comprehensive check, use the e2fsck program."));
 187         return 1;
 188 }
 189 
 190 static int
 191 _ext2_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
 192 {
 193         struct ext2_fs* f;
 194         PedSector       old_length = fs->geom->length;
 195 
 196         PED_ASSERT (fs->geom->dev == geom->dev, return 0);
 197 
 198         if (fs->geom->start != geom->start)
 199         {
 200                 ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
 201                       PED_EXCEPTION_CANCEL,
 202                       _("Sorry, can't move the start of ext2 partitions yet!"));
 203                 return 0;
 204         }
 205 
 206         geom->dev->boot_dirty = 1;
 207 
 208         f = (struct ext2_fs *) fs->type_specific;
 209 
 210 /* ensure that the geometry contains the new and old geometry */
 211         if (old_length > geom->length) {
 212                 if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
 213                                     timer))
 214                         goto error;
 215 
 216                 fs->geom->length = geom->length;
 217                 fs->geom->end = fs->geom->start + geom->length - 1;
 218         } else {
 219                 fs->geom->length = geom->length;
 220                 fs->geom->end = fs->geom->start + geom->length - 1;
 221 
 222                 if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
 223                                     timer))
 224                         goto error;
 225         }
 226         return 1;
 227 
 228 error:
 229         return 0;
 230 }
 231 
 232 static PedConstraint*
 233 _ext2_get_create_constraint (const PedDevice* dev)
 234 {
 235         PedGeometry     full_dev;
 236 
 237         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
 238                 return NULL;
 239 
 240         return ped_constraint_new (
 241                         ped_alignment_any, ped_alignment_any,
 242                         &full_dev, &full_dev,
 243                         64, dev->length);
 244 }
 245 
 246 static PedConstraint*
 247 _ext2_get_resize_constraint (const PedFileSystem* fs)
 248 {
 249         struct ext2_fs* f = (struct ext2_fs *) fs->type_specific;
 250         PedDevice*      dev = fs->geom->dev;
 251         PedAlignment    start_align;
 252         PedGeometry     start_sector;
 253         PedGeometry     full_dev;
 254         PedSector       min_size;
 255 
 256         if (!ped_alignment_init (&start_align, fs->geom->start, 0))
 257                 return NULL;
 258         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
 259                 return NULL;
 260         if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
 261                 return NULL;
 262         min_size = (EXT2_SUPER_BLOCKS_COUNT(f->sb)
 263                         - EXT2_SUPER_FREE_BLOCKS_COUNT(f->sb))
 264                    * (f->blocksize / dev->sector_size);
 265 
 266         return ped_constraint_new (&start_align, ped_alignment_any,
 267                                    &start_sector, &full_dev, min_size,
 268                                    dev->length);
 269 }
 270 #endif /* !DISCOVER_ONLY */
 271 
 272 static PedFileSystemOps _ext2_ops = {
 273         .probe =                _ext2_probe,
 274 #ifndef DISCOVER_ONLY
 275         .clobber =      _ext2_clobber,
 276         .open =         _ext2_open,
 277         .create =         _ext2_create,
 278         .close =                _ext2_close,
 279         .check =          _ext2_check,
 280         .resize =               _ext2_resize,
 281         .copy =           NULL,
 282         .get_create_constraint =        _ext2_get_create_constraint,
 283         .get_copy_constraint =  NULL,
 284         .get_resize_constraint =        _ext2_get_resize_constraint
 285 #else /* !DISCOVER_ONLY */
 286         .clobber =      NULL,
 287         .open =         NULL,
 288         .create =         NULL,
 289         .close =                NULL,
 290         .check =          NULL,
 291         .resize =               NULL,
 292         .copy =           NULL,
 293         .get_create_constraint =        NULL,
 294         .get_copy_constraint =  NULL,
 295         .get_resize_constraint =        NULL
 296 #endif /* !DISCOVER_ONLY */
 297 };
 298 
 299 static PedFileSystemOps _ext3_ops = {
 300         .probe =                _ext3_probe,
 301 #ifndef DISCOVER_ONLY
 302         .clobber =      _ext2_clobber,
 303         .open =         _ext2_open,
 304         .create =         NULL,
 305         .close =                _ext2_close,
 306         .check =          _ext2_check,
 307         .resize =               _ext2_resize,
 308         .copy =           NULL,
 309         .get_create_constraint =        _ext2_get_create_constraint,
 310         .get_copy_constraint =  NULL,
 311         .get_resize_constraint =        _ext2_get_resize_constraint
 312 #else /* !DISCOVER_ONLY */
 313         .clobber =      NULL,
 314         .open =         NULL,
 315         .create =         NULL,
 316         .close =                NULL,
 317         .check =          NULL,
 318         .resize =               NULL,
 319         .copy =           NULL,
 320         .get_create_constraint =        NULL,
 321         .get_copy_constraint =  NULL,
 322         .get_resize_constraint =        NULL
 323 #endif /* !DISCOVER_ONLY */
 324 };
 325 
 326 #define EXT23_BLOCK_SIZES ((int[6]){512, 1024, 2048, 4096, 8192, 0})
 327 
 328 static PedFileSystemType _ext2_type = {
 329        .next =           NULL,
 330        .ops =            &_ext2_ops,
 331        .name =           "ext2",
 332        .block_sizes =      EXT23_BLOCK_SIZES
 333 };
 334 
 335 static PedFileSystemType _ext3_type = {
 336        .next =           NULL,
 337        .ops =            &_ext3_ops,
 338        .name =           "ext3",
 339        .block_sizes =      EXT23_BLOCK_SIZES
 340 };
 341 
 342 void ped_file_system_ext2_init ()
 343 {
 344         ped_file_system_type_register (&_ext2_type);
 345         ped_file_system_type_register (&_ext3_type);
 346 }
 347 
 348 void ped_file_system_ext2_done ()
 349 {
 350         ped_file_system_type_unregister (&_ext2_type);
 351         ped_file_system_type_unregister (&_ext3_type);
 352 }