blob: a56229f91eca7e223cd1ac57105281f337e5df05 [file] [log] [blame]
/*
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);
}