diff options
Diffstat (limited to '')
-rw-r--r-- | libparted/labels/loop.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/libparted/labels/loop.c b/libparted/labels/loop.c new file mode 100644 index 0000000..45d169d --- /dev/null +++ b/libparted/labels/loop.c @@ -0,0 +1,316 @@ +/* + libparted - a library for manipulating disk partitions + Copyright (C) 1999-2000, 2007-2014, 2019-2023 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <config.h> + +#include <parted/parted.h> +#include <parted/debug.h> +#include <parted/endian.h> +#include <stdbool.h> + +#include "pt-tools.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 = loop_alloc (dev); + if (!disk) + goto error; + + void *buf; + if (!ptt_read_sector (dev, 0, &buf)) + goto error_destroy_disk; + int found_sig = !strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)); + free (buf); + + int result; + if (found_sig) { + 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; +} + +static PedDisk* +loop_alloc (const PedDevice* dev) +{ + PED_ASSERT (dev != NULL); + + if (dev->length < 256) + return NULL; + PedDisk *disk = _ped_disk_alloc ((PedDevice*)dev, &loop_disk_type); + PED_ASSERT (disk != NULL); + PedGeometry *geom = ped_geometry_new (dev, 0, dev->length); + PED_ASSERT (geom != NULL); + PedPartition *part = ped_partition_new (disk, PED_PARTITION_NORMAL, + NULL, geom->start, geom->end); + PED_ASSERT (part != NULL); + ped_geometry_destroy (geom); + PedConstraint *constraint_any = ped_constraint_any (dev); + if (!ped_disk_add_partition (disk, part, constraint_any)) + goto error; + ped_constraint_destroy (constraint_any); + return disk; + error: + ped_constraint_destroy (constraint_any); + ped_disk_destroy (disk); + return NULL; +} + +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); + + _ped_disk_free (disk); +} + +static int +loop_read (PedDisk* disk) +{ + PedDevice* dev = NULL; + PedGeometry* geom; + PedFileSystemType* fs_type; + PedPartition* part; + PedConstraint* constraint_any; + + PED_ASSERT (disk != NULL); + dev = disk->dev; + constraint_any = ped_constraint_any (dev); + + ped_disk_delete_all (disk); + + void *buf; + if (!ptt_read_sector (dev, 0, &buf)) + goto error; + + int found_sig = !strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE)); + free (buf); + geom = ped_geometry_new (dev, 0, dev->length); + if (!geom) + goto error; + + fs_type = ped_file_system_probe (geom); + if (!fs_type && !found_sig) + goto error_free_geom; + + part = ped_partition_new (disk, PED_PARTITION_NORMAL, + fs_type, geom->start, geom->end); + ped_geometry_destroy (geom); + if (!part) + goto error; + + 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) +{ + size_t buflen = disk->dev->sector_size; + char *buf = alloca (buflen); + PedPartition *part = ped_disk_get_partition (disk, 1); + /* if there is already a filesystem on the disk, we don't need to write the signature */ + if (part && part->fs_type) + return 1; + if (!ped_device_read (disk->dev, buf, 0, 1)) + return 0; + 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); + if (result == NULL) + return NULL; + result->num = part->num; + return result; +} + +static void +loop_partition_destroy (PedPartition* part) +{ + 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 bool +loop_get_max_supported_partition_count (const PedDisk* disk, int *max_n) +{ + *max_n = 1; + return true; +} + +#include "pt-common.h" +PT_define_limit_functions (loop) + +static PedDiskOps loop_disk_ops = { + clobber: NULL, + write: NULL_IF_DISCOVER_ONLY (loop_write), + + partition_set_name: NULL, + partition_get_name: NULL, + + PT_op_function_initializers (loop) +}; + +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); +} |