2 libparted - a library for manipulating disk partitions
3 Copyright (C) 2005, 2007, 2009-2010 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * \brief The PedUnit module provides a standard mechanism for describing
25 * and parsing locations within devices in human-friendly plain text.
27 * Internally, libparted uses PedSector (which is typedef'ed to be long long
28 * in <parted/device.h>) to describe device locations such as the start and
29 * end of partitions. However, sector numbers are often long and unintuitive.
30 * For example, my extended partition starts at sector 208845. PedUnit allows
31 * this location to be represented in more intutitive ways, including "106Mb",
32 * "0Gb" and "0%", as well as "208845s". PedUnit aims to provide facilities
33 * to provide a consistent system for describing device locations all
34 * throughout libparted.
36 * PedUnit provides two basic services: converting a PedSector into a text
37 * representation, and parsing a text representation into a PedSector.
38 * PedUnit currently supports these units:
40 * sectors, bytes, kilobytes, megabytes, gigabytes, terabytes, compact,
41 * cylinder and percent.
43 * PedUnit has a global variable that contains the default unit for all
53 #include <parted/parted.h>
54 #include <parted/debug.h>
60 #define N_(String) String
63 # define _(String) dgettext (PACKAGE, String)
65 # define _(String) (String)
66 #endif /* ENABLE_NLS */
69 static PedUnit default_unit = PED_UNIT_COMPACT;
70 static const char* unit_names[] = {
89 * \brief Set the default \p unit used by subsequent calls to the PedUnit API.
91 * In particular, this affects how locations inside error messages
92 * (exceptions) are displayed.
95 ped_unit_set_default (PedUnit unit)
102 * \brief Get the current default unit.
105 ped_unit_get_default ()
111 * Get the byte size of a given \p unit.
114 ped_unit_get_size (const PedDevice* dev, PedUnit unit)
116 PedSector cyl_size = dev->bios_geom.heads * dev->bios_geom.sectors;
119 case PED_UNIT_SECTOR: return dev->sector_size;
120 case PED_UNIT_BYTE: return 1;
121 case PED_UNIT_KILOBYTE: return PED_KILOBYTE_SIZE;
122 case PED_UNIT_MEGABYTE: return PED_MEGABYTE_SIZE;
123 case PED_UNIT_GIGABYTE: return PED_GIGABYTE_SIZE;
124 case PED_UNIT_TERABYTE: return PED_TERABYTE_SIZE;
125 case PED_UNIT_KIBIBYTE: return PED_KIBIBYTE_SIZE;
126 case PED_UNIT_MEBIBYTE: return PED_MEBIBYTE_SIZE;
127 case PED_UNIT_GIBIBYTE: return PED_GIBIBYTE_SIZE;
128 case PED_UNIT_TEBIBYTE: return PED_TEBIBYTE_SIZE;
129 case PED_UNIT_CYLINDER: return cyl_size * dev->sector_size;
130 case PED_UNIT_CHS: return dev->sector_size;
132 case PED_UNIT_PERCENT:
133 return dev->length * dev->sector_size / 100;
135 case PED_UNIT_COMPACT:
136 ped_exception_throw (
137 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
138 _("Cannot get unit size for special unit "
144 PED_ASSERT(0, return 0);
149 * Get a textual (non-internationalized) representation of a \p unit.
151 * For example, the textual representation of PED_UNIT_SECTOR is "s".
154 ped_unit_get_name (PedUnit unit)
156 return unit_names[unit];
160 * Get a unit based on its textual representation: \p unit_name.
162 * For example, ped_unit_get_by_name("Mb") returns PED_UNIT_MEGABYTE.
165 ped_unit_get_by_name (const char* unit_name)
168 for (unit = PED_UNIT_FIRST; unit <= PED_UNIT_LAST; unit++) {
169 if (!strcasecmp (unit_names[unit], unit_name))
176 ped_strdup (const char *str)
179 result = ped_malloc (strlen (str) + 1);
182 strcpy (result, str);
187 * \brief Get a string that describes the location of the \p byte on
190 * The string is described with the desired \p unit.
191 * The returned string must be freed with free().
194 ped_unit_format_custom_byte (const PedDevice* dev, PedSector byte, PedUnit unit)
197 PedSector sector = byte / dev->sector_size;
201 PED_ASSERT (dev != NULL, return NULL);
203 /* CHS has a special comma-separated format. */
204 if (unit == PED_UNIT_CHS) {
205 const PedCHSGeometry *chs = &dev->bios_geom;
206 snprintf (buf, 100, "%lld,%lld,%lld",
207 sector / chs->sectors / chs->heads,
208 (sector / chs->sectors) % chs->heads,
209 sector % chs->sectors);
210 return ped_strdup (buf);
213 /* Cylinders, sectors and bytes should be rounded down... */
214 if (unit == PED_UNIT_CYLINDER
215 || unit == PED_UNIT_SECTOR
216 || unit == PED_UNIT_BYTE) {
217 snprintf (buf, 100, "%lld%s",
218 byte / ped_unit_get_size (dev, unit),
219 ped_unit_get_name (unit));
220 return ped_strdup (buf);
223 if (unit == PED_UNIT_COMPACT) {
224 if (byte >= 10LL * PED_TERABYTE_SIZE)
225 unit = PED_UNIT_TERABYTE;
226 else if (byte >= 10LL * PED_GIGABYTE_SIZE)
227 unit = PED_UNIT_GIGABYTE;
228 else if (byte >= 10LL * PED_MEGABYTE_SIZE)
229 unit = PED_UNIT_MEGABYTE;
230 else if (byte >= 10LL * PED_KILOBYTE_SIZE)
231 unit = PED_UNIT_KILOBYTE;
233 unit = PED_UNIT_BYTE;
236 /* IEEE754 says that 100.5 has to be rounded to 100 (by printf) */
237 /* but 101.5 has to be rounded to 102... so we multiply by 1+E. */
238 /* This just divide by 2 the natural IEEE754 extended precision */
239 /* and won't cause any trouble before 1000 TB */
240 d = ((double)byte / ped_unit_get_size (dev, unit))
241 * (1. + DBL_EPSILON);
242 w = d + ( (d < 10. ) ? 0.005 :
250 snprintf (buf, 100, "%.*f%s", p, d, ped_unit_get_name(unit));
252 snprintf (buf, 100, "%1$.*2$f%3$s", d, p, ped_unit_get_name (unit));
255 return ped_strdup (buf);
259 * \brief Get a string that describes the location of the \p byte on
262 * The string is described with the default unit, which is set
263 * by ped_unit_set_default().
264 * The returned string must be freed with free().
267 ped_unit_format_byte (const PedDevice* dev, PedSector byte)
269 PED_ASSERT (dev != NULL, return NULL);
270 return ped_unit_format_custom_byte (dev, byte, default_unit);
274 * \brief Get a string that describes the location \p sector on device \p dev.
276 * The string is described with the desired \p unit.
277 * The returned string must be freed with free().
280 ped_unit_format_custom (const PedDevice* dev, PedSector sector, PedUnit unit)
282 PED_ASSERT (dev != NULL, return NULL);
283 return ped_unit_format_custom_byte(dev, sector*dev->sector_size, unit);
287 * \brief Get a string that describes the location \p sector on device \p dev.
289 * The string is described with the default unit, which is set
290 * by ped_unit_set_default().
291 * The returned string must be freed with free().
294 ped_unit_format (const PedDevice* dev, PedSector sector)
296 PED_ASSERT (dev != NULL, return NULL);
297 return ped_unit_format_custom_byte (dev, sector * dev->sector_size,
302 * If \p str contains a valid description of a location on \p dev,
303 * then \p *sector is modified to describe the location and a geometry
304 * is created in \p *range describing a 2 units large area centered on
305 * \p *sector. If the \p range as described here would be partially outside
306 * the device \p dev, the geometry returned is the intersection between the
307 * former and the whole device geometry. If no units are specified, then the
308 * default unit is assumed.
310 * \return \c 1 if \p str is a valid location description, \c 0 otherwise
313 ped_unit_parse (const char* str, const PedDevice* dev, PedSector *sector,
316 return ped_unit_parse_custom (str, dev, default_unit, sector, range);
319 /* Inefficiently removes all spaces from a string, in-place. */
321 strip_string (char* str)
325 for (i = 0; str[i] != 0; i++) {
326 if (isspace (str[i])) {
328 for (j = i + 1; str[j] != 0; j++)
335 /* Find non-number suffix. Eg: find_suffix("32Mb") returns a pointer to
338 find_suffix (const char* str)
340 while (str[0] != 0 && (isdigit (str[0]) || strchr(",.-", str[0])))
346 remove_punct (char* str)
350 for (i = 0; str[i]; i++) {
351 if (ispunct (str[i]))
357 is_chs (const char* str)
362 for (i = 0; str[i]; i++)
363 punct_count += ispunct (str[i]) != 0;
364 return punct_count == 2;
368 parse_chs (const char* str, const PedDevice* dev, PedSector* sector,
371 PedSector cyl_size = dev->bios_geom.heads * dev->bios_geom.sectors;
374 char* copy = ped_strdup (str);
380 if (sscanf (copy, "%d %d %d",
381 &chs.cylinders, &chs.heads, &chs.sectors) != 3) {
382 ped_exception_throw (
383 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
384 _("\"%s\" has invalid syntax for locations."),
386 goto error_free_copy;
389 if (chs.heads >= dev->bios_geom.heads) {
390 ped_exception_throw (
391 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
392 _("The maximum head value is %d."),
393 dev->bios_geom.heads - 1);
394 goto error_free_copy;
396 if (chs.sectors >= dev->bios_geom.sectors) {
397 ped_exception_throw (
398 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
399 _("The maximum sector value is %d."),
400 dev->bios_geom.sectors - 1);
401 goto error_free_copy;
404 *sector = 1LL * chs.cylinders * cyl_size
405 + chs.heads * dev->bios_geom.sectors
408 if (*sector >= dev->length) {
409 ped_exception_throw (
410 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
411 _("The location %s is outside of the "
414 goto error_free_copy;
417 *range = ped_geometry_new (dev, *sector, 1);
419 return !range || *range != NULL;
430 clip (const PedDevice* dev, PedSector sector)
434 if (sector > dev->length - 1)
435 return dev->length - 1;
440 geometry_from_centre_radius (const PedDevice* dev,
441 PedSector sector, PedSector radius)
443 PedSector start = clip (dev, sector - radius);
444 PedSector end = clip (dev, sector + radius);
445 if (sector - end > radius || start - sector > radius)
447 return ped_geometry_new (dev, start, end - start + 1);
451 parse_unit_suffix (const char* suffix, PedUnit suggested_unit)
453 if (strlen (suffix) > 1 && tolower (suffix[1]) == 'i') {
454 switch (tolower (suffix[0])) {
455 case 'k': return PED_UNIT_KIBIBYTE;
456 case 'm': return PED_UNIT_MEBIBYTE;
457 case 'g': return PED_UNIT_GIBIBYTE;
458 case 't': return PED_UNIT_TEBIBYTE;
460 } else if (strlen (suffix) > 0) {
461 switch (tolower (suffix[0])) {
462 case 's': return PED_UNIT_SECTOR;
463 case 'b': return PED_UNIT_BYTE;
464 case 'k': return PED_UNIT_KILOBYTE;
465 case 'm': return PED_UNIT_MEGABYTE;
466 case 'g': return PED_UNIT_GIGABYTE;
467 case 't': return PED_UNIT_TERABYTE;
468 case 'c': return PED_UNIT_CYLINDER;
469 case '%': return PED_UNIT_PERCENT;
473 if (suggested_unit == PED_UNIT_COMPACT) {
474 if (default_unit == PED_UNIT_COMPACT)
475 return PED_UNIT_MEGABYTE;
480 return suggested_unit;
484 * If \p str contains a valid description of a location on \p dev, then
485 * \p *sector is modified to describe the location and a geometry is created
486 * in \p *range describing a 2 units large area centered on \p *sector. If the
487 * \p range as described here would be partially outside the device \p dev, the
488 * geometry returned is the intersection between the former and the whole
489 * device geometry. If no units are specified, then the default unit is
492 * \throws PED_EXCEPTION_ERROR if \p str contains invalid description of a
494 * \throws PED_EXCEPTION_ERROR if location described by \p str
495 * is outside of the device \p dev->path
497 * \return \c 1 if \p str is a valid location description, \c 0 otherwise.
500 ped_unit_parse_custom (const char* str, const PedDevice* dev, PedUnit unit,
501 PedSector* sector, PedGeometry** range)
510 return parse_chs (str, dev, sector, range);
512 copy = ped_strdup (str);
517 suffix = find_suffix (copy);
518 unit = parse_unit_suffix (suffix, unit);
521 if (sscanf (copy, "%lf", &num) != 1) {
522 ped_exception_throw (
524 PED_EXCEPTION_CANCEL,
525 _("Invalid number."));
526 goto error_free_copy;
529 unit_size = ped_unit_get_size (dev, unit);
530 radius = ped_div_round_up (unit_size, dev->sector_size) - 1;
534 *sector = num * unit_size / dev->sector_size;
535 /* negative numbers count from the end */
537 *sector += dev->length;
539 *range = geometry_from_centre_radius (dev, *sector, radius);
541 ped_exception_throw (
542 PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
543 _("The location %s is outside of the "
546 goto error_free_copy;
549 *sector = clip (dev, *sector);