]>
Commit | Line | Data |
---|---|---|
b48cdebc KZ |
1 | |
2 | #include "fdiskP.h" | |
3 | ||
4 | /** | |
5 | * fdisk_new_table: | |
6 | * | |
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 | |
9 | * real on-disk data. | |
10 | * | |
11 | * Returns: newly allocated table struct. | |
12 | */ | |
13 | struct fdisk_table *fdisk_new_table(void) | |
14 | { | |
15 | struct fdisk_table *tb = NULL; | |
16 | ||
17 | tb = calloc(1, sizeof(*tb)); | |
18 | if (!tb) | |
19 | return NULL; | |
20 | ||
21 | DBG(TAB, dbgprint("alloc")); | |
22 | tb->refcount = 1; | |
23 | INIT_LIST_HEAD(&tb->parts); | |
24 | return tb; | |
25 | } | |
26 | ||
27 | /** | |
28 | * fdisk_reset_table: | |
29 | * @tb: tab pointer | |
30 | * | |
31 | * Removes all entries (filesystems) from the table. The filesystems with zero | |
32 | * reference count will be deallocated. | |
33 | * | |
34 | * Returns: 0 on success or negative number in case of error. | |
35 | */ | |
36 | int fdisk_reset_table(struct fdisk_table *tb) | |
37 | { | |
38 | if (!tb) | |
39 | return -EINVAL; | |
40 | ||
41 | DBG(TAB, dbgprint("reset")); | |
42 | ||
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); | |
47 | } | |
48 | ||
04406c0d | 49 | tb->nents = 0; |
b48cdebc KZ |
50 | return 0; |
51 | } | |
52 | ||
53 | /** | |
54 | * fdisk_ref_table: | |
55 | * @tb: table pointer | |
56 | * | |
57 | * Incremparts reference counter. | |
58 | */ | |
59 | void fdisk_ref_table(struct fdisk_table *tb) | |
60 | { | |
61 | if (tb) | |
62 | tb->refcount++; | |
63 | } | |
64 | ||
65 | /** | |
66 | * fdisk_unref_table: | |
67 | * @tb: table pointer | |
68 | * | |
69 | * De-incremparts reference counter, on zero the @tb is automatically | |
70 | * deallocated by fdisk_free_table(). | |
71 | */ | |
72 | void fdisk_unref_table(struct fdisk_table *tb) | |
73 | { | |
74 | if (!tb) | |
75 | return; | |
76 | ||
77 | tb->refcount--; | |
78 | if (tb->refcount <= 0) { | |
79 | fdisk_reset_table(tb); | |
80 | ||
81 | DBG(TAB, dbgprint("free")); | |
82 | free(tb); | |
83 | } | |
84 | } | |
85 | ||
86 | /** | |
87 | * fdisk_table_is_empty: | |
88 | * @tb: pointer to tab | |
89 | * | |
90 | * Returns: 1 if the table is without filesystems, or 0. | |
91 | */ | |
92 | int fdisk_table_is_empty(struct fdisk_table *tb) | |
93 | { | |
94 | assert(tb); | |
95 | return tb == NULL || list_empty(&tb->parts) ? 1 : 0; | |
96 | } | |
97 | ||
04406c0d KZ |
98 | /** |
99 | * fdisk_table_get_nents: | |
100 | * @tb: pointer to tab | |
101 | * | |
102 | * Returns: number of entries in table. | |
103 | */ | |
104 | int fdisk_table_get_nents(struct fdisk_table *tb) | |
105 | { | |
106 | return tb ? tb->nents : 0; | |
107 | } | |
6c89f750 KZ |
108 | |
109 | /** | |
110 | * fdisk_table_next_partition: | |
111 | * @tb: tab pointer | |
112 | * @itr: iterator | |
113 | * @pa: returns the next tab entry | |
114 | * | |
115 | * Returns: 0 on success, negative number in case of error or 1 at the end of list. | |
116 | * | |
117 | * Example: | |
118 | * <informalexample> | |
119 | * <programlisting> | |
120 | * while(fdisk_table_next_partition(tb, itr, &pa) == 0) { | |
121 | * ... | |
122 | * } | |
123 | * </programlisting> | |
124 | * </informalexample> | |
125 | */ | |
126 | int fdisk_table_next_partition( | |
127 | struct fdisk_table *tb, | |
128 | struct fdisk_iter *itr, | |
129 | struct fdisk_partition **pa) | |
130 | { | |
131 | int rc = 1; | |
132 | ||
133 | assert(tb); | |
134 | assert(itr); | |
135 | assert(pa); | |
136 | ||
137 | if (!tb || !itr || !pa) | |
138 | return -EINVAL; | |
139 | *pa = NULL; | |
140 | ||
141 | if (!itr->head) | |
142 | FDISK_ITER_INIT(itr, &tb->parts); | |
143 | if (itr->p != itr->head) { | |
144 | FDISK_ITER_ITERATE(itr, *pa, struct fdisk_partition, parts); | |
145 | rc = 0; | |
146 | } | |
147 | ||
148 | return rc; | |
149 | } | |
150 | ||
28b6a23c KZ |
151 | struct fdisk_partition *fdisk_table_get_partition( |
152 | struct fdisk_table *tb, | |
153 | size_t n) | |
154 | { | |
155 | struct fdisk_partition *pa = NULL; | |
156 | struct fdisk_iter itr; | |
157 | ||
158 | if (!tb) | |
159 | return NULL; | |
160 | ||
161 | fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); | |
162 | ||
163 | while (fdisk_table_next_partition(tb, &itr, &pa) == 0) { | |
164 | if (n == 0) | |
165 | return pa; | |
166 | n--; | |
167 | } | |
168 | ||
169 | return NULL; | |
170 | } | |
171 | ||
b48cdebc KZ |
172 | /** |
173 | * fdisk_table_add_partition | |
174 | * @tb: tab pointer | |
175 | * @pa: new entry | |
176 | * | |
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. | |
180 | * | |
181 | * Returns: 0 on success or negative number in case of error. | |
182 | */ | |
183 | int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa) | |
184 | { | |
185 | assert(tb); | |
186 | assert(pa); | |
187 | ||
188 | if (!tb || !pa) | |
189 | return -EINVAL; | |
190 | ||
191 | fdisk_ref_partition(pa); | |
192 | list_add_tail(&pa->parts, &tb->parts); | |
04406c0d | 193 | tb->nents++; |
b48cdebc | 194 | |
81c29a73 KZ |
195 | DBG(TAB, dbgprint("add entry %p [start=%ju, end=%ju, size=%ju, freespace=%s]", |
196 | pa, pa->start, pa->end, pa->size, | |
6c89f750 | 197 | pa->freespace ? "yes" : "no")); |
b48cdebc KZ |
198 | return 0; |
199 | } | |
200 | ||
2cec7949 KZ |
201 | /* inserts @pa after @poz */ |
202 | static int table_insert_partition( | |
203 | struct fdisk_table *tb, | |
204 | struct fdisk_partition *poz, | |
205 | struct fdisk_partition *pa) | |
206 | { | |
207 | assert(tb); | |
208 | assert(pa); | |
209 | ||
210 | fdisk_ref_partition(pa); | |
211 | if (poz) | |
212 | list_add(&pa->parts, &poz->parts); | |
213 | else | |
214 | list_add(&pa->parts, &tb->parts); | |
215 | tb->nents++; | |
216 | ||
217 | DBG(TAB, dbgprint("insert entry %p [start=%ju, end=%ju, size=%ju, freespace=%s]", | |
218 | pa, pa->start, pa->end, pa->size, | |
219 | pa->freespace ? "yes" : "no")); | |
220 | return 0; | |
221 | } | |
222 | ||
b48cdebc KZ |
223 | /** |
224 | * fdisk_table_remove_partition | |
225 | * @tb: tab pointer | |
226 | * @pa: new entry | |
227 | * | |
228 | * Removes the @pa from the table and de-increment reference counter of the @pa. The | |
229 | * partition with zero reference counter will be deallocated. Don't forget to use | |
230 | * fdisk_ref_partition() before call fdisk_table_remove_partition() if you want | |
231 | * to use @pa later. | |
232 | * | |
233 | * Returns: 0 on success or negative number in case of error. | |
234 | */ | |
235 | int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa) | |
236 | { | |
237 | assert(tb); | |
238 | assert(pa); | |
239 | ||
240 | if (!tb || !pa) | |
241 | return -EINVAL; | |
242 | ||
243 | DBG(TAB, dbgprint("remove entry %p", pa)); | |
244 | list_del(&pa->parts); | |
245 | INIT_LIST_HEAD(&pa->parts); | |
246 | ||
247 | fdisk_unref_partition(pa); | |
04406c0d KZ |
248 | tb->nents--; |
249 | ||
b48cdebc KZ |
250 | return 0; |
251 | } | |
6c89f750 | 252 | |
2cec7949 KZ |
253 | /** |
254 | * fdisk_get_partitions | |
255 | * @cxt: fdisk context | |
256 | * @tb: returns table | |
257 | * | |
258 | * This function adds partitions from disklabel to @table, it allocates a new | |
259 | * table if if @table points to NULL. | |
260 | * | |
261 | * Returns 0 on success, otherwise, a corresponding error. | |
262 | */ | |
263 | int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb) | |
264 | { | |
265 | size_t i; | |
266 | ||
267 | if (!cxt || !cxt->label || !tb) | |
268 | return -EINVAL; | |
269 | if (!cxt->label->op->get_part) | |
270 | return -ENOSYS; | |
271 | ||
272 | DBG(LABEL, dbgprint("get table")); | |
273 | ||
274 | if (!*tb && !(*tb = fdisk_new_table())) | |
275 | return -ENOMEM; | |
276 | ||
277 | for (i = 0; i < cxt->label->nparts_max; i++) { | |
278 | struct fdisk_partition *pa = NULL; | |
279 | ||
280 | if (fdisk_get_partition(cxt, i, &pa) != 0) | |
281 | continue; | |
282 | if (fdisk_partition_is_used(pa)) | |
283 | fdisk_table_add_partition(*tb, pa); | |
284 | fdisk_unref_partition(pa); | |
285 | } | |
286 | ||
287 | return 0; | |
288 | } | |
289 | ||
290 | int fdisk_table_add_freespace( | |
81c29a73 | 291 | struct fdisk_context *cxt, |
6c89f750 KZ |
292 | struct fdisk_table *tb, |
293 | uint64_t start, | |
2cec7949 KZ |
294 | uint64_t end, |
295 | int dosort) | |
6c89f750 KZ |
296 | { |
297 | struct fdisk_partition *pa = fdisk_new_partition(); | |
2cec7949 | 298 | int rc = 0; |
6c89f750 KZ |
299 | |
300 | assert(tb); | |
301 | ||
2cec7949 KZ |
302 | if (!pa) |
303 | return -ENOMEM; | |
6c89f750 | 304 | pa->freespace = 1; |
81c29a73 | 305 | pa->start = fdisk_align_lba_in_range(cxt, start, start, end); |
6c89f750 KZ |
306 | pa->end = end; |
307 | pa->size = pa->end - pa->start + 1ULL; | |
308 | ||
2cec7949 KZ |
309 | if (!dosort) |
310 | rc = fdisk_table_add_partition(tb, pa); | |
311 | else { | |
312 | struct fdisk_partition *x, *best = NULL; | |
313 | struct fdisk_iter itr; | |
314 | ||
315 | fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); | |
316 | while (fdisk_table_next_partition(tb, &itr, &x) == 0) { | |
317 | if (x->end < pa->start && (!best || best->end < x->end)) | |
318 | best = x; | |
319 | } | |
320 | rc = table_insert_partition(tb, best, pa); | |
321 | } | |
6c89f750 KZ |
322 | fdisk_unref_partition(pa); |
323 | return rc; | |
324 | } | |
2cec7949 KZ |
325 | |
326 | ||
6c89f750 | 327 | /** |
2cec7949 | 328 | * fdisk_get_freespaces |
6c89f750 | 329 | * @cxt: fdisk context |
2cec7949 | 330 | * @tb: returns table |
6c89f750 | 331 | * |
2cec7949 KZ |
332 | * This function adds freespace (described by fdisk_partition) to @table, it |
333 | * allocates a new table if if @table points to NULL. | |
334 | ||
6c89f750 KZ |
335 | * Returns 0 on success, otherwise, a corresponding error. |
336 | */ | |
2cec7949 | 337 | int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb) |
6c89f750 | 338 | { |
2cec7949 | 339 | int dosort, rc = 0; |
6c89f750 KZ |
340 | size_t i; |
341 | uint64_t last, grain; | |
342 | ||
2cec7949 KZ |
343 | DBG(LABEL, dbgprint("get freespace")); |
344 | ||
6c89f750 KZ |
345 | if (!cxt || !cxt->label || !tb) |
346 | return -EINVAL; | |
2cec7949 KZ |
347 | if (!*tb && !(*tb = fdisk_new_table())) |
348 | return -ENOMEM; | |
6c89f750 | 349 | |
2cec7949 KZ |
350 | /* label specific way */ |
351 | if (cxt->label->op->get_freespace) | |
352 | return cxt->label->op->get_freespace(cxt, *tb); | |
6c89f750 | 353 | |
2cec7949 KZ |
354 | /* generic way -- check for gaps betten partitions */ |
355 | dosort = !fdisk_table_is_empty(*tb); | |
6c89f750 KZ |
356 | last = cxt->first_lba; |
357 | grain = cxt->grain / cxt->sector_size; | |
358 | ||
2cec7949 KZ |
359 | for (i = 0; rc == 0 && i < cxt->label->nparts_max; i++) { |
360 | struct fdisk_partition *pa = NULL; | |
361 | ||
6c89f750 KZ |
362 | if (fdisk_get_partition(cxt, i, &pa)) |
363 | continue; | |
2cec7949 KZ |
364 | if (!fdisk_partition_is_used(pa)) { |
365 | fdisk_unref_partition(pa); | |
6c89f750 | 366 | continue; |
2cec7949 | 367 | } |
6c89f750 KZ |
368 | |
369 | /* add free-space (before partition) to the list */ | |
2cec7949 KZ |
370 | if (last + grain < pa->start) { |
371 | rc = fdisk_table_add_freespace(cxt, *tb, | |
6c89f750 | 372 | last + (last > cxt->first_lba ? 1 : 0), |
2cec7949 KZ |
373 | pa->start - 1, |
374 | dosort); | |
6c89f750 | 375 | } |
2cec7949 | 376 | |
6c89f750 | 377 | last = pa->end; |
6c89f750 | 378 | fdisk_unref_partition(pa); |
6c89f750 KZ |
379 | } |
380 | ||
381 | /* add free-space (behind last partition) to the list */ | |
2cec7949 KZ |
382 | if (rc == 0 && last + grain < cxt->total_sectors - 1) |
383 | rc = fdisk_table_add_freespace(cxt, *tb, | |
6c89f750 | 384 | last + (last > cxt->first_lba ? 1 : 0), |
2cec7949 KZ |
385 | cxt->last_lba, |
386 | dosort); | |
387 | return rc; | |
6c89f750 KZ |
388 | } |
389 | ||
390 | /** | |
391 | * fdisk_table_to_string | |
392 | * @tb: table | |
393 | * @cxt: fdisk context | |
394 | * @cols: array with wanted FDISK_COL_* columns | |
395 | * @ncols: number of items in the cols array | |
849968b9 | 396 | * @data: returns table as a newlly allocated string or NULL for empty PT |
6c89f750 KZ |
397 | * |
398 | * If no @cols are specified then the default is printed (see | |
399 | * fdisk_get_columns() for the default columns). | |
400 | ||
401 | * Returns 0 on success, otherwise, a corresponding error. | |
402 | */ | |
403 | int fdisk_table_to_string(struct fdisk_table *tb, | |
404 | struct fdisk_context *cxt, | |
405 | int *cols, | |
406 | size_t ncols, | |
407 | char **data) | |
408 | { | |
409 | int *org_cols = cols, rc = 0; | |
410 | struct tt *tt = NULL; | |
411 | const struct fdisk_column *col; | |
412 | struct fdisk_partition *pa = NULL; | |
413 | struct fdisk_iter itr; | |
414 | size_t j; | |
415 | ||
416 | if (!cxt || !tb || !data) | |
417 | return -EINVAL; | |
418 | ||
419 | DBG(TAB, dbgprint("generate string")); | |
849968b9 KZ |
420 | *data = NULL; |
421 | ||
422 | if (!fdisk_table_get_nents(tb)) | |
423 | return 0; | |
6c89f750 KZ |
424 | |
425 | if (!cols || !ncols) { | |
426 | rc = fdisk_get_columns(cxt, 0, &cols, &ncols); | |
427 | if (rc) | |
428 | return rc; | |
429 | } | |
430 | ||
431 | tt = tt_new_table(TT_FL_FREEDATA); | |
432 | if (!tt) { | |
433 | rc = -ENOMEM; | |
434 | goto done; | |
435 | } | |
436 | ||
437 | /* define columns */ | |
438 | for (j = 0; j < ncols; j++) { | |
439 | col = fdisk_label_get_column(cxt->label, cols[j]); | |
d0059a24 KZ |
440 | if (col) |
441 | tt_define_column(tt, col->name, col->width, col->tt_flags); | |
6c89f750 KZ |
442 | } |
443 | ||
444 | fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); | |
445 | ||
446 | /* convert partition to string and add to tt */ | |
447 | while (fdisk_table_next_partition(tb, &itr, &pa) == 0) { | |
448 | struct tt_line *ln = tt_add_line(tt, NULL); | |
449 | if (!ln) { | |
450 | rc = -ENOMEM; | |
451 | goto done; | |
452 | } | |
453 | ||
454 | DBG(TAB, dbgprint(" string from part #%zu", pa->partno + 1)); | |
455 | ||
456 | /* set data for the columns */ | |
457 | for (j = 0; j < ncols; j++) { | |
6c89f750 | 458 | char *cdata = NULL; |
6c89f750 KZ |
459 | |
460 | col = fdisk_label_get_column(cxt->label, cols[j]); | |
461 | if (!col) | |
462 | continue; | |
9f7fdeaf | 463 | if (fdisk_partition_to_string(pa, cxt, col->id, &cdata)) |
6c89f750 KZ |
464 | continue; |
465 | tt_line_set_data(ln, j, cdata); | |
466 | } | |
467 | } | |
468 | ||
469 | rc = 0; | |
6c89f750 KZ |
470 | if (!tt_is_empty(tt)) |
471 | rc = tt_print_table_to_string(tt, data); | |
472 | else | |
473 | DBG(TAB, dbgprint("tt empty")); | |
474 | done: | |
475 | if (org_cols != cols) | |
476 | free(cols); | |
477 | tt_free_table(tt); | |
478 | return rc; | |
479 | } |