disk.c revision 7e7bd3dccbfe8f79e25e5c1554b5bc3a9aaca321
/*
libparted - a library for manipulating disk partitions
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2007
Free Software Foundation, Inc.
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/>.
*/
/** \file disk.c */
/**
* \addtogroup PedDisk
*
* \brief Disk label access.
*
* Most programs will need to use ped_disk_new() or ped_disk_new_fresh() to get
* anything done. A PedDisk is always associated with a device and has a
* partition table. There are different types of partition tables (or disk
* labels). These are represented by the PedDiskType enumeration.
*
* @{
*/
#include <config.h>
#if ENABLE_NLS
# include <libintl.h>
#else
#endif /* ENABLE_NLS */
/* UPDATE MODE functions */
#ifdef DEBUG
#endif
PedPartition* part);
PedPartition* part);
void
{
/* pretend that "next" isn't part of the struct :-) */
}
void
{
if (last)
else
}
/**
* Deprecated: use ped_disk_type_regiser.
*/
void
{
}
/**
* Deprecated: use ped_disk_type_unregiser.
*/
void
{
}
/**
* Return the next disk type registers, after "type". If "type" is
* NULL, returns the first disk type.
*
* \return Next disk; NULL if "type" is the last registered disk type.
*/
{
if (type)
else
return disk_types;
}
/**
* Return the disk type with a name of "name".
*
* \return Disk type; NULL if no match.
*/
ped_disk_type_get (const char* name)
{
break;
return walk;
}
/**
* Return the type of partition table detected on "dev".
*
* \return Type; NULL if none was detected.
*/
{
if (!ped_device_open (dev))
return NULL;
break;
}
if (ped_exception)
return walk;
}
/**
* Read the partition table off a device (if one is found).
*
* \warning May modify \p dev->cylinders, \p dev->heads and \p dev->sectors
* if the partition table indicates that the existing values
* are incorrect.
*
* \return A new \link _PedDisk PedDisk \endlink object;
* NULL on failure (e.g. partition table not detected).
*/
{
if (!ped_device_open (dev))
goto error;
if (!type) {
_("%s: unrecognised disk label"),
goto error_close_dev;
}
if (!disk)
goto error_close_dev;
goto error_destroy_disk;
disk->needs_clobber = 0;
return disk;
return NULL;
}
static int
{
if (!new_part)
goto error;
if (!constraint_exact)
goto error_destroy_new_part;
return 1;
return 0;
}
/**
* Clone a \link _PedDisk PedDisk \endlink object.
*
* \return Deep copy of \p old_disk, NULL on failure.
*/
{
return NULL);
if (!new_disk)
goto error;
if (ped_partition_is_active (old_part)) {
goto error_destroy_new_disk;
}
}
return new_disk;
return NULL;
}
/**
* Remove all identifying signatures of a partition table,
* except for partition tables of a given type.
*
* \return 0 on error, 1 otherwise.
*
* \sa ped_disk_clobber()
*/
int
{
if (!ped_device_open (dev))
goto error;
int probed;
continue;
if (!probed)
goto error_close_dev;
}
}
return 1;
return 0;
}
/**
* Remove all identifying signatures of a partition table,
*
* \return 0 on error, 1 otherwise.
*
* \sa ped_disk_clobber_exclude()
*/
int
{
}
/**
* Create a new partition table on \p dev.
*
* This new partition table is only created in-memory, and nothing is written
* to disk until ped_disk_commit_to_dev() is called.
*
* \return The newly constructed \link _PedDisk PedDisk \endlink,
* NULL on failure.
*/
{
if (!disk)
goto error;
return disk;
return NULL;
}
{
if (!disk)
goto error;
return disk;
return NULL;
}
void
{
}
/**
* Close \p disk.
*
* What this function does depends on the PedDiskType of \p disk,
* but you can generally assume that outstanding writes are flushed
* (this mainly means that _ped_disk_free is called).
*/
void
{
}
/**
* Tell the operating system kernel about the partition table layout
* of \p disk.
*
* This is rather loosely defined: for example, on old versions of Linux,
* it simply calls the BLKRRPART ioctl, which tells the kernel to
* reread the partition table. On newer versions (2.4.x), it will
* use the new blkpg interface to tell Linux where each partition
* a specific type of partition table.
*
* \return 0 on failure, 1 otherwise.
*/
int
{
goto error;
goto error_close_dev;
return 1;
return 0;
}
/**
* Write the changes made to the in-memory description
* of a partition table to the device.
*
* \return 0 on failure, 1 otherwise.
*/
int
{
_("This libparted doesn't have write support for "
"%s. Perhaps it was compiled read-only."),
goto error;
}
goto error;
if (disk->needs_clobber) {
goto error_close_dev;
disk->needs_clobber = 0;
}
goto error_close_dev;
return 1;
return 0;
}
/*
* This function writes the in-memory changes to a partition table to
* disk and informs the operating system of the changes.
*
* \note Equivalent to calling first ped_disk_commit_to_dev(), then
* ped_disk_commit_to_os().
*
* \return 0 on failure, 1 otherwise.
*/
int
{
if (!ped_disk_commit_to_dev (disk))
return 0;
return ped_disk_commit_to_os (disk);
}
/**
* \addtogroup PedPartition
*
* @{
*/
/**
* Check whether a partition is mounted or busy in some
* other way.
*
* \note An extended partition is busy if any logical partitions are mounted.
*
* \return \c 1 if busy.
*/
int
{
}
/**
* Return a path that can be used to address the partition in the
* operating system.
*/
char*
{
}
/** @} */
/**
* \addtogroup PedDisk
*
* @{
*/
/**
* Perform a sanity check on a partition table.
*
* \note The check performed is generic (i.e. it does not depends on the label
* type of the disk.
*
* \throws PED_EXCEPTION_WARNING if a partition type ID does not match the file
* system on it.
*
* \return 0 if the check fails, 1 otherwise.
*/
int
{
continue;
if (!geom)
continue;
|| length_error > max_length_error) {
_("Partition %d is %s, but the file system is "
"%s."),
if (choice != PED_EXCEPTION_IGNORE)
return 0;
}
}
return 1;
}
/**
* This function checks if a particular type of partition table supports
* a feature.
*
* \return 1 if \p disk_type supports \p feature, 0 otherwise.
*/
int
{
}
/**
* Get the number of primary partitions.
*/
int
{
int count = 0;
if (ped_partition_is_active (walk)
count++;
}
return count;
}
/**
* Get the highest partition number on \p disk.
*/
int
{
int highest = -1;
}
return highest;
}
/**
* Get the maximum number of (primary) partitions the disk label supports.
*
* For example, MacIntosh partition maps can have different sizes,
* and accordingly support a different number of partitions.
*/
int
{
return 0);
}
/**
* \internal We turned a really nasty bureaucracy problem into an elegant maths
* problem :-) Basically, there are some constraints to a partition's
* geometry:
*
* (1) it must start and end on a "disk" block, determined by the disk label
* (not the hardware). (constraint represented by a PedAlignment)
*
* (2) if we're resizing a partition, we MIGHT need to keep each block aligned.
* Eg: if an ext2 file system has 4k blocks, then we can only move the start
* by a multiple of 4k. (constraint represented by a PedAlignment)
*
* (3) we need to keep the start and end within the device's physical
* boundaries. (constraint represented by a PedGeometry)
*
* Satisfying (1) and (2) simultaneously required a bit of fancy maths ;-) See
* ped_alignment_intersect()
*
* The application of these constraints is in disk_*.c's *_partition_align()
* function.
*/
static int
{
const PedDiskType* disk_type;
}
static int
{
const PedDiskType* disk_type;
}
/**
* Gives all the (active) partitions a number. It should preserve the numbers
* and orders as much as possible.
*/
static int
{
int i;
int end;
/* first "sort" already-numbered partitions. (e.g. if a logical partition
* is removed, then all logical partitions that were number higher MUST be
* renumbered)
*/
for (i=1; i<=end; i++) {
if (walk) {
if (!_partition_enumerate (walk))
return 0;
}
}
/* now, number un-numbered partitions */
if (!_partition_enumerate (walk))
return 0;
}
}
return 1;
}
static int
{
while (next) {
while (1) {
break;
}
}
return 1;
}
static int
{
if (!disk->update_mode)
}
static int
{
}
}
return 1;
}
static int
{
if (!extended_part)
return 1;
disk,
NULL,
}
}
disk,
NULL,
if (last)
else
}
return 1;
}
static int
{
if (!_disk_remove_freespace (disk))
return 0;
if (!_alloc_extended_freespace (disk))
return 0;
last_end = -1;
}
}
if (last)
else
}
return 1;
}
/**
* Update mode: used when updating the internal representation of the partition
* table. In update mode, the metadata and freespace placeholder/virtual
* partitions are removed, making it much easier for various manipulation
* routines...
*/
static void
{
if (!disk->update_mode) {
#ifdef DEBUG
#endif
disk->update_mode++;
#ifdef DEBUG
#endif
} else {
disk->update_mode++;
}
}
static void
{
/* re-allocate metadata BEFORE leaving update mode, to prevent infinite
* recursion (metadata allocation requires update mode)
*/
#ifdef DEBUG
#endif
disk->update_mode--;
#ifdef DEBUG
#endif
} else {
disk->update_mode--;
}
}
/** @} */
/**
* \addtogroup PedPartition
*
* \brief Partition access.
*
* @{
*/
const PedFileSystemType* fs_type,
{
if (!part)
goto error;
goto error_free_part;
return part;
return NULL;
}
void
{
}
int
const PedConstraint* external,
{
if (!intersection)
goto fail;
if (!solution)
goto fail_free_intersection;
return 1;
fail:
return 0;
}
/**
* Create a new \link _PedPartition PedPartition \endlink on \p disk.
*
* \param type One of \p PED_PARTITION_NORMAL, \p PED_PARTITION_EXTENDED,
* \p PED_PARTITION_LOGICAL.
*
* \note The constructed partition is not added to <tt>disk</tt>'s
* partition table. Use ped_disk_add_partition() to do this.
*
* \return A new \link _PedPartition PedPartition \endlink object,
* NULL on failure.
*
* \throws PED_EXCEPTION_ERROR if \p type is \p EXTENDED or \p LOGICAL but the
* label does not support this concept.
*/
{
int supports_extended;
if (!supports_extended
&& (type == PED_PARTITION_EXTENDED
|| type == PED_PARTITION_LOGICAL)) {
_("%s disk labels do not support extended "
"partitions."),
goto error;
}
if (!part)
goto error;
goto error_destroy_part;
}
return part;
return NULL;
}
/**
* Destroy a \link _PedPartition PedPartition \endlink object.
*
* \note Should not be called on a partition that is in a partition table.
* Use ped_disk_delete_partition() instead.
*/
void
{
}
/**
* Return whether or not the partition is "active".
*
* A partition is active if \p part->type is neither \p PED_PARTITION_METADATA
* nor \p PED_PARTITION_FREE.
*/
int
{
}
/**
* Set the state (\c 1 or \c 0) of a flag on a partition.
*
* Flags are disk label specific, although they have a global
* "namespace": the flag PED_PARTITION_BOOT, for example, roughly means
* "this" partition is bootable". But this means different things on different
* disk labels (and may not be defined on some disk labels). For example,
* on MS-DOS disk labels, there can only be one boot partition, and this
* refers to the partition that will be booted from on startup. On PC98
* disk labels, the user can choose from any bootable partition on startup.
*
* \note It is an error to call this on an unavailable flag -- use
* ped_partition_is_flag_available() to determine which flags are available
* for a given disk label.
*
* \throws PED_EXCEPTION_ERROR if the requested flag is not available for this
* label.
*/
int
{
"The flag '%s' is not available for %s disk labels.",
return 0;
}
}
/**
* Get the state (\c 1 or \c 0) of a flag on a partition.
*
* See ped_partition_set_flag() for conditions that must hold.
*
* \todo Where's the check for flag availability?
*/
int
{
return 0);
}
/**
* Check whether a given flag is available on a partition.
*
* \return \c 1 if the flag is available.
*/
int
{
return 0);
}
/**
* Sets the system type on the partition to \p fs_type.
*
* \note The file system may be opened, to get more information about the
* file system, e.g. to determine if it's FAT16 or FAT32.
*
* \return \c 0 on failure.
*/
int
{
const PedDiskType* disk_type;
}
static int
{
if (!ped_disk_type_check_feature (
"%s disk labels do not support partition names.",
return 0;
}
return 1;
}
/**
* Sets the name of a partition.
*
* \note This will only work if the disk label supports it.
* You can use
* \code
* ped_disk_type_check_feature (part->disk->type, PED_DISK_TYPE_PARTITION_NAME);
* \endcode
* to check whether this feature is enabled for a label.
*
* \note \p name will not be modified by libparted. It can be freed
* by the caller immediately after ped_partition_set_name() is called.
*
* \return \c 1 on success, \c 0 otherwise.
*/
int
{
return 0;
return 0);
return 1;
}
/**
* Returns the name of a partition \p part. This will only work if the disk
* label supports it.
*
* \note The returned string should not be modified. It should
* not be referenced after the partition is destroyed.
*/
const char*
{
return NULL;
return NULL);
}
/** @} */
/**
* \addtogroup PedDisk
*
* @{
*/
{
break;
}
return walk;
}
/**
* Return the next partition after \p part on \p disk. If \p part is \c NULL,
* return the first partition. If \p part is the last partition, returns
* \c NULL. If \p part is an extended partition, returns the first logical
* partition. If this is called repeatedly passing the return value as \p part,
* a depth-first traversal is executed.
*
* \return The next partition, \c NULL if no more partitions left.
*/
{
if (!part)
return NULL;
}
/** @} */
#ifdef DEBUG
static int
{
}
if (!ped_disk_extended_partition (disk))
return 1;
}
return 1;
}
#endif
/**
* Returns the partition numbered \p num.
*
* \return \c NULL if the specified partition does not exist.
*/
{
return walk;
}
return NULL;
}
/**
* Returns the partition that contains sect. If sect lies within a logical
* partition, then the logical partition is returned (not the extended
* partition).
*/
{
return walk;
}
/* should never get here, unless sect is outside of disk's useable
* part, or we're in "update mode", and the free space place-holders
* have been removed with _disk_remove_freespace()
*/
return NULL;
}
/* I'm beginning to agree with Sedgewick :-/ */
static int
{
} else {
else
}
return 1;
}
static int
{
return 1;
}
static int
{
} else {
} else {
}
}
return 1;
}
/*
*UPDATE MODE ONLY
*/
static int
{
break;
}
if (walk) {
} else {
if (last) {
} else {
else
}
}
return 1;
}
static PedConstraint*
{
} else {
min_start = 0;
}
}
if (walk)
return NULL;
return ped_constraint_new_from_max (&free_space);
}
/*
* Returns \c 0 if the partition, \p part overlaps with any partitions on the
* \p disk. The geometry of \p part is taken to be \p geom, NOT \p part->geom
* (the idea here is to check if \p geom is valid, before changing \p part).
*
* This is useful for seeing if a resized partitions new geometry is going to
* fit, without the existing geomtry getting in the way.
*
* Note: overlap with an extended partition is also allowed, provided that
* \p geom lies completely inside the extended partition.
*/
static int
{
continue;
continue;
continue;
continue;
return 0;
}
}
return 1;
}
static int
{
_("%s disk labels don't support logical or extended "
"partitions."),
return 0;
}
if (ped_partition_is_active (part)
_("Too many primary partitions."));
return 0;
}
}
_("Can't add a logical partition to %s, because "
"there is no extended partition."),
return 0;
}
return 1;
}
static int
{
_("Can't have more than one extended partition on %s."),
return 0;
}
_("Can't have logical partitions outside of "
"the extended partition."));
return 0;
}
}
return 1;
}
static int
{
return 0;
}
_("Can't have a logical partition outside of the "
"extended partition on %s."),
return 0;
}
_("Can't have overlapping partitions."));
return 0;
}
_("Can't have a primary partition inside an extended "
"partition."));
return 0;
}
return 1;
}
/**
* Adds PedPartition \p part to PedPartition \p disk.
*
* \warning The partition's geometry may be changed, subject to \p constraint.
* You could set \p constraint to <tt>ped_constraint_exact(&part->geom)</tt>,
* but many partition table schemes have special requirements on the start
* and end of partitions. Therefore, having an overly strict constraint
* will probably mean that this function will fail (in which
* case \p part will be left unmodified)
* \p part is assigned a number (\p part->num) in this process.
*
* \return \c 0 on failure.
*/
int
const PedConstraint* constraint)
{
return 0;
if (ped_partition_is_active (part)) {
if (!constraints && constraint) {
_("Can't have overlapping partitions."));
goto error;
}
if (!_partition_enumerate (part))
goto error;
goto error;
}
goto error;
goto error;
#ifdef DEBUG
if (!_disk_check_sanity (disk))
return 0;
#endif
return 1;
return 0;
}
/**
* Removes PedPartition \p part from PedDisk \p disk.
*
* If \p part is an extended partition, it must not contain any logical
* partitions. \p part is *NOT* destroyed. The caller must call
* ped_partition_destroy(), or use ped_disk_delete_partition() instead.
*
* \return \c 0 on error.
*/
int
{
return 1;
return 0;
}
static int
/**
* Removes \p part from \p disk, and destroys \p part.
*
* \return \c 0 on failure.
*/
int
{
return 1;
}
static int
{
return 0;
}
return 1;
}
/**
* Removes and destroys all partitions on \p disk.
*
* \return \c 0 on failure.
*/
int
{
return 0;
}
return 1;
}
/**
* Sets the geometry of \p part (i.e. change a partitions location). This can
* fail for many reasons, e.g. can't overlap with other partitions. If it
* does fail, \p part will remain unchanged. Returns \c 0 on failure. \p part's
* geometry may be set to something different from \p start and \p end subject
* to \p constraint.
*
* \warning The constraint warning from ped_disk_add_partition() applies.
*
* \note this function does not modify the contents of the partition. You need
* to call ped_file_system_resize() separately.
*/
int
const PedConstraint* constraint,
{
if (!constraints && constraint) {
_("Can't have overlapping partitions."));
goto error_pop_update_mode;
}
goto error_pop_update_mode;
goto error_pop_update_mode;
/* remove and add, to ensure the ordering gets updated if necessary */
return 1;
return 0;
}
/**
* Grow PedPartition \p part geometry to the maximum possible subject to
* \p constraint. The new geometry will be a superset of the old geometry.
*
* \return 0 on failure
*/
int
const PedConstraint* constraint)
{
} else {
global_min_start = 0;
}
else
else
new_end))
goto error;
return 1;
return 0;
}
/**
* Get the maximum geometry \p part can be grown to, subject to
* \p constraint.
*
* \return \c NULL on failure.
*/
const PedConstraint* constraint)
{
return NULL;
/* this assertion should never fail, because the old
* geometry was valid
*/
return NULL);
return max_geom;
}
/**
* Reduce the size of the extended partition to a minimum while still wrapping
* its logical partitions. If there are no logical partitions, remove the
* extended partition.
*
* \return 0 on failure.
*/
int
{
int status;
if (!ext_part)
return 1;
if (!first_logical) {
}
last_logical = walk;
return status;
}
/**
* @}
*/
/**
* \addtogroup PedPartition
*
* @{
*/
/**
* Returns a name that seems mildly appropriate for a partition type \p type.
*
* Eg, if you pass (PED_PARTITION_LOGICAL & PED_PARTITION_FREESPACE), it
* will return "free". This isn't to be taken too seriously - it's just
* useful for user interfaces, so you can show the user something ;-)
*
* \note The returned string will be in English. However,
* translations are provided, so the caller can call
* dgettext("parted", RESULT) on the result.
*
*/
const char*
{
if (type & PED_PARTITION_METADATA)
return N_("metadata");
else if (type & PED_PARTITION_FREESPACE)
return N_("free");
else if (type & PED_PARTITION_EXTENDED)
return N_("extended");
else if (type & PED_PARTITION_LOGICAL)
return N_("logical");
else
return N_("primary");
}
/**
* Returns a name for a \p flag, e.g. PED_PARTITION_BOOT will return "boot".
*
* \note The returned string will be in English. However,
* translations are provided, so the caller can call
* dgettext("parted", RESULT) on the result.
*/
const char*
{
switch (flag) {
case PED_PARTITION_BOOT:
return N_("boot");
case PED_PARTITION_ROOT:
return N_("root");
case PED_PARTITION_SWAP:
return N_("swap");
case PED_PARTITION_HIDDEN:
return N_("hidden");
case PED_PARTITION_RAID:
return N_("raid");
case PED_PARTITION_LVM:
return N_("lvm");
case PED_PARTITION_LBA:
return N_("lba");
case PED_PARTITION_HPSERVICE:
return N_("hp-service");
case PED_PARTITION_PALO:
return N_("palo");
case PED_PARTITION_PREP:
return N_("prep");
return N_("msftres");
default:
_("Unknown partition flag, %d."),
flag);
return NULL;
}
}
/**
* Iterates through all flags.
*
* ped_partition_flag_next(0) returns the first flag
*
* \return the next flag, or 0 if there are no more flags
*/
{
}
/**
* Returns the flag associated with \p name.
*
* \p name can be the English
* string, or the translation for the native language.
*/
ped_partition_flag_get_by_name (const char* name)
{
const char* flag_name;
return flag;
}
return 0;
}
static void
{
printf (" %-10s %02d (%d->%d)\n",
}
/** @} */
/**
* \addtogroup PedDisk
*
* @{
*/
/**
* Prints a summary of disk's partitions. Useful for debugging.
*/
void
{
}
/** @} */