1 /*
2 libparted - a library for manipulating disk partitions
3 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2007
4 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /** \file disk.c */
21
22 /**
23 * \addtogroup PedDisk
24 *
25 * \brief Disk label access.
26 *
27 * Most programs will need to use ped_disk_new() or ped_disk_new_fresh() to get
28 * anything done. A PedDisk is always associated with a device and has a
29 * partition table. There are different types of partition tables (or disk
30 * labels). These are represented by the PedDiskType enumeration.
31 *
32 * @{
33 */
34
35 #include <config.h>
36
37 #include <parted/parted.h>
38 #include <parted/debug.h>
39
40 #if ENABLE_NLS
41 # include <libintl.h>
42 # define _(String) dgettext (PACKAGE, String)
43 # define N_(String) (String)
44 #else
45 # define _(String) (String)
46 # define N_(String) (String)
47 #endif /* ENABLE_NLS */
48
49 /* UPDATE MODE functions */
50 #ifdef DEBUG
51 static int _disk_check_sanity (PedDisk* disk);
52 #endif
53 static void _disk_push_update_mode (PedDisk* disk);
54 static void _disk_pop_update_mode (PedDisk* disk);
55 static int _disk_raw_insert_before (PedDisk* disk, PedPartition* loc,
56 PedPartition* part);
57 static int _disk_raw_insert_after (PedDisk* disk, PedPartition* loc,
58 PedPartition* part);
59 static int _disk_raw_remove (PedDisk* disk, PedPartition* part);
60 static int _disk_raw_add (PedDisk* disk, PedPartition* part);
61
62 static PedDiskType* disk_types = NULL;
63
64 void
ped_disk_type_register(PedDiskType * disk_type)65 ped_disk_type_register (PedDiskType* disk_type)
66 {
67 PED_ASSERT (disk_type != NULL, return);
68 PED_ASSERT (disk_type->ops != NULL, return);
69 PED_ASSERT (disk_type->name != NULL, return);
70
71 /* pretend that "next" isn't part of the struct :-) */
72 ((struct _PedDiskType*) disk_type)->next = disk_types;
73 disk_types = (struct _PedDiskType*) disk_type;
74 }
75
76 void
ped_disk_type_unregister(PedDiskType * disk_type)77 ped_disk_type_unregister (PedDiskType* disk_type)
78 {
79 PedDiskType* walk;
80 PedDiskType* last = NULL;
81
82 PED_ASSERT (disk_types != NULL, return);
83 PED_ASSERT (disk_type != NULL, return);
84
85 for (walk = disk_types; walk && walk != disk_type;
86 last = walk, walk = walk->next);
87
88 PED_ASSERT (walk != NULL, return);
89 if (last)
90 ((struct _PedDiskType*) last)->next = disk_type->next;
91 else
92 disk_types = disk_type->next;
93 }
94
95 /**
96 * Deprecated: use ped_disk_type_regiser.
97 */
98 void
ped_register_disk_type(PedDiskType * disk_type)99 ped_register_disk_type (PedDiskType* disk_type)
100 {
101 ped_disk_type_register (disk_type);
102 }
103
104 /**
105 * Deprecated: use ped_disk_type_unregiser.
106 */
107 void
ped_unregister_disk_type(PedDiskType * disk_type)108 ped_unregister_disk_type (PedDiskType* disk_type)
109 {
110 ped_disk_type_unregister (disk_type);
111 }
112
113 /**
114 * Return the next disk type registers, after "type". If "type" is
115 * NULL, returns the first disk type.
116 *
117 * \return Next disk; NULL if "type" is the last registered disk type.
118 */
119 PedDiskType*
ped_disk_type_get_next(PedDiskType * type)120 ped_disk_type_get_next (PedDiskType* type)
121 {
122 if (type)
123 return type->next;
124 else
125 return disk_types;
126 }
127
128 /**
129 * Return the disk type with a name of "name".
130 *
131 * \return Disk type; NULL if no match.
132 */
133 PedDiskType*
ped_disk_type_get(const char * name)134 ped_disk_type_get (const char* name)
135 {
136 PedDiskType* walk = NULL;
137
138 PED_ASSERT (name != NULL, return NULL);
139
140 for (walk = ped_disk_type_get_next (NULL); walk;
141 walk = ped_disk_type_get_next (walk))
142 if (strcasecmp (walk->name, name) == 0)
143 break;
144
145 return walk;
146 }
147
148 /**
149 * Return the type of partition table detected on "dev".
150 *
151 * \return Type; NULL if none was detected.
152 */
153 PedDiskType*
ped_disk_probe(PedDevice * dev)154 ped_disk_probe (PedDevice* dev)
155 {
156 PedDiskType *walk = NULL;
157
158 PED_ASSERT (dev != NULL, return NULL);
159
160 if (!ped_device_open (dev))
161 return NULL;
162
163 ped_exception_fetch_all ();
164 for (walk = ped_disk_type_get_next (NULL); walk;
165 walk = ped_disk_type_get_next (walk)) {
166 if (walk->ops->probe (dev))
167 break;
168 }
169
170 if (ped_exception)
171 ped_exception_catch ();
172 ped_exception_leave_all ();
173
174 ped_device_close (dev);
175 return walk;
176 }
177
178 /**
179 * Read the partition table off a device (if one is found).
180 *
181 * \warning May modify \p dev->cylinders, \p dev->heads and \p dev->sectors
182 * if the partition table indicates that the existing values
183 * are incorrect.
184 *
185 * \return A new \link _PedDisk PedDisk \endlink object;
186 * NULL on failure (e.g. partition table not detected).
187 */
188 PedDisk*
ped_disk_new(PedDevice * dev)189 ped_disk_new (PedDevice* dev)
190 {
191 PedDiskType* type;
192 PedDisk* disk;
193
194 PED_ASSERT (dev != NULL, return NULL);
195
196 if (!ped_device_open (dev))
197 goto error;
198
199 type = ped_disk_probe (dev);
200 if (!type) {
201 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
202 _("%s: unrecognised disk label"),
203 dev->path);
204 goto error_close_dev;
205 }
206 disk = ped_disk_new_fresh (dev, type);
207 if (!disk)
208 goto error_close_dev;
209 if (!type->ops->read (disk))
210 goto error_destroy_disk;
211 disk->needs_clobber = 0;
212 ped_device_close (dev);
213 return disk;
214
215 error_destroy_disk:
216 ped_disk_destroy (disk);
217 error_close_dev:
218 ped_device_close (dev);
219 error:
220 return NULL;
221 }
222
223 static int
_add_duplicate_part(PedDisk * disk,PedPartition * old_part)224 _add_duplicate_part (PedDisk* disk, PedPartition* old_part)
225 {
226 PedPartition* new_part;
227 PedConstraint* constraint_exact;
228
229 new_part = disk->type->ops->partition_duplicate (old_part);
230 if (!new_part)
231 goto error;
232 new_part->disk = disk;
233
234 constraint_exact = ped_constraint_exact (&new_part->geom);
235 if (!constraint_exact)
236 goto error_destroy_new_part;
237 if (!ped_disk_add_partition (disk, new_part, constraint_exact))
238 goto error_destroy_constraint_exact;
239 ped_constraint_destroy (constraint_exact);
240 return 1;
241
242 error_destroy_constraint_exact:
243 ped_constraint_destroy (constraint_exact);
244 error_destroy_new_part:
245 ped_partition_destroy (new_part);
246 error:
247 return 0;
248 }
249
250 /**
251 * Clone a \link _PedDisk PedDisk \endlink object.
252 *
253 * \return Deep copy of \p old_disk, NULL on failure.
254 */
255 PedDisk*
ped_disk_duplicate(const PedDisk * old_disk)256 ped_disk_duplicate (const PedDisk* old_disk)
257 {
258 PedDisk* new_disk;
259 PedPartition* old_part;
260
261 PED_ASSERT (old_disk != NULL, return NULL);
262 PED_ASSERT (!old_disk->update_mode, return NULL);
263 PED_ASSERT (old_disk->type->ops->duplicate != NULL, return NULL);
264 PED_ASSERT (old_disk->type->ops->partition_duplicate != NULL,
265 return NULL);
266
267 new_disk = old_disk->type->ops->duplicate (old_disk);
268 if (!new_disk)
269 goto error;
270
271 _disk_push_update_mode (new_disk);
272 for (old_part = ped_disk_next_partition (old_disk, NULL); old_part;
273 old_part = ped_disk_next_partition (old_disk, old_part)) {
274 if (ped_partition_is_active (old_part)) {
275 if (!_add_duplicate_part (new_disk, old_part))
276 goto error_destroy_new_disk;
277 }
278 }
279 _disk_pop_update_mode (new_disk);
280 return new_disk;
281
282 error_destroy_new_disk:
283 ped_disk_destroy (new_disk);
284 error:
285 return NULL;
286 }
287
288 /**
289 * Remove all identifying signatures of a partition table,
290 * except for partition tables of a given type.
291 *
292 * \return 0 on error, 1 otherwise.
293 *
294 * \sa ped_disk_clobber()
295 */
296 int
ped_disk_clobber_exclude(PedDevice * dev,const PedDiskType * exclude)297 ped_disk_clobber_exclude (PedDevice* dev, const PedDiskType* exclude)
298 {
299 PedDiskType* walk;
300
301 PED_ASSERT (dev != NULL, goto error);
302
303 if (!ped_device_open (dev))
304 goto error;
305
306 for (walk = ped_disk_type_get_next (NULL); walk;
307 walk = ped_disk_type_get_next (walk)) {
308 int probed;
309
310 if (walk == exclude)
311 continue;
312
313 ped_exception_fetch_all ();
314 probed = walk->ops->probe (dev);
315 if (!probed)
316 ped_exception_catch ();
317 ped_exception_leave_all ();
318
319 if (probed && walk->ops->clobber) {
320 if (!walk->ops->clobber (dev))
321 goto error_close_dev;
322 }
323 }
324 ped_device_close (dev);
325 return 1;
326
327 error_close_dev:
328 ped_device_close (dev);
329 error:
330 return 0;
331 }
332
333 /**
334 * Remove all identifying signatures of a partition table,
335 *
336 * \return 0 on error, 1 otherwise.
337 *
338 * \sa ped_disk_clobber_exclude()
339 */
340 int
ped_disk_clobber(PedDevice * dev)341 ped_disk_clobber (PedDevice* dev)
342 {
343 return ped_disk_clobber_exclude (dev, NULL);
344 }
345
346 /**
347 * Create a new partition table on \p dev.
348 *
349 * This new partition table is only created in-memory, and nothing is written
350 * to disk until ped_disk_commit_to_dev() is called.
351 *
352 * \return The newly constructed \link _PedDisk PedDisk \endlink,
353 * NULL on failure.
354 */
355 PedDisk*
ped_disk_new_fresh(PedDevice * dev,const PedDiskType * type)356 ped_disk_new_fresh (PedDevice* dev, const PedDiskType* type)
357 {
358 PedDisk* disk;
359
360 PED_ASSERT (dev != NULL, return NULL);
361 PED_ASSERT (type != NULL, return NULL);
362 PED_ASSERT (type->ops->alloc != NULL, return NULL);
363
364 disk = type->ops->alloc (dev);
365 if (!disk)
366 goto error;
367 _disk_pop_update_mode (disk);
368 PED_ASSERT (disk->update_mode == 0, goto error_destroy_disk);
369
370 disk->needs_clobber = 1;
371 return disk;
372
373 error_destroy_disk:
374 ped_disk_destroy (disk);
375 error:
376 return NULL;
377 }
378
379 PedDisk*
_ped_disk_alloc(const PedDevice * dev,const PedDiskType * disk_type)380 _ped_disk_alloc (const PedDevice* dev, const PedDiskType* disk_type)
381 {
382 PedDisk* disk;
383
384 disk = (PedDisk*) ped_malloc (sizeof (PedDisk));
385 if (!disk)
386 goto error;
387
388 disk->dev = (PedDevice*)dev;
389 disk->type = disk_type;
390 disk->update_mode = 1;
391 disk->part_list = NULL;
392 return disk;
393
394 ped_free (disk);
395 error:
396 return NULL;
397 }
398
399 void
_ped_disk_free(PedDisk * disk)400 _ped_disk_free (PedDisk* disk)
401 {
402 _disk_push_update_mode (disk);
403 ped_disk_delete_all (disk);
404 ped_free (disk);
405 }
406
407 /**
408 * Close \p disk.
409 *
410 * What this function does depends on the PedDiskType of \p disk,
411 * but you can generally assume that outstanding writes are flushed
412 * (this mainly means that _ped_disk_free is called).
413 */
414 void
ped_disk_destroy(PedDisk * disk)415 ped_disk_destroy (PedDisk* disk)
416 {
417 PED_ASSERT (disk != NULL, return);
418 PED_ASSERT (!disk->update_mode, return);
419
420 disk->type->ops->free (disk);
421 }
422
423 /**
424 * Tell the operating system kernel about the partition table layout
425 * of \p disk.
426 *
427 * This is rather loosely defined: for example, on old versions of Linux,
428 * it simply calls the BLKRRPART ioctl, which tells the kernel to
429 * reread the partition table. On newer versions (2.4.x), it will
430 * use the new blkpg interface to tell Linux where each partition
431 * starts/ends, etc. In this case, Linux does not need to have support for
432 * a specific type of partition table.
433 *
434 * \return 0 on failure, 1 otherwise.
435 */
436 int
ped_disk_commit_to_os(PedDisk * disk)437 ped_disk_commit_to_os (PedDisk* disk)
438 {
439 PED_ASSERT (disk != NULL, return 0);
440
441 if (!ped_device_open (disk->dev))
442 goto error;
443 if (!ped_architecture->disk_ops->disk_commit (disk))
444 goto error_close_dev;
445 ped_device_close (disk->dev);
446 return 1;
447
448 error_close_dev:
449 ped_device_close (disk->dev);
450 error:
451 return 0;
452 }
453
454 /**
455 * Write the changes made to the in-memory description
456 * of a partition table to the device.
457 *
458 * \return 0 on failure, 1 otherwise.
459 */
460 int
ped_disk_commit_to_dev(PedDisk * disk)461 ped_disk_commit_to_dev (PedDisk* disk)
462 {
463 PED_ASSERT (disk != NULL, goto error);
464 PED_ASSERT (!disk->update_mode, goto error);
465
466 if (!disk->type->ops->write) {
467 ped_exception_throw (
468 PED_EXCEPTION_ERROR,
469 PED_EXCEPTION_CANCEL,
470 _("This libparted doesn't have write support for "
471 "%s. Perhaps it was compiled read-only."),
472 disk->type->name);
473 goto error;
474 }
475
476 if (!ped_device_open (disk->dev))
477 goto error;
478
479 if (disk->needs_clobber) {
480 if (!ped_disk_clobber_exclude (disk->dev, disk->type))
481 goto error_close_dev;
482 disk->needs_clobber = 0;
483 }
484 if (!disk->type->ops->write (disk))
485 goto error_close_dev;
486 ped_device_close (disk->dev);
487 return 1;
488
489 error_close_dev:
490 ped_device_close (disk->dev);
491 error:
492 return 0;
493 }
494
495 /*
496 * This function writes the in-memory changes to a partition table to
497 * disk and informs the operating system of the changes.
498 *
499 * \note Equivalent to calling first ped_disk_commit_to_dev(), then
500 * ped_disk_commit_to_os().
501 *
502 * \return 0 on failure, 1 otherwise.
503 */
504 int
ped_disk_commit(PedDisk * disk)505 ped_disk_commit (PedDisk* disk)
506 {
507 if (!ped_disk_commit_to_dev (disk))
508 return 0;
509 return ped_disk_commit_to_os (disk);
510 }
511
512 /**
513 * \addtogroup PedPartition
514 *
515 * @{
516 */
517
518 /**
519 * Check whether a partition is mounted or busy in some
520 * other way.
521 *
522 * \note An extended partition is busy if any logical partitions are mounted.
523 *
524 * \return \c 1 if busy.
525 */
526 int
ped_partition_is_busy(const PedPartition * part)527 ped_partition_is_busy (const PedPartition* part)
528 {
529 PED_ASSERT (part != NULL, return 1);
530
531 return ped_architecture->disk_ops->partition_is_busy (part);
532 }
533
534 /**
535 * Return a path that can be used to address the partition in the
536 * operating system.
537 */
538 char*
ped_partition_get_path(const PedPartition * part)539 ped_partition_get_path (const PedPartition* part)
540 {
541 PED_ASSERT (part != NULL, return NULL);
542
543 return ped_architecture->disk_ops->partition_get_path (part);
544 }
545
546 /** @} */
547
548 /**
549 * \addtogroup PedDisk
550 *
551 * @{
552 */
553
554 /**
555 * Perform a sanity check on a partition table.
556 *
557 * \note The check performed is generic (i.e. it does not depends on the label
558 * type of the disk.
559 *
560 * \throws PED_EXCEPTION_WARNING if a partition type ID does not match the file
561 * system on it.
562 *
563 * \return 0 if the check fails, 1 otherwise.
564 */
565 int
ped_disk_check(const PedDisk * disk)566 ped_disk_check (const PedDisk* disk)
567 {
568 PedPartition* walk;
569
570 PED_ASSERT (disk != NULL, return 0);
571
572 for (walk = disk->part_list; walk;
573 walk = ped_disk_next_partition (disk, walk)) {
574 const PedFileSystemType* fs_type = walk->fs_type;
575 PedGeometry* geom;
576 PedSector length_error;
577 PedSector max_length_error;
578
579 if (!ped_partition_is_active (walk) || !fs_type)
580 continue;
581
582 geom = ped_file_system_probe_specific (fs_type, &walk->geom);
583 if (!geom)
584 continue;
585
586 length_error = abs (walk->geom.length - geom->length);
587 max_length_error = PED_MAX (4096, walk->geom.length / 100);
588 if (!ped_geometry_test_inside (&walk->geom, geom)
589 || length_error > max_length_error) {
590 char* part_size = ped_unit_format (disk->dev, walk->geom.length);
591 char* fs_size = ped_unit_format (disk->dev, geom->length);
592 PedExceptionOption choice;
593
594 choice = ped_exception_throw (
595 PED_EXCEPTION_WARNING,
596 PED_EXCEPTION_IGNORE_CANCEL,
597 _("Partition %d is %s, but the file system is "
598 "%s."),
599 walk->num, part_size, fs_size);
600
601 ped_free (part_size);
602 ped_free (fs_size);
603
604 if (choice != PED_EXCEPTION_IGNORE)
605 return 0;
606 }
607 }
608
609 return 1;
610 }
611
612 /**
613 * This function checks if a particular type of partition table supports
614 * a feature.
615 *
616 * \return 1 if \p disk_type supports \p feature, 0 otherwise.
617 */
618 int
ped_disk_type_check_feature(const PedDiskType * disk_type,PedDiskTypeFeature feature)619 ped_disk_type_check_feature (const PedDiskType* disk_type,
620 PedDiskTypeFeature feature)
621 {
622 return (disk_type->features & feature) != 0;
623 }
624
625 /**
626 * Get the number of primary partitions.
627 */
628 int
ped_disk_get_primary_partition_count(const PedDisk * disk)629 ped_disk_get_primary_partition_count (const PedDisk* disk)
630 {
631 PedPartition* walk;
632 int count = 0;
633
634 PED_ASSERT (disk != NULL, return 0);
635
636 for (walk = disk->part_list; walk;
637 walk = ped_disk_next_partition (disk, walk)) {
638 if (ped_partition_is_active (walk)
639 && ! (walk->type & PED_PARTITION_LOGICAL))
640 count++;
641 }
642
643 return count;
644 }
645
646 /**
647 * Get the highest partition number on \p disk.
648 */
649 int
ped_disk_get_last_partition_num(const PedDisk * disk)650 ped_disk_get_last_partition_num (const PedDisk* disk)
651 {
652 PedPartition* walk;
653 int highest = -1;
654
655 PED_ASSERT (disk != NULL, return 0);
656
657 for (walk = disk->part_list; walk;
658 walk = ped_disk_next_partition (disk, walk)) {
659 if (walk->num > highest)
660 highest = walk->num;
661 }
662
663 return highest;
664 }
665
666 /**
667 * Get the maximum number of (primary) partitions the disk label supports.
668 *
669 * For example, MacIntosh partition maps can have different sizes,
670 * and accordingly support a different number of partitions.
671 */
672 int
ped_disk_get_max_primary_partition_count(const PedDisk * disk)673 ped_disk_get_max_primary_partition_count (const PedDisk* disk)
674 {
675 PED_ASSERT (disk->type != NULL, return 0);
676 PED_ASSERT (disk->type->ops->get_max_primary_partition_count != NULL,
677 return 0);
678
679 return disk->type->ops->get_max_primary_partition_count (disk);
680 }
681
682 /**
683 * \internal We turned a really nasty bureaucracy problem into an elegant maths
684 * problem :-) Basically, there are some constraints to a partition's
685 * geometry:
686 *
687 * (1) it must start and end on a "disk" block, determined by the disk label
688 * (not the hardware). (constraint represented by a PedAlignment)
689 *
690 * (2) if we're resizing a partition, we MIGHT need to keep each block aligned.
691 * Eg: if an ext2 file system has 4k blocks, then we can only move the start
692 * by a multiple of 4k. (constraint represented by a PedAlignment)
693 *
694 * (3) we need to keep the start and end within the device's physical
695 * boundaries. (constraint represented by a PedGeometry)
696 *
697 * Satisfying (1) and (2) simultaneously required a bit of fancy maths ;-) See
698 * ped_alignment_intersect()
699 *
700 * The application of these constraints is in disk_*.c's *_partition_align()
701 * function.
702 */
703 static int
_partition_align(PedPartition * part,const PedConstraint * constraint)704 _partition_align (PedPartition* part, const PedConstraint* constraint)
705 {
706 const PedDiskType* disk_type;
707
708 PED_ASSERT (part != NULL, return 0);
709 PED_ASSERT (part->num != -1, return 0);
710 PED_ASSERT (part->disk != NULL, return 0);
711 disk_type = part->disk->type;
712 PED_ASSERT (disk_type != NULL, return 0);
713 PED_ASSERT (disk_type->ops->partition_align != NULL, return 0);
714 PED_ASSERT (part->disk->update_mode, return 0);
715
716 return disk_type->ops->partition_align (part, constraint);
717 }
718
719 static int
_partition_enumerate(PedPartition * part)720 _partition_enumerate (PedPartition* part)
721 {
722 const PedDiskType* disk_type;
723
724 PED_ASSERT (part != NULL, return 0);
725 PED_ASSERT (part->disk != NULL, return 0);
726 disk_type = part->disk->type;
727 PED_ASSERT (disk_type != NULL, return 0);
728 PED_ASSERT (disk_type->ops->partition_enumerate != NULL, return 0);
729
730 return disk_type->ops->partition_enumerate (part);
731 }
732
733 /**
734 * Gives all the (active) partitions a number. It should preserve the numbers
735 * and orders as much as possible.
736 */
737 static int
ped_disk_enumerate_partitions(PedDisk * disk)738 ped_disk_enumerate_partitions (PedDisk* disk)
739 {
740 PedPartition* walk;
741 int i;
742 int end;
743
744 PED_ASSERT (disk != NULL, return 0);
745
746 /* first "sort" already-numbered partitions. (e.g. if a logical partition
747 * is removed, then all logical partitions that were number higher MUST be
748 * renumbered)
749 */
750 end = ped_disk_get_last_partition_num (disk);
751 for (i=1; i<=end; i++) {
752 walk = ped_disk_get_partition (disk, i);
753 if (walk) {
754 if (!_partition_enumerate (walk))
755 return 0;
756 }
757 }
758
759 /* now, number un-numbered partitions */
760 for (walk = disk->part_list; walk;
761 walk = ped_disk_next_partition (disk, walk)) {
762 if (ped_partition_is_active (walk) && walk->num == -1) {
763 if (!_partition_enumerate (walk))
764 return 0;
765 }
766 }
767
768 return 1;
769 }
770
771 static int
_disk_remove_metadata(PedDisk * disk)772 _disk_remove_metadata (PedDisk* disk)
773 {
774 PedPartition* walk = NULL;
775 PedPartition* next;
776
777 PED_ASSERT (disk != NULL, return 0);
778
779 next = ped_disk_next_partition (disk, walk);
780
781 while (next) {
782 walk = next;
783 while (1) {
784 next = ped_disk_next_partition (disk, next);
785 if (!next || next->type & PED_PARTITION_METADATA)
786 break;
787 }
788 if (walk->type & PED_PARTITION_METADATA)
789 ped_disk_delete_partition (disk, walk);
790 }
791 return 1;
792 }
793
794 static int
_disk_alloc_metadata(PedDisk * disk)795 _disk_alloc_metadata (PedDisk* disk)
796 {
797 PED_ASSERT (disk != NULL, return 0);
798
799 if (!disk->update_mode)
800 _disk_remove_metadata (disk);
801
802 return disk->type->ops->alloc_metadata (disk);
803 }
804
805 static int
_disk_remove_freespace(PedDisk * disk)806 _disk_remove_freespace (PedDisk* disk)
807 {
808 PedPartition* walk;
809 PedPartition* next;
810
811 walk = ped_disk_next_partition (disk, NULL);
812 for (; walk; walk = next) {
813 next = ped_disk_next_partition (disk, walk);
814
815 if (walk->type & PED_PARTITION_FREESPACE) {
816 _disk_raw_remove (disk, walk);
817 ped_partition_destroy (walk);
818 }
819 }
820
821 return 1;
822 }
823
824 static int
_alloc_extended_freespace(PedDisk * disk)825 _alloc_extended_freespace (PedDisk* disk)
826 {
827 PedSector last_end;
828 PedPartition* walk;
829 PedPartition* last;
830 PedPartition* free_space;
831 PedPartition* extended_part;
832
833 extended_part = ped_disk_extended_partition (disk);
834 if (!extended_part)
835 return 1;
836
837 last_end = extended_part->geom.start;
838 last = NULL;
839
840 for (walk = extended_part->part_list; walk; walk = walk->next) {
841 if (walk->geom.start > last_end + 1) {
842 free_space = ped_partition_new (
843 disk,
844 PED_PARTITION_FREESPACE
845 | PED_PARTITION_LOGICAL,
846 NULL,
847 last_end + 1, walk->geom.start - 1);
848 _disk_raw_insert_before (disk, walk, free_space);
849 }
850
851 last = walk;
852 last_end = last->geom.end;
853 }
854
855 if (last_end < extended_part->geom.end) {
856 free_space = ped_partition_new (
857 disk,
858 PED_PARTITION_FREESPACE | PED_PARTITION_LOGICAL,
859 NULL,
860 last_end + 1, extended_part->geom.end);
861
862 if (last)
863 return _disk_raw_insert_after (disk, last, free_space);
864 else
865 extended_part->part_list = free_space;
866 }
867
868 return 1;
869 }
870
871 static int
_disk_alloc_freespace(PedDisk * disk)872 _disk_alloc_freespace (PedDisk* disk)
873 {
874 PedSector last_end;
875 PedPartition* walk;
876 PedPartition* last;
877 PedPartition* free_space;
878
879 if (!_disk_remove_freespace (disk))
880 return 0;
881 if (!_alloc_extended_freespace (disk))
882 return 0;
883
884 last = NULL;
885 last_end = -1;
886
887 for (walk = disk->part_list; walk; walk = walk->next) {
888 if (walk->geom.start > last_end + 1) {
889 free_space = ped_partition_new (disk,
890 PED_PARTITION_FREESPACE, NULL,
891 last_end + 1, walk->geom.start - 1);
892 _disk_raw_insert_before (disk, walk, free_space);
893 }
894
895 last = walk;
896 last_end = last->geom.end;
897 }
898
899 if (last_end < disk->dev->length - 1) {
900 free_space = ped_partition_new (disk,
901 PED_PARTITION_FREESPACE, NULL,
902 last_end + 1, disk->dev->length - 1);
903 if (last)
904 return _disk_raw_insert_after (disk, last, free_space);
905 else
906 disk->part_list = free_space;
907 }
908
909 return 1;
910 }
911
912 /**
913 * Update mode: used when updating the internal representation of the partition
914 * table. In update mode, the metadata and freespace placeholder/virtual
915 * partitions are removed, making it much easier for various manipulation
916 * routines...
917 */
918 static void
_disk_push_update_mode(PedDisk * disk)919 _disk_push_update_mode (PedDisk* disk)
920 {
921 if (!disk->update_mode) {
922 #ifdef DEBUG
923 _disk_check_sanity (disk);
924 #endif
925
926 _disk_remove_freespace (disk);
927 disk->update_mode++;
928 _disk_remove_metadata (disk);
929
930 #ifdef DEBUG
931 _disk_check_sanity (disk);
932 #endif
933 } else {
934 disk->update_mode++;
935 }
936 }
937
938 static void
_disk_pop_update_mode(PedDisk * disk)939 _disk_pop_update_mode (PedDisk* disk)
940 {
941 PED_ASSERT (disk->update_mode, return);
942
943 if (disk->update_mode == 1) {
944 /* re-allocate metadata BEFORE leaving update mode, to prevent infinite
945 * recursion (metadata allocation requires update mode)
946 */
947 #ifdef DEBUG
948 _disk_check_sanity (disk);
949 #endif
950
951 _disk_alloc_metadata (disk);
952 disk->update_mode--;
953 _disk_alloc_freespace (disk);
954
955 #ifdef DEBUG
956 _disk_check_sanity (disk);
957 #endif
958 } else {
959 disk->update_mode--;
960 }
961 }
962
963 /** @} */
964
965 /**
966 * \addtogroup PedPartition
967 *
968 * \brief Partition access.
969 *
970 * @{
971 */
972
973 PedPartition*
_ped_partition_alloc(const PedDisk * disk,PedPartitionType type,const PedFileSystemType * fs_type,PedSector start,PedSector end)974 _ped_partition_alloc (const PedDisk* disk, PedPartitionType type,
975 const PedFileSystemType* fs_type,
976 PedSector start, PedSector end)
977 {
978 PedPartition* part;
979
980 PED_ASSERT (disk != NULL, return 0);
981
982 part = (PedPartition*) ped_malloc (sizeof (PedPartition));
983 if (!part)
984 goto error;
985
986 part->prev = NULL;
987 part->next = NULL;
988
989 part->disk = (PedDisk*) disk;
990 if (!ped_geometry_init (&part->geom, disk->dev, start, end - start + 1))
991 goto error_free_part;
992
993 part->num = -1;
994 part->type = type;
995 part->part_list = NULL;
996 part->fs_type = fs_type;
997
998 return part;
999
1000 error_free_part:
1001 ped_free (part);
1002 error:
1003 return NULL;
1004 }
1005
1006 void
_ped_partition_free(PedPartition * part)1007 _ped_partition_free (PedPartition* part)
1008 {
1009 ped_free (part);
1010 }
1011
1012 int
_ped_partition_attempt_align(PedPartition * part,const PedConstraint * external,PedConstraint * internal)1013 _ped_partition_attempt_align (PedPartition* part,
1014 const PedConstraint* external,
1015 PedConstraint* internal)
1016 {
1017 PedConstraint* intersection;
1018 PedGeometry* solution;
1019
1020 intersection = ped_constraint_intersect (external, internal);
1021 ped_constraint_destroy (internal);
1022 if (!intersection)
1023 goto fail;
1024
1025 solution = ped_constraint_solve_nearest (intersection, &part->geom);
1026 if (!solution)
1027 goto fail_free_intersection;
1028 ped_geometry_set (&part->geom, solution->start, solution->length);
1029 ped_geometry_destroy (solution);
1030 ped_constraint_destroy (intersection);
1031 return 1;
1032
1033 fail_free_intersection:
1034 ped_constraint_destroy (intersection);
1035 fail:
1036 return 0;
1037 }
1038
1039 /**
1040 * Create a new \link _PedPartition PedPartition \endlink on \p disk.
1041 *
1042 * \param type One of \p PED_PARTITION_NORMAL, \p PED_PARTITION_EXTENDED,
1043 * \p PED_PARTITION_LOGICAL.
1044 *
1045 * \note The constructed partition is not added to <tt>disk</tt>'s
1046 * partition table. Use ped_disk_add_partition() to do this.
1047 *
1048 * \return A new \link _PedPartition PedPartition \endlink object,
1049 * NULL on failure.
1050 *
1051 * \throws PED_EXCEPTION_ERROR if \p type is \p EXTENDED or \p LOGICAL but the
1052 * label does not support this concept.
1053 */
1054 PedPartition*
ped_partition_new(const PedDisk * disk,PedPartitionType type,const PedFileSystemType * fs_type,PedSector start,PedSector end)1055 ped_partition_new (const PedDisk* disk, PedPartitionType type,
1056 const PedFileSystemType* fs_type, PedSector start,
1057 PedSector end)
1058 {
1059 int supports_extended;
1060 PedPartition* part;
1061
1062 PED_ASSERT (disk != NULL, return NULL);
1063 PED_ASSERT (disk->type->ops->partition_new != NULL, return NULL);
1064
1065 supports_extended = ped_disk_type_check_feature (disk->type,
1066 PED_DISK_TYPE_EXTENDED);
1067
1068 if (!supports_extended
1069 && (type == PED_PARTITION_EXTENDED
1070 || type == PED_PARTITION_LOGICAL)) {
1071 ped_exception_throw (
1072 PED_EXCEPTION_ERROR,
1073 PED_EXCEPTION_CANCEL,
1074 _("%s disk labels do not support extended "
1075 "partitions."),
1076 disk->type->name);
1077 goto error;
1078 }
1079
1080 part = disk->type->ops->partition_new (disk, type, fs_type, start, end);
1081 if (!part)
1082 goto error;
1083
1084 if (fs_type || part->type == PED_PARTITION_EXTENDED) {
1085 if (!ped_partition_set_system (part, fs_type))
1086 goto error_destroy_part;
1087 }
1088 return part;
1089
1090 error_destroy_part:
1091 ped_partition_destroy (part);
1092 error:
1093 return NULL;
1094 }
1095
1096 /**
1097 * Destroy a \link _PedPartition PedPartition \endlink object.
1098 *
1099 * \note Should not be called on a partition that is in a partition table.
1100 * Use ped_disk_delete_partition() instead.
1101 */
1102 void
ped_partition_destroy(PedPartition * part)1103 ped_partition_destroy (PedPartition* part)
1104 {
1105 PED_ASSERT (part != NULL, return);
1106 PED_ASSERT (part->disk != NULL, return);
1107 PED_ASSERT (part->disk->type->ops->partition_new != NULL, return);
1108
1109 part->disk->type->ops->partition_destroy (part);
1110 }
1111
1112
1113 /**
1114 * Return whether or not the partition is "active".
1115 *
1116 * A partition is active if \p part->type is neither \p PED_PARTITION_METADATA
1117 * nor \p PED_PARTITION_FREE.
1118 */
1119 int
ped_partition_is_active(const PedPartition * part)1120 ped_partition_is_active (const PedPartition* part)
1121 {
1122 PED_ASSERT (part != NULL, return 0);
1123
1124 return !(part->type & PED_PARTITION_FREESPACE
1125 || part->type & PED_PARTITION_METADATA);
1126 }
1127
1128 /**
1129 * Set the state (\c 1 or \c 0) of a flag on a partition.
1130 *
1131 * Flags are disk label specific, although they have a global
1132 * "namespace": the flag PED_PARTITION_BOOT, for example, roughly means
1133 * "this" partition is bootable". But this means different things on different
1134 * disk labels (and may not be defined on some disk labels). For example,
1135 * on MS-DOS disk labels, there can only be one boot partition, and this
1136 * refers to the partition that will be booted from on startup. On PC98
1137 * disk labels, the user can choose from any bootable partition on startup.
1138 *
1139 * \note It is an error to call this on an unavailable flag -- use
1140 * ped_partition_is_flag_available() to determine which flags are available
1141 * for a given disk label.
1142 *
1143 * \throws PED_EXCEPTION_ERROR if the requested flag is not available for this
1144 * label.
1145 */
1146 int
ped_partition_set_flag(PedPartition * part,PedPartitionFlag flag,int state)1147 ped_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
1148 {
1149 PedDiskOps* ops;
1150
1151 PED_ASSERT (part != NULL, return 0);
1152 PED_ASSERT (part->disk != NULL, return 0);
1153 PED_ASSERT (ped_partition_is_active (part), return 0);
1154
1155 ops = part->disk->type->ops;
1156 PED_ASSERT (ops->partition_set_flag != NULL, return 0);
1157 PED_ASSERT (ops->partition_is_flag_available != NULL, return 0);
1158
1159 if (!ops->partition_is_flag_available (part, flag)) {
1160 ped_exception_throw (
1161 PED_EXCEPTION_ERROR,
1162 PED_EXCEPTION_CANCEL,
1163 "The flag '%s' is not available for %s disk labels.",
1164 ped_partition_flag_get_name (flag),
1165 part->disk->type->name);
1166 return 0;
1167 }
1168
1169 return ops->partition_set_flag (part, flag, state);
1170 }
1171
1172 /**
1173 * Get the state (\c 1 or \c 0) of a flag on a partition.
1174 *
1175 * See ped_partition_set_flag() for conditions that must hold.
1176 *
1177 * \todo Where's the check for flag availability?
1178 */
1179 int
ped_partition_get_flag(const PedPartition * part,PedPartitionFlag flag)1180 ped_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
1181 {
1182 PED_ASSERT (part != NULL, return 0);
1183 PED_ASSERT (part->disk != NULL, return 0);
1184 PED_ASSERT (part->disk->type->ops->partition_get_flag != NULL,
1185 return 0);
1186 PED_ASSERT (ped_partition_is_active (part), return 0);
1187
1188 return part->disk->type->ops->partition_get_flag (part, flag);
1189 }
1190
1191 /**
1192 * Check whether a given flag is available on a partition.
1193 *
1194 * \return \c 1 if the flag is available.
1195 */
1196 int
ped_partition_is_flag_available(const PedPartition * part,PedPartitionFlag flag)1197 ped_partition_is_flag_available (const PedPartition* part,
1198 PedPartitionFlag flag)
1199 {
1200 PED_ASSERT (part != NULL, return 0);
1201 PED_ASSERT (part->disk != NULL, return 0);
1202 PED_ASSERT (part->disk->type->ops->partition_is_flag_available != NULL,
1203 return 0);
1204 PED_ASSERT (ped_partition_is_active (part), return 0);
1205
1206 return part->disk->type->ops->partition_is_flag_available (part, flag);
1207 }
1208
1209 /**
1210 * Sets the system type on the partition to \p fs_type.
1211 *
1212 * \note The file system may be opened, to get more information about the
1213 * file system, e.g. to determine if it's FAT16 or FAT32.
1214 *
1215 * \return \c 0 on failure.
1216 */
1217 int
ped_partition_set_system(PedPartition * part,const PedFileSystemType * fs_type)1218 ped_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1219 {
1220 const PedDiskType* disk_type;
1221
1222 PED_ASSERT (part != NULL, return 0);
1223 PED_ASSERT (ped_partition_is_active (part), return 0);
1224 PED_ASSERT (part->disk != NULL, return 0);
1225 disk_type = part->disk->type;
1226 PED_ASSERT (disk_type != NULL, return 0);
1227 PED_ASSERT (disk_type->ops != NULL, return 0);
1228 PED_ASSERT (disk_type->ops->partition_set_system != NULL, return 0);
1229
1230 return disk_type->ops->partition_set_system (part, fs_type);
1231 }
1232
1233 static int
_assert_partition_name_feature(const PedDiskType * disk_type)1234 _assert_partition_name_feature (const PedDiskType* disk_type)
1235 {
1236 if (!ped_disk_type_check_feature (
1237 disk_type, PED_DISK_TYPE_PARTITION_NAME)) {
1238 ped_exception_throw (
1239 PED_EXCEPTION_ERROR,
1240 PED_EXCEPTION_CANCEL,
1241 "%s disk labels do not support partition names.",
1242 disk_type->name);
1243 return 0;
1244 }
1245 return 1;
1246 }
1247
1248 /**
1249 * Sets the name of a partition.
1250 *
1251 * \note This will only work if the disk label supports it.
1252 * You can use
1253 * \code
1254 * ped_disk_type_check_feature (part->disk->type, PED_DISK_TYPE_PARTITION_NAME);
1255 * \endcode
1256 * to check whether this feature is enabled for a label.
1257 *
1258 * \note \p name will not be modified by libparted. It can be freed
1259 * by the caller immediately after ped_partition_set_name() is called.
1260 *
1261 * \return \c 1 on success, \c 0 otherwise.
1262 */
1263 int
ped_partition_set_name(PedPartition * part,const char * name)1264 ped_partition_set_name (PedPartition* part, const char* name)
1265 {
1266 PED_ASSERT (part != NULL, return 0);
1267 PED_ASSERT (part->disk != NULL, return 0);
1268 PED_ASSERT (ped_partition_is_active (part), return 0);
1269 PED_ASSERT (name != NULL, return 0);
1270
1271 if (!_assert_partition_name_feature (part->disk->type))
1272 return 0;
1273
1274 PED_ASSERT (part->disk->type->ops->partition_set_name != NULL,
1275 return 0);
1276 part->disk->type->ops->partition_set_name (part, name);
1277 return 1;
1278 }
1279
1280 /**
1281 * Returns the name of a partition \p part. This will only work if the disk
1282 * label supports it.
1283 *
1284 * \note The returned string should not be modified. It should
1285 * not be referenced after the partition is destroyed.
1286 */
1287 const char*
ped_partition_get_name(const PedPartition * part)1288 ped_partition_get_name (const PedPartition* part)
1289 {
1290 PED_ASSERT (part != NULL, return NULL);
1291 PED_ASSERT (part->disk != NULL, return 0);
1292 PED_ASSERT (ped_partition_is_active (part), return 0);
1293
1294 if (!_assert_partition_name_feature (part->disk->type))
1295 return NULL;
1296
1297 PED_ASSERT (part->disk->type->ops->partition_get_name != NULL,
1298 return NULL);
1299 return part->disk->type->ops->partition_get_name (part);
1300 }
1301
1302 /** @} */
1303
1304 /**
1305 * \addtogroup PedDisk
1306 *
1307 * @{
1308 */
1309
1310 PedPartition*
ped_disk_extended_partition(const PedDisk * disk)1311 ped_disk_extended_partition (const PedDisk* disk)
1312 {
1313 PedPartition* walk;
1314
1315 PED_ASSERT (disk != NULL, return 0);
1316
1317 for (walk = disk->part_list; walk; walk = walk->next) {
1318 if (walk->type == PED_PARTITION_EXTENDED)
1319 break;
1320 }
1321 return walk;
1322 }
1323
1324 /**
1325 * Return the next partition after \p part on \p disk. If \p part is \c NULL,
1326 * return the first partition. If \p part is the last partition, returns
1327 * \c NULL. If \p part is an extended partition, returns the first logical
1328 * partition. If this is called repeatedly passing the return value as \p part,
1329 * a depth-first traversal is executed.
1330 *
1331 * \return The next partition, \c NULL if no more partitions left.
1332 */
1333 PedPartition*
ped_disk_next_partition(const PedDisk * disk,const PedPartition * part)1334 ped_disk_next_partition (const PedDisk* disk, const PedPartition* part)
1335 {
1336 PED_ASSERT (disk != NULL, return 0);
1337
1338 if (!part)
1339 return disk->part_list;
1340 if (part->type == PED_PARTITION_EXTENDED)
1341 return part->part_list ? part->part_list : part->next;
1342 if (part->next)
1343 return part->next;
1344 if (part->type & PED_PARTITION_LOGICAL)
1345 return ped_disk_extended_partition (disk)->next;
1346 return NULL;
1347 }
1348
1349 /** @} */
1350
1351 #ifdef DEBUG
1352 static int
_disk_check_sanity(PedDisk * disk)1353 _disk_check_sanity (PedDisk* disk)
1354 {
1355 PedPartition* walk;
1356
1357 PED_ASSERT (disk != NULL, return 0);
1358
1359 for (walk = disk->part_list; walk; walk = walk->next) {
1360 PED_ASSERT (!(walk->type & PED_PARTITION_LOGICAL), return 0);
1361 PED_ASSERT (!walk->prev || walk->prev->next == walk, return 0);
1362 }
1363
1364 if (!ped_disk_extended_partition (disk))
1365 return 1;
1366
1367 for (walk = ped_disk_extended_partition (disk)->part_list; walk;
1368 walk = walk->next) {
1369 PED_ASSERT (walk->type & PED_PARTITION_LOGICAL, return 0);
1370 if (walk->prev)
1371 PED_ASSERT (walk->prev->next == walk, return 0);
1372 }
1373 return 1;
1374 }
1375 #endif
1376
1377 /**
1378 * Returns the partition numbered \p num.
1379 *
1380 * \return \c NULL if the specified partition does not exist.
1381 */
1382 PedPartition*
ped_disk_get_partition(const PedDisk * disk,int num)1383 ped_disk_get_partition (const PedDisk* disk, int num)
1384 {
1385 PedPartition* walk;
1386
1387 PED_ASSERT (disk != NULL, return 0);
1388
1389 for (walk = disk->part_list; walk;
1390 walk = ped_disk_next_partition (disk, walk)) {
1391 if (walk->num == num && !(walk->type & PED_PARTITION_FREESPACE))
1392 return walk;
1393 }
1394
1395 return NULL;
1396 }
1397
1398 /**
1399 * Returns the partition that contains sect. If sect lies within a logical
1400 * partition, then the logical partition is returned (not the extended
1401 * partition).
1402 */
1403 PedPartition*
ped_disk_get_partition_by_sector(const PedDisk * disk,PedSector sect)1404 ped_disk_get_partition_by_sector (const PedDisk* disk, PedSector sect)
1405 {
1406 PedPartition* walk;
1407
1408 PED_ASSERT (disk != NULL, return 0);
1409
1410 for (walk = disk->part_list; walk;
1411 walk = ped_disk_next_partition (disk, walk)) {
1412 if (ped_geometry_test_sector_inside (&walk->geom, sect)
1413 && walk->type != PED_PARTITION_EXTENDED)
1414 return walk;
1415 }
1416
1417 /* should never get here, unless sect is outside of disk's useable
1418 * part, or we're in "update mode", and the free space place-holders
1419 * have been removed with _disk_remove_freespace()
1420 */
1421 return NULL;
1422 }
1423
1424 /* I'm beginning to agree with Sedgewick :-/ */
1425 static int
_disk_raw_insert_before(PedDisk * disk,PedPartition * loc,PedPartition * part)1426 _disk_raw_insert_before (PedDisk* disk, PedPartition* loc, PedPartition* part)
1427 {
1428 PED_ASSERT (disk != NULL, return 0);
1429 PED_ASSERT (loc != NULL, return 0);
1430 PED_ASSERT (part != NULL, return 0);
1431
1432 part->prev = loc->prev;
1433 part->next = loc;
1434 if (part->prev) {
1435 part->prev->next = part;
1436 } else {
1437 if (loc->type & PED_PARTITION_LOGICAL)
1438 ped_disk_extended_partition (disk)->part_list = part;
1439 else
1440 disk->part_list = part;
1441 }
1442 loc->prev = part;
1443
1444 return 1;
1445 }
1446
1447 static int
_disk_raw_insert_after(PedDisk * disk,PedPartition * loc,PedPartition * part)1448 _disk_raw_insert_after (PedDisk* disk, PedPartition* loc, PedPartition* part)
1449 {
1450 PED_ASSERT (disk != NULL, return 0);
1451 PED_ASSERT (loc != NULL, return 0);
1452 PED_ASSERT (part != NULL, return 0);
1453
1454 part->prev = loc;
1455 part->next = loc->next;
1456 if (loc->next)
1457 loc->next->prev = part;
1458 loc->next = part;
1459
1460 return 1;
1461 }
1462
1463 static int
_disk_raw_remove(PedDisk * disk,PedPartition * part)1464 _disk_raw_remove (PedDisk* disk, PedPartition* part)
1465 {
1466 PED_ASSERT (disk != NULL, return 0);
1467 PED_ASSERT (part != NULL, return 0);
1468
1469 if (part->prev) {
1470 part->prev->next = part->next;
1471 if (part->next)
1472 part->next->prev = part->prev;
1473 } else {
1474 if (part->type & PED_PARTITION_LOGICAL) {
1475 ped_disk_extended_partition (disk)->part_list
1476 = part->next;
1477 } else {
1478 disk->part_list = part->next;
1479 }
1480 if (part->next)
1481 part->next->prev = NULL;
1482 }
1483
1484 return 1;
1485 }
1486
1487 /*
1488 *UPDATE MODE ONLY
1489 */
1490 static int
_disk_raw_add(PedDisk * disk,PedPartition * part)1491 _disk_raw_add (PedDisk* disk, PedPartition* part)
1492 {
1493 PedPartition* walk;
1494 PedPartition* last;
1495 PedPartition* ext_part;
1496
1497 PED_ASSERT (disk->update_mode, return 0);
1498
1499 ext_part = ped_disk_extended_partition (disk);
1500
1501 last = NULL;
1502 walk = (part->type & PED_PARTITION_LOGICAL) ?
1503 ext_part->part_list : disk->part_list;
1504
1505 for (; walk; last = walk, walk = walk->next) {
1506 if (walk->geom.start > part->geom.end)
1507 break;
1508 }
1509
1510 if (walk) {
1511 return _disk_raw_insert_before (disk, walk, part);
1512 } else {
1513 if (last) {
1514 return _disk_raw_insert_after (disk, last, part);
1515 } else {
1516 if (part->type & PED_PARTITION_LOGICAL)
1517 ext_part->part_list = part;
1518 else
1519 disk->part_list = part;
1520 }
1521 }
1522
1523 return 1;
1524 }
1525
1526 static PedConstraint*
_partition_get_overlap_constraint(PedPartition * part,PedGeometry * geom)1527 _partition_get_overlap_constraint (PedPartition* part, PedGeometry* geom)
1528 {
1529 PedSector min_start;
1530 PedSector max_end;
1531 PedPartition* walk;
1532 PedGeometry free_space;
1533
1534 PED_ASSERT (part->disk->update_mode, return NULL);
1535 PED_ASSERT (part->geom.dev == geom->dev, return NULL);
1536
1537 if (part->type & PED_PARTITION_LOGICAL) {
1538 PedPartition* ext_part;
1539
1540 ext_part = ped_disk_extended_partition (part->disk);
1541 PED_ASSERT (ext_part != NULL, return NULL);
1542
1543 min_start = ext_part->geom.start;
1544 max_end = ext_part->geom.end;
1545 walk = ext_part->part_list;
1546 } else {
1547 min_start = 0;
1548 max_end = part->disk->dev->length - 1;
1549 walk = part->disk->part_list;
1550 }
1551
1552 while (walk != NULL
1553 && (walk->geom.start < geom->start
1554 || min_start >= walk->geom.start)) {
1555 if (walk != part)
1556 min_start = walk->geom.end + 1;
1557 walk = walk->next;
1558 }
1559
1560 if (walk == part)
1561 walk = walk->next;
1562
1563 if (walk)
1564 max_end = walk->geom.start - 1;
1565
1566 if (min_start >= max_end)
1567 return NULL;
1568
1569 ped_geometry_init (&free_space, part->disk->dev,
1570 min_start, max_end - min_start + 1);
1571 return ped_constraint_new_from_max (&free_space);
1572 }
1573
1574 /*
1575 * Returns \c 0 if the partition, \p part overlaps with any partitions on the
1576 * \p disk. The geometry of \p part is taken to be \p geom, NOT \p part->geom
1577 * (the idea here is to check if \p geom is valid, before changing \p part).
1578 *
1579 * This is useful for seeing if a resized partitions new geometry is going to
1580 * fit, without the existing geomtry getting in the way.
1581 *
1582 * Note: overlap with an extended partition is also allowed, provided that
1583 * \p geom lies completely inside the extended partition.
1584 */
1585 static int
_disk_check_part_overlaps(PedDisk * disk,PedPartition * part)1586 _disk_check_part_overlaps (PedDisk* disk, PedPartition* part)
1587 {
1588 PedPartition* walk;
1589
1590 PED_ASSERT (disk != NULL, return 0);
1591 PED_ASSERT (part != NULL, return 0);
1592
1593 for (walk = ped_disk_next_partition (disk, NULL); walk;
1594 walk = ped_disk_next_partition (disk, walk)) {
1595 if (walk->type & PED_PARTITION_FREESPACE)
1596 continue;
1597 if (walk == part)
1598 continue;
1599 if (part->type & PED_PARTITION_EXTENDED
1600 && walk->type & PED_PARTITION_LOGICAL)
1601 continue;
1602
1603 if (ped_geometry_test_overlap (&walk->geom, &part->geom)) {
1604 if (walk->type & PED_PARTITION_EXTENDED
1605 && part->type & PED_PARTITION_LOGICAL
1606 && ped_geometry_test_inside (&walk->geom,
1607 &part->geom))
1608 continue;
1609 return 0;
1610 }
1611 }
1612
1613 return 1;
1614 }
1615
1616 static int
_partition_check_basic_sanity(PedDisk * disk,PedPartition * part)1617 _partition_check_basic_sanity (PedDisk* disk, PedPartition* part)
1618 {
1619 PedPartition* ext_part = ped_disk_extended_partition (disk);
1620
1621 PED_ASSERT (part->disk == disk, return 0);
1622
1623 PED_ASSERT (part->geom.start >= 0, return 0);
1624 PED_ASSERT (part->geom.end < disk->dev->length, return 0);
1625 PED_ASSERT (part->geom.start <= part->geom.end, return 0);
1626
1627 if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)
1628 && (part->type == PED_PARTITION_EXTENDED
1629 || part->type == PED_PARTITION_LOGICAL)) {
1630 ped_exception_throw (
1631 PED_EXCEPTION_ERROR,
1632 PED_EXCEPTION_CANCEL,
1633 _("%s disk labels don't support logical or extended "
1634 "partitions."),
1635 disk->type->name);
1636 return 0;
1637 }
1638
1639 if (ped_partition_is_active (part)
1640 && ! (part->type & PED_PARTITION_LOGICAL)) {
1641 if (ped_disk_get_primary_partition_count (disk) + 1
1642 > ped_disk_get_max_primary_partition_count (disk)) {
1643 ped_exception_throw (
1644 PED_EXCEPTION_ERROR,
1645 PED_EXCEPTION_CANCEL,
1646 _("Too many primary partitions."));
1647 return 0;
1648 }
1649 }
1650
1651 if ((part->type & PED_PARTITION_LOGICAL) && !ext_part) {
1652 ped_exception_throw (
1653 PED_EXCEPTION_ERROR,
1654 PED_EXCEPTION_CANCEL,
1655 _("Can't add a logical partition to %s, because "
1656 "there is no extended partition."),
1657 disk->dev->path);
1658 return 0;
1659 }
1660
1661 return 1;
1662 }
1663
1664 static int
_check_extended_partition(PedDisk * disk,PedPartition * part)1665 _check_extended_partition (PedDisk* disk, PedPartition* part)
1666 {
1667 PedPartition* walk;
1668 PedPartition* ext_part;
1669
1670 PED_ASSERT (disk != NULL, return 0);
1671 ext_part = ped_disk_extended_partition (disk);
1672 if (!ext_part) ext_part = part;
1673 PED_ASSERT (ext_part != NULL, return 0);
1674
1675 if (part != ext_part) {
1676 ped_exception_throw (
1677 PED_EXCEPTION_ERROR,
1678 PED_EXCEPTION_CANCEL,
1679 _("Can't have more than one extended partition on %s."),
1680 disk->dev->path);
1681 return 0;
1682 }
1683
1684 for (walk = ext_part->part_list; walk; walk = walk->next) {
1685 if (!ped_geometry_test_inside (&ext_part->geom, &walk->geom)) {
1686 ped_exception_throw (
1687 PED_EXCEPTION_ERROR,
1688 PED_EXCEPTION_CANCEL,
1689 _("Can't have logical partitions outside of "
1690 "the extended partition."));
1691 return 0;
1692 }
1693 }
1694 return 1;
1695 }
1696
1697 static int
_check_partition(PedDisk * disk,PedPartition * part)1698 _check_partition (PedDisk* disk, PedPartition* part)
1699 {
1700 PedPartition* ext_part = ped_disk_extended_partition (disk);
1701
1702 PED_ASSERT (part->geom.start <= part->geom.end, return 0);
1703
1704 if (part->type == PED_PARTITION_EXTENDED) {
1705 if (!_check_extended_partition (disk, part))
1706 return 0;
1707 }
1708
1709 if (part->type & PED_PARTITION_LOGICAL
1710 && !ped_geometry_test_inside (&ext_part->geom, &part->geom)) {
1711 ped_exception_throw (
1712 PED_EXCEPTION_ERROR,
1713 PED_EXCEPTION_CANCEL,
1714 _("Can't have a logical partition outside of the "
1715 "extended partition on %s."),
1716 disk->dev->path);
1717 return 0;
1718 }
1719
1720 if (!_disk_check_part_overlaps (disk, part)) {
1721 ped_exception_throw (
1722 PED_EXCEPTION_ERROR,
1723 PED_EXCEPTION_CANCEL,
1724 _("Can't have overlapping partitions."));
1725 return 0;
1726 }
1727
1728 if (! (part->type & PED_PARTITION_LOGICAL)
1729 && ext_part && ext_part != part
1730 && ped_geometry_test_inside (&ext_part->geom, &part->geom)) {
1731 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1732 _("Can't have a primary partition inside an extended "
1733 "partition."));
1734 return 0;
1735 }
1736
1737 return 1;
1738 }
1739
1740 /**
1741 * Adds PedPartition \p part to PedPartition \p disk.
1742 *
1743 * \warning The partition's geometry may be changed, subject to \p constraint.
1744 * You could set \p constraint to <tt>ped_constraint_exact(&part->geom)</tt>,
1745 * but many partition table schemes have special requirements on the start
1746 * and end of partitions. Therefore, having an overly strict constraint
1747 * will probably mean that this function will fail (in which
1748 * case \p part will be left unmodified)
1749 * \p part is assigned a number (\p part->num) in this process.
1750 *
1751 * \return \c 0 on failure.
1752 */
1753 int
ped_disk_add_partition(PedDisk * disk,PedPartition * part,const PedConstraint * constraint)1754 ped_disk_add_partition (PedDisk* disk, PedPartition* part,
1755 const PedConstraint* constraint)
1756 {
1757 PedConstraint* overlap_constraint = NULL;
1758 PedConstraint* constraints = NULL;
1759
1760 PED_ASSERT (disk != NULL, return 0);
1761 PED_ASSERT (part != NULL, return 0);
1762
1763 if (!_partition_check_basic_sanity (disk, part))
1764 return 0;
1765
1766 _disk_push_update_mode (disk);
1767
1768 if (ped_partition_is_active (part)) {
1769 overlap_constraint
1770 = _partition_get_overlap_constraint (part, &part->geom);
1771 constraints = ped_constraint_intersect (overlap_constraint,
1772 constraint);
1773
1774 if (!constraints && constraint) {
1775 ped_exception_throw (
1776 PED_EXCEPTION_ERROR,
1777 PED_EXCEPTION_CANCEL,
1778 _("Can't have overlapping partitions."));
1779 goto error;
1780 }
1781
1782 if (!_partition_enumerate (part))
1783 goto error;
1784 if (!_partition_align (part, constraints))
1785 goto error;
1786 }
1787 if (!_check_partition (disk, part))
1788 goto error;
1789 if (!_disk_raw_add (disk, part))
1790 goto error;
1791
1792 ped_constraint_destroy (overlap_constraint);
1793 ped_constraint_destroy (constraints);
1794 _disk_pop_update_mode (disk);
1795 #ifdef DEBUG
1796 if (!_disk_check_sanity (disk))
1797 return 0;
1798 #endif
1799 return 1;
1800
1801 error:
1802 ped_constraint_destroy (overlap_constraint);
1803 ped_constraint_destroy (constraints);
1804 _disk_pop_update_mode (disk);
1805 return 0;
1806 }
1807
1808 /**
1809 * Removes PedPartition \p part from PedDisk \p disk.
1810 *
1811 * If \p part is an extended partition, it must not contain any logical
1812 * partitions. \p part is *NOT* destroyed. The caller must call
1813 * ped_partition_destroy(), or use ped_disk_delete_partition() instead.
1814 *
1815 * \return \c 0 on error.
1816 */
1817 int
ped_disk_remove_partition(PedDisk * disk,PedPartition * part)1818 ped_disk_remove_partition (PedDisk* disk, PedPartition* part)
1819 {
1820 PED_ASSERT (disk != NULL, return 0);
1821 PED_ASSERT (part != NULL, return 0);
1822
1823 _disk_push_update_mode (disk);
1824 PED_ASSERT (part->part_list == NULL, goto error);
1825 _disk_raw_remove (disk, part);
1826 _disk_pop_update_mode (disk);
1827 ped_disk_enumerate_partitions (disk);
1828 return 1;
1829
1830 error:
1831 _disk_pop_update_mode (disk);
1832 return 0;
1833 }
1834
1835 static int
1836 ped_disk_delete_all_logical (PedDisk* disk);
1837
1838 /**
1839 * Removes \p part from \p disk, and destroys \p part.
1840 *
1841 * \return \c 0 on failure.
1842 */
1843 int
ped_disk_delete_partition(PedDisk * disk,PedPartition * part)1844 ped_disk_delete_partition (PedDisk* disk, PedPartition* part)
1845 {
1846 PED_ASSERT (disk != NULL, return 0);
1847 PED_ASSERT (part != NULL, return 0);
1848
1849 _disk_push_update_mode (disk);
1850 if (part->type == PED_PARTITION_EXTENDED)
1851 ped_disk_delete_all_logical (disk);
1852 ped_disk_remove_partition (disk, part);
1853 ped_partition_destroy (part);
1854 _disk_pop_update_mode (disk);
1855
1856 return 1;
1857 }
1858
1859 static int
ped_disk_delete_all_logical(PedDisk * disk)1860 ped_disk_delete_all_logical (PedDisk* disk)
1861 {
1862 PedPartition* walk;
1863 PedPartition* next;
1864 PedPartition* ext_part;
1865
1866 PED_ASSERT (disk != NULL, return 0);
1867 ext_part = ped_disk_extended_partition (disk);
1868 PED_ASSERT (ext_part != NULL, return 0);
1869
1870 for (walk = ext_part->part_list; walk; walk = next) {
1871 next = walk->next;
1872
1873 if (!ped_disk_delete_partition (disk, walk))
1874 return 0;
1875 }
1876 return 1;
1877 }
1878
1879 /**
1880 * Removes and destroys all partitions on \p disk.
1881 *
1882 * \return \c 0 on failure.
1883 */
1884 int
ped_disk_delete_all(PedDisk * disk)1885 ped_disk_delete_all (PedDisk* disk)
1886 {
1887 PedPartition* walk;
1888 PedPartition* next;
1889
1890 PED_ASSERT (disk != NULL, return 0);
1891
1892 _disk_push_update_mode (disk);
1893
1894 for (walk = disk->part_list; walk; walk = next) {
1895 next = walk->next;
1896
1897 if (!ped_disk_delete_partition (disk, walk))
1898 return 0;
1899 }
1900
1901 _disk_pop_update_mode (disk);
1902
1903 return 1;
1904 }
1905
1906 /**
1907 * Sets the geometry of \p part (i.e. change a partitions location). This can
1908 * fail for many reasons, e.g. can't overlap with other partitions. If it
1909 * does fail, \p part will remain unchanged. Returns \c 0 on failure. \p part's
1910 * geometry may be set to something different from \p start and \p end subject
1911 * to \p constraint.
1912 *
1913 * \warning The constraint warning from ped_disk_add_partition() applies.
1914 *
1915 * \note this function does not modify the contents of the partition. You need
1916 * to call ped_file_system_resize() separately.
1917 */
1918 int
ped_disk_set_partition_geom(PedDisk * disk,PedPartition * part,const PedConstraint * constraint,PedSector start,PedSector end)1919 ped_disk_set_partition_geom (PedDisk* disk, PedPartition* part,
1920 const PedConstraint* constraint,
1921 PedSector start, PedSector end)
1922 {
1923 PedConstraint* overlap_constraint = NULL;
1924 PedConstraint* constraints = NULL;
1925 PedGeometry old_geom;
1926 PedGeometry new_geom;
1927
1928 PED_ASSERT (disk != NULL, return 0);
1929 PED_ASSERT (part != NULL, return 0);
1930 PED_ASSERT (part->disk == disk, return 0);
1931
1932 old_geom = part->geom;
1933 ped_geometry_init (&new_geom, part->geom.dev, start, end - start + 1);
1934
1935 _disk_push_update_mode (disk);
1936
1937 overlap_constraint
1938 = _partition_get_overlap_constraint (part, &new_geom);
1939 constraints = ped_constraint_intersect (overlap_constraint, constraint);
1940 if (!constraints && constraint) {
1941 ped_exception_throw (
1942 PED_EXCEPTION_ERROR,
1943 PED_EXCEPTION_CANCEL,
1944 _("Can't have overlapping partitions."));
1945 goto error_pop_update_mode;
1946 }
1947
1948 part->geom = new_geom;
1949 if (!_partition_align (part, constraints))
1950 goto error_pop_update_mode;
1951 if (!_check_partition (disk, part))
1952 goto error_pop_update_mode;
1953
1954 /* remove and add, to ensure the ordering gets updated if necessary */
1955 _disk_raw_remove (disk, part);
1956 _disk_raw_add (disk, part);
1957
1958 _disk_pop_update_mode (disk);
1959
1960 ped_constraint_destroy (overlap_constraint);
1961 ped_constraint_destroy (constraints);
1962 return 1;
1963
1964 error_pop_update_mode:
1965 _disk_pop_update_mode (disk);
1966 ped_constraint_destroy (overlap_constraint);
1967 ped_constraint_destroy (constraints);
1968 part->geom = old_geom;
1969 return 0;
1970 }
1971
1972 /**
1973 * Grow PedPartition \p part geometry to the maximum possible subject to
1974 * \p constraint. The new geometry will be a superset of the old geometry.
1975 *
1976 * \return 0 on failure
1977 */
1978 int
ped_disk_maximize_partition(PedDisk * disk,PedPartition * part,const PedConstraint * constraint)1979 ped_disk_maximize_partition (PedDisk* disk, PedPartition* part,
1980 const PedConstraint* constraint)
1981 {
1982 PedGeometry old_geom;
1983 PedSector global_min_start;
1984 PedSector global_max_end;
1985 PedSector new_start;
1986 PedSector new_end;
1987 PedPartition* ext_part = ped_disk_extended_partition (disk);
1988 PedConstraint* constraint_any;
1989
1990 PED_ASSERT (disk != NULL, return 0);
1991 PED_ASSERT (part != NULL, return 0);
1992
1993 if (part->type & PED_PARTITION_LOGICAL) {
1994 PED_ASSERT (ext_part != NULL, return 0);
1995 global_min_start = ext_part->geom.start;
1996 global_max_end = ext_part->geom.end;
1997 } else {
1998 global_min_start = 0;
1999 global_max_end = disk->dev->length - 1;
2000 }
2001
2002 old_geom = part->geom;
2003
2004 _disk_push_update_mode (disk);
2005
2006 if (part->prev)
2007 new_start = part->prev->geom.end + 1;
2008 else
2009 new_start = global_min_start;
2010
2011 if (part->next)
2012 new_end = part->next->geom.start - 1;
2013 else
2014 new_end = global_max_end;
2015
2016 if (!ped_disk_set_partition_geom (disk, part, constraint, new_start,
2017 new_end))
2018 goto error;
2019
2020 _disk_pop_update_mode (disk);
2021 return 1;
2022
2023 error:
2024 constraint_any = ped_constraint_any (disk->dev);
2025 ped_disk_set_partition_geom (disk, part, constraint_any,
2026 old_geom.start, old_geom.end);
2027 ped_constraint_destroy (constraint_any);
2028 _disk_pop_update_mode (disk);
2029 return 0;
2030 }
2031
2032 /**
2033 * Get the maximum geometry \p part can be grown to, subject to
2034 * \p constraint.
2035 *
2036 * \return \c NULL on failure.
2037 */
2038 PedGeometry*
ped_disk_get_max_partition_geometry(PedDisk * disk,PedPartition * part,const PedConstraint * constraint)2039 ped_disk_get_max_partition_geometry (PedDisk* disk, PedPartition* part,
2040 const PedConstraint* constraint)
2041 {
2042 PedGeometry old_geom;
2043 PedGeometry* max_geom;
2044 PedConstraint* constraint_exact;
2045
2046 PED_ASSERT(disk != NULL, return NULL);
2047 PED_ASSERT(part != NULL, return NULL);
2048 PED_ASSERT(ped_partition_is_active (part), return NULL);
2049
2050 old_geom = part->geom;
2051 if (!ped_disk_maximize_partition (disk, part, constraint))
2052 return NULL;
2053 max_geom = ped_geometry_duplicate (&part->geom);
2054
2055 constraint_exact = ped_constraint_exact (&old_geom);
2056 ped_disk_set_partition_geom (disk, part, constraint_exact,
2057 old_geom.start, old_geom.end);
2058 ped_constraint_destroy (constraint_exact);
2059
2060 /* this assertion should never fail, because the old
2061 * geometry was valid
2062 */
2063 PED_ASSERT (ped_geometry_test_equal (&part->geom, &old_geom),
2064 return NULL);
2065
2066 return max_geom;
2067 }
2068
2069 /**
2070 * Reduce the size of the extended partition to a minimum while still wrapping
2071 * its logical partitions. If there are no logical partitions, remove the
2072 * extended partition.
2073 *
2074 * \return 0 on failure.
2075 */
2076 int
ped_disk_minimize_extended_partition(PedDisk * disk)2077 ped_disk_minimize_extended_partition (PedDisk* disk)
2078 {
2079 PedPartition* first_logical;
2080 PedPartition* last_logical;
2081 PedPartition* walk;
2082 PedPartition* ext_part;
2083 PedConstraint* constraint;
2084 int status;
2085
2086 PED_ASSERT (disk != NULL, return 0);
2087
2088 ext_part = ped_disk_extended_partition (disk);
2089 if (!ext_part)
2090 return 1;
2091
2092 _disk_push_update_mode (disk);
2093
2094 first_logical = ext_part->part_list;
2095 if (!first_logical) {
2096 _disk_pop_update_mode (disk);
2097 return ped_disk_delete_partition (disk, ext_part);
2098 }
2099
2100 for (walk = first_logical; walk->next; walk = walk->next);
2101 last_logical = walk;
2102
2103 constraint = ped_constraint_any (disk->dev);
2104 status = ped_disk_set_partition_geom (disk, ext_part, constraint,
2105 first_logical->geom.start,
2106 last_logical->geom.end);
2107 ped_constraint_destroy (constraint);
2108
2109 _disk_pop_update_mode (disk);
2110 return status;
2111 }
2112
2113 /**
2114 * @}
2115 */
2116
2117 /**
2118 * \addtogroup PedPartition
2119 *
2120 * @{
2121 */
2122
2123 /**
2124 * Returns a name that seems mildly appropriate for a partition type \p type.
2125 *
2126 * Eg, if you pass (PED_PARTITION_LOGICAL & PED_PARTITION_FREESPACE), it
2127 * will return "free". This isn't to be taken too seriously - it's just
2128 * useful for user interfaces, so you can show the user something ;-)
2129 *
2130 * \note The returned string will be in English. However,
2131 * translations are provided, so the caller can call
2132 * dgettext("parted", RESULT) on the result.
2133 *
2134 */
2135 const char*
ped_partition_type_get_name(PedPartitionType type)2136 ped_partition_type_get_name (PedPartitionType type)
2137 {
2138 if (type & PED_PARTITION_METADATA)
2139 return N_("metadata");
2140 else if (type & PED_PARTITION_FREESPACE)
2141 return N_("free");
2142 else if (type & PED_PARTITION_EXTENDED)
2143 return N_("extended");
2144 else if (type & PED_PARTITION_LOGICAL)
2145 return N_("logical");
2146 else
2147 return N_("primary");
2148 }
2149
2150
2151 /**
2152 * Returns a name for a \p flag, e.g. PED_PARTITION_BOOT will return "boot".
2153 *
2154 * \note The returned string will be in English. However,
2155 * translations are provided, so the caller can call
2156 * dgettext("parted", RESULT) on the result.
2157 */
2158 const char*
ped_partition_flag_get_name(PedPartitionFlag flag)2159 ped_partition_flag_get_name (PedPartitionFlag flag)
2160 {
2161 switch (flag) {
2162 case PED_PARTITION_BOOT:
2163 return N_("boot");
2164 case PED_PARTITION_ROOT:
2165 return N_("root");
2166 case PED_PARTITION_SWAP:
2167 return N_("swap");
2168 case PED_PARTITION_HIDDEN:
2169 return N_("hidden");
2170 case PED_PARTITION_RAID:
2171 return N_("raid");
2172 case PED_PARTITION_LVM:
2173 return N_("lvm");
2174 case PED_PARTITION_LBA:
2175 return N_("lba");
2176 case PED_PARTITION_HPSERVICE:
2177 return N_("hp-service");
2178 case PED_PARTITION_PALO:
2179 return N_("palo");
2180 case PED_PARTITION_PREP:
2181 return N_("prep");
2182 case PED_PARTITION_MSFT_RESERVED:
2183 return N_("msftres");
2184
2185 default:
2186 ped_exception_throw (
2187 PED_EXCEPTION_BUG,
2188 PED_EXCEPTION_CANCEL,
2189 _("Unknown partition flag, %d."),
2190 flag);
2191 return NULL;
2192 }
2193 }
2194
2195 /**
2196 * Iterates through all flags.
2197 *
2198 * ped_partition_flag_next(0) returns the first flag
2199 *
2200 * \return the next flag, or 0 if there are no more flags
2201 */
2202 PedPartitionFlag
ped_partition_flag_next(PedPartitionFlag flag)2203 ped_partition_flag_next (PedPartitionFlag flag)
2204 {
2205 return (flag + 1) % (PED_PARTITION_LAST_FLAG + 1);
2206 }
2207
2208 /**
2209 * Returns the flag associated with \p name.
2210 *
2211 * \p name can be the English
2212 * string, or the translation for the native language.
2213 */
2214 PedPartitionFlag
ped_partition_flag_get_by_name(const char * name)2215 ped_partition_flag_get_by_name (const char* name)
2216 {
2217 PedPartitionFlag flag;
2218 const char* flag_name;
2219
2220 for (flag = ped_partition_flag_next (0); flag;
2221 flag = ped_partition_flag_next (flag)) {
2222 flag_name = ped_partition_flag_get_name (flag);
2223 if (strcasecmp (name, flag_name) == 0
2224 || strcasecmp (name, _(flag_name)) == 0)
2225 return flag;
2226 }
2227
2228 return 0;
2229 }
2230
2231 static void
ped_partition_print(const PedPartition * part)2232 ped_partition_print (const PedPartition* part)
2233 {
2234 PED_ASSERT (part != NULL, return);
2235
2236 printf (" %-10s %02d (%d->%d)\n",
2237 ped_partition_type_get_name (part->type),
2238 part->num,
2239 (int) part->geom.start, (int) part->geom.end);
2240 }
2241
2242 /** @} */
2243
2244 /**
2245 * \addtogroup PedDisk
2246 *
2247 * @{
2248 */
2249
2250 /**
2251 * Prints a summary of disk's partitions. Useful for debugging.
2252 */
2253 void
ped_disk_print(const PedDisk * disk)2254 ped_disk_print (const PedDisk* disk)
2255 {
2256 PedPartition* part;
2257
2258 PED_ASSERT (disk != NULL, return);
2259
2260 for (part = disk->part_list; part;
2261 part = ped_disk_next_partition (disk, part))
2262 ped_partition_print (part);
2263 }
2264
2265 /** @} */
2266