7 * The table is a container for struct fdisk_partition entries. The container
8 * does not have any real connection with label (partition table) and with
11 * Returns: newly allocated table struct.
13 struct fdisk_table
*fdisk_new_table(void)
15 struct fdisk_table
*tb
= NULL
;
17 tb
= calloc(1, sizeof(*tb
));
21 DBG(TAB
, ul_debugobj(tb
, "alloc"));
23 INIT_LIST_HEAD(&tb
->parts
);
31 * Removes all entries (filesystems) from the table. The filesystems with zero
32 * reference count will be deallocated.
34 * Returns: 0 on success or negative number in case of error.
36 int fdisk_reset_table(struct fdisk_table
*tb
)
41 DBG(TAB
, ul_debugobj(tb
, "reset"));
43 while (!list_empty(&tb
->parts
)) {
44 struct fdisk_partition
*pa
= list_entry(tb
->parts
.next
,
45 struct fdisk_partition
, parts
);
46 fdisk_table_remove_partition(tb
, pa
);
57 * Incremparts reference counter.
59 void fdisk_ref_table(struct fdisk_table
*tb
)
69 * De-incremparts reference counter, on zero the @tb is automatically
70 * deallocated by fdisk_free_table().
72 void fdisk_unref_table(struct fdisk_table
*tb
)
78 if (tb
->refcount
<= 0) {
79 fdisk_reset_table(tb
);
81 DBG(TAB
, ul_debugobj(tb
, "free"));
87 * fdisk_table_is_empty:
90 * Returns: 1 if the table is without filesystems, or 0.
92 int fdisk_table_is_empty(struct fdisk_table
*tb
)
95 return tb
== NULL
|| list_empty(&tb
->parts
) ? 1 : 0;
99 * fdisk_table_get_nents:
100 * @tb: pointer to tab
102 * Returns: number of entries in table.
104 int fdisk_table_get_nents(struct fdisk_table
*tb
)
106 return tb
? tb
->nents
: 0;
110 * fdisk_table_next_partition:
113 * @pa: returns the next tab entry
115 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
120 * while(fdisk_table_next_partition(tb, itr, &pa) == 0) {
126 int fdisk_table_next_partition(
127 struct fdisk_table
*tb
,
128 struct fdisk_iter
*itr
,
129 struct fdisk_partition
**pa
)
137 if (!tb
|| !itr
|| !pa
)
142 FDISK_ITER_INIT(itr
, &tb
->parts
);
143 if (itr
->p
!= itr
->head
) {
144 FDISK_ITER_ITERATE(itr
, *pa
, struct fdisk_partition
, parts
);
151 struct fdisk_partition
*fdisk_table_get_partition(
152 struct fdisk_table
*tb
,
155 struct fdisk_partition
*pa
= NULL
;
156 struct fdisk_iter itr
;
161 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
163 while (fdisk_table_next_partition(tb
, &itr
, &pa
) == 0) {
173 * fdisk_table_add_partition
177 * Adds a new entry to table and increment @pa reference counter. Don't forget to
178 * use fdisk_unref_pa() after fdisk_table_add_partition() if you want to keep
179 * the @pa referenced by the table only.
181 * Returns: 0 on success or negative number in case of error.
183 int fdisk_table_add_partition(struct fdisk_table
*tb
, struct fdisk_partition
*pa
)
191 fdisk_ref_partition(pa
);
192 list_add_tail(&pa
->parts
, &tb
->parts
);
195 DBG(TAB
, ul_debugobj(tb
, "add entry %p [start=%ju, end=%ju, size=%ju, %s %s %s]",
196 pa
, pa
->start
, pa
->end
, pa
->size
,
197 fdisk_partition_is_freespace(pa
) ? "freespace" : "",
198 fdisk_partition_is_nested(pa
) ? "nested" : "",
199 fdisk_partition_is_container(pa
) ? "container" : "primary"));
203 /* inserts @pa after @poz */
204 static int table_insert_partition(
205 struct fdisk_table
*tb
,
206 struct fdisk_partition
*poz
,
207 struct fdisk_partition
*pa
)
212 fdisk_ref_partition(pa
);
214 list_add(&pa
->parts
, &poz
->parts
);
216 list_add(&pa
->parts
, &tb
->parts
);
219 DBG(TAB
, ul_debugobj(tb
, "insert entry %p pre=%p [start=%ju, end=%ju, size=%ju, %s %s %s]",
220 pa
, poz
? poz
: NULL
, pa
->start
, pa
->end
, pa
->size
,
221 fdisk_partition_is_freespace(pa
) ? "freespace" : "",
222 fdisk_partition_is_nested(pa
) ? "nested" : "",
223 fdisk_partition_is_container(pa
) ? "container" : "primary"));
228 * fdisk_table_remove_partition
232 * Removes the @pa from the table and de-increment reference counter of the @pa. The
233 * partition with zero reference counter will be deallocated. Don't forget to use
234 * fdisk_ref_partition() before call fdisk_table_remove_partition() if you want
237 * Returns: 0 on success or negative number in case of error.
239 int fdisk_table_remove_partition(struct fdisk_table
*tb
, struct fdisk_partition
*pa
)
247 DBG(TAB
, ul_debugobj(tb
, "remove entry %p", pa
));
248 list_del(&pa
->parts
);
249 INIT_LIST_HEAD(&pa
->parts
);
251 fdisk_unref_partition(pa
);
258 * fdisk_get_partitions
259 * @cxt: fdisk context
262 * This function adds partitions from disklabel to @table, it allocates a new
263 * table if if @table points to NULL.
265 * Returns 0 on success, otherwise, a corresponding error.
267 int fdisk_get_partitions(struct fdisk_context
*cxt
, struct fdisk_table
**tb
)
271 if (!cxt
|| !cxt
->label
|| !tb
)
273 if (!cxt
->label
->op
->get_part
)
276 DBG(CXT
, ul_debugobj(cxt
, "get table"));
278 if (!*tb
&& !(*tb
= fdisk_new_table()))
281 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
282 struct fdisk_partition
*pa
= NULL
;
284 if (fdisk_get_partition(cxt
, i
, &pa
) != 0)
286 if (fdisk_partition_is_used(pa
))
287 fdisk_table_add_partition(*tb
, pa
);
288 fdisk_unref_partition(pa
);
294 int fdisk_dump_table(struct fdisk_table
*tb
, FILE *f
)
296 struct fdisk_partition
*pa
;
297 struct fdisk_iter itr
;
303 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
305 fprintf(f
, "--table--%p\n", tb
);
306 while (fdisk_table_next_partition(tb
, &itr
, &pa
) == 0) {
307 fprintf(f
, "%d: ", i
++);
308 fdisk_dump_partition(pa
, f
);
315 typedef int (*fdisk_partcmp_t
)(struct fdisk_partition
*, struct fdisk_partition
*);
317 static int cmp_parts_wrapper(struct list_head
*a
, struct list_head
*b
, void *data
)
319 struct fdisk_partition
*pa
= list_entry(a
, struct fdisk_partition
, parts
),
320 *pb
= list_entry(b
, struct fdisk_partition
, parts
);
322 fdisk_partcmp_t cmp
= (fdisk_partcmp_t
) data
;
327 int fdisk_table_sort_partitions(struct fdisk_table
*tb
,
328 int (*cmp
)(struct fdisk_partition
*,
329 struct fdisk_partition
*))
334 list_sort(&tb
->parts
, cmp_parts_wrapper
, (void *) cmp
);
338 /* allocates a new freespace description */
339 static int new_freespace(struct fdisk_context
*cxt
,
342 struct fdisk_partition
*parent
,
343 struct fdisk_partition
**pa
)
352 *pa
= fdisk_new_partition();
356 (*pa
)->freespace
= 1;
357 (*pa
)->start
= fdisk_align_lba_in_range(cxt
, start
, start
, end
);
359 (*pa
)->size
= (*pa
)->end
- (*pa
)->start
+ 1ULL;
362 (*pa
)->parent_partno
= parent
->partno
;
366 /* add freespace description to the right place within @tb */
367 static int table_add_freespace(
368 struct fdisk_context
*cxt
,
369 struct fdisk_table
*tb
,
372 struct fdisk_partition
*parent
)
374 struct fdisk_partition
*pa
, *x
, *real_parent
= NULL
, *best
= NULL
;
375 struct fdisk_iter itr
;
380 rc
= new_freespace(cxt
, start
, end
, parent
, &pa
);
385 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
387 while (fdisk_table_next_partition(tb
, &itr
, &x
) == 0) {
388 if (x
->partno
== parent
->partno
) {
394 DBG(TAB
, ul_debugobj(tb
, "not found freespace parent (partno=%zu)",
396 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
400 while (fdisk_table_next_partition(tb
, &itr
, &x
) == 0) {
401 if (x
->end
< pa
->start
&& (!best
|| best
->end
< x
->end
))
405 if (!best
&& real_parent
)
407 rc
= table_insert_partition(tb
, best
, pa
);
409 fdisk_unref_partition(pa
);
413 /* analyze @cont(ainer) in @parts and add all detected freespace into @tb, note
414 * that @parts has to be sorted by partition starts */
415 static int check_container_freespace(struct fdisk_context
*cxt
,
416 struct fdisk_table
*parts
,
417 struct fdisk_table
*tb
,
418 struct fdisk_partition
*cont
)
420 struct fdisk_iter itr
;
421 struct fdisk_partition
*pa
;
422 uint64_t x
, last
, grain
;
423 uint64_t lastplusoff
;
431 last
= fdisk_partition_get_start(cont
);
432 grain
= cxt
->grain
> cxt
->sector_size
? cxt
->grain
/ cxt
->sector_size
: 1;
433 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
435 while (fdisk_table_next_partition(parts
, &itr
, &pa
) == 0) {
436 if (!pa
->used
|| !fdisk_partition_is_nested(pa
))
439 lastplusoff
= last
+ cxt
->first_lba
;
440 if (pa
->start
> lastplusoff
&& pa
->start
- lastplusoff
> grain
)
441 rc
= table_add_freespace(cxt
, tb
, lastplusoff
, pa
->start
, cont
);
447 /* free-space remaining in extended partition */
448 x
= fdisk_partition_get_start(cont
) + fdisk_partition_get_size(cont
) - 1;
449 lastplusoff
= last
+ cxt
->first_lba
;
450 if (lastplusoff
< x
&& x
- lastplusoff
> grain
)
451 rc
= table_add_freespace(cxt
, tb
, lastplusoff
, x
, cont
);
457 * fdisk_get_freespaces
458 * @cxt: fdisk context
461 * This function adds freespace (described by fdisk_partition) to @table, it
462 * allocates a new table if the @table points to NULL.
464 * Note that free space smaller than grain (see fdisk_topology_get_grain()) is
467 * Returns 0 on success, otherwise, a corresponding error.
469 int fdisk_get_freespaces(struct fdisk_context
*cxt
, struct fdisk_table
**tb
)
472 uint64_t last
, grain
;
473 struct fdisk_table
*parts
= NULL
;
474 struct fdisk_partition
*pa
;
475 struct fdisk_iter itr
;
477 DBG(CXT
, ul_debugobj(cxt
, "get freespace"));
479 if (!cxt
|| !cxt
->label
|| !tb
)
481 if (!*tb
&& !(*tb
= fdisk_new_table()))
484 rc
= fdisk_get_partitions(cxt
, &parts
);
487 fdisk_table_sort_partitions(parts
, fdisk_partition_cmp_start
);
488 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
489 last
= cxt
->first_lba
;
490 grain
= cxt
->grain
> cxt
->sector_size
? cxt
->grain
/ cxt
->sector_size
: 1;
492 /* analyze gaps between partitions */
493 while (rc
== 0 && fdisk_table_next_partition(parts
, &itr
, &pa
) == 0) {
494 if (!pa
->used
|| pa
->wholedisk
|| fdisk_partition_is_nested(pa
))
496 DBG(CXT
, ul_debugobj(cxt
, "freespace analyze: partno=%zu, start=%ju, end=%ju",
497 pa
->partno
, pa
->start
, pa
->end
));
498 if (last
+ grain
<= pa
->start
) {
499 rc
= table_add_freespace(cxt
, *tb
,
500 last
+ (last
> cxt
->first_lba
? 1 : 0),
501 pa
->start
- 1, NULL
);
503 /* add gaps between logical partitions */
504 if (fdisk_partition_is_container(pa
))
505 rc
= check_container_freespace(cxt
, parts
, *tb
, pa
);
509 /* add free-space behind last partition to the end of the table (so
510 * don't use table_add_freespace()) */
511 if (rc
== 0 && last
+ grain
< cxt
->total_sectors
- 1) {
512 rc
= new_freespace(cxt
,
513 last
+ (last
> cxt
->first_lba
? 1 : 0),
514 cxt
->last_lba
, NULL
, &pa
);
516 fdisk_table_add_partition(*tb
, pa
);
517 fdisk_unref_partition(pa
);
521 DBG(LABEL
, fdisk_dump_table(*tb
, stderr
));
523 fdisk_unref_table(parts
);
528 * fdisk_table_wrong_order:
531 * Returns: 1 of the table is not in disk order
533 int fdisk_table_wrong_order(struct fdisk_table
*tb
)
535 struct fdisk_partition
*pa
;
536 struct fdisk_iter itr
;
539 DBG(TAB
, ul_debugobj(tb
, "wrong older check"));
541 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
542 while (tb
&& fdisk_table_next_partition(tb
, &itr
, &pa
) == 0) {
543 if (pa
->start
< last
)