| /* |
| 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); |
| } |