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=%ju)",
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
;
430 last
= fdisk_partition_get_start(cont
) + cxt
->first_lba
;
431 grain
= cxt
->grain
> cxt
->sector_size
? cxt
->grain
/ cxt
->sector_size
: 1;
432 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
434 while (fdisk_table_next_partition(parts
, &itr
, &pa
) == 0) {
436 if (!pa
->used
|| !fdisk_partition_is_nested(pa
))
438 lastfree
= pa
->start
- 1 - cxt
->first_lba
;
439 if (last
+ grain
< lastfree
)
440 rc
= table_add_freespace(cxt
, tb
, last
+ grain
, lastfree
, cont
);
446 /* free-space remaining in extended partition */
447 x
= fdisk_partition_get_start(cont
) + fdisk_partition_get_size(cont
) - 1;
448 if (last
+ grain
< x
)
449 rc
= table_add_freespace(cxt
, tb
, last
+ grain
, x
- 1, cont
);
455 * fdisk_get_freespaces
456 * @cxt: fdisk context
459 * This function adds freespace (described by fdisk_partition) to @table, it
460 * allocates a new table if the @table points to NULL.
462 * Returns 0 on success, otherwise, a corresponding error.
464 int fdisk_get_freespaces(struct fdisk_context
*cxt
, struct fdisk_table
**tb
)
467 uint64_t last
, grain
;
468 struct fdisk_table
*parts
= NULL
;
469 struct fdisk_partition
*pa
;
470 struct fdisk_iter itr
;
472 DBG(CXT
, ul_debugobj(cxt
, "get freespace"));
474 if (!cxt
|| !cxt
->label
|| !tb
)
476 if (!*tb
&& !(*tb
= fdisk_new_table()))
479 rc
= fdisk_get_partitions(cxt
, &parts
);
482 fdisk_table_sort_partitions(parts
, fdisk_partition_cmp_start
);
483 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
484 last
= cxt
->first_lba
;
485 grain
= cxt
->grain
> cxt
->sector_size
? cxt
->grain
/ cxt
->sector_size
: 1;
487 /* analyze gaps between partitions */
488 while (rc
== 0 && fdisk_table_next_partition(parts
, &itr
, &pa
) == 0) {
489 if (!pa
->used
|| pa
->wholedisk
|| fdisk_partition_is_nested(pa
))
491 DBG(CXT
, ul_debugobj(cxt
, "freespace analyze: partno=%zu, start=%ju, end=%ju",
492 pa
->partno
, pa
->start
, pa
->end
));
493 if (last
+ grain
< pa
->start
) {
494 rc
= table_add_freespace(cxt
, *tb
,
495 last
+ (last
> cxt
->first_lba
? 1 : 0),
496 pa
->start
- 1, NULL
);
498 /* add gaps between logical partitions */
499 if (fdisk_partition_is_container(pa
))
500 rc
= check_container_freespace(cxt
, parts
, *tb
, pa
);
504 /* add free-space behind last partition to the end of the table (so
505 * don't use table_add_freespace()) */
506 if (rc
== 0 && last
+ grain
< cxt
->total_sectors
- 1) {
507 rc
= new_freespace(cxt
,
508 last
+ (last
> cxt
->first_lba
? 1 : 0),
509 cxt
->last_lba
, NULL
, &pa
);
511 fdisk_table_add_partition(*tb
, pa
);
512 fdisk_unref_partition(pa
);
516 DBG(LABEL
, fdisk_dump_table(*tb
, stderr
));
518 fdisk_unref_table(parts
);
523 * fdisk_table_to_string
525 * @cxt: fdisk context
526 * @cols: array with wanted FDISK_COL_* columns
527 * @ncols: number of items in the cols array
528 * @data: returns table as a newlly allocated string or NULL for empty PT
530 * If no @cols are specified then the default is printed (see
531 * fdisk_get_columns() for the default columns).
533 * Returns 0 on success, otherwise, a corresponding error.
535 int fdisk_table_to_string(struct fdisk_table
*tb
,
536 struct fdisk_context
*cxt
,
541 int *org_cols
= cols
, rc
= 0;
542 struct tt
*tt
= NULL
;
543 const struct fdisk_column
*col
;
544 struct fdisk_partition
*pa
= NULL
;
545 struct fdisk_iter itr
;
548 if (!cxt
|| !tb
|| !data
)
551 DBG(TAB
, ul_debugobj(tb
, "generate string"));
554 if (!fdisk_table_get_nents(tb
))
557 if (!cols
|| !ncols
) {
558 rc
= fdisk_get_columns(cxt
, 0, &cols
, &ncols
);
563 tt
= tt_new_table(TT_FL_FREEDATA
);
570 for (j
= 0; j
< ncols
; j
++) {
571 col
= fdisk_label_get_column(cxt
->label
, cols
[j
]);
573 tt_define_column(tt
, col
->name
, col
->width
, col
->tt_flags
);
576 fdisk_reset_iter(&itr
, FDISK_ITER_FORWARD
);
578 /* convert partition to string and add to tt */
579 while (fdisk_table_next_partition(tb
, &itr
, &pa
) == 0) {
580 struct tt_line
*ln
= tt_add_line(tt
, NULL
);
586 DBG(TAB
, ul_debugobj(tb
, " string from part #%zu [%p]",
587 pa
->partno
+ 1, pa
));
589 /* set data for the columns */
590 for (j
= 0; j
< ncols
; j
++) {
593 col
= fdisk_label_get_column(cxt
->label
, cols
[j
]);
596 if (fdisk_partition_to_string(pa
, cxt
, col
->id
, &cdata
))
598 tt_line_set_data(ln
, j
, cdata
);
603 if (!tt_is_empty(tt
))
604 rc
= tt_print_table_to_string(tt
, data
);
606 DBG(TAB
, ul_debugobj(tb
, "tt empty"));
608 if (org_cols
!= cols
)