diff options
Diffstat (limited to 'usr/src/lib/libparted/common/libparted/unit.c')
-rw-r--r-- | usr/src/lib/libparted/common/libparted/unit.c | 565 |
1 files changed, 0 insertions, 565 deletions
diff --git a/usr/src/lib/libparted/common/libparted/unit.c b/usr/src/lib/libparted/common/libparted/unit.c deleted file mode 100644 index 29c4ed50ce..0000000000 --- a/usr/src/lib/libparted/common/libparted/unit.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - libparted - a library for manipulating disk partitions - Copyright (C) 2005, 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 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 unit.c */ - -/** - * \addtogroup PedUnit - * - * \brief The PedUnit module provides a standard mechanism for describing - * and parsing locations within devices in human-friendly plain text. - * - * Internally, libparted uses PedSector (which is typedef'ed to be long long - * in <parted/device.h>) to describe device locations such as the start and - * end of partitions. However, sector numbers are often long and unintuitive. - * For example, my extended partition starts at sector 208845. PedUnit allows - * this location to be represented in more intutitive ways, including "106Mb", - * "0Gb" and "0%", as well as "208845s". PedUnit aims to provide facilities - * to provide a consistent system for describing device locations all - * throughout libparted. - * - * PedUnit provides two basic services: converting a PedSector into a text - * representation, and parsing a text representation into a PedSector. - * PedUnit currently supports these units: - * - * sectors, bytes, kilobytes, megabytes, gigabytes, terabytes, compact, - * cylinder and percent. - * - * PedUnit has a global variable that contains the default unit for all - * conversions. - * - * @{ - */ - - - - -#include <config.h> -#include <parted/parted.h> -#include <parted/debug.h> - -#include <ctype.h> -#include <stdio.h> -#include <float.h> - -#define N_(String) String -#if ENABLE_NLS -# include <libintl.h> -# define _(String) dgettext (PACKAGE, String) -#else -# define _(String) (String) -#endif /* ENABLE_NLS */ - - -static PedUnit default_unit = PED_UNIT_COMPACT; -static const char* unit_names[] = { - "s", - "B", - "kB", - "MB", - "GB", - "TB", - "compact", - "cyl", - "chs", - "%", - "kiB", - "MiB", - "GiB", - "TiB" -}; - - -/** - * \brief Set the default \p unit used by subsequent calls to the PedUnit API. - * - * In particular, this affects how locations inside error messages - * (exceptions) are displayed. - */ -void -ped_unit_set_default (PedUnit unit) -{ - default_unit = unit; -} - - -/** - * \brief Get the current default unit. - */ -PedUnit -ped_unit_get_default () -{ - return default_unit; -} - -/** - * Get the byte size of a given \p unit. - */ -long long -ped_unit_get_size (const PedDevice* dev, PedUnit unit) -{ - PedSector cyl_size = dev->bios_geom.heads * dev->bios_geom.sectors; - - switch (unit) { - case PED_UNIT_SECTOR: return dev->sector_size; - case PED_UNIT_BYTE: return 1; - case PED_UNIT_KILOBYTE: return PED_KILOBYTE_SIZE; - case PED_UNIT_MEGABYTE: return PED_MEGABYTE_SIZE; - case PED_UNIT_GIGABYTE: return PED_GIGABYTE_SIZE; - case PED_UNIT_TERABYTE: return PED_TERABYTE_SIZE; - case PED_UNIT_KIBIBYTE: return PED_KIBIBYTE_SIZE; - case PED_UNIT_MEBIBYTE: return PED_MEBIBYTE_SIZE; - case PED_UNIT_GIBIBYTE: return PED_GIBIBYTE_SIZE; - case PED_UNIT_TEBIBYTE: return PED_TEBIBYTE_SIZE; - case PED_UNIT_CYLINDER: return cyl_size * dev->sector_size; - case PED_UNIT_CHS: return dev->sector_size; - - case PED_UNIT_PERCENT: - return dev->length * dev->sector_size / 100; - - case PED_UNIT_COMPACT: - ped_exception_throw ( - PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, - _("Cannot get unit size for special unit " - "'COMPACT'.")); - return 0; - } - - /* never reached */ - PED_ASSERT(0, return 0); - return 0; -} - -/** - * Get a textual (non-internationalized) representation of a \p unit. - * - * For example, the textual representation of PED_UNIT_SECTOR is "s". - */ -const char* -ped_unit_get_name (PedUnit unit) -{ - return unit_names[unit]; -} - -/** - * Get a unit based on its textual representation: \p unit_name. - * - * For example, ped_unit_get_by_name("Mb") returns PED_UNIT_MEGABYTE. - */ -PedUnit -ped_unit_get_by_name (const char* unit_name) -{ - PedUnit unit; - for (unit = PED_UNIT_FIRST; unit <= PED_UNIT_LAST; unit++) { - if (!strcasecmp (unit_names[unit], unit_name)) - return unit; - } - return -1; -} - -static char* -ped_strdup (const char *str) -{ - char *result; - result = ped_malloc (strlen (str) + 1); - if (!result) - return NULL; - strcpy (result, str); - return result; -} - -/** - * \brief Get a string that describes the location of the \p byte on - * device \p dev. - * - * The string is described with the desired \p unit. - * The returned string must be freed with ped_free(). - */ -char* -ped_unit_format_custom_byte (const PedDevice* dev, PedSector byte, PedUnit unit) -{ - char buf[100]; - PedSector sector = byte / dev->sector_size; - double d, w; - int p; - - PED_ASSERT (dev != NULL, return NULL); - - /* CHS has a special comma-separated format. */ - if (unit == PED_UNIT_CHS) { - const PedCHSGeometry *chs = &dev->bios_geom; - snprintf (buf, 100, "%lld,%lld,%lld", - sector / chs->sectors / chs->heads, - (sector / chs->sectors) % chs->heads, - sector % chs->sectors); - return ped_strdup (buf); - } - - /* Cylinders, sectors and bytes should be rounded down... */ - if (unit == PED_UNIT_CYLINDER - || unit == PED_UNIT_SECTOR - || unit == PED_UNIT_BYTE) { - snprintf (buf, 100, "%lld%s", - byte / ped_unit_get_size (dev, unit), - ped_unit_get_name (unit)); - return ped_strdup (buf); - } - - if (unit == PED_UNIT_COMPACT) { - if (byte >= 10LL * PED_TERABYTE_SIZE) - unit = PED_UNIT_TERABYTE; - else if (byte >= 10LL * PED_GIGABYTE_SIZE) - unit = PED_UNIT_GIGABYTE; - else if (byte >= 10LL * PED_MEGABYTE_SIZE) - unit = PED_UNIT_MEGABYTE; - else if (byte >= 10LL * PED_KILOBYTE_SIZE) - unit = PED_UNIT_KILOBYTE; - else - unit = PED_UNIT_BYTE; - } - - /* IEEE754 says that 100.5 has to be rounded to 100 (by printf) */ - /* but 101.5 has to be rounded to 102... so we multiply by 1+E. */ - /* This just divide by 2 the natural IEEE754 extended precision */ - /* and won't cause any trouble before 1000 TB */ - d = ((double)byte / (double)ped_unit_get_size (dev, unit)) - * (1. + DBL_EPSILON); - w = d + ( (d < 10. ) ? 0.005 : - (d < 100.) ? 0.05 : - 0.5 ); - p = (w < 10. ) ? 2 : - (w < 100.) ? 1 : - 0 ; - -#ifdef __BEOS__ - snprintf (buf, 100, "%.*f%s", p, d, ped_unit_get_name(unit)); -#else - snprintf (buf, 100, "%1$.*2$f%3$s", d, p, ped_unit_get_name (unit)); -#endif - - return ped_strdup (buf); -} - -/** - * \brief Get a string that describes the location of the \p byte on - * device \p dev. - * - * The string is described with the default unit, which is set - * by ped_unit_set_default(). - * The returned string must be freed with ped_free(). - */ -char* -ped_unit_format_byte (const PedDevice* dev, PedSector byte) -{ - PED_ASSERT (dev != NULL, return NULL); - return ped_unit_format_custom_byte (dev, byte, default_unit); -} - -/** - * \brief Get a string that describes the location \p sector on device \p dev. - * - * The string is described with the desired \p unit. - * The returned string must be freed with ped_free(). - */ -char* -ped_unit_format_custom (const PedDevice* dev, PedSector sector, PedUnit unit) -{ - PED_ASSERT (dev != NULL, return NULL); - return ped_unit_format_custom_byte(dev, sector*dev->sector_size, unit); -} - -/** - * \brief Get a string that describes the location \p sector on device \p dev. - * - * The string is described with the default unit, which is set - * by ped_unit_set_default(). - * The returned string must be freed with ped_free(). - */ -char* -ped_unit_format (const PedDevice* dev, PedSector sector) -{ - PED_ASSERT (dev != NULL, return NULL); - return ped_unit_format_custom_byte (dev, sector * dev->sector_size, - default_unit); -} - -/** - * If \p str contains a valid description of a location on \p dev, - * then \p *sector is modified to describe the location and a geometry - * is created in \p *range describing a 2 units large area centered on - * \p *sector. If the \p range as described here would be partially outside - * the device \p dev, the geometry returned is the intersection between the - * former and the whole device geometry. If no units are specified, then the - * default unit is assumed. - * - * \return \c 1 if \p str is a valid location description, \c 0 otherwise - */ -int -ped_unit_parse (const char* str, const PedDevice* dev, PedSector *sector, - PedGeometry** range) -{ - return ped_unit_parse_custom (str, dev, default_unit, sector, range); -} - -/* Inefficiently removes all spaces from a string, in-place. */ -static void -strip_string (char* str) -{ - int i; - - for (i = 0; str[i] != 0; i++) { - if (isspace (str[i])) { - int j; - for (j = i + 1; str[j] != 0; j++) - str[j - 1] = str[j]; - } - } -} - - -/* Find non-number suffix. Eg: find_suffix("32Mb") returns a pointer to - * "Mb". */ -static char* -find_suffix (const char* str) -{ - while (str[0] != 0 && (isdigit (str[0]) || strchr(",.-", str[0]))) - str++; - return (char *) str; -} - -static void -remove_punct (char* str) -{ - int i = 0; - - for (i = 0; str[i]; i++) { - if (ispunct (str[i])) - str[i] = ' '; - } -} - -static int -is_chs (const char* str) -{ - int punct_count = 0; - int i = 0; - - for (i = 0; str[i]; i++) - punct_count += ispunct (str[i]) != 0; - return punct_count == 2; -} - -static int -parse_chs (const char* str, const PedDevice* dev, PedSector* sector, - PedGeometry** range) -{ - PedSector cyl_size = dev->bios_geom.heads * dev->bios_geom.sectors; - char* copy = ped_strdup (str); - PedCHSGeometry chs; - - copy = ped_strdup (str); - if (!copy) - return 0; - strip_string (copy); - remove_punct (copy); - - if (sscanf (copy, "%d %d %d", - &chs.cylinders, &chs.heads, &chs.sectors) != 3) { - ped_exception_throw ( - PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, - _("\"%s\" has invalid syntax for locations."), - copy); - goto error_free_copy; - } - - if (chs.heads >= dev->bios_geom.heads) { - ped_exception_throw ( - PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, - _("The maximum head value is %d."), - dev->bios_geom.heads - 1); - goto error_free_copy; - } - if (chs.sectors >= dev->bios_geom.sectors) { - ped_exception_throw ( - PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, - _("The maximum sector value is %d."), - dev->bios_geom.sectors - 1); - goto error_free_copy; - } - - *sector = 1LL * chs.cylinders * cyl_size - + chs.heads * dev->bios_geom.sectors - + chs.sectors; - - if (*sector >= dev->length) { - ped_exception_throw ( - PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, - _("The location %s is outside of the " - "device %s."), - str, dev->path); - goto error_free_copy; - } - if (range) - *range = ped_geometry_new (dev, *sector, 1); - ped_free (copy); - return !range || *range != NULL; - -error_free_copy: - ped_free (copy); - *sector = 0; - if (range) - *range = NULL; - return 0; -} - -static PedSector -clip (const PedDevice* dev, PedSector sector) -{ - if (sector < 0) - return 0; - if (sector > dev->length - 1) - return dev->length - 1; - return sector; -} - -static PedGeometry* -geometry_from_centre_radius (const PedDevice* dev, - PedSector sector, PedSector radius) -{ - PedSector start = clip (dev, sector - radius); - PedSector end = clip (dev, sector + radius); - if (sector - end > radius || start - sector > radius) - return NULL; - return ped_geometry_new (dev, start, end - start + 1); -} - -static PedUnit -parse_unit_suffix (const char* suffix, PedUnit suggested_unit) -{ - if (strlen (suffix) > 1 && tolower (suffix[1]) == 'i') { - switch (tolower (suffix[0])) { - case 'k': return PED_UNIT_KIBIBYTE; - case 'm': return PED_UNIT_MEBIBYTE; - case 'g': return PED_UNIT_GIBIBYTE; - case 't': return PED_UNIT_TEBIBYTE; - } - } else if (strlen (suffix) > 0) { - switch (tolower (suffix[0])) { - case 's': return PED_UNIT_SECTOR; - case 'b': return PED_UNIT_BYTE; - case 'k': return PED_UNIT_KILOBYTE; - case 'm': return PED_UNIT_MEGABYTE; - case 'g': return PED_UNIT_GIGABYTE; - case 't': return PED_UNIT_TERABYTE; - case 'c': return PED_UNIT_CYLINDER; - case '%': return PED_UNIT_PERCENT; - } - } - - if (suggested_unit == PED_UNIT_COMPACT) { - if (default_unit == PED_UNIT_COMPACT) - return PED_UNIT_MEGABYTE; - else - return default_unit; - } - - return suggested_unit; -} - -/** - * If \p str contains a valid description of a location on \p dev, then - * \p *sector is modified to describe the location and a geometry is created - * in \p *range describing a 2 units large area centered on \p *sector. If the - * \p range as described here would be partially outside the device \p dev, the - * geometry returned is the intersection between the former and the whole - * device geometry. If no units are specified, then the default unit is - * assumed. - * - * \throws PED_EXCEPTION_ERROR if \p str contains invalid description of a - * location - * \throws PED_EXCEPTION_ERROR if location described by \p str - * is outside of the device \p dev->path - * - * \return \c 1 if \p str is a valid location description, \c 0 otherwise. - */ -int -ped_unit_parse_custom (const char* str, const PedDevice* dev, PedUnit unit, - PedSector* sector, PedGeometry** range) -{ - char* copy; - char* suffix; - double num; - long long unit_size; - PedSector radius; - - if (is_chs (str)) - return parse_chs (str, dev, sector, range); - - copy = ped_strdup (str); - if (!copy) - goto error; - strip_string (copy); - - suffix = find_suffix (copy); - unit = parse_unit_suffix (suffix, unit); - suffix[0] = 0; - - if (sscanf (copy, "%lf", &num) != 1) { - ped_exception_throw ( - PED_EXCEPTION_ERROR, - PED_EXCEPTION_CANCEL, - _("Invalid number.")); - goto error_free_copy; - } - - unit_size = ped_unit_get_size (dev, unit); - radius = ped_div_round_up (unit_size, dev->sector_size) - 1; - if (radius < 0) - radius = 0; - - *sector = num * unit_size / dev->sector_size; - /* negative numbers count from the end */ - if (copy[0] == '-') - *sector += dev->length; - if (range) { - *range = geometry_from_centre_radius (dev, *sector, radius); - if (!*range) { - ped_exception_throw ( - PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, - _("The location %s is outside of the " - "device %s."), - str, dev->path); - goto error_free_copy; - } - } - *sector = clip (dev, *sector); - - ped_free (copy); - return 1; - -error_free_copy: - ped_free (copy); -error: - *sector = 0; - if (range) - *range = NULL; - return 0; -} - - -/** @} */ |