summaryrefslogtreecommitdiff
path: root/usr/src/lib/libparted/common/libparted/unit.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libparted/common/libparted/unit.c')
-rw-r--r--usr/src/lib/libparted/common/libparted/unit.c565
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;
-}
-
-
-/** @} */