| /* |
| interface.c -- parted binding glue to libext2resize |
| 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| /* VERSION: libext2resize 1.1.6 (by Lennert) |
| * merged 1.1.11 changes (by Andrew) |
| */ |
| |
| #include <config.h> |
| |
| #include <parted/parted.h> |
| #include "ext2.h" |
| #include "parted_io.h" |
| |
| static PedFileSystemType _ext2_type; |
| static PedFileSystemType _ext3_type; |
| |
| struct ext2_dev_handle* ext2_make_dev_handle_from_parted_geometry(PedGeometry* geom); |
| |
| static PedGeometry* |
| _ext2_generic_probe (PedGeometry* geom, int expect_ext3) |
| { |
| struct ext2_super_block sb; |
| |
| if (!ped_geometry_read(geom, &sb, 2, 2)) |
| return NULL; |
| |
| if (EXT2_SUPER_MAGIC(sb) == EXT2_SUPER_MAGIC_CONST) { |
| PedSector block_size = 1 << (EXT2_SUPER_LOG_BLOCK_SIZE(sb) + 1); |
| PedSector block_count = EXT2_SUPER_BLOCKS_COUNT(sb); |
| PedSector group_blocks = EXT2_SUPER_BLOCKS_PER_GROUP(sb); |
| PedSector group_nr = EXT2_SUPER_BLOCK_GROUP_NR(sb); |
| PedSector first_data_block = EXT2_SUPER_FIRST_DATA_BLOCK(sb); |
| int version = EXT2_SUPER_REV_LEVEL(sb); |
| int is_ext3 = (EXT2_SUPER_FEATURE_COMPAT(sb) |
| & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0; |
| |
| if (expect_ext3 != is_ext3) |
| return NULL; |
| |
| if (version > 0 && group_nr > 0) { |
| PedSector start; |
| PedGeometry probe_geom; |
| |
| start = geom->start |
| - group_blocks * group_nr |
| - first_data_block; |
| |
| if (start < 0) |
| return NULL; |
| ped_geometry_init (&probe_geom, geom->dev, |
| start, block_count * block_size); |
| return _ext2_generic_probe (&probe_geom, expect_ext3); |
| } else { |
| return ped_geometry_new (geom->dev, geom->start, |
| block_count * block_size); |
| } |
| } |
| return NULL; |
| } |
| |
| static PedGeometry* |
| _ext2_probe (PedGeometry* geom) |
| { |
| return _ext2_generic_probe (geom, 0); |
| } |
| |
| static PedGeometry* |
| _ext3_probe (PedGeometry* geom) |
| { |
| return _ext2_generic_probe (geom, 1); |
| } |
| |
| #ifndef DISCOVER_ONLY |
| static int |
| _ext2_clobber (PedGeometry* geom) |
| { |
| struct ext2_super_block sb; |
| |
| if (!ped_geometry_read(geom, &sb, 2, 2)) |
| return 0; |
| if (EXT2_SUPER_MAGIC(sb) != EXT2_SUPER_MAGIC_CONST) |
| return 1; |
| |
| sb.s_magic = 0; |
| return ped_geometry_write(geom, &sb, 2, 2); |
| } |
| |
| static PedFileSystem* |
| _ext2_open (PedGeometry* geom) |
| { |
| PedFileSystem* fs; |
| struct ext2_fs* fs_info; |
| struct ext2_dev_handle* handle; |
| |
| fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); |
| if (!fs) goto error; |
| |
| fs->type = &_ext2_type; |
| fs->geom = ped_geometry_duplicate (geom); |
| fs->checked = 1; |
| |
| handle = ext2_make_dev_handle_from_parted_geometry(fs->geom); |
| if (!handle) goto error_free_fs; |
| |
| fs_info = (struct ext2_fs*) ext2_open(handle, 0); |
| if (!fs_info) goto error_free_handle; |
| |
| fs->type_specific = (void*) fs_info; |
| fs_info->opt_verbose = 0; |
| |
| return fs; |
| |
| error_free_handle: |
| ext2_destroy_dev_handle(handle); |
| error_free_fs: |
| ped_free(fs); |
| error: |
| return NULL; |
| } |
| |
| static PedFileSystem* |
| _ext2_create (PedGeometry* geom, PedTimer* timer) |
| { |
| PedFileSystem* fs; |
| struct ext2_fs* fs_info; |
| struct ext2_dev_handle* handle; |
| |
| fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); |
| if (!fs) goto error; |
| |
| fs->type = &_ext2_type; |
| fs->geom = ped_geometry_duplicate (geom); |
| |
| handle = ext2_make_dev_handle_from_parted_geometry(fs->geom); |
| if (!handle) goto error_free_fs; |
| |
| fs_info = ext2_mkfs (handle, 0, 0, 0, 0, -1, -1, timer); |
| if (!fs_info) goto error_free_handle; |
| |
| fs->type_specific = (void*) fs_info; |
| fs_info->opt_verbose = 0; |
| |
| return fs; |
| |
| error_free_handle: |
| ext2_destroy_dev_handle(handle); |
| error_free_fs: |
| ped_free(fs); |
| error: |
| return NULL; |
| } |
| |
| static int |
| _ext2_close (PedFileSystem *fs) |
| { |
| struct ext2_dev_handle* handle; |
| |
| handle = ((struct ext2_fs*)fs->type_specific)->devhandle; |
| ext2_close(fs->type_specific); |
| ext2_destroy_dev_handle(handle); |
| |
| ped_free(fs); |
| return 1; |
| } |
| |
| static int |
| _ext2_check (PedFileSystem *fs, PedTimer* timer) |
| { |
| ped_exception_throw (PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK, |
| _("The ext2 file system passed a basic check. For a more " |
| "comprehensive check, use the e2fsck program.")); |
| return 1; |
| } |
| |
| static int |
| _ext2_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) |
| { |
| struct ext2_fs* f; |
| PedSector old_length = fs->geom->length; |
| |
| PED_ASSERT (fs->geom->dev == geom->dev, return 0); |
| |
| if (fs->geom->start != geom->start) |
| { |
| ped_exception_throw (PED_EXCEPTION_NO_FEATURE, |
| PED_EXCEPTION_CANCEL, |
| _("Sorry, can't move the start of ext2 partitions yet!")); |
| return 0; |
| } |
| |
| geom->dev->boot_dirty = 1; |
| |
| f = (struct ext2_fs *) fs->type_specific; |
| |
| /* ensure that the geometry contains the new and old geometry */ |
| if (old_length > geom->length) { |
| if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9), |
| timer)) |
| goto error; |
| |
| fs->geom->length = geom->length; |
| fs->geom->end = fs->geom->start + geom->length - 1; |
| } else { |
| fs->geom->length = geom->length; |
| fs->geom->end = fs->geom->start + geom->length - 1; |
| |
| if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9), |
| timer)) |
| goto error; |
| } |
| return 1; |
| |
| error: |
| return 0; |
| } |
| |
| static PedConstraint* |
| _ext2_get_create_constraint (const PedDevice* dev) |
| { |
| PedGeometry full_dev; |
| |
| if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1)) |
| return NULL; |
| |
| return ped_constraint_new ( |
| ped_alignment_any, ped_alignment_any, |
| &full_dev, &full_dev, |
| 64, dev->length); |
| } |
| |
| static PedConstraint* |
| _ext2_get_resize_constraint (const PedFileSystem* fs) |
| { |
| struct ext2_fs* f = (struct ext2_fs *) fs->type_specific; |
| PedDevice* dev = fs->geom->dev; |
| PedAlignment start_align; |
| PedGeometry start_sector; |
| PedGeometry full_dev; |
| PedSector min_size; |
| |
| if (!ped_alignment_init (&start_align, fs->geom->start, 0)) |
| return NULL; |
| if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1)) |
| return NULL; |
| if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1)) |
| return NULL; |
| min_size = (EXT2_SUPER_BLOCKS_COUNT(f->sb) |
| - EXT2_SUPER_FREE_BLOCKS_COUNT(f->sb)) |
| * (f->blocksize / dev->sector_size); |
| |
| return ped_constraint_new (&start_align, ped_alignment_any, |
| &start_sector, &full_dev, min_size, |
| dev->length); |
| } |
| #endif /* !DISCOVER_ONLY */ |
| |
| static PedFileSystemOps _ext2_ops = { |
| probe: _ext2_probe, |
| #ifndef DISCOVER_ONLY |
| clobber: _ext2_clobber, |
| open: _ext2_open, |
| create: _ext2_create, |
| close: _ext2_close, |
| check: _ext2_check, |
| resize: _ext2_resize, |
| copy: NULL, |
| get_create_constraint: _ext2_get_create_constraint, |
| get_copy_constraint: NULL, |
| get_resize_constraint: _ext2_get_resize_constraint |
| #else /* !DISCOVER_ONLY */ |
| clobber: NULL, |
| open: NULL, |
| create: NULL, |
| close: NULL, |
| check: NULL, |
| resize: NULL, |
| copy: NULL, |
| get_create_constraint: NULL, |
| get_copy_constraint: NULL, |
| get_resize_constraint: NULL |
| #endif /* !DISCOVER_ONLY */ |
| }; |
| |
| static PedFileSystemOps _ext3_ops = { |
| probe: _ext3_probe, |
| #ifndef DISCOVER_ONLY |
| clobber: _ext2_clobber, |
| open: _ext2_open, |
| create: NULL, |
| close: _ext2_close, |
| check: _ext2_check, |
| resize: _ext2_resize, |
| copy: NULL, |
| get_create_constraint: _ext2_get_create_constraint, |
| get_copy_constraint: NULL, |
| get_resize_constraint: _ext2_get_resize_constraint |
| #else /* !DISCOVER_ONLY */ |
| clobber: NULL, |
| open: NULL, |
| create: NULL, |
| close: NULL, |
| check: NULL, |
| resize: NULL, |
| copy: NULL, |
| get_create_constraint: NULL, |
| get_copy_constraint: NULL, |
| get_resize_constraint: NULL |
| #endif /* !DISCOVER_ONLY */ |
| }; |
| |
| #define EXT23_BLOCK_SIZES ((int[6]){512, 1024, 2048, 4096, 8192, 0}) |
| |
| static PedFileSystemType _ext2_type = { |
| next: NULL, |
| ops: &_ext2_ops, |
| name: "ext2", |
| block_sizes: EXT23_BLOCK_SIZES |
| }; |
| |
| static PedFileSystemType _ext3_type = { |
| next: NULL, |
| ops: &_ext3_ops, |
| name: "ext3", |
| block_sizes: EXT23_BLOCK_SIZES |
| }; |
| |
| void ped_file_system_ext2_init () |
| { |
| ped_file_system_type_register (&_ext2_type); |
| ped_file_system_type_register (&_ext3_type); |
| } |
| |
| void ped_file_system_ext2_done () |
| { |
| ped_file_system_type_unregister (&_ext2_type); |
| ped_file_system_type_unregister (&_ext3_type); |
| } |