]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/table.c
taskset: Accept 0 pid for current process
[thirdparty/util-linux.git] / libfdisk / src / table.c
CommitLineData
b48cdebc
KZ
1
2#include "fdiskP.h"
3
3c5ee57c
KZ
4/**
5 * SECTION: table
705854f3 6 * @title: Table
3c5ee57c
KZ
7 * @short_description: container for fdisk partitions
8 *
9 * The fdisk_table is simple container for fdisk_partitions. The table is no
10 * directly connected to label data (partition table), and table changes don't
11 * affect in-memory or on-disk data.
12 */
13
b48cdebc
KZ
14/**
15 * fdisk_new_table:
16 *
17 * The table is a container for struct fdisk_partition entries. The container
18 * does not have any real connection with label (partition table) and with
19 * real on-disk data.
20 *
21 * Returns: newly allocated table struct.
22 */
23struct fdisk_table *fdisk_new_table(void)
24{
25 struct fdisk_table *tb = NULL;
26
27 tb = calloc(1, sizeof(*tb));
28 if (!tb)
29 return NULL;
30
d71bd2f0 31 DBG(TAB, ul_debugobj(tb, "alloc"));
b48cdebc
KZ
32 tb->refcount = 1;
33 INIT_LIST_HEAD(&tb->parts);
34 return tb;
35}
36
37/**
38 * fdisk_reset_table:
39 * @tb: tab pointer
40 *
9e930041 41 * Removes all entries (partitions) from the table. The partitions with zero
3c0e6b15
KZ
42 * reference count will be deallocated. This function does not modify partition
43 * table.
b48cdebc
KZ
44 *
45 * Returns: 0 on success or negative number in case of error.
46 */
47int fdisk_reset_table(struct fdisk_table *tb)
48{
49 if (!tb)
50 return -EINVAL;
51
d71bd2f0 52 DBG(TAB, ul_debugobj(tb, "reset"));
b48cdebc
KZ
53
54 while (!list_empty(&tb->parts)) {
55 struct fdisk_partition *pa = list_entry(tb->parts.next,
56 struct fdisk_partition, parts);
57 fdisk_table_remove_partition(tb, pa);
58 }
59
04406c0d 60 tb->nents = 0;
b48cdebc
KZ
61 return 0;
62}
63
64/**
65 * fdisk_ref_table:
66 * @tb: table pointer
67 *
9e930041 68 * Increments reference counter.
b48cdebc
KZ
69 */
70void fdisk_ref_table(struct fdisk_table *tb)
71{
72 if (tb)
73 tb->refcount++;
74}
75
76/**
77 * fdisk_unref_table:
78 * @tb: table pointer
79 *
5225bdad 80 * Decrements reference counter, on zero the @tb is automatically
5175ae87 81 * deallocated.
b48cdebc
KZ
82 */
83void fdisk_unref_table(struct fdisk_table *tb)
84{
85 if (!tb)
86 return;
87
88 tb->refcount--;
89 if (tb->refcount <= 0) {
90 fdisk_reset_table(tb);
91
d71bd2f0 92 DBG(TAB, ul_debugobj(tb, "free"));
b48cdebc
KZ
93 free(tb);
94 }
95}
96
97/**
98 * fdisk_table_is_empty:
99 * @tb: pointer to tab
100 *
101 * Returns: 1 if the table is without filesystems, or 0.
102 */
103int fdisk_table_is_empty(struct fdisk_table *tb)
104{
b48cdebc
KZ
105 return tb == NULL || list_empty(&tb->parts) ? 1 : 0;
106}
107
04406c0d
KZ
108/**
109 * fdisk_table_get_nents:
110 * @tb: pointer to tab
111 *
112 * Returns: number of entries in table.
113 */
e54b1c6f 114size_t fdisk_table_get_nents(struct fdisk_table *tb)
04406c0d
KZ
115{
116 return tb ? tb->nents : 0;
117}
6c89f750
KZ
118
119/**
120 * fdisk_table_next_partition:
121 * @tb: tab pointer
122 * @itr: iterator
123 * @pa: returns the next tab entry
124 *
125 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
126 *
127 * Example:
128 * <informalexample>
129 * <programlisting>
130 * while(fdisk_table_next_partition(tb, itr, &pa) == 0) {
131 * ...
132 * }
133 * </programlisting>
134 * </informalexample>
135 */
136int fdisk_table_next_partition(
137 struct fdisk_table *tb,
138 struct fdisk_iter *itr,
139 struct fdisk_partition **pa)
140{
141 int rc = 1;
142
6c89f750
KZ
143 if (!tb || !itr || !pa)
144 return -EINVAL;
145 *pa = NULL;
146
147 if (!itr->head)
148 FDISK_ITER_INIT(itr, &tb->parts);
149 if (itr->p != itr->head) {
150 FDISK_ITER_ITERATE(itr, *pa, struct fdisk_partition, parts);
151 rc = 0;
152 }
153
154 return rc;
155}
156
b17c1f14
KZ
157/**
158 * fdisk_table_get_partition:
159 * @tb: tab pointer
160 * @n: number of entry in table
161 *
162 * Returns: n-th entry from table or NULL
163 */
28b6a23c
KZ
164struct fdisk_partition *fdisk_table_get_partition(
165 struct fdisk_table *tb,
166 size_t n)
167{
168 struct fdisk_partition *pa = NULL;
169 struct fdisk_iter itr;
170
171 if (!tb)
172 return NULL;
173
174 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
175
176 while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
177 if (n == 0)
178 return pa;
179 n--;
180 }
181
182 return NULL;
183}
184
b17c1f14
KZ
185/**
186 * fdisk_table_get_partition_by_partno:
187 * @tb: tab pointer
188 * @partno: partition number
189 *
190 * Returns: partition with @partno or NULL.
191 */
192struct fdisk_partition *fdisk_table_get_partition_by_partno(
193 struct fdisk_table *tb,
194 size_t partno)
195{
196 struct fdisk_partition *pa = NULL;
197 struct fdisk_iter itr;
198
199 if (!tb)
200 return NULL;
201
202 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
203
204 while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
205 if (pa->partno == partno)
206 return pa;
207 }
208
209 return NULL;
210}
211
b48cdebc
KZ
212/**
213 * fdisk_table_add_partition
214 * @tb: tab pointer
215 * @pa: new entry
216 *
217 * Adds a new entry to table and increment @pa reference counter. Don't forget to
0c07055c 218 * use fdisk_unref_partition() after fdisk_table_add_partition() if you want to keep
b48cdebc
KZ
219 * the @pa referenced by the table only.
220 *
221 * Returns: 0 on success or negative number in case of error.
222 */
223int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa)
224{
b48cdebc
KZ
225 if (!tb || !pa)
226 return -EINVAL;
227
1882b3a6
KZ
228 if (!list_empty(&pa->parts))
229 return -EBUSY;
230
b48cdebc
KZ
231 fdisk_ref_partition(pa);
232 list_add_tail(&pa->parts, &tb->parts);
04406c0d 233 tb->nents++;
b48cdebc 234
d71bd2f0 235 DBG(TAB, ul_debugobj(tb, "add entry %p [start=%ju, end=%ju, size=%ju, %s %s %s]",
bbfc2429
KZ
236 pa,
237 (uintmax_t) fdisk_partition_get_start(pa),
e1efda47
KZ
238 fdisk_partition_has_end(pa) ? (uintmax_t) fdisk_partition_get_end(pa) : 0,
239 fdisk_partition_has_size(pa) ? (uintmax_t) fdisk_partition_get_size(pa) : 0,
e77313a6
KZ
240 fdisk_partition_is_freespace(pa) ? "freespace" : "",
241 fdisk_partition_is_nested(pa) ? "nested" : "",
5139eca7 242 fdisk_partition_is_container(pa) ? "container" : "primary"));
b48cdebc
KZ
243 return 0;
244}
245
2cec7949
KZ
246/* inserts @pa after @poz */
247static int table_insert_partition(
248 struct fdisk_table *tb,
249 struct fdisk_partition *poz,
250 struct fdisk_partition *pa)
251{
252 assert(tb);
253 assert(pa);
254
255 fdisk_ref_partition(pa);
256 if (poz)
257 list_add(&pa->parts, &poz->parts);
258 else
259 list_add(&pa->parts, &tb->parts);
260 tb->nents++;
261
d71bd2f0 262 DBG(TAB, ul_debugobj(tb, "insert entry %p pre=%p [start=%ju, end=%ju, size=%ju, %s %s %s]",
bbfc2429
KZ
263 pa, poz ? poz : NULL,
264 (uintmax_t) fdisk_partition_get_start(pa),
265 (uintmax_t) fdisk_partition_get_end(pa),
266 (uintmax_t) fdisk_partition_get_size(pa),
5139eca7
KZ
267 fdisk_partition_is_freespace(pa) ? "freespace" : "",
268 fdisk_partition_is_nested(pa) ? "nested" : "",
2248aaf9 269 fdisk_partition_is_container(pa) ? "container" : ""));
2cec7949
KZ
270 return 0;
271}
272
b48cdebc
KZ
273/**
274 * fdisk_table_remove_partition
275 * @tb: tab pointer
276 * @pa: new entry
277 *
278 * Removes the @pa from the table and de-increment reference counter of the @pa. The
279 * partition with zero reference counter will be deallocated. Don't forget to use
280 * fdisk_ref_partition() before call fdisk_table_remove_partition() if you want
281 * to use @pa later.
282 *
283 * Returns: 0 on success or negative number in case of error.
284 */
285int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa)
286{
b48cdebc
KZ
287 if (!tb || !pa)
288 return -EINVAL;
289
d71bd2f0 290 DBG(TAB, ul_debugobj(tb, "remove entry %p", pa));
b48cdebc
KZ
291 list_del(&pa->parts);
292 INIT_LIST_HEAD(&pa->parts);
293
294 fdisk_unref_partition(pa);
04406c0d
KZ
295 tb->nents--;
296
b48cdebc
KZ
297 return 0;
298}
6c89f750 299
2cec7949
KZ
300/**
301 * fdisk_get_partitions
302 * @cxt: fdisk context
303 * @tb: returns table
304 *
305 * This function adds partitions from disklabel to @table, it allocates a new
73ec5e16 306 * table if @table points to NULL.
2cec7949 307 *
705854f3 308 * Returns: 0 on success, otherwise, a corresponding error.
2cec7949
KZ
309 */
310int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb)
311{
312 size_t i;
313
314 if (!cxt || !cxt->label || !tb)
315 return -EINVAL;
316 if (!cxt->label->op->get_part)
317 return -ENOSYS;
318
1bb387bd 319 DBG(CXT, ul_debugobj(cxt, " -- get table --"));
2cec7949
KZ
320
321 if (!*tb && !(*tb = fdisk_new_table()))
322 return -ENOMEM;
323
324 for (i = 0; i < cxt->label->nparts_max; i++) {
325 struct fdisk_partition *pa = NULL;
326
327 if (fdisk_get_partition(cxt, i, &pa) != 0)
328 continue;
329 if (fdisk_partition_is_used(pa))
330 fdisk_table_add_partition(*tb, pa);
331 fdisk_unref_partition(pa);
332 }
333
334 return 0;
335}
336
264ef987 337void fdisk_debug_print_table(struct fdisk_table *tb)
764b697c
KZ
338{
339 struct fdisk_iter itr;
340 struct fdisk_partition *pa;
341
342 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
343 while (fdisk_table_next_partition(tb, &itr, &pa) == 0)
264ef987 344 ul_debugobj(tb, "partition %p [partno=%zu, start=%ju, end=%ju, size=%ju%s%s%s] ",
764b697c
KZ
345 pa, pa->partno,
346 (uintmax_t) fdisk_partition_get_start(pa),
347 (uintmax_t) fdisk_partition_get_end(pa),
264ef987
KZ
348 (uintmax_t) fdisk_partition_get_size(pa),
349 fdisk_partition_is_nested(pa) ? " nested" : "",
350 fdisk_partition_is_freespace(pa) ? " freespace" : "",
351 fdisk_partition_is_container(pa) ? " container" : "");
764b697c
KZ
352
353}
354
355
e5c93999
KZ
356typedef int (*fdisk_partcmp_t)(struct fdisk_partition *, struct fdisk_partition *);
357
358static int cmp_parts_wrapper(struct list_head *a, struct list_head *b, void *data)
359{
360 struct fdisk_partition *pa = list_entry(a, struct fdisk_partition, parts),
361 *pb = list_entry(b, struct fdisk_partition, parts);
362
363 fdisk_partcmp_t cmp = (fdisk_partcmp_t) data;
364
365 return cmp(pa, pb);
366}
367
764b697c 368
5175ae87
KZ
369/**
370 * fdisk_table_sort_partitions:
371 * @tb: table
372 * @cmp: compare function
373 *
374 * Sort partition in the table.
705854f3
KZ
375 *
376 * Returns: 0 on success, <0 on error.
5175ae87 377 */
e5c93999
KZ
378int fdisk_table_sort_partitions(struct fdisk_table *tb,
379 int (*cmp)(struct fdisk_partition *,
380 struct fdisk_partition *))
381{
382 if (!tb)
383 return -EINVAL;
384
264ef987 385 /*
764b697c 386 DBG(TAB, ul_debugobj(tb, "Before sort:"));
264ef987
KZ
387 ON_DBG(TAB, fdisk_debug_print_table(tb));
388 */
764b697c 389
e5c93999 390 list_sort(&tb->parts, cmp_parts_wrapper, (void *) cmp);
764b697c 391
264ef987 392 /*
764b697c 393 DBG(TAB, ul_debugobj(tb, "After sort:"));
264ef987
KZ
394 ON_DBG(TAB, fdisk_debug_print_table(tb));
395 */
764b697c 396
e5c93999
KZ
397 return 0;
398}
399
5139eca7
KZ
400/* allocates a new freespace description */
401static int new_freespace(struct fdisk_context *cxt,
0073a4cf
KZ
402 fdisk_sector_t start,
403 fdisk_sector_t end,
5139eca7
KZ
404 struct fdisk_partition *parent,
405 struct fdisk_partition **pa)
406{
b362a4cb
KZ
407 fdisk_sector_t aligned_start, size;
408
5139eca7
KZ
409 assert(cxt);
410 assert(pa);
411
412 *pa = NULL;
413
414 if (start == end)
415 return 0;
5139eca7 416
9c76f85f 417 assert(start >= cxt->first_lba);
bbfc2429
KZ
418 assert(end);
419 assert(end > start);
420
b362a4cb
KZ
421 aligned_start = fdisk_align_lba_in_range(cxt, start, start, end);
422 size = end - aligned_start + 1ULL;
423
424 if (size == 0) {
425 DBG(TAB, ul_debug("ignore freespace (aligned size is zero)"));
426 return 0;
427 }
428
429 *pa = fdisk_new_partition();
430 if (!*pa)
431 return -ENOMEM;
432
5139eca7 433 (*pa)->freespace = 1;
b362a4cb
KZ
434 (*pa)->start = aligned_start;
435 (*pa)->size = size;
5139eca7
KZ
436
437 if (parent)
438 (*pa)->parent_partno = parent->partno;
439 return 0;
440}
441
442/* add freespace description to the right place within @tb */
03643931 443static int table_add_freespace(
81c29a73 444 struct fdisk_context *cxt,
6c89f750 445 struct fdisk_table *tb,
0073a4cf
KZ
446 fdisk_sector_t start,
447 fdisk_sector_t end,
bd5e8291 448 struct fdisk_partition *parent)
6c89f750 449{
bd5e8291
KZ
450 struct fdisk_partition *pa, *x, *real_parent = NULL, *best = NULL;
451 struct fdisk_iter itr;
5139eca7 452 int rc = 0;
6c89f750
KZ
453
454 assert(tb);
455
5139eca7
KZ
456 rc = new_freespace(cxt, start, end, parent, &pa);
457 if (rc)
2cec7949 458 return -ENOMEM;
5139eca7
KZ
459 if (!pa)
460 return 0;
2248aaf9 461
bbfc2429
KZ
462 assert(fdisk_partition_has_start(pa));
463 assert(fdisk_partition_has_end(pa));
464
2248aaf9
KZ
465 DBG(TAB, ul_debugobj(tb, "adding freespace"));
466
bd5e8291 467 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
0123bd1a 468 if (parent && fdisk_partition_has_partno(parent)) {
2cec7949 469 while (fdisk_table_next_partition(tb, &itr, &x) == 0) {
2248aaf9 470 if (!fdisk_partition_has_partno(x))
0123bd1a 471 continue;
bd5e8291
KZ
472 if (x->partno == parent->partno) {
473 real_parent = x;
474 break;
475 }
476 }
477 if (!real_parent) {
73548d6e 478 DBG(TAB, ul_debugobj(tb, "not found freespace parent (partno=%zu)",
bd5e8291
KZ
479 parent->partno));
480 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
2cec7949 481 }
2cec7949 482 }
bd5e8291
KZ
483
484 while (fdisk_table_next_partition(tb, &itr, &x) == 0) {
7ee26cbf 485 fdisk_sector_t the_end, best_end = 0;
bbfc2429
KZ
486
487 if (!fdisk_partition_has_end(x))
488 continue;
489
7ee26cbf 490 the_end = fdisk_partition_get_end(x);
764b697c
KZ
491 if (best)
492 best_end = fdisk_partition_get_end(best);
bbfc2429 493
7ee26cbf 494 if (the_end < pa->start && (!best || best_end < the_end))
bd5e8291
KZ
495 best = x;
496 }
497
498 if (!best && real_parent)
499 best = real_parent;
500 rc = table_insert_partition(tb, best, pa);
501
6c89f750 502 fdisk_unref_partition(pa);
2248aaf9
KZ
503
504 DBG(TAB, ul_debugobj(tb, "adding freespace DONE [rc=%d]", rc));
6c89f750
KZ
505 return rc;
506}
2cec7949 507
5139eca7
KZ
508/* analyze @cont(ainer) in @parts and add all detected freespace into @tb, note
509 * that @parts has to be sorted by partition starts */
510static int check_container_freespace(struct fdisk_context *cxt,
511 struct fdisk_table *parts,
512 struct fdisk_table *tb,
513 struct fdisk_partition *cont)
514{
515 struct fdisk_iter itr;
516 struct fdisk_partition *pa;
0073a4cf 517 fdisk_sector_t x, last, grain, lastplusoff;
5139eca7
KZ
518 int rc = 0;
519
520 assert(cxt);
521 assert(parts);
522 assert(tb);
523 assert(cont);
ecf40cda 524 assert(fdisk_partition_has_start(cont));
5139eca7 525
2248aaf9
KZ
526 DBG(TAB, ul_debugobj(tb, "analyze container 0x%p", cont));
527
5fd7160e 528 last = fdisk_partition_get_start(cont);
5139eca7
KZ
529 grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1;
530 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
531
fdbd7bb9
RM
532 DBG(CXT, ul_debugobj(cxt, "initialized: last=%ju, grain=%ju",
533 (uintmax_t)last, (uintmax_t)grain));
764b697c 534
5139eca7 535 while (fdisk_table_next_partition(parts, &itr, &pa) == 0) {
764b697c 536
fdbd7bb9
RM
537 DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju",
538 pa->partno, (uintmax_t)pa->start));
764b697c 539
ecf40cda
KZ
540 if (!pa->used || !fdisk_partition_is_nested(pa)
541 || !fdisk_partition_has_start(pa))
5139eca7 542 continue;
5fd7160e 543
764b697c
KZ
544 DBG(CXT, ul_debugobj(cxt, "freespace container analyze: partno=%zu, start=%ju, end=%ju",
545 pa->partno,
546 (uintmax_t) fdisk_partition_get_start(pa),
547 (uintmax_t) fdisk_partition_get_end(pa)));
548
5fd7160e
KZ
549 lastplusoff = last + cxt->first_lba;
550 if (pa->start > lastplusoff && pa->start - lastplusoff > grain)
551 rc = table_add_freespace(cxt, tb, lastplusoff, pa->start, cont);
5139eca7 552 if (rc)
2248aaf9 553 goto done;
bbfc2429 554 last = fdisk_partition_get_end(pa);
5139eca7
KZ
555 }
556
557 /* free-space remaining in extended partition */
558 x = fdisk_partition_get_start(cont) + fdisk_partition_get_size(cont) - 1;
5fd7160e 559 lastplusoff = last + cxt->first_lba;
2248aaf9
KZ
560 if (lastplusoff < x && x - lastplusoff > grain) {
561 DBG(TAB, ul_debugobj(tb, "add remaining space in container 0x%p", cont));
5fd7160e 562 rc = table_add_freespace(cxt, tb, lastplusoff, x, cont);
2248aaf9
KZ
563 }
564
565done:
566 DBG(TAB, ul_debugobj(tb, "analyze container 0x%p DONE [rc=%d]", cont, rc));
5139eca7
KZ
567 return rc;
568}
569
2cec7949 570
6c89f750 571/**
2cec7949 572 * fdisk_get_freespaces
6c89f750 573 * @cxt: fdisk context
2cec7949 574 * @tb: returns table
6c89f750 575 *
2cec7949 576 * This function adds freespace (described by fdisk_partition) to @table, it
5139eca7 577 * allocates a new table if the @table points to NULL.
c743bf74 578 *
0c07055c
KZ
579 * Note that free space smaller than grain (see fdisk_get_grain_size()) is
580 * ignored.
9a76780f 581 *
705854f3 582 * Returns: 0 on success, otherwise, a corresponding error.
6c89f750 583 */
2cec7949 584int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
6c89f750 585{
bd5e8291 586 int rc = 0;
1bb387bd 587 size_t nparts = 0;
0073a4cf 588 fdisk_sector_t last, grain;
e5c93999 589 struct fdisk_table *parts = NULL;
5139eca7 590 struct fdisk_partition *pa;
e5c93999 591 struct fdisk_iter itr;
6c89f750 592
1bb387bd 593 DBG(CXT, ul_debugobj(cxt, "-- get freespace --"));
2cec7949 594
6c89f750
KZ
595 if (!cxt || !cxt->label || !tb)
596 return -EINVAL;
2cec7949
KZ
597 if (!*tb && !(*tb = fdisk_new_table()))
598 return -ENOMEM;
5139eca7 599
e5c93999
KZ
600 rc = fdisk_get_partitions(cxt, &parts);
601 if (rc)
602 goto done;
19ff8ff7 603
e5c93999
KZ
604 fdisk_table_sort_partitions(parts, fdisk_partition_cmp_start);
605 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
6c89f750 606 last = cxt->first_lba;
03643931 607 grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1;
6c89f750 608
fdbd7bb9
RM
609 DBG(CXT, ul_debugobj(cxt, "initialized: last=%ju, grain=%ju",
610 (uintmax_t)last, (uintmax_t)grain));
19ff8ff7 611
e5c93999 612 /* analyze gaps between partitions */
5139eca7 613 while (rc == 0 && fdisk_table_next_partition(parts, &itr, &pa) == 0) {
19ff8ff7 614
fdbd7bb9
RM
615 DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju",
616 pa->partno, (uintmax_t)pa->start));
19ff8ff7 617
ecf40cda
KZ
618 if (!pa->used || pa->wholedisk || fdisk_partition_is_nested(pa)
619 || !fdisk_partition_has_start(pa))
03643931 620 continue;
d71bd2f0 621 DBG(CXT, ul_debugobj(cxt, "freespace analyze: partno=%zu, start=%ju, end=%ju",
bbfc2429
KZ
622 pa->partno,
623 (uintmax_t) fdisk_partition_get_start(pa),
624 (uintmax_t) fdisk_partition_get_end(pa)));
83677b99
KZ
625
626 /* We ignore small free spaces (smaller than grain) to keep partitions
ae1e82e0
EG
627 * aligned, the exception is space before the first partition when
628 * cxt->first_lba is aligned. */
84801818 629 if (last + grain < pa->start
ae1e82e0
EG
630 || (nparts == 0 &&
631 (fdisk_align_lba(cxt, last, FDISK_ALIGN_UP) <
632 pa->start))) {
03643931 633 rc = table_add_freespace(cxt, *tb,
1037269f 634 last + (nparts == 0 ? 0 : 1),
bd5e8291 635 pa->start - 1, NULL);
6c89f750 636 }
5139eca7
KZ
637 /* add gaps between logical partitions */
638 if (fdisk_partition_is_container(pa))
639 rc = check_container_freespace(cxt, parts, *tb, pa);
9a76780f
FK
640
641 if (fdisk_partition_has_end(pa)) {
642 fdisk_sector_t pa_end = fdisk_partition_get_end(pa);
643 if (pa_end > last)
644 last = fdisk_partition_get_end(pa);
645 }
1bb387bd 646 nparts++;
6c89f750
KZ
647 }
648
5139eca7
KZ
649 /* add free-space behind last partition to the end of the table (so
650 * don't use table_add_freespace()) */
1116884c 651 if (rc == 0 && last + grain < cxt->last_lba - 1) {
2248aaf9 652 DBG(CXT, ul_debugobj(cxt, "freespace behind last partition detected"));
5139eca7 653 rc = new_freespace(cxt,
1bb387bd 654 last + (last > cxt->first_lba || nparts ? 1 : 0),
5139eca7
KZ
655 cxt->last_lba, NULL, &pa);
656 if (pa) {
657 fdisk_table_add_partition(*tb, pa);
658 fdisk_unref_partition(pa);
03643931 659 }
aa423fd3 660 }
03643931 661
e5c93999
KZ
662done:
663 fdisk_unref_table(parts);
2248aaf9
KZ
664
665 DBG(CXT, ul_debugobj(cxt, "get freespace DONE [rc=%d]", rc));
2cec7949 666 return rc;
6c89f750
KZ
667}
668
8b60872e
KZ
669/**
670 * fdisk_table_wrong_order:
671 * @tb: table
672 *
673 * Returns: 1 of the table is not in disk order
674 */
675int fdisk_table_wrong_order(struct fdisk_table *tb)
676{
677 struct fdisk_partition *pa;
678 struct fdisk_iter itr;
0073a4cf 679 fdisk_sector_t last = 0;
8b60872e
KZ
680
681 DBG(TAB, ul_debugobj(tb, "wrong older check"));
682
683 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
684 while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) {
fbec8d9f 685 if (!fdisk_partition_has_start(pa) || fdisk_partition_is_wholedisk(pa))
ecf40cda 686 continue;
8b60872e
KZ
687 if (pa->start < last)
688 return 1;
689 last = pa->start;
690 }
691 return 0;
692}
385810d2 693
3c0e6b15
KZ
694/**
695 * fdisk_apply_table:
696 * @cxt: context
697 * @tb: table
698 *
699 * Add partitions from table @tb to the in-memory disk label. See
75a8e726 700 * fdisk_add_partition(), fdisk_delete_all_partitions(). The partitions
3186f4a9 701 * that does not define start (or does not follow the default start)
9e930041 702 * are ignored.
3c0e6b15
KZ
703 *
704 * Returns: 0 on success, <0 on error.
705 */
706int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb)
707{
708 struct fdisk_partition *pa;
709 struct fdisk_iter itr;
710 int rc = 0;
711
712 assert(cxt);
713 assert(tb);
714
715 DBG(TAB, ul_debugobj(tb, "applying to context %p", cxt));
716
717 fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
718 while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) {
ecf40cda 719 if (!fdisk_partition_has_start(pa) && !pa->start_follow_default)
3186f4a9 720 continue;
c3bc7483 721 rc = fdisk_add_partition(cxt, pa, NULL);
3c0e6b15
KZ
722 if (rc)
723 break;
724 }
725
726 return rc;
727}
728
1dd63a3b
KZ
729int fdisk_diff_tables(struct fdisk_table *a, struct fdisk_table *b,
730 struct fdisk_iter *itr,
731 struct fdisk_partition **res, int *change)
732{
4813a521 733 struct fdisk_partition *pa = NULL, *pb;
1dd63a3b
KZ
734 int rc = 1;
735
736 assert(itr);
737 assert(res);
738 assert(change);
739
740 DBG(TAB, ul_debugobj(a, "table diff [new table=%p]", b));
741
742 if (a && (itr->head == NULL || itr->head == &a->parts)) {
743 DBG(TAB, ul_debugobj(a, " scanning old table"));
744 do {
745 rc = fdisk_table_next_partition(a, itr, &pa);
746 if (rc != 0)
747 break;
748 } while (!fdisk_partition_has_partno(pa));
749 }
750
751 if (rc == 1 && b) {
752 DBG(TAB, ul_debugobj(a, " scanning new table"));
753 if (itr->head != &b->parts) {
754 DBG(TAB, ul_debugobj(a, " initialize to TAB=%p", b));
755 fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
756 }
757
758 while (fdisk_table_next_partition(b, itr, &pb) == 0) {
759 if (!fdisk_partition_has_partno(pb))
760 continue;
761 if (a == NULL ||
762 fdisk_table_get_partition_by_partno(a, pb->partno) == NULL) {
763 DBG(TAB, ul_debugobj(a, " #%zu ADDED", pb->partno));
764 *change = FDISK_DIFF_ADDED;
765 *res = pb;
766 return 0;
767 }
768 }
769 }
770
771 if (rc) {
772 DBG(TAB, ul_debugobj(a, "table diff done [rc=%d]", rc));
773 return rc; /* error or done */
774 }
775
776 pb = fdisk_table_get_partition_by_partno(b, pa->partno);
777
778 if (!pb) {
779 DBG(TAB, ul_debugobj(a, " #%zu REMOVED", pa->partno));
780 *change = FDISK_DIFF_REMOVED;
781 *res = pa;
782 } else if (pb->start != pa->start) {
783 DBG(TAB, ul_debugobj(a, " #%zu MOVED", pb->partno));
784 *change = FDISK_DIFF_MOVED;
785 *res = pb;
786 } else if (pb->size != pa->size) {
787 DBG(TAB, ul_debugobj(a, " #%zu RESIZED", pb->partno));
788 *change = FDISK_DIFF_RESIZED;
789 *res = pb;
790 } else {
791 DBG(TAB, ul_debugobj(a, " #%zu UNCHANGED", pb->partno));
792 *change = FDISK_DIFF_UNCHANGED;
793 *res = pa;
794 }
795 return 0;
796}
797