blob: 9a7e0d622fdf7b767916e789f16fe0432e7d3482 [file] [log] [blame]
/*
libparted - a library for manipulating disk partitions
Copyright (C) 1999, 2000, 2007 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
*/
#include <config.h>
#include <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) dgettext (PACKAGE, String)
#else
# define _(String) (String)
#endif /* ENABLE_NLS */
#define LOOP_SIGNATURE "GNU Parted Loopback 0"
static PedDiskType loop_disk_type;
static PedDisk* loop_alloc (const PedDevice* dev);
static void loop_free (PedDisk* disk);
static int
loop_probe (const PedDevice* dev)
{
PedDisk* disk;
char buf [512];
int result;
if (dev->sector_size != 512)
return 0;
disk = loop_alloc (dev);
if (!disk)
goto error;
if (!ped_device_read (dev, buf, 0, 1))
goto error_destroy_disk;
if (strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)) == 0) {
result = 1;
} else {
PedGeometry* geom;
geom = ped_geometry_new (dev, 0, disk->dev->length);
if (!geom)
goto error_destroy_disk;
result = ped_file_system_probe (geom) != NULL;
ped_geometry_destroy (geom);
}
loop_free (disk);
return result;
error_destroy_disk:
loop_free (disk);
error:
return 0;
}
#ifndef DISCOVER_ONLY
static int
loop_clobber (PedDevice* dev)
{
char buf [512];
PedSector i = 0;
PED_ASSERT (dev != NULL, return 0);
memset (buf, 0, 512);
while (loop_probe (dev)) {
if (!ped_device_write (dev, buf, i++, 1))
return 0;
}
return 1;
}
#endif /* !DISCOVER_ONLY */
static PedDisk*
loop_alloc (const PedDevice* dev)
{
PED_ASSERT (dev != NULL, return 0);
if (dev->length < 256)
return NULL;
return _ped_disk_alloc ((PedDevice*)dev, &loop_disk_type);
}
static PedDisk*
loop_duplicate (const PedDisk* disk)
{
return ped_disk_new_fresh (disk->dev, &loop_disk_type);
}
static void
loop_free (PedDisk* disk)
{
PED_ASSERT (disk != NULL, return);
_ped_disk_free (disk);
}
static int
loop_read (PedDisk* disk)
{
PedDevice* dev = NULL;
char buf [512];
PedGeometry* geom;
PedFileSystemType* fs_type;
PedPartition* part;
PedConstraint* constraint_any;
PED_ASSERT (disk != NULL, return 0);
dev = disk->dev;
constraint_any = ped_constraint_any (dev);
ped_disk_delete_all (disk);
if (!ped_device_read (dev, buf, 0, 1))
goto error;
if (!strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)))
return 1;
geom = ped_geometry_new (dev, 0, dev->length);
if (!geom)
goto error;
fs_type = ped_file_system_probe (geom);
if (!fs_type)
goto error_free_geom;
part = ped_partition_new (disk, 0, fs_type, geom->start, geom->end);
ped_geometry_destroy (geom);
if (!part)
goto error;
part->fs_type = fs_type;
if (!ped_disk_add_partition (disk, part, constraint_any))
goto error;
ped_constraint_destroy (constraint_any);
return 1;
error_free_geom:
ped_geometry_destroy (geom);
error:
ped_constraint_destroy (constraint_any);
return 0;
}
#ifndef DISCOVER_ONLY
static int
loop_write (const PedDisk* disk)
{
char buf [512];
if (ped_disk_get_partition (disk, 1)) {
if (!ped_device_read (disk->dev, buf, 0, 1))
return 0;
if (strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)) != 0)
return 1;
memset (buf, 0, strlen (LOOP_SIGNATURE));
return ped_device_write (disk->dev, buf, 0, 1);
}
memset (buf, 0, 512);
strcpy (buf, LOOP_SIGNATURE);
return ped_device_write (disk->dev, buf, 0, 1);
}
#endif /* !DISCOVER_ONLY */
static PedPartition*
loop_partition_new (const PedDisk* disk, PedPartitionType part_type,
const PedFileSystemType* fs_type,
PedSector start, PedSector end)
{
PedPartition* part;
part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
if (!part)
return NULL;
part->disk_specific = NULL;
return part;
}
static PedPartition*
loop_partition_duplicate (const PedPartition* part)
{
PedPartition* result;
result = ped_partition_new (part->disk, part->type, part->fs_type,
part->geom.start, part->geom.end);
result->num = part->num;
return result;
}
static void
loop_partition_destroy (PedPartition* part)
{
ped_free (part);
}
static int
loop_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
{
part->fs_type = fs_type;
return 1;
}
static int
loop_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
{
return 0;
}
static int
loop_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
{
return 0;
}
static int
loop_partition_align (PedPartition* part, const PedConstraint* constraint)
{
PedGeometry* new_geom;
new_geom = ped_constraint_solve_nearest (constraint, &part->geom);
if (!new_geom) {
ped_exception_throw (
PED_EXCEPTION_ERROR,
PED_EXCEPTION_CANCEL,
_("Unable to satisfy all constraints on the "
"partition."));
return 0;
}
ped_geometry_set (&part->geom, new_geom->start, new_geom->length);
ped_geometry_destroy (new_geom);
return 1;
}
static int
loop_partition_is_flag_available (const PedPartition* part,
PedPartitionFlag flag)
{
return 0;
}
static int
loop_partition_enumerate (PedPartition* part)
{
part->num = 1;
return 1;
}
static int
loop_alloc_metadata (PedDisk* disk)
{
return 1;
}
static int
loop_get_max_primary_partition_count (const PedDisk* disk)
{
return 1;
}
static PedDiskOps loop_disk_ops = {
probe: loop_probe,
#ifndef DISCOVER_ONLY
clobber: loop_clobber,
#else
clobber: NULL,
#endif
alloc: loop_alloc,
duplicate: loop_duplicate,
free: loop_free,
read: loop_read,
#ifndef DISCOVER_ONLY
write: loop_write,
#else
write: NULL,
#endif
partition_new: loop_partition_new,
partition_duplicate: loop_partition_duplicate,
partition_destroy: loop_partition_destroy,
partition_set_system: loop_partition_set_system,
partition_set_flag: loop_partition_set_flag,
partition_get_flag: loop_partition_get_flag,
partition_is_flag_available: loop_partition_is_flag_available,
partition_set_name: NULL,
partition_get_name: NULL,
partition_align: loop_partition_align,
partition_enumerate: loop_partition_enumerate,
alloc_metadata: loop_alloc_metadata,
get_max_primary_partition_count:
loop_get_max_primary_partition_count
};
static PedDiskType loop_disk_type = {
next: NULL,
name: "loop",
ops: &loop_disk_ops,
features: 0
};
void
ped_disk_loop_init ()
{
ped_disk_type_register (&loop_disk_type);
}
void
ped_disk_loop_done ()
{
ped_disk_type_unregister (&loop_disk_type);
}