]>
Commit | Line | Data |
---|---|---|
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 | */ | |
23 | struct 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 | */ | |
47 | int 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 | */ |
70 | void 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 | */ |
83 | void 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 | */ | |
103 | int 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 | 114 | size_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 | */ | |
136 | int 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 |
164 | struct 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 | */ | |
192 | struct 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 | */ | |
223 | int 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 */ |
247 | static 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 | */ | |
285 | int 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 | */ |
310 | int 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 | 337 | void 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 |
356 | typedef int (*fdisk_partcmp_t)(struct fdisk_partition *, struct fdisk_partition *); |
357 | ||
358 | static 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 |
378 | int 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 */ |
401 | static 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 | 443 | static 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 */ | |
510 | static 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 | ||
565 | done: | |
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 | 584 | int 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 |
662 | done: |
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 | */ | |
675 | int 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 | */ | |
706 | int 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 |
729 | int 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 |