1N/A/*
1N/A interface.c -- parted binding glue to libext2resize
1N/A Copyright (C) 1998-2000, 2007-2010 Free Software Foundation, Inc.
1N/A
1N/A This program is free software; you can redistribute it and/or modify
1N/A it under the terms of the GNU General Public License as published by
1N/A the Free Software Foundation; either version 3 of the License, or
1N/A (at your option) any later version.
1N/A
1N/A This program is distributed in the hope that it will be useful,
1N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A GNU General Public License for more details.
1N/A
1N/A You should have received a copy of the GNU General Public License
1N/A along with this program. If not, see <http://www.gnu.org/licenses/>.
1N/A*/
1N/A
1N/A/* VERSION: libext2resize 1.1.6 (by Lennert)
1N/A * merged 1.1.11 changes (by Andrew)
1N/A */
1N/A
1N/A#include <config.h>
1N/A
1N/A#include <parted/parted.h>
1N/A#include "ext2.h"
1N/A#include "parted_io.h"
1N/A
1N/Astatic PedFileSystemType _ext2_type;
1N/Astatic PedFileSystemType _ext3_type;
1N/A
1N/Astruct ext2_dev_handle* ext2_make_dev_handle_from_parted_geometry(PedGeometry* geom);
1N/A
1N/Astatic PedGeometry*
1N/A_ext2_generic_probe (PedGeometry* geom, int expect_ext_ver)
1N/A{
1N/A void *sb_v;
1N/A if (!ped_geometry_read_alloc(geom, &sb_v, 2, 2))
1N/A return NULL;
1N/A struct ext2_super_block *sb = sb_v;
1N/A
1N/A if (EXT2_SUPER_MAGIC(*sb) == EXT2_SUPER_MAGIC_CONST) {
1N/A PedSector block_size = 1 << (EXT2_SUPER_LOG_BLOCK_SIZE(*sb) + 1);
1N/A PedSector block_count = EXT2_SUPER_BLOCKS_COUNT(*sb);
1N/A PedSector group_blocks = EXT2_SUPER_BLOCKS_PER_GROUP(*sb);
1N/A PedSector group_nr = EXT2_SUPER_BLOCK_GROUP_NR(*sb);
1N/A PedSector first_data_block = EXT2_SUPER_FIRST_DATA_BLOCK(*sb);
1N/A int version = EXT2_SUPER_REV_LEVEL(*sb);
1N/A int is_ext3 = 0;
1N/A int is_ext4 = 0;
1N/A
1N/A is_ext3 = (EXT2_SUPER_FEATURE_COMPAT (*sb)
1N/A & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0;
1N/A if (is_ext3) {
1N/A is_ext4 = ((EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
1N/A & EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
1N/A || (EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
1N/A & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
1N/A || (EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
1N/A & EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
1N/A || (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
1N/A & EXT4_FEATURE_INCOMPAT_EXTENTS)
1N/A || (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
1N/A & EXT4_FEATURE_INCOMPAT_64BIT)
1N/A || (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
1N/A & EXT4_FEATURE_INCOMPAT_FLEX_BG));
1N/A if (is_ext4)
1N/A is_ext3 = 0;
1N/A }
1N/A free (sb);
1N/A
1N/A if (expect_ext_ver == 2 && (is_ext3 || is_ext4))
1N/A return NULL;
1N/A if (expect_ext_ver == 3 && !is_ext3)
1N/A return NULL;
1N/A else if (expect_ext_ver == 4 && !is_ext4)
1N/A return NULL;
1N/A
1N/A if (version > 0 && group_nr > 0) {
1N/A PedSector start;
1N/A PedGeometry probe_geom;
1N/A
1N/A start = geom->start
1N/A - group_blocks * group_nr
1N/A - first_data_block;
1N/A
1N/A if (start < 0)
1N/A return NULL;
1N/A ped_geometry_init (&probe_geom, geom->dev,
1N/A start, block_count * block_size);
1N/A return _ext2_generic_probe (&probe_geom,
1N/A expect_ext_ver);
1N/A } else {
1N/A return ped_geometry_new (geom->dev, geom->start,
1N/A block_count * block_size);
1N/A }
1N/A }
1N/A else {
1N/A free (sb);
1N/A }
1N/A
1N/A return NULL;
1N/A}
1N/A
1N/Astatic PedGeometry*
1N/A_ext2_probe (PedGeometry* geom)
1N/A{
1N/A return _ext2_generic_probe (geom, 2);
1N/A}
1N/A
1N/Astatic PedGeometry*
1N/A_ext3_probe (PedGeometry* geom)
1N/A{
1N/A return _ext2_generic_probe (geom, 3);
1N/A}
1N/A
1N/Astatic PedGeometry*
1N/A_ext4_probe (PedGeometry* geom)
1N/A{
1N/A return _ext2_generic_probe (geom, 4);
1N/A}
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/Astatic int
1N/A_ext2_clobber (PedGeometry* geom)
1N/A{
1N/A void *sb_v;
1N/A int ok = 0;
1N/A
1N/A if (ped_geometry_read_alloc(geom, &sb_v, 2, 2)) {
1N/A struct ext2_super_block *sb = sb_v;
1N/A /* Clobber only if there's a matching magic number. */
1N/A if (EXT2_SUPER_MAGIC(*sb) != EXT2_SUPER_MAGIC_CONST) {
1N/A ok = 1;
1N/A } else {
1N/A sb->s_magic = 0;
1N/A ok = ped_geometry_write(geom, sb, 2, 2);
1N/A }
1N/A free (sb);
1N/A }
1N/A return ok;
1N/A}
1N/A
1N/Astatic PedFileSystem*
1N/A_ext2_open (PedGeometry* geom)
1N/A{
1N/A PedFileSystem* fs;
1N/A struct ext2_fs* fs_info;
1N/A struct ext2_dev_handle* handle;
1N/A
1N/A fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
1N/A if (!fs) goto error;
1N/A
1N/A fs->type = &_ext2_type;
1N/A fs->geom = ped_geometry_duplicate (geom);
1N/A fs->checked = 1;
1N/A
1N/A handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
1N/A if (!handle) goto error_free_fs;
1N/A
1N/A fs_info = (struct ext2_fs*) ext2_open(handle, 0);
1N/A if (!fs_info) goto error_free_handle;
1N/A
1N/A fs->type_specific = (void*) fs_info;
1N/A fs_info->opt_verbose = 0;
1N/A
1N/A return fs;
1N/A
1N/Aerror_free_handle:
1N/A ext2_destroy_dev_handle(handle);
1N/Aerror_free_fs:
1N/A free(fs);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic PedFileSystem*
1N/A_ext2_create (PedGeometry* geom, PedTimer* timer)
1N/A{
1N/A PedFileSystem* fs;
1N/A struct ext2_fs* fs_info;
1N/A struct ext2_dev_handle* handle;
1N/A
1N/A fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
1N/A if (!fs) goto error;
1N/A
1N/A fs->type = &_ext2_type;
1N/A fs->geom = ped_geometry_duplicate (geom);
1N/A
1N/A handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
1N/A if (!handle) goto error_free_fs;
1N/A
1N/A fs_info = ext2_mkfs (handle, 0, 0, 0, 0, -1, -1, timer);
1N/A if (!fs_info) goto error_free_handle;
1N/A
1N/A fs->type_specific = (void*) fs_info;
1N/A fs_info->opt_verbose = 0;
1N/A
1N/A return fs;
1N/A
1N/Aerror_free_handle:
1N/A ext2_destroy_dev_handle(handle);
1N/Aerror_free_fs:
1N/A free(fs);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic int
1N/A_ext2_close (PedFileSystem *fs)
1N/A{
1N/A struct ext2_dev_handle* handle;
1N/A
1N/A handle = ((struct ext2_fs*)fs->type_specific)->devhandle;
1N/A ext2_close(fs->type_specific);
1N/A ext2_destroy_dev_handle(handle);
1N/A
1N/A free(fs);
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_ext2_check (PedFileSystem *fs, PedTimer* timer)
1N/A{
1N/A ped_exception_throw (PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
1N/A _("The ext2 file system passed a basic check. For a more "
1N/A "comprehensive check, use the e2fsck program."));
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/A_ext2_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
1N/A{
1N/A struct ext2_fs* f;
1N/A PedSector old_length = fs->geom->length;
1N/A
1N/A PED_ASSERT (fs->geom->dev == geom->dev, return 0);
1N/A
1N/A if (fs->geom->start != geom->start)
1N/A {
1N/A ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Sorry, can't move the start of ext2 partitions yet!"));
1N/A return 0;
1N/A }
1N/A
1N/A geom->dev->boot_dirty = 1;
1N/A
1N/A f = (struct ext2_fs *) fs->type_specific;
1N/A
1N/A/* ensure that the geometry contains the new and old geometry */
1N/A if (old_length > geom->length) {
1N/A if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
1N/A timer))
1N/A goto error;
1N/A
1N/A fs->geom->length = geom->length;
1N/A fs->geom->end = fs->geom->start + geom->length - 1;
1N/A } else {
1N/A fs->geom->length = geom->length;
1N/A fs->geom->end = fs->geom->start + geom->length - 1;
1N/A
1N/A if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
1N/A timer))
1N/A goto error;
1N/A }
1N/A return 1;
1N/A
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/Astatic PedConstraint*
1N/A_ext2_get_create_constraint (const PedDevice* dev)
1N/A{
1N/A PedGeometry full_dev;
1N/A
1N/A if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
1N/A return NULL;
1N/A
1N/A return ped_constraint_new (
1N/A ped_alignment_any, ped_alignment_any,
1N/A &full_dev, &full_dev,
1N/A 64, dev->length);
1N/A}
1N/A
1N/Astatic PedConstraint*
1N/A_ext2_get_resize_constraint (const PedFileSystem* fs)
1N/A{
1N/A struct ext2_fs* f = (struct ext2_fs *) fs->type_specific;
1N/A PedDevice* dev = fs->geom->dev;
1N/A PedAlignment start_align;
1N/A PedGeometry start_sector;
1N/A PedGeometry full_dev;
1N/A PedSector min_size;
1N/A
1N/A if (!ped_alignment_init (&start_align, fs->geom->start, 0))
1N/A return NULL;
1N/A if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
1N/A return NULL;
1N/A if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
1N/A return NULL;
1N/A min_size = (EXT2_SUPER_BLOCKS_COUNT(f->sb)
1N/A - EXT2_SUPER_FREE_BLOCKS_COUNT(f->sb))
1N/A * (f->blocksize / dev->sector_size);
1N/A
1N/A return ped_constraint_new (&start_align, ped_alignment_any,
1N/A &start_sector, &full_dev, min_size,
1N/A dev->length);
1N/A}
1N/A#endif /* !DISCOVER_ONLY */
1N/A
1N/Astatic PedFileSystemOps _ext2_ops = {
1N/A .probe = _ext2_probe,
1N/A#ifndef DISCOVER_ONLY
1N/A .clobber = _ext2_clobber,
1N/A .open = _ext2_open,
1N/A .create = _ext2_create,
1N/A .close = _ext2_close,
1N/A .check = _ext2_check,
1N/A .resize = _ext2_resize,
1N/A .copy = NULL,
1N/A .get_create_constraint = _ext2_get_create_constraint,
1N/A .get_copy_constraint = NULL,
1N/A .get_resize_constraint = _ext2_get_resize_constraint
1N/A#else /* !DISCOVER_ONLY */
1N/A .clobber = NULL,
1N/A .open = NULL,
1N/A .create = NULL,
1N/A .close = NULL,
1N/A .check = NULL,
1N/A .resize = NULL,
1N/A .copy = NULL,
1N/A .get_create_constraint = NULL,
1N/A .get_copy_constraint = NULL,
1N/A .get_resize_constraint = NULL
1N/A#endif /* !DISCOVER_ONLY */
1N/A};
1N/A
1N/Astatic PedFileSystemOps _ext3_ops = {
1N/A .probe = _ext3_probe,
1N/A#ifndef DISCOVER_ONLY
1N/A .clobber = _ext2_clobber,
1N/A .open = _ext2_open,
1N/A .create = NULL,
1N/A .close = _ext2_close,
1N/A .check = _ext2_check,
1N/A .resize = _ext2_resize,
1N/A .copy = NULL,
1N/A .get_create_constraint = _ext2_get_create_constraint,
1N/A .get_copy_constraint = NULL,
1N/A .get_resize_constraint = _ext2_get_resize_constraint
1N/A#else /* !DISCOVER_ONLY */
1N/A .clobber = NULL,
1N/A .open = NULL,
1N/A .create = NULL,
1N/A .close = NULL,
1N/A .check = NULL,
1N/A .resize = NULL,
1N/A .copy = NULL,
1N/A .get_create_constraint = NULL,
1N/A .get_copy_constraint = NULL,
1N/A .get_resize_constraint = NULL
1N/A#endif /* !DISCOVER_ONLY */
1N/A};
1N/A
1N/Astatic PedFileSystemOps _ext4_ops = {
1N/A .probe = _ext4_probe,
1N/A .clobber = NULL,
1N/A .open = NULL,
1N/A .create = NULL,
1N/A .close = NULL,
1N/A .check = NULL,
1N/A .resize = NULL,
1N/A .copy = NULL,
1N/A .get_create_constraint = NULL,
1N/A .get_copy_constraint = NULL,
1N/A .get_resize_constraint = NULL
1N/A};
1N/A
1N/A#define EXT23_BLOCK_SIZES ((int[6]){512, 1024, 2048, 4096, 8192, 0})
1N/A
1N/Astatic PedFileSystemType _ext2_type = {
1N/A .next = NULL,
1N/A .ops = &_ext2_ops,
1N/A .name = "ext2",
1N/A .block_sizes = EXT23_BLOCK_SIZES
1N/A};
1N/A
1N/Astatic PedFileSystemType _ext3_type = {
1N/A .next = NULL,
1N/A .ops = &_ext3_ops,
1N/A .name = "ext3",
1N/A .block_sizes = EXT23_BLOCK_SIZES
1N/A};
1N/A
1N/Astatic PedFileSystemType _ext4_type = {
1N/A .next = NULL,
1N/A .ops = &_ext4_ops,
1N/A .name = "ext4",
1N/A .block_sizes = EXT23_BLOCK_SIZES
1N/A};
1N/A
1N/Avoid ped_file_system_ext2_init ()
1N/A{
1N/A ped_file_system_type_register (&_ext2_type);
1N/A ped_file_system_type_register (&_ext3_type);
1N/A ped_file_system_type_register (&_ext4_type);
1N/A}
1N/A
1N/Avoid ped_file_system_ext2_done ()
1N/A{
1N/A ped_file_system_type_unregister (&_ext2_type);
1N/A ped_file_system_type_unregister (&_ext3_type);
1N/A ped_file_system_type_unregister (&_ext4_type);
1N/A}