]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/partition.c
libfdisk: improve partition copy on resize
[thirdparty/util-linux.git] / libfdisk / src / partition.c
CommitLineData
8c0a7f91
KZ
1
2#include "c.h"
3#include "strutils.h"
4
131e38a2
KZ
5#ifdef HAVE_LIBBLKID
6# include <blkid.h>
7#endif
8
8c0a7f91
KZ
9#include "fdiskP.h"
10
3c5ee57c
KZ
11/**
12 * SECTION: partition
705854f3
KZ
13 * @title: Partition
14 * @short_description: generic label independent partition abstraction
3c5ee57c
KZ
15 *
16 * The fdisk_partition provides label independent abstraction. The partitions
17 * are not directly connected with partition table (label) data. Any change to
18 * fdisk_partition does not affects in-memory or on-disk label data.
19 *
20 * The fdisk_partition is possible to use as a template for
21 * fdisk_add_partition() or fdisk_set_partition() operations.
22 */
ecf40cda
KZ
23
24static void init_partition(struct fdisk_partition *pa)
25{
26 FDISK_INIT_UNDEF(pa->size);
27 FDISK_INIT_UNDEF(pa->start);
ecf40cda
KZ
28 FDISK_INIT_UNDEF(pa->partno);
29 FDISK_INIT_UNDEF(pa->parent_partno);
30 FDISK_INIT_UNDEF(pa->boot);
31
32 INIT_LIST_HEAD(&pa->parts);
33}
34
5175ae87
KZ
35/**
36 * fdisk_new_partition:
37 *
38 * Returns: new instance.
39 */
8c0a7f91
KZ
40struct fdisk_partition *fdisk_new_partition(void)
41{
42 struct fdisk_partition *pa = calloc(1, sizeof(*pa));
43
d6cfa8b3 44 pa->refcount = 1;
ecf40cda 45 init_partition(pa);
d71bd2f0 46 DBG(PART, ul_debugobj(pa, "alloc"));
8c0a7f91
KZ
47 return pa;
48}
49
5175ae87
KZ
50/**
51 * fdisk_reset_partition:
52 * @pa: partition
53 *
54 * Resets partition content.
55 */
8c0a7f91
KZ
56void fdisk_reset_partition(struct fdisk_partition *pa)
57{
d6cfa8b3
KZ
58 int ref;
59
8c0a7f91
KZ
60 if (!pa)
61 return;
d6cfa8b3 62
d71bd2f0 63 DBG(PART, ul_debugobj(pa, "reset"));
d6cfa8b3 64 ref = pa->refcount;
ecf40cda 65
dfc6db2a 66 fdisk_unref_parttype(pa->type);
8c0a7f91
KZ
67 free(pa->name);
68 free(pa->uuid);
69 free(pa->attrs);
131e38a2
KZ
70 free(pa->fstype);
71 free(pa->fsuuid);
72 free(pa->fslabel);
504c5947
VD
73 free(pa->start_chs);
74 free(pa->end_chs);
ecf40cda 75
8c0a7f91 76 memset(pa, 0, sizeof(*pa));
d6cfa8b3 77 pa->refcount = ref;
ecf40cda
KZ
78
79 init_partition(pa);
8c0a7f91
KZ
80}
81
98e15beb
KZ
82static struct fdisk_partition *__copy_partition(struct fdisk_partition *o)
83{
84 struct fdisk_partition *n = fdisk_new_partition();
85
86 if (!n)
87 return NULL;
10c39f03 88
98e15beb 89 memcpy(n, o, sizeof(*n));
10c39f03
KZ
90
91 /* do not copy reference to lists, etc.*/
92 n->refcount = 1;
93 INIT_LIST_HEAD(&n->parts);
94
98e15beb
KZ
95 if (n->type)
96 fdisk_ref_parttype(n->type);
97 if (o->name)
98 n->name = strdup(o->name);
99 if (o->uuid)
100 n->uuid = strdup(o->uuid);
101 if (o->attrs)
102 n->attrs = strdup(o->attrs);
131e38a2
KZ
103 if (o->fstype)
104 n->fstype = strdup(o->fstype);
105 if (o->fsuuid)
106 n->fsuuid = strdup(o->fsuuid);
107 if (o->fslabel)
108 n->fslabel = strdup(o->fslabel);
79f37ec4
VT
109 if (o->start_chs)
110 n->start_chs = strdup(o->start_chs);
111 if (o->end_chs)
112 n->end_chs = strdup(o->end_chs);
131e38a2 113
98e15beb
KZ
114 return n;
115}
116
5175ae87
KZ
117/**
118 * fdisk_ref_partition:
705854f3 119 * @pa: partition pointer
5175ae87 120 *
9e930041 121 * Increments reference counter.
5175ae87 122 */
d6cfa8b3
KZ
123void fdisk_ref_partition(struct fdisk_partition *pa)
124{
125 if (pa)
126 pa->refcount++;
127}
128
5175ae87
KZ
129/**
130 * fdisk_unref_partition:
a3d83488 131 * @pa: partition pointer
5175ae87 132 *
9e930041 133 * Decrements reference counter, on zero the @pa is automatically
5175ae87
KZ
134 * deallocated.
135 */
d6cfa8b3 136void fdisk_unref_partition(struct fdisk_partition *pa)
8c0a7f91
KZ
137{
138 if (!pa)
139 return;
d6cfa8b3
KZ
140
141 pa->refcount--;
142 if (pa->refcount <= 0) {
6c89f750 143 list_del(&pa->parts);
bb09ebfe 144 fdisk_reset_partition(pa);
c3bc7483 145 DBG(PART, ul_debugobj(pa, "free"));
d6cfa8b3
KZ
146 free(pa);
147 }
8c0a7f91
KZ
148}
149
5175ae87
KZ
150/**
151 * fdisk_partition_set_start:
152 * @pa: partition
ecf40cda
KZ
153 * @off: offset in sectors, maximal is UINT64_MAX-1
154 *
155 * Note that zero is valid offset too. Use fdisk_partition_unset_start() to
131e38a2 156 * undefine the offset.
5175ae87
KZ
157 *
158 * Returns: 0 on success, <0 on error.
159 */
0073a4cf 160int fdisk_partition_set_start(struct fdisk_partition *pa, fdisk_sector_t off)
8c0a7f91
KZ
161{
162 if (!pa)
163 return -EINVAL;
ecf40cda
KZ
164 if (FDISK_IS_UNDEF(off))
165 return -ERANGE;
8c0a7f91 166 pa->start = off;
131e38a2 167 pa->fs_probed = 0;
8c0a7f91
KZ
168 return 0;
169}
170
ecf40cda
KZ
171/**
172 * fdisk_partition_unset_start:
173 * @pa: partition
174 *
175 * Sets the size as undefined. See fdisk_partition_has_start().
176 *
177 * Returns: 0 on success, <0 on error.
178 */
179int fdisk_partition_unset_start(struct fdisk_partition *pa)
180{
181 if (!pa)
182 return -EINVAL;
183 FDISK_INIT_UNDEF(pa->start);
131e38a2 184 pa->fs_probed = 0;
ecf40cda
KZ
185 return 0;
186}
187
5175ae87
KZ
188/**
189 * fdisk_partition_get_start:
190 * @pa: partition
191 *
ecf40cda
KZ
192 * The zero is also valid offset. The function may return random undefined
193 * value when start offset is undefined (for example after
194 * fdisk_partition_unset_start()). Always use fdisk_partition_has_start() to be
195 * sure that you work with valid numbers.
196 *
5175ae87
KZ
197 * Returns: start offset in sectors
198 */
0073a4cf 199fdisk_sector_t fdisk_partition_get_start(struct fdisk_partition *pa)
8c0a7f91 200{
ecf40cda
KZ
201 return pa->start;
202}
203
204/**
205 * fdisk_partition_has_start:
206 * @pa: partition
207 *
208 * Returns: 1 or 0
209 */
210int fdisk_partition_has_start(struct fdisk_partition *pa)
211{
212 return pa && !FDISK_IS_UNDEF(pa->start);
8c0a7f91
KZ
213}
214
ecf40cda 215
5175ae87
KZ
216/**
217 * fdisk_partition_cmp_start:
218 * @a: partition
219 * @b: partition
ecf40cda 220 *
4863ddad 221 * Compares partitions according to start offset, See fdisk_table_sort_partitions().
ecf40cda
KZ
222 *
223 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
5175ae87 224 */
e5c93999
KZ
225int fdisk_partition_cmp_start(struct fdisk_partition *a,
226 struct fdisk_partition *b)
227{
764b697c
KZ
228 int no_a = FDISK_IS_UNDEF(a->start),
229 no_b = FDISK_IS_UNDEF(b->start);
19ff8ff7 230
764b697c 231 if (no_a && no_b)
19ff8ff7 232 return 0;
764b697c 233 if (no_a)
19ff8ff7 234 return -1;
764b697c 235 if (no_b)
19ff8ff7
KZ
236 return 1;
237
238 return cmp_numbers(a->start, b->start);
e5c93999
KZ
239}
240
5175ae87 241/**
ecf40cda 242 * fdisk_partition_start_follow_default
5175ae87 243 * @pa: partition
ecf40cda 244 * @enable: 0|1
5175ae87 245 *
4863ddad 246 * When @pa used as a template for fdisk_add_partition() when force label driver
ecf40cda 247 * to use the first possible space for the new partition.
5175ae87
KZ
248 *
249 * Returns: 0 on success, <0 on error.
250 */
ecf40cda 251int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable)
8c0a7f91
KZ
252{
253 if (!pa)
254 return -EINVAL;
ecf40cda 255 pa->start_follow_default = enable ? 1 : 0;
8c0a7f91
KZ
256 return 0;
257}
258
5175ae87 259/**
ecf40cda 260 * fdisk_partition_start_is_default:
5175ae87
KZ
261 * @pa: partition
262 *
ecf40cda
KZ
263 * See fdisk_partition_start_follow_default().
264 *
265 * Returns: 1 if the partition follows default
5175ae87 266 */
ecf40cda 267int fdisk_partition_start_is_default(struct fdisk_partition *pa)
8c0a7f91 268{
ecf40cda
KZ
269 assert(pa);
270 return pa->start_follow_default;
8c0a7f91
KZ
271}
272
5175ae87 273/**
ecf40cda 274 * fdisk_partition_set_size:
5175ae87 275 * @pa: partition
ecf40cda 276 * @sz: size in sectors, maximal is UIN64_MAX-1
5175ae87 277 *
ecf40cda
KZ
278 * Note that zero is valid size too. Use fdisk_partition_unset_size() to
279 * undefine the size.
5175ae87
KZ
280 *
281 * Returns: 0 on success, <0 on error.
282 */
0073a4cf 283int fdisk_partition_set_size(struct fdisk_partition *pa, fdisk_sector_t sz)
8c0a7f91
KZ
284{
285 if (!pa)
286 return -EINVAL;
ecf40cda
KZ
287 if (FDISK_IS_UNDEF(sz))
288 return -ERANGE;
289 pa->size = sz;
131e38a2 290 pa->fs_probed = 0;
8c0a7f91
KZ
291 return 0;
292}
293
5175ae87 294/**
ecf40cda
KZ
295 * fdisk_partition_unset_size:
296 * @pa: partition
297 *
298 * Sets the size as undefined. See fdisk_partition_has_size().
299 *
300 * Returns: 0 on success, <0 on error.
301 */
302int fdisk_partition_unset_size(struct fdisk_partition *pa)
303{
304 if (!pa)
305 return -EINVAL;
306 FDISK_INIT_UNDEF(pa->size);
131e38a2 307 pa->fs_probed = 0;
ecf40cda
KZ
308 return 0;
309}
310
311/**
312 * fdisk_partition_get_size:
5175ae87
KZ
313 * @pa: partition
314 *
ecf40cda
KZ
315 * The zero is also valid size. The function may return random undefined
316 * value when size is undefined (for example after fdisk_partition_unset_size()).
4863ddad 317 * Always use fdisk_partition_has_size() to be sure that you work with valid
ecf40cda
KZ
318 * numbers.
319 *
320 * Returns: size offset in sectors
5175ae87 321 */
0073a4cf 322fdisk_sector_t fdisk_partition_get_size(struct fdisk_partition *pa)
8c0a7f91 323{
ecf40cda 324 return pa->size;
8c0a7f91
KZ
325}
326
ecf40cda
KZ
327/**
328 * fdisk_partition_has_size:
329 * @pa: partition
330 *
331 * Returns: 1 or 0
332 */
333int fdisk_partition_has_size(struct fdisk_partition *pa)
334{
335 return pa && !FDISK_IS_UNDEF(pa->size);
336}
337
338/**
339 * fdisk_partition_size_explicit:
340 * @pa: partition
341 * @enable: 0|1
342 *
343 * By default libfdisk aligns the size when add the new partition (by
0c07055c 344 * fdisk_add_partition()). If you want to disable this functionality use
ecf40cda
KZ
345 * @enable = 1.
346 *
347 * Returns: 0 on success, <0 on error.
348 */
349int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable)
350{
351 if (!pa)
352 return -EINVAL;
353 pa->size_explicit = enable ? 1 : 0;
354 return 0;
355}
356
0123bd1a
KZ
357/**
358 * fdisk_partition_set_partno:
359 * @pa: partition
9e930041 360 * @num: partition number (0 is the first partition, maximal is SIZE_MAX-1)
0123bd1a
KZ
361 *
362 * Note that zero is valid partno too. Use fdisk_partition_unset_partno() to
363 * undefine the partno.
364 *
365 * Returns: 0 on success, <0 on error.
366 */
367int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num)
368{
369 if (!pa)
370 return -EINVAL;
371 if (FDISK_IS_UNDEF(num))
372 return -ERANGE;
373 pa->partno = num;
374 return 0;
375}
ecf40cda 376
5175ae87 377/**
0123bd1a 378 * fdisk_partition_unset_partno:
5175ae87 379 * @pa: partition
5175ae87 380 *
0123bd1a 381 * Sets the partno as undefined. See fdisk_partition_has_partno().
5175ae87
KZ
382 *
383 * Returns: 0 on success, <0 on error.
384 */
0123bd1a 385int fdisk_partition_unset_partno(struct fdisk_partition *pa)
8c0a7f91
KZ
386{
387 if (!pa)
388 return -EINVAL;
0123bd1a 389 FDISK_INIT_UNDEF(pa->partno);
8c0a7f91
KZ
390 return 0;
391}
392
0123bd1a
KZ
393/**
394 * fdisk_partition_get_partno:
395 * @pa: partition
396 *
4863ddad 397 * The zero is also valid partition number. The function may return random
0123bd1a
KZ
398 * value when partno is undefined (for example after fdisk_partition_unset_partno()).
399 * Always use fdisk_partition_has_partno() to be sure that you work with valid
400 * numbers.
401 *
402 * Returns: partition number (0 is the first partition)
403 */
8c0a7f91
KZ
404size_t fdisk_partition_get_partno(struct fdisk_partition *pa)
405{
0123bd1a 406 return pa->partno;
8c0a7f91
KZ
407}
408
0123bd1a
KZ
409/**
410 * fdisk_partition_has_partno:
411 * @pa: partition
412 *
413 * Returns: 1 or 0
414 */
415int fdisk_partition_has_partno(struct fdisk_partition *pa)
416{
417 return pa && !FDISK_IS_UNDEF(pa->partno);
418}
419
420
421/**
422 * fdisk_partition_cmp_partno:
423 * @a: partition
424 * @b: partition
425 *
4863ddad 426 * Compares partitions according to partition number See fdisk_table_sort_partitions().
0123bd1a
KZ
427 *
428 * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
429 */
e5c93999
KZ
430int fdisk_partition_cmp_partno(struct fdisk_partition *a,
431 struct fdisk_partition *b)
432{
433 return a->partno - b->partno;
434}
435
0123bd1a
KZ
436/**
437 * fdisk_partition_partno_follow_default
438 * @pa: partition
439 * @enable: 0|1
440 *
4863ddad 441 * When @pa used as a template for fdisk_add_partition() when force label driver
0123bd1a
KZ
442 * to add a new partition to the default (next) position.
443 *
444 * Returns: 0 on success, <0 on error.
445 */
446int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable)
447{
448 if (!pa)
449 return -EINVAL;
450 pa->partno_follow_default = enable ? 1 : 0;
451 return 0;
452}
453
dfc6db2a
KZ
454/**
455 * fdisk_partition_set_type:
456 * @pa: partition
457 * @type: partition type
458 *
9e930041 459 * Sets partition type.
dfc6db2a
KZ
460 *
461 * Returns: 0 on success, <0 on error.
462 */
78049787 463int fdisk_partition_set_type(struct fdisk_partition *pa,
dfc6db2a 464 struct fdisk_parttype *type)
8c0a7f91
KZ
465{
466 if (!pa)
467 return -EINVAL;
dfc6db2a
KZ
468
469 fdisk_ref_parttype(type);
470 fdisk_unref_parttype(pa->type);
471 pa->type = type;
472
8c0a7f91
KZ
473 return 0;
474}
475
dfc6db2a
KZ
476/**
477 * fdisk_partition_get_type:
478 * @pa: partition
479 *
480 * Returns: pointer to partition type.
481 */
482struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa)
8c0a7f91
KZ
483{
484 return pa ? pa->type : NULL;
485}
486
487int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name)
488{
489 char *p = NULL;
490
491 if (!pa)
492 return -EINVAL;
493 if (name) {
494 p = strdup(name);
495 if (!p)
496 return -ENOMEM;
497 }
498 free(pa->name);
499 pa->name = p;
500 return 0;
501}
502
503const char *fdisk_partition_get_name(struct fdisk_partition *pa)
504{
505 return pa ? pa->name : NULL;
506}
507
508int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid)
509{
510 char *p = NULL;
511
512 if (!pa)
513 return -EINVAL;
514 if (uuid) {
515 p = strdup(uuid);
516 if (!p)
517 return -ENOMEM;
518 }
519 free(pa->uuid);
520 pa->uuid = p;
521 return 0;
522}
523
bbfc2429
KZ
524/**
525 * fdisk_partition_has_end:
526 * @pa: partition
527 *
528 * Returns: 1 if the partition has defined last sector
529 */
530int fdisk_partition_has_end(struct fdisk_partition *pa)
531{
532 return pa && !FDISK_IS_UNDEF(pa->start) && !FDISK_IS_UNDEF(pa->size);
533}
732aefdf 534
bbfc2429
KZ
535/**
536 * fdisk_partition_get_end:
537 * @pa: partition
538 *
539 * This function may returns absolute non-sense, always check
540 * fdisk_partition_has_end().
541 *
542 * Note that partition end is defined by fdisk_partition_set_start() and
543 * fdisk_partition_set_size().
544 *
545 * Returns: last partition sector LBA.
546 */
547fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa)
548{
549 return pa->start + pa->size - (pa->size == 0 ? 0 : 1);
550}
0051ec9b 551
5175ae87 552/**
0123bd1a 553 * fdisk_partition_end_follow_default
5175ae87
KZ
554 * @pa: partition
555 * @enable: 0|1
556 *
98e15beb
KZ
557 * When @pa used as a template for fdisk_add_partition() when force label
558 * driver to use all the possible space for the new partition.
5175ae87
KZ
559 *
560 * Returns: 0 on success, <0 on error.
561 */
732aefdf
KZ
562int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable)
563{
564 if (!pa)
565 return -EINVAL;
566 pa->end_follow_default = enable ? 1 : 0;
567 return 0;
568}
569
0051ec9b
KZ
570/**
571 * fdisk_partition_end_is_default:
572 * @pa: partition
573 *
574 * Returns: 1 if the partition follows default
575 */
576int fdisk_partition_end_is_default(struct fdisk_partition *pa)
577{
578 assert(pa);
579 return pa->end_follow_default;
580}
581
4863ddad
KZ
582/**
583 * fdisk_partition_get_uuid:
584 * @pa: partition
585 *
586 * Returns: partition UUID as string
587 */
8c0a7f91
KZ
588const char *fdisk_partition_get_uuid(struct fdisk_partition *pa)
589{
590 return pa ? pa->uuid : NULL;
591}
592
4863ddad
KZ
593/**
594 * fdisk_partition_get_attrs:
595 * @pa: partition
596 *
597 * Returns: partition attributes in string format
598 */
8c0a7f91
KZ
599const char *fdisk_partition_get_attrs(struct fdisk_partition *pa)
600{
601 return pa ? pa->attrs : NULL;
602}
603
4863ddad
KZ
604/**
605 * fdisk_partition_set_attrs:
606 * @pa: partition
607 * @attrs: attributes
608 *
609 * Sets @attrs to @pa.
610 *
611 * Return: 0 on success, <0 on error.
612 */
c77ba531
KZ
613int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs)
614{
615 char *p = NULL;
616
617 if (!pa)
618 return -EINVAL;
619 if (attrs) {
620 p = strdup(attrs);
621 if (!p)
622 return -ENOMEM;
623 }
624 free(pa->attrs);
625 pa->attrs = p;
626 return 0;
627}
628
4863ddad
KZ
629/**
630 * fdisk_partition_is_nested:
631 * @pa: partition
632 *
633 * Returns: 1 if the partition is nested (e.g. MBR logical partition)
634 */
bd5e8291 635int fdisk_partition_is_nested(struct fdisk_partition *pa)
8c0a7f91 636{
ecf40cda 637 return pa && !FDISK_IS_UNDEF(pa->parent_partno);
8c0a7f91
KZ
638}
639
4863ddad
KZ
640/**
641 * fdisk_partition_is_container:
642 * @pa: partition
643 *
644 * Returns: 1 if the partition is container (e.g. MBR extended partition)
645 */
bd5e8291 646int fdisk_partition_is_container(struct fdisk_partition *pa)
8c0a7f91 647{
bd5e8291 648 return pa && pa->container;
8c0a7f91
KZ
649}
650
4863ddad
KZ
651/**
652 * fdisk_partition_get_parent:
653 * @pa: partition
0be901e5 654 * @parent: parent parno
4863ddad
KZ
655 *
656 * Returns: returns devno of the parent
657 */
03643931
KZ
658int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
659{
660 if (pa && parent)
661 *parent = pa->parent_partno;
662 else
663 return -EINVAL;
664 return 0;
665}
666
4863ddad
KZ
667/**
668 * fdisk_partition_is_used:
669 * @pa: partition
670 *
671 * Returns: 1 if the partition points to some area
672 */
8c0a7f91
KZ
673int fdisk_partition_is_used(struct fdisk_partition *pa)
674{
675 return pa && pa->used;
676}
677
4863ddad
KZ
678/**
679 * fdisk_partition_is_bootable:
680 * @pa: partition
681 *
682 * Returns: 1 if the partition has enabled boot flag
683 */
59c8e95b
KZ
684int fdisk_partition_is_bootable(struct fdisk_partition *pa)
685{
150d98ee 686 return pa && pa->boot == 1;
59c8e95b
KZ
687}
688
4863ddad
KZ
689/**
690 * fdisk_partition_is_freespace:
691 * @pa: partition
692 *
693 * Returns: 1 if @pa points to freespace
694 */
1de9fddb
KZ
695int fdisk_partition_is_freespace(struct fdisk_partition *pa)
696{
697 return pa && pa->freespace;
698}
699
4863ddad
KZ
700/**
701 * fdisk_partition_is_wholedisk:
702 * @pa: partition
703 *
704 * Returns: 1 if the partition is special whole-disk (e.g. SUN) partition
705 */
943271e2
KZ
706int fdisk_partition_is_wholedisk(struct fdisk_partition *pa)
707{
708 return pa && pa->wholedisk;
709}
710
4863ddad
KZ
711/**
712 * fdisk_partition_next_partno:
713 * @pa: partition
714 * @cxt: context
715 * @n: returns partition number
716 *
53625d1a
KZ
717 * If @pa specified and partno-follow-default (see fdisk_partition_partno_follow_default())
718 * enabled then returns next expected partno or -ERANGE on error.
4863ddad 719 *
992f7cba 720 * If @pa is NULL, or @pa does not specify any semantic for the next partno
53625d1a 721 * then use Ask API to ask user for the next partno. In this case returns 1 if
73afd3f8 722 * no free partition available. If fdisk dialogs are disabled then returns -EINVAL.
53625d1a
KZ
723 *
724 * Returns: 0 on success, <0 on error, or 1 for non-free partno by Ask API.
4863ddad 725 */
77d6a70a 726int fdisk_partition_next_partno(
77d6a70a 727 struct fdisk_partition *pa,
6c89f750 728 struct fdisk_context *cxt,
77d6a70a
KZ
729 size_t *n)
730{
1c3c92cd
KZ
731 if (!cxt || !n)
732 return -EINVAL;
77d6a70a
KZ
733
734 if (pa && pa->partno_follow_default) {
735 size_t i;
736
d71bd2f0 737 DBG(PART, ul_debugobj(pa, "next partno (follow default)"));
732aefdf 738
6c89f750 739 for (i = 0; i < cxt->label->nparts_max; i++) {
77d6a70a
KZ
740 if (!fdisk_is_partition_used(cxt, i)) {
741 *n = i;
732aefdf 742 return 0;
77d6a70a
KZ
743 }
744 }
732aefdf
KZ
745 return -ERANGE;
746
0123bd1a 747 } else if (pa && fdisk_partition_has_partno(pa)) {
732aefdf 748
d71bd2f0 749 DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno));
732aefdf 750
e1cfb304
KZ
751 if (pa->partno >= cxt->label->nparts_max ||
752 fdisk_is_partition_used(cxt, pa->partno))
77d6a70a
KZ
753 return -ERANGE;
754 *n = pa->partno;
992f7cba
KZ
755 return 0;
756
757 } else if (fdisk_has_dialogs(cxt))
77d6a70a
KZ
758 return fdisk_ask_partnum(cxt, n, 1);
759
992f7cba 760 return -EINVAL;
77d6a70a 761}
8c0a7f91 762
131e38a2
KZ
763static int probe_partition_content(struct fdisk_context *cxt, struct fdisk_partition *pa)
764{
765 int rc = 1; /* nothing */
766
767 DBG(PART, ul_debugobj(pa, "start probe #%zu partition [cxt %p] >>>", pa->partno, cxt));
768
769 /* zeroize the current setting */
770 strdup_to_struct_member(pa, fstype, NULL);
771 strdup_to_struct_member(pa, fsuuid, NULL);
772 strdup_to_struct_member(pa, fslabel, NULL);
773
774 if (!fdisk_partition_has_start(pa) ||
775 !fdisk_partition_has_size(pa))
776 goto done;
777
778#ifdef HAVE_LIBBLKID
779 else {
780 uintmax_t start, size;
781
782 blkid_probe pr = blkid_new_probe();
783 if (!pr)
784 goto done;
785
786 DBG(PART, ul_debugobj(pa, "blkid prober: %p", pr));
787
788 start = fdisk_partition_get_start(pa) * fdisk_get_sector_size(cxt);
789 size = fdisk_partition_get_size(pa) * fdisk_get_sector_size(cxt);
790
791 if (blkid_probe_set_device(pr, cxt->dev_fd, start, size) == 0
792 && blkid_do_fullprobe(pr) == 0) {
793
794 const char *data;
795 rc = 0;
796
797 if (!blkid_probe_lookup_value(pr, "TYPE", &data, NULL))
798 rc = strdup_to_struct_member(pa, fstype, data);
799
800 if (!rc && !blkid_probe_lookup_value(pr, "LABEL", &data, NULL))
801 rc = strdup_to_struct_member(pa, fslabel, data);
802
803 if (!rc && !blkid_probe_lookup_value(pr, "UUID", &data, NULL))
804 rc = strdup_to_struct_member(pa, fsuuid, data);
805 }
806
807 blkid_free_probe(pr);
808 pa->fs_probed = 1;
809 }
810#endif /* HAVE_LIBBLKID */
811
812done:
813 DBG(PART, ul_debugobj(pa, "<<< end probe #%zu partition[cxt %p, rc=%d]", pa->partno, cxt, rc));
814 return rc;
815}
816
8c0a7f91
KZ
817/**
818 * fdisk_partition_to_string:
819 * @pa: partition
705854f3 820 * @cxt: context
bd85d11f 821 * @id: field (FDISK_FIELD_*)
8c0a7f91
KZ
822 * @data: returns string with allocated data
823 *
824 * Returns info about partition converted to printable string.
825 *
0e65dcde 826 * For example
4e76cecd
KZ
827 * <informalexample>
828 * <programlisting>
9e930041 829 * struct fdisk_partition *pa;
8c0a7f91
KZ
830 *
831 * fdisk_get_partition(cxt, 0, &pa);
bd85d11f 832 * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
8c0a7f91
KZ
833 * printf("first partition uuid: %s\n", data);
834 * free(data);
d6cfa8b3 835 * fdisk_unref_partition(pa);
4e76cecd
KZ
836 * </programlisting>
837 * </informalexample>
8c0a7f91
KZ
838 *
839 * returns UUID for the first partition.
840 *
705854f3 841 * Returns: 0 on success, otherwise, a corresponding error.
8c0a7f91 842 */
8c0a7f91 843int fdisk_partition_to_string(struct fdisk_partition *pa,
6c89f750 844 struct fdisk_context *cxt,
8c0a7f91
KZ
845 int id,
846 char **data)
847{
848 char *p = NULL;
849 int rc = 0;
77d6a70a 850 uint64_t x;
8c0a7f91 851
edc4cf94 852 if (!pa || !cxt || !data)
8c0a7f91
KZ
853 return -EINVAL;
854
855 switch (id) {
bd85d11f 856 case FDISK_FIELD_DEVICE:
1de9fddb
KZ
857 if (pa->freespace)
858 p = strdup(_("Free space"));
0123bd1a
KZ
859 else if (fdisk_partition_has_partno(pa) && cxt->dev_path) {
860 if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
861 rc = asprintf(&p, "%c", (int) pa->partno + 'a');
862 else
863 p = fdisk_partname(cxt->dev_path, pa->partno + 1);
864 }
8c0a7f91 865 break;
bd85d11f 866 case FDISK_FIELD_BOOT:
4d156d92 867 p = fdisk_partition_is_bootable(pa) ? strdup("*") : NULL;
d6faa8e0 868 break;
bd85d11f 869 case FDISK_FIELD_START:
ecf40cda
KZ
870 if (fdisk_partition_has_start(pa)) {
871 x = fdisk_cround(cxt, pa->start);
872 rc = pa->start_post ?
fdbd7bb9
RM
873 asprintf(&p, "%"PRIu64"%c", x, pa->start_post) :
874 asprintf(&p, "%"PRIu64, x);
ecf40cda 875 }
8c0a7f91 876 break;
bd85d11f 877 case FDISK_FIELD_END:
bbfc2429
KZ
878 if (fdisk_partition_has_end(pa)) {
879 x = fdisk_cround(cxt, fdisk_partition_get_end(pa));
880 rc = pa->end_post ?
fdbd7bb9
RM
881 asprintf(&p, "%"PRIu64"%c", x, pa->end_post) :
882 asprintf(&p, "%"PRIu64, x);
bbfc2429 883 }
8c0a7f91 884 break;
bd85d11f 885 case FDISK_FIELD_SIZE:
ecf40cda
KZ
886 if (fdisk_partition_has_size(pa)) {
887 uint64_t sz = pa->size * cxt->sector_size;
888
354f8cc8
KZ
889 switch (cxt->sizeunit) {
890 case FDISK_SIZEUNIT_BYTES:
fdbd7bb9 891 rc = asprintf(&p, "%"PRIu64"", sz);
354f8cc8
KZ
892 break;
893 case FDISK_SIZEUNIT_HUMAN:
894 if (fdisk_is_details(cxt))
895 rc = pa->size_post ?
fdbd7bb9
RM
896 asprintf(&p, "%"PRIu64"%c", sz, pa->size_post) :
897 asprintf(&p, "%"PRIu64, sz);
354f8cc8
KZ
898 else {
899 p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
900 if (!p)
901 rc = -ENOMEM;
902 }
903 break;
ecf40cda 904 }
8c0a7f91
KZ
905 }
906 break;
bd85d11f 907 case FDISK_FIELD_CYLINDERS:
c1be496a
KZ
908 {
909 uintmax_t sz = fdisk_partition_has_size(pa) ? pa->size : 0;
910 if (sz)
fdbd7bb9
RM
911 /* Why we need to cast that to uintmax_t? */
912 rc = asprintf(&p, "%ju", (uintmax_t)(sz / (cxt->geom.heads * cxt->geom.sectors)) + 1);
77d6a70a 913 break;
c1be496a 914 }
bd85d11f 915 case FDISK_FIELD_SECTORS:
0073a4cf
KZ
916 rc = asprintf(&p, "%ju",
917 fdisk_partition_has_size(pa) ? (uintmax_t) pa->size : 0);
d6faa8e0 918 break;
bd85d11f 919 case FDISK_FIELD_BSIZE:
fdbd7bb9 920 rc = asprintf(&p, "%"PRIu64, pa->bsize);
82ebc7de 921 break;
bd85d11f 922 case FDISK_FIELD_FSIZE:
fdbd7bb9 923 rc = asprintf(&p, "%"PRIu64, pa->fsize);
82ebc7de 924 break;
bd85d11f 925 case FDISK_FIELD_CPG:
fdbd7bb9 926 rc = asprintf(&p, "%"PRIu64, pa->cpg);
82ebc7de 927 break;
bd85d11f 928 case FDISK_FIELD_TYPE:
dc45b86e 929 p = pa->type && pa->type->name ? strdup(_(pa->type->name)) : NULL;
8c0a7f91 930 break;
bd85d11f 931 case FDISK_FIELD_TYPEID:
a745611d
KZ
932 if (pa->type && fdisk_parttype_get_string(pa->type))
933 rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type));
d6faa8e0 934 else if (pa->type)
a745611d 935 rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type));
d6faa8e0 936 break;
bd85d11f 937 case FDISK_FIELD_UUID:
72986803 938 p = pa->uuid && *pa->uuid? strdup(pa->uuid) : NULL;
8c0a7f91 939 break;
bd85d11f 940 case FDISK_FIELD_NAME:
72986803 941 p = pa->name && *pa->name ? strdup(pa->name) : NULL;
8c0a7f91 942 break;
bd85d11f 943 case FDISK_FIELD_ATTR:
72986803 944 p = pa->attrs && *pa->attrs ? strdup(pa->attrs) : NULL;
8c0a7f91 945 break;
bd85d11f 946 case FDISK_FIELD_SADDR:
72986803 947 p = pa->start_chs && *pa->start_chs ? strdup(pa->start_chs) : NULL;
d6faa8e0 948 break;
bd85d11f 949 case FDISK_FIELD_EADDR:
72986803 950 p = pa->end_chs && *pa->end_chs? strdup(pa->end_chs) : NULL;
d6faa8e0 951 break;
131e38a2
KZ
952 case FDISK_FIELD_FSUUID:
953 if (pa->fs_probed || probe_partition_content(cxt, pa) == 0)
954 p = pa->fsuuid && *pa->fsuuid ? strdup(pa->fsuuid) : NULL;
955 break;
956 case FDISK_FIELD_FSLABEL:
957 if (pa->fs_probed || probe_partition_content(cxt, pa) == 0)
958 p = pa->fslabel && *pa->fslabel ? strdup(pa->fslabel) : NULL;
959 break;
960 case FDISK_FIELD_FSTYPE:
961 if (pa->fs_probed || probe_partition_content(cxt, pa) == 0)
962 p = pa->fstype && *pa->fstype ? strdup(pa->fstype) : NULL;
963 break;
8c0a7f91
KZ
964 default:
965 return -EINVAL;
966 }
967
edc4cf94 968 if (rc < 0) {
82ebc7de 969 rc = -ENOMEM;
edc4cf94
KZ
970 free(p);
971 p = NULL;
972
973 } else if (rc > 0)
82ebc7de
KZ
974 rc = 0;
975
edc4cf94
KZ
976 *data = p;
977
8c0a7f91
KZ
978 return rc;
979}
187de51c 980
131e38a2 981
187de51c
KZ
982/**
983 * fdisk_get_partition:
e11c6684 984 * @cxt: context
0123bd1a 985 * @partno: partition number (0 is the first partition)
e11c6684 986 * @pa: returns data about partition
187de51c 987 *
0123bd1a
KZ
988 * Reads disklabel and fills in @pa with data about partition @n.
989 *
990 * Note that partno may address unused partition and then this function does
991 * not fill anything to @pa. See fdisk_is_partition_used(). If @pa points to
992 * NULL then the function allocates a newly allocated fdisk_partition struct,
993 * use fdisk_unref_partition() to deallocate.
187de51c
KZ
994 *
995 * Returns: 0 on success, otherwise, a corresponding error.
996 */
997int fdisk_get_partition(struct fdisk_context *cxt, size_t partno,
998 struct fdisk_partition **pa)
999{
1000 int rc;
6c89f750 1001 struct fdisk_partition *np = NULL;
187de51c
KZ
1002
1003 if (!cxt || !cxt->label || !pa)
1004 return -EINVAL;
1005 if (!cxt->label->op->get_part)
1006 return -ENOSYS;
6c89f750
KZ
1007 if (!fdisk_is_partition_used(cxt, partno))
1008 return -EINVAL;
187de51c
KZ
1009
1010 if (!*pa) {
6c89f750 1011 np = *pa = fdisk_new_partition();
187de51c
KZ
1012 if (!*pa)
1013 return -ENOMEM;
1014 } else
1015 fdisk_reset_partition(*pa);
6c89f750 1016
187de51c
KZ
1017 (*pa)->partno = partno;
1018 rc = cxt->label->op->get_part(cxt, partno, *pa);
6c89f750
KZ
1019
1020 if (rc) {
1021 if (np) {
1022 fdisk_unref_partition(np);
1023 *pa = NULL;
1024 } else
1025 fdisk_reset_partition(*pa);
892c89eb
KZ
1026 } else
1027 (*pa)->size_explicit = 1;
187de51c
KZ
1028 return rc;
1029}
1030
98e15beb 1031static struct fdisk_partition *resize_get_by_offset(
167a2b52
KZ
1032 struct fdisk_table *tb,
1033 struct fdisk_partition *cur,
1034 fdisk_sector_t off)
98e15beb
KZ
1035{
1036 struct fdisk_partition *pa = NULL;
1037 struct fdisk_iter itr;
1038
1039 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
1040
1041 while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
1042 if (!fdisk_partition_has_start(pa) || !fdisk_partition_has_size(pa))
1043 continue;
167a2b52
KZ
1044 if (fdisk_partition_is_nested(cur) &&
1045 pa->parent_partno != cur->parent_partno)
1046 continue;
98e15beb
KZ
1047 if (off >= pa->start && off < pa->start + pa->size)
1048 return pa;
1049 }
1050
1051 return NULL;
1052}
1053
1054/*
1055 * Verify that area addressed by @start is freespace or the @cur[rent]
1056 * partition and continue to the next table entries until it's freespace, and
1057 * counts size of all this space.
1058 *
1059 * This is core of the partition start offset move operation. We can move the
1060 * start within the current partition of to the another free space. It's
1061 * forbidden to move start of the partition to another already defined
1062 * partition.
1063 */
1064static int resize_get_last_possible(
1065 struct fdisk_table *tb,
1066 struct fdisk_partition *cur,
1067 fdisk_sector_t start,
1068 fdisk_sector_t *maxsz)
1069{
1070 struct fdisk_partition *pa = NULL, *last = NULL;
1071 struct fdisk_iter itr;
1072
1073 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
1074
1075 *maxsz = 0;
c134c8b1 1076 DBG(TAB, ul_debugobj(tb, "checking last possible for start=%ju", (uintmax_t) start));
22f4c464 1077
98e15beb
KZ
1078
1079 while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
22f4c464 1080
537b4db1 1081 DBG(TAB, ul_debugobj(tb, " checking entry %p [partno=%zu start=%ju, end=%ju, size=%ju%s%s%s]",
22f4c464 1082 pa,
537b4db1 1083 fdisk_partition_get_partno(pa),
22f4c464
KZ
1084 (uintmax_t) fdisk_partition_get_start(pa),
1085 (uintmax_t) fdisk_partition_get_end(pa),
1086 (uintmax_t) fdisk_partition_get_size(pa),
537b4db1
KZ
1087 fdisk_partition_is_freespace(pa) ? " freespace" : "",
1088 fdisk_partition_is_nested(pa) ? " nested" : "",
1089 fdisk_partition_is_container(pa) ? " container" : ""));
22f4c464 1090
98e15beb
KZ
1091 if (!fdisk_partition_has_start(pa) ||
1092 !fdisk_partition_has_size(pa) ||
5ec4400d 1093 (fdisk_partition_is_container(pa) && pa != cur)) {
22f4c464 1094 DBG(TAB, ul_debugobj(tb, " ignored (no start/size or container)"));
98e15beb 1095 continue;
22f4c464 1096 }
83677b99 1097
5ec4400d
KZ
1098 if (fdisk_partition_is_nested(pa)
1099 && fdisk_partition_is_container(cur)
1100 && pa->parent_partno == cur->partno) {
1101 DBG(TAB, ul_debugobj(tb, " ignore (nested child of the current partition)"));
1102 continue;
1103 }
1104
c134c8b1
KZ
1105 /* The current is nested, free space has to be nested within the same parent */
1106 if (fdisk_partition_is_nested(cur)
1107 && pa->parent_partno != cur->parent_partno) {
1108 DBG(TAB, ul_debugobj(tb, " ignore (nested required)"));
1109 continue;
1110 }
1111
98e15beb
KZ
1112 if (!last) {
1113 if (start >= pa->start && start < pa->start + pa->size) {
22f4c464
KZ
1114 if (fdisk_partition_is_freespace(pa) || pa == cur) {
1115 DBG(TAB, ul_debugobj(tb, " accepted as last"));
98e15beb 1116 last = pa;
22f4c464
KZ
1117 } else {
1118 DBG(TAB, ul_debugobj(tb, " failed to set last"));
98e15beb 1119 break;
22f4c464 1120 }
83677b99 1121
c134c8b1 1122
83677b99 1123 *maxsz = pa->size - (start - pa->start);
c134c8b1 1124 DBG(TAB, ul_debugobj(tb, " new max=%ju", (uintmax_t) *maxsz));
98e15beb
KZ
1125 }
1126 } else if (!fdisk_partition_is_freespace(pa) && pa != cur) {
22f4c464 1127 DBG(TAB, ul_debugobj(tb, " no free space behind current"));
98e15beb
KZ
1128 break;
1129 } else {
1130 last = pa;
2f35c1ea 1131 *maxsz = pa->size - (start - pa->start);
c134c8b1 1132 DBG(TAB, ul_debugobj(tb, " new max=%ju (last updated)", (uintmax_t) *maxsz));
98e15beb
KZ
1133 }
1134 }
1135
1136 if (last)
1137 DBG(PART, ul_debugobj(cur, "resize: max size=%ju", (uintmax_t) *maxsz));
83677b99
KZ
1138 else
1139 DBG(PART, ul_debugobj(cur, "resize: nothing usable after %ju", (uintmax_t) start));
98e15beb 1140
83677b99 1141 return last ? 0 : -1;
98e15beb
KZ
1142}
1143
1144/*
1145 * Uses template @tpl to recount start and size change of the partition @res. The
1146 * @tpl->size and @tpl->start are interpreted as relative to the current setting.
1147 */
1148static int recount_resize(
1149 struct fdisk_context *cxt, size_t partno,
1150 struct fdisk_partition *res, struct fdisk_partition *tpl)
1151{
83677b99 1152 fdisk_sector_t start, size, xsize;
98e15beb
KZ
1153 struct fdisk_partition *cur = NULL;
1154 struct fdisk_table *tb = NULL;
1155 int rc;
1156
f2be8b3d 1157 DBG(PART, ul_debugobj(tpl, ">>> resize requested"));
98e15beb
KZ
1158
1159 FDISK_INIT_UNDEF(start);
1160 FDISK_INIT_UNDEF(size);
1161
1162 rc = fdisk_get_partitions(cxt, &tb);
1163 if (!rc)
1164 rc = fdisk_get_freespaces(cxt, &tb);
f11eedf5
KZ
1165 if (rc) {
1166 fdisk_unref_table(tb);
98e15beb 1167 return rc;
f11eedf5 1168 }
98e15beb 1169
537b4db1
KZ
1170 fdisk_table_sort_partitions(tb, fdisk_partition_cmp_start);
1171
1172 DBG(PART, ul_debugobj(tpl, "resize partition partno=%zu in table:", partno));
1173 ON_DBG(PART, fdisk_debug_print_table(tb));
1174
98e15beb
KZ
1175 cur = fdisk_table_get_partition_by_partno(tb, partno);
1176 if (!cur) {
1177 fdisk_unref_table(tb);
1178 return -EINVAL;
1179 }
1180
1181 /* 1a) set new start - change relative to the current on-disk setting */
1182 if (tpl->movestart && fdisk_partition_has_start(tpl)) {
1183 start = fdisk_partition_get_start(cur);
1184 if (tpl->movestart == FDISK_MOVE_DOWN) {
1185 if (fdisk_partition_get_start(tpl) > start)
1186 goto erange;
1187 start -= fdisk_partition_get_start(tpl);
1188 } else
1189 start += fdisk_partition_get_start(tpl);
1190
f2be8b3d 1191 DBG(PART, ul_debugobj(tpl, "resize: moving start %s relative, new start: %ju",
fdbd7bb9 1192 tpl->movestart == FDISK_MOVE_DOWN ? "DOWN" : "UP", (uintmax_t)start));
f2be8b3d 1193
98e15beb 1194 /* 1b) set new start - absolute number */
f2be8b3d 1195 } else if (fdisk_partition_has_start(tpl)) {
98e15beb 1196 start = fdisk_partition_get_start(tpl);
fdbd7bb9
RM
1197 DBG(PART, ul_debugobj(tpl, "resize: moving start to absolute offset: %ju",
1198 (uintmax_t)start));
f2be8b3d 1199 }
98e15beb
KZ
1200
1201 /* 2) verify that start is within the current partition or any freespace area */
1202 if (!FDISK_IS_UNDEF(start)) {
167a2b52
KZ
1203 struct fdisk_partition *area = resize_get_by_offset(tb, cur, start);
1204
98e15beb
KZ
1205 if (area == cur)
1206 DBG(PART, ul_debugobj(tpl, "resize: start points to the current partition"));
339ca841 1207 else if (area && fdisk_partition_is_freespace(area))
98e15beb 1208 DBG(PART, ul_debugobj(tpl, "resize: start points to freespace"));
339ca841
KZ
1209 else if (!area && start >= cxt->first_lba && start < cxt->first_lba + (cxt->grain / cxt->sector_size))
1210 DBG(PART, ul_debugobj(tpl, "resize: start points before first partition"));
167a2b52
KZ
1211 else {
1212 DBG(PART, ul_debugobj(tpl, "resize: start verification failed"));
98e15beb 1213 goto erange;
167a2b52 1214 }
98e15beb
KZ
1215 } else {
1216 /* no change, start points to the current partition */
f2be8b3d 1217 DBG(PART, ul_debugobj(tpl, "resize: start unchanged"));
98e15beb
KZ
1218 start = fdisk_partition_get_start(cur);
1219 }
1220
1221 /* 3a) set new size -- reduce */
1222 if (tpl->resize == FDISK_RESIZE_REDUCE && fdisk_partition_has_size(tpl)) {
1223 DBG(PART, ul_debugobj(tpl, "resize: reduce"));
1224 size = fdisk_partition_get_size(cur);
1225 if (fdisk_partition_get_size(tpl) > size)
1226 goto erange;
1227 size -= fdisk_partition_get_size(tpl);
1228
1229 /* 3b) set new size -- enlarge */
1230 } else if (tpl->resize == FDISK_RESIZE_ENLARGE && fdisk_partition_has_size(tpl)) {
1231 DBG(PART, ul_debugobj(tpl, "resize: enlarge"));
1232 size = fdisk_partition_get_size(cur);
1233 size += fdisk_partition_get_size(tpl);
1234
1235 /* 3c) set new size -- no size specified, enlarge to all freespace */
1236 } else if (tpl->resize == FDISK_RESIZE_ENLARGE) {
1237 DBG(PART, ul_debugobj(tpl, "resize: enlarge to all possible"));
1238 if (resize_get_last_possible(tb, cur, start, &size))
1239 goto erange;
1240
1241 /* 3d) set new size -- absolute number */
1242 } else if (fdisk_partition_has_size(tpl)) {
1243 DBG(PART, ul_debugobj(tpl, "resize: new absolute size"));
1244 size = fdisk_partition_get_size(tpl);
1245 }
1246
1247 /* 4) verify that size is within the current partition or next free space */
83677b99
KZ
1248 xsize = !FDISK_IS_UNDEF(size) ? size : fdisk_partition_get_size(cur);
1249
1250 if (fdisk_partition_has_size(cur)) {
98e15beb 1251 fdisk_sector_t maxsz;
83677b99 1252
98e15beb
KZ
1253 if (resize_get_last_possible(tb, cur, start, &maxsz))
1254 goto erange;
83677b99
KZ
1255 DBG(PART, ul_debugobj(tpl, "resize: size=%ju, max=%ju",
1256 (uintmax_t) xsize, (uintmax_t) maxsz));
1257 if (xsize > maxsz)
98e15beb 1258 goto erange;
83677b99
KZ
1259 }
1260
1261 if (!FDISK_IS_UNDEF(size)) {
f2be8b3d 1262 DBG(PART, ul_debugobj(tpl, "resize: size unchanged (undefined)"));
98e15beb
KZ
1263 }
1264
f2be8b3d
KZ
1265
1266 DBG(PART, ul_debugobj(tpl, "<<< resize: SUCCESS: start %ju->%ju; size %ju->%ju",
98e15beb
KZ
1267 (uintmax_t) fdisk_partition_get_start(cur), (uintmax_t) start,
1268 (uintmax_t) fdisk_partition_get_size(cur), (uintmax_t) size));
1269 res->start = start;
1270 res->size = size;
1271 fdisk_unref_table(tb);
1272 return 0;
1273erange:
f2be8b3d 1274 DBG(PART, ul_debugobj(tpl, "<<< resize: FAILED"));
339ca841 1275 fdisk_warnx(cxt, _("Failed to resize partition #%zu."), partno + 1);
98e15beb
KZ
1276 fdisk_unref_table(tb);
1277 return -ERANGE;
1278
1279}
1280
0dad2177
KZ
1281/**
1282 * fdisk_set_partition:
1283 * @cxt: context
0123bd1a 1284 * @partno: partition number (0 is the first partition)
0dad2177
KZ
1285 * @pa: new partition setting
1286 *
0123bd1a
KZ
1287 * Modifies disklabel according to setting with in @pa.
1288 *
0dad2177
KZ
1289 * Returns: 0 on success, <0 on error.
1290 */
1291int fdisk_set_partition(struct fdisk_context *cxt, size_t partno,
1292 struct fdisk_partition *pa)
1293{
131e38a2
KZ
1294 struct fdisk_partition *xpa = pa, *tmp = NULL;
1295 int rc, wipe = 0;
98e15beb 1296
0dad2177
KZ
1297 if (!cxt || !cxt->label || !pa)
1298 return -EINVAL;
1299 if (!cxt->label->op->set_part)
1300 return -ENOSYS;
1301
131e38a2
KZ
1302 pa->fs_probed = 0;
1303
a3a125b9
KZ
1304 if (!fdisk_is_partition_used(cxt, partno)) {
1305 pa->partno = partno;
1306 return fdisk_add_partition(cxt, pa, NULL);
1307 }
1308
98e15beb
KZ
1309 if (pa->resize || fdisk_partition_has_start(pa) || fdisk_partition_has_size(pa)) {
1310 xpa = __copy_partition(pa);
b2b52925
KZ
1311 if (!xpa) {
1312 rc = -ENOMEM;
1313 goto done;
1314 }
98e15beb
KZ
1315 xpa->movestart = 0;
1316 xpa->resize = 0;
1317 FDISK_INIT_UNDEF(xpa->size);
1318 FDISK_INIT_UNDEF(xpa->start);
1319
1320 rc = recount_resize(cxt, partno, xpa, pa);
1321 if (rc)
1322 goto done;
1323 }
1324
1325 DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju)",
1326 partno, xpa,
1327 (uintmax_t) fdisk_partition_get_start(xpa),
1328 (uintmax_t) fdisk_partition_get_end(xpa),
1329 (uintmax_t) fdisk_partition_get_size(xpa)));
0dad2177 1330
131e38a2
KZ
1331 /* disable wipe for old offset/size setting */
1332 if (fdisk_get_partition(cxt, partno, &tmp) == 0 && tmp) {
1333 wipe = fdisk_set_wipe_area(cxt, fdisk_partition_get_start(tmp),
1334 fdisk_partition_get_size(tmp), FALSE);
1335 fdisk_unref_partition(tmp);
1336 }
1337
1338 /* call label driver */
98e15beb 1339 rc = cxt->label->op->set_part(cxt, partno, xpa);
131e38a2
KZ
1340
1341 /* enable wipe for new offset/size */
1342 if (!rc && wipe)
1343 fdisk_wipe_partition(cxt, partno, TRUE);
98e15beb 1344done:
c949fa98 1345 DBG(CXT, ul_debugobj(cxt, "set_partition() rc=%d", rc));
98e15beb
KZ
1346 if (xpa != pa)
1347 fdisk_unref_partition(xpa);
1348 return rc;
0dad2177 1349}
187de51c 1350
131e38a2
KZ
1351/**
1352 * fdisk_wipe_partition:
1353 * @cxt: fdisk context
1354 * @partno: partition number
1355 * @enable: 0 or 1
1356 *
1357 * Enable/disable filesystems/RAIDs wiping in area defined by partition start and size.
1358 *
1359 * Returns: <0 in case of error, 0 on success
be163aa0 1360 * Since: 2.29
131e38a2
KZ
1361 */
1362int fdisk_wipe_partition(struct fdisk_context *cxt, size_t partno, int enable)
1363{
1364 struct fdisk_partition *pa = NULL;
1365 int rc;
1366
1367 rc = fdisk_get_partition(cxt, partno, &pa);
1368 if (rc)
1369 return rc;
1370
1371 rc = fdisk_set_wipe_area(cxt, fdisk_partition_get_start(pa),
1372 fdisk_partition_get_size(pa), enable);
1373 fdisk_unref_partition(pa);
1374 return rc < 0 ? rc : 0;
1375}
1376
29f2e825
KZ
1377/**
1378 * fdisk_partition_has_wipe:
1379 * @cxt: fdisk context
1380 * @pa: partition
1381 *
8d3e3e6b
KZ
1382 * Since: 2.30
1383 *
29f2e825
KZ
1384 * Returns: 1 if the area specified by @pa will be wiped by write command, or 0.
1385 */
1386int fdisk_partition_has_wipe(struct fdisk_context *cxt, struct fdisk_partition *pa)
1387{
1388 return fdisk_has_wipe_area(cxt, fdisk_partition_get_start(pa),
1389 fdisk_partition_get_size(pa));
1390}
1391
98e15beb 1392
187de51c
KZ
1393/**
1394 * fdisk_add_partition:
1395 * @cxt: fdisk context
c3bc7483 1396 * @pa: template for the partition (or NULL)
e11c6684 1397 * @partno: NULL or returns new partition number
187de51c 1398 *
9e930041 1399 * If @pa is not specified or any @pa item is missing the libfdisk will ask by
187de51c
KZ
1400 * fdisk_ask_ API.
1401 *
2cb47542
KZ
1402 * The @pa template is is important for non-interactive partitioning,
1403 * especially for MBR where is necessary to differentiate between
1404 * primary/logical; this is done by start offset or/and partno.
1405 * The rules for MBR:
1406 *
1407 * A) template specifies start within extended partition: add logical
1408 * B) template specifies start out of extended partition: add primary
1409 * C) template specifies start (or default), partno < 4: add primary
1410 * D) template specifies default start, partno >= 4: add logical
1411 *
1412 * otherwise MBR driver uses Ask-API to get missing information.
1413 *
0123bd1a 1414 * Adds a new partition to disklabel.
187de51c 1415 *
0123bd1a 1416 * Returns: 0 on success, <0 on error.
187de51c
KZ
1417 */
1418int fdisk_add_partition(struct fdisk_context *cxt,
c3bc7483
KZ
1419 struct fdisk_partition *pa,
1420 size_t *partno)
187de51c 1421{
732aefdf
KZ
1422 int rc;
1423
187de51c
KZ
1424 if (!cxt || !cxt->label)
1425 return -EINVAL;
1426 if (!cxt->label->op->add_part)
1427 return -ENOSYS;
1428 if (fdisk_missing_geometry(cxt))
1429 return -EINVAL;
1430
131e38a2
KZ
1431 if (pa) {
1432 pa->fs_probed = 0;
1573e955
KZ
1433 DBG(CXT, ul_debugobj(cxt, "adding new partition %p", pa));
1434 if (fdisk_partition_has_start(pa))
1435 DBG(CXT, ul_debugobj(cxt, " start: %ju", (uintmax_t) fdisk_partition_get_start(pa)));
1436 if (fdisk_partition_has_end(pa))
1437 DBG(CXT, ul_debugobj(cxt, " end: %ju", (uintmax_t) fdisk_partition_get_end(pa)));
1438 if (fdisk_partition_has_size(pa))
1439 DBG(CXT, ul_debugobj(cxt, " size: %ju", (uintmax_t) fdisk_partition_get_size(pa)));
1440
1441 DBG(CXT, ul_debugobj(cxt, " defaults: start=%s, end=%s, partno=%s",
c3bc7483
KZ
1442 pa->start_follow_default ? "yes" : "no",
1443 pa->end_follow_default ? "yes" : "no",
1444 pa->partno_follow_default ? "yes" : "no"));
131e38a2 1445 } else
c3bc7483
KZ
1446 DBG(CXT, ul_debugobj(cxt, "adding partition"));
1447
1448 rc = cxt->label->op->add_part(cxt, pa, partno);
732aefdf 1449
d71bd2f0 1450 DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc));
732aefdf 1451 return rc;
187de51c
KZ
1452}
1453
1454/**
1455 * fdisk_delete_partition:
1456 * @cxt: fdisk context
0123bd1a 1457 * @partno: partition number to delete (0 is the first partition)
187de51c 1458 *
0123bd1a 1459 * Deletes a @partno partition from disklabel.
187de51c 1460 *
e11c6684 1461 * Returns: 0 on success, <0 on error
187de51c 1462 */
e11c6684 1463int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno)
187de51c
KZ
1464{
1465 if (!cxt || !cxt->label)
1466 return -EINVAL;
e11c6684 1467 if (!cxt->label->op->del_part)
187de51c
KZ
1468 return -ENOSYS;
1469
131e38a2
KZ
1470 fdisk_wipe_partition(cxt, partno, 0);
1471
d71bd2f0 1472 DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd",
e11c6684
KZ
1473 cxt->label->name, partno));
1474 return cxt->label->op->del_part(cxt, partno);
187de51c 1475}
3c0e6b15
KZ
1476
1477/**
1478 * fdisk_delete_all_partitions:
1479 * @cxt: fdisk context
1480 *
0123bd1a 1481 * Delete all used partitions from disklabel.
3c0e6b15
KZ
1482 *
1483 * Returns: 0 on success, otherwise, a corresponding error.
1484 */
1485int fdisk_delete_all_partitions(struct fdisk_context *cxt)
1486{
1487 size_t i;
30ca5e70 1488 int rc = 0;
3c0e6b15
KZ
1489
1490 if (!cxt || !cxt->label)
1491 return -EINVAL;
1492
1493 for (i = 0; i < cxt->label->nparts_max; i++) {
1494
1495 if (!fdisk_is_partition_used(cxt, i))
1496 continue;
1497 rc = fdisk_delete_partition(cxt, i);
1498 if (rc)
1499 break;
1500 }
1501
1502 return rc;
1503}
1504
0123bd1a
KZ
1505/**
1506 * fdisk_is_partition_used:
705854f3 1507 * @cxt: context
0123bd1a
KZ
1508 * @n: partition number (0 is the first partition)
1509 *
0d034857
KZ
1510 * Check if the partition number @n is used by partition table. This function
1511 * does not check if the device is used (e.g. mounted) by system!
1512 *
0123bd1a
KZ
1513 * This is faster than fdisk_get_partition() + fdisk_partition_is_used().
1514 *
1515 * Returns: 0 or 1
e11c6684
KZ
1516 */
1517int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n)
1518{
1519 if (!cxt || !cxt->label)
1520 return -EINVAL;
1521 if (!cxt->label->op->part_is_used)
1522 return -ENOSYS;
1523
1524 return cxt->label->op->part_is_used(cxt, n);
1525}
1526