317 lines
6.8 KiB
C
Executable File
317 lines
6.8 KiB
C
Executable File
/*
|
|
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);
|
|
}
|