/src/util-linux/libfdisk/src/partition.c
Line | Count | Source |
1 | | |
2 | | #include "c.h" |
3 | | #include "strutils.h" |
4 | | |
5 | | #ifdef HAVE_LIBBLKID |
6 | | # include <blkid.h> |
7 | | #endif |
8 | | |
9 | | #include "fdiskP.h" |
10 | | |
11 | | /** |
12 | | * SECTION: partition |
13 | | * @title: Partition |
14 | | * @short_description: generic label independent partition abstraction |
15 | | * |
16 | | * The fdisk_partition provides label independent abstraction. The partitions |
17 | | * are not directly connected with partition table (label) data. Any change to |
18 | | * fdisk_partition does not affects in-memory or on-disk label data. |
19 | | * |
20 | | * The fdisk_partition is possible to use as a template for |
21 | | * fdisk_add_partition() or fdisk_set_partition() operations. |
22 | | */ |
23 | | |
24 | | static void init_partition(struct fdisk_partition *pa) |
25 | 39.2k | { |
26 | 39.2k | FDISK_INIT_UNDEF(pa->size); |
27 | 39.2k | FDISK_INIT_UNDEF(pa->start); |
28 | 39.2k | FDISK_INIT_UNDEF(pa->partno); |
29 | 39.2k | FDISK_INIT_UNDEF(pa->parent_partno); |
30 | 39.2k | FDISK_INIT_UNDEF(pa->boot); |
31 | | |
32 | 39.2k | INIT_LIST_HEAD(&pa->parts); |
33 | 39.2k | } |
34 | | |
35 | | /** |
36 | | * fdisk_new_partition: |
37 | | * |
38 | | * Returns: new instance. |
39 | | */ |
40 | | struct fdisk_partition *fdisk_new_partition(void) |
41 | 19.6k | { |
42 | 19.6k | struct fdisk_partition *pa = calloc(1, sizeof(*pa)); |
43 | 19.6k | if (!pa) |
44 | 0 | return NULL; |
45 | | |
46 | 19.6k | pa->refcount = 1; |
47 | 19.6k | init_partition(pa); |
48 | 19.6k | DBG(PART, ul_debugobj(pa, "alloc")); |
49 | 19.6k | return pa; |
50 | 19.6k | } |
51 | | |
52 | | /** |
53 | | * fdisk_reset_partition: |
54 | | * @pa: partition |
55 | | * |
56 | | * Resets partition content. |
57 | | */ |
58 | | void fdisk_reset_partition(struct fdisk_partition *pa) |
59 | 19.6k | { |
60 | 19.6k | int ref; |
61 | | |
62 | 19.6k | if (!pa) |
63 | 0 | return; |
64 | | |
65 | 19.6k | DBG(PART, ul_debugobj(pa, "reset")); |
66 | 19.6k | ref = pa->refcount; |
67 | | |
68 | 19.6k | fdisk_unref_parttype(pa->type); |
69 | 19.6k | free(pa->name); |
70 | 19.6k | free(pa->uuid); |
71 | 19.6k | free(pa->attrs); |
72 | 19.6k | free(pa->fstype); |
73 | 19.6k | free(pa->fsuuid); |
74 | 19.6k | free(pa->fslabel); |
75 | 19.6k | free(pa->start_chs); |
76 | 19.6k | free(pa->end_chs); |
77 | | |
78 | 19.6k | memset(pa, 0, sizeof(*pa)); |
79 | 19.6k | pa->refcount = ref; |
80 | | |
81 | 19.6k | init_partition(pa); |
82 | 19.6k | } |
83 | | |
84 | | static struct fdisk_partition *__copy_partition(struct fdisk_partition *o) |
85 | 0 | { |
86 | 0 | struct fdisk_partition *n = fdisk_new_partition(); |
87 | 0 | int rc; |
88 | |
|
89 | 0 | if (!n) |
90 | 0 | return NULL; |
91 | | |
92 | 0 | memcpy(n, o, sizeof(*n)); |
93 | | |
94 | | /* do not copy reference to lists, etc.*/ |
95 | 0 | n->refcount = 1; |
96 | 0 | INIT_LIST_HEAD(&n->parts); |
97 | |
|
98 | 0 | if (n->type) |
99 | 0 | fdisk_ref_parttype(n->type); |
100 | | |
101 | | /* note that strdup_between_structs() deallocates destination pointer, |
102 | | * so make sure it's NULL as we call memcpy() before ... */ |
103 | 0 | n->name = NULL; |
104 | 0 | rc = strdup_between_structs(n, o, name); |
105 | |
|
106 | 0 | n->uuid = NULL; |
107 | 0 | if (!rc) |
108 | 0 | rc = strdup_between_structs(n, o, uuid); |
109 | 0 | n->attrs = NULL; |
110 | 0 | if (!rc) |
111 | 0 | rc = strdup_between_structs(n, o, attrs); |
112 | 0 | n->fstype = NULL; |
113 | 0 | if (!rc) |
114 | 0 | rc = strdup_between_structs(n, o, fstype); |
115 | 0 | n->fsuuid = NULL; |
116 | 0 | if (!rc) |
117 | 0 | rc = strdup_between_structs(n, o, fsuuid); |
118 | 0 | n->fslabel = NULL; |
119 | 0 | if (!rc) |
120 | 0 | rc = strdup_between_structs(n, o, fslabel); |
121 | 0 | n->start_chs = NULL; |
122 | 0 | if (!rc) |
123 | 0 | rc = strdup_between_structs(n, o, start_chs); |
124 | 0 | n->end_chs = NULL; |
125 | 0 | if (!rc) |
126 | 0 | rc = strdup_between_structs(n, o, end_chs); |
127 | |
|
128 | 0 | if (rc) { |
129 | 0 | fdisk_unref_partition(n); |
130 | 0 | n = NULL; |
131 | 0 | } |
132 | 0 | return n; |
133 | 0 | } |
134 | | |
135 | | /** |
136 | | * fdisk_ref_partition: |
137 | | * @pa: partition pointer |
138 | | * |
139 | | * Increments reference counter. |
140 | | */ |
141 | | void fdisk_ref_partition(struct fdisk_partition *pa) |
142 | 18.2k | { |
143 | 18.2k | if (pa) |
144 | 18.2k | pa->refcount++; |
145 | 18.2k | } |
146 | | |
147 | | /** |
148 | | * fdisk_unref_partition: |
149 | | * @pa: partition pointer |
150 | | * |
151 | | * Decrements reference counter, on zero the @pa is automatically |
152 | | * deallocated. |
153 | | */ |
154 | | void fdisk_unref_partition(struct fdisk_partition *pa) |
155 | 37.9k | { |
156 | 37.9k | if (!pa) |
157 | 0 | return; |
158 | | |
159 | 37.9k | pa->refcount--; |
160 | 37.9k | if (pa->refcount <= 0) { |
161 | 19.6k | list_del(&pa->parts); |
162 | 19.6k | fdisk_reset_partition(pa); |
163 | 19.6k | DBG(PART, ul_debugobj(pa, "free")); |
164 | 19.6k | free(pa); |
165 | 19.6k | } |
166 | 37.9k | } |
167 | | |
168 | | /** |
169 | | * fdisk_partition_set_start: |
170 | | * @pa: partition |
171 | | * @off: offset in sectors, maximal is UINT64_MAX-1 |
172 | | * |
173 | | * Note that zero is valid offset too. Use fdisk_partition_unset_start() to |
174 | | * undefine the offset. |
175 | | * |
176 | | * Returns: 0 on success, <0 on error. |
177 | | */ |
178 | | int fdisk_partition_set_start(struct fdisk_partition *pa, fdisk_sector_t off) |
179 | 3.44k | { |
180 | 3.44k | if (!pa) |
181 | 0 | return -EINVAL; |
182 | 3.44k | if (FDISK_IS_UNDEF(off)) |
183 | 194 | return -ERANGE; |
184 | 3.25k | pa->start = off; |
185 | 3.25k | pa->fs_probed = 0; |
186 | 3.25k | return 0; |
187 | 3.44k | } |
188 | | |
189 | | /** |
190 | | * fdisk_partition_unset_start: |
191 | | * @pa: partition |
192 | | * |
193 | | * Sets the size as undefined. See fdisk_partition_has_start(). |
194 | | * |
195 | | * Returns: 0 on success, <0 on error. |
196 | | */ |
197 | | int fdisk_partition_unset_start(struct fdisk_partition *pa) |
198 | 0 | { |
199 | 0 | if (!pa) |
200 | 0 | return -EINVAL; |
201 | 0 | FDISK_INIT_UNDEF(pa->start); |
202 | 0 | pa->fs_probed = 0; |
203 | 0 | return 0; |
204 | 0 | } |
205 | | |
206 | | /** |
207 | | * fdisk_partition_get_start: |
208 | | * @pa: partition |
209 | | * |
210 | | * The zero is also valid offset. The function may return random undefined |
211 | | * value when start offset is undefined (for example after |
212 | | * fdisk_partition_unset_start()). Always use fdisk_partition_has_start() to be |
213 | | * sure that you work with valid numbers. |
214 | | * |
215 | | * Returns: start offset in sectors |
216 | | */ |
217 | | fdisk_sector_t fdisk_partition_get_start(struct fdisk_partition *pa) |
218 | 0 | { |
219 | 0 | return pa->start; |
220 | 0 | } |
221 | | |
222 | | /** |
223 | | * fdisk_partition_has_start: |
224 | | * @pa: partition |
225 | | * |
226 | | * Returns: 1 or 0 |
227 | | */ |
228 | | int fdisk_partition_has_start(struct fdisk_partition *pa) |
229 | 18.2k | { |
230 | 18.2k | return pa && !FDISK_IS_UNDEF(pa->start); |
231 | 18.2k | } |
232 | | |
233 | | |
234 | | /** |
235 | | * fdisk_partition_cmp_start: |
236 | | * @a: partition |
237 | | * @b: partition |
238 | | * |
239 | | * Compares partitions according to start offset, See fdisk_table_sort_partitions(). |
240 | | * |
241 | | * Return: 0 if the same, <0 if @b greater, >0 if @a greater. |
242 | | */ |
243 | | int fdisk_partition_cmp_start(struct fdisk_partition *a, |
244 | | struct fdisk_partition *b) |
245 | 0 | { |
246 | 0 | int no_a = FDISK_IS_UNDEF(a->start), |
247 | 0 | no_b = FDISK_IS_UNDEF(b->start); |
248 | |
|
249 | 0 | if (no_a && no_b) |
250 | 0 | return 0; |
251 | 0 | if (no_a) |
252 | 0 | return -1; |
253 | 0 | if (no_b) |
254 | 0 | return 1; |
255 | | |
256 | 0 | return cmp_numbers(a->start, b->start); |
257 | 0 | } |
258 | | |
259 | | /** |
260 | | * fdisk_partition_start_follow_default |
261 | | * @pa: partition |
262 | | * @enable: 0|1 |
263 | | * |
264 | | * When @pa is used as a template for fdisk_add_partition(), it follows the driver's default for |
265 | | * the beginning of the partition. For DOS, it is the first usable space, while for GPT, it is |
266 | | * the first sector of the largest area. |
267 | | * |
268 | | * Returns: 0 on success, <0 on error. |
269 | | */ |
270 | | int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable) |
271 | 34.3k | { |
272 | 34.3k | if (!pa) |
273 | 0 | return -EINVAL; |
274 | 34.3k | pa->start_follow_default = enable ? 1 : 0; |
275 | 34.3k | return 0; |
276 | 34.3k | } |
277 | | |
278 | | /** |
279 | | * fdisk_partition_start_is_default: |
280 | | * @pa: partition |
281 | | * |
282 | | * See fdisk_partition_start_follow_default(). |
283 | | * |
284 | | * Returns: 1 if the partition follows default |
285 | | */ |
286 | | int fdisk_partition_start_is_default(struct fdisk_partition *pa) |
287 | 0 | { |
288 | 0 | assert(pa); |
289 | 0 | return pa->start_follow_default; |
290 | 0 | } |
291 | | |
292 | | /** |
293 | | * fdisk_partition_set_size: |
294 | | * @pa: partition |
295 | | * @sz: size in sectors, maximal is UIN64_MAX-1 |
296 | | * |
297 | | * Note that zero is valid size too. Use fdisk_partition_unset_size() to |
298 | | * undefine the size. |
299 | | * |
300 | | * Returns: 0 on success, <0 on error. |
301 | | */ |
302 | | int fdisk_partition_set_size(struct fdisk_partition *pa, fdisk_sector_t sz) |
303 | 1.55k | { |
304 | 1.55k | if (!pa) |
305 | 0 | return -EINVAL; |
306 | 1.55k | if (FDISK_IS_UNDEF(sz)) |
307 | 194 | return -ERANGE; |
308 | 1.35k | pa->size = sz; |
309 | 1.35k | pa->fs_probed = 0; |
310 | 1.35k | return 0; |
311 | 1.55k | } |
312 | | |
313 | | /** |
314 | | * fdisk_partition_unset_size: |
315 | | * @pa: partition |
316 | | * |
317 | | * Sets the size as undefined. See fdisk_partition_has_size(). |
318 | | * |
319 | | * Returns: 0 on success, <0 on error. |
320 | | */ |
321 | | int fdisk_partition_unset_size(struct fdisk_partition *pa) |
322 | 0 | { |
323 | 0 | if (!pa) |
324 | 0 | return -EINVAL; |
325 | 0 | FDISK_INIT_UNDEF(pa->size); |
326 | 0 | pa->fs_probed = 0; |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |
330 | | /** |
331 | | * fdisk_partition_get_size: |
332 | | * @pa: partition |
333 | | * |
334 | | * The zero is also valid size. The function may return random undefined |
335 | | * value when size is undefined (for example after fdisk_partition_unset_size()). |
336 | | * Always use fdisk_partition_has_size() to be sure that you work with valid |
337 | | * numbers. |
338 | | * |
339 | | * Returns: size offset in sectors |
340 | | */ |
341 | | fdisk_sector_t fdisk_partition_get_size(struct fdisk_partition *pa) |
342 | 0 | { |
343 | 0 | return pa->size; |
344 | 0 | } |
345 | | |
346 | | /** |
347 | | * fdisk_partition_has_size: |
348 | | * @pa: partition |
349 | | * |
350 | | * Returns: 1 or 0 |
351 | | */ |
352 | | int fdisk_partition_has_size(struct fdisk_partition *pa) |
353 | 18.2k | { |
354 | 18.2k | return pa && !FDISK_IS_UNDEF(pa->size); |
355 | 18.2k | } |
356 | | |
357 | | /** |
358 | | * fdisk_partition_size_explicit: |
359 | | * @pa: partition |
360 | | * @enable: 0|1 |
361 | | * |
362 | | * By default libfdisk aligns the size when add the new partition (by |
363 | | * fdisk_add_partition()). If you want to disable this functionality use |
364 | | * @enable = 1. |
365 | | * |
366 | | * Returns: 0 on success, <0 on error. |
367 | | */ |
368 | | int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable) |
369 | 1.55k | { |
370 | 1.55k | if (!pa) |
371 | 0 | return -EINVAL; |
372 | 1.55k | pa->size_explicit = enable ? 1 : 0; |
373 | 1.55k | return 0; |
374 | 1.55k | } |
375 | | |
376 | | /** |
377 | | * fdisk_partition_set_partno: |
378 | | * @pa: partition |
379 | | * @num: partition number (0 is the first partition, maximal is SIZE_MAX-1) |
380 | | * |
381 | | * Note that zero is valid partno too. Use fdisk_partition_unset_partno() to |
382 | | * undefine the partno. |
383 | | * |
384 | | * Returns: 0 on success, <0 on error. |
385 | | */ |
386 | | int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num) |
387 | 432 | { |
388 | 432 | if (!pa) |
389 | 0 | return -EINVAL; |
390 | 432 | if (FDISK_IS_UNDEF(num)) |
391 | 0 | return -ERANGE; |
392 | 432 | pa->partno = num; |
393 | 432 | return 0; |
394 | 432 | } |
395 | | |
396 | | /** |
397 | | * fdisk_partition_unset_partno: |
398 | | * @pa: partition |
399 | | * |
400 | | * Sets the partno as undefined. See fdisk_partition_has_partno(). |
401 | | * |
402 | | * Returns: 0 on success, <0 on error. |
403 | | */ |
404 | | int fdisk_partition_unset_partno(struct fdisk_partition *pa) |
405 | 0 | { |
406 | 0 | if (!pa) |
407 | 0 | return -EINVAL; |
408 | 0 | FDISK_INIT_UNDEF(pa->partno); |
409 | 0 | return 0; |
410 | 0 | } |
411 | | |
412 | | /** |
413 | | * fdisk_partition_get_partno: |
414 | | * @pa: partition |
415 | | * |
416 | | * The zero is also valid partition number. The function may return random |
417 | | * value when partno is undefined (for example after fdisk_partition_unset_partno()). |
418 | | * Always use fdisk_partition_has_partno() to be sure that you work with valid |
419 | | * numbers. |
420 | | * |
421 | | * Returns: partition number (0 is the first partition) |
422 | | */ |
423 | | size_t fdisk_partition_get_partno(struct fdisk_partition *pa) |
424 | 0 | { |
425 | 0 | return pa->partno; |
426 | 0 | } |
427 | | |
428 | | /** |
429 | | * fdisk_partition_has_partno: |
430 | | * @pa: partition |
431 | | * |
432 | | * Returns: 1 or 0 |
433 | | */ |
434 | | int fdisk_partition_has_partno(struct fdisk_partition *pa) |
435 | 0 | { |
436 | 0 | return pa && !FDISK_IS_UNDEF(pa->partno); |
437 | 0 | } |
438 | | |
439 | | |
440 | | /** |
441 | | * fdisk_partition_cmp_partno: |
442 | | * @a: partition |
443 | | * @b: partition |
444 | | * |
445 | | * Compares partitions according to partition number See fdisk_table_sort_partitions(). |
446 | | * |
447 | | * Return: 0 if the same, <0 if @b greater, >0 if @a greater. |
448 | | */ |
449 | | int fdisk_partition_cmp_partno(struct fdisk_partition *a, |
450 | | struct fdisk_partition *b) |
451 | 0 | { |
452 | 0 | return a->partno - b->partno; |
453 | 0 | } |
454 | | |
455 | | /** |
456 | | * fdisk_partition_partno_follow_default |
457 | | * @pa: partition |
458 | | * @enable: 0|1 |
459 | | * |
460 | | * When @pa used as a template for fdisk_add_partition() when force label driver |
461 | | * to add a new partition to the default (next) position. |
462 | | * |
463 | | * Returns: 0 on success, <0 on error. |
464 | | */ |
465 | | int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable) |
466 | 20.0k | { |
467 | 20.0k | if (!pa) |
468 | 0 | return -EINVAL; |
469 | 20.0k | pa->partno_follow_default = enable ? 1 : 0; |
470 | 20.0k | return 0; |
471 | 20.0k | } |
472 | | |
473 | | /** |
474 | | * fdisk_partition_set_type: |
475 | | * @pa: partition |
476 | | * @type: partition type |
477 | | * |
478 | | * Sets partition type. |
479 | | * |
480 | | * Returns: 0 on success, <0 on error. |
481 | | */ |
482 | | int fdisk_partition_set_type(struct fdisk_partition *pa, |
483 | | struct fdisk_parttype *type) |
484 | 0 | { |
485 | 0 | if (!pa) |
486 | 0 | return -EINVAL; |
487 | | |
488 | 0 | fdisk_ref_parttype(type); |
489 | 0 | fdisk_unref_parttype(pa->type); |
490 | 0 | pa->type = type; |
491 | |
|
492 | 0 | return 0; |
493 | 0 | } |
494 | | |
495 | | /** |
496 | | * fdisk_partition_get_type: |
497 | | * @pa: partition |
498 | | * |
499 | | * Returns: pointer to partition type. |
500 | | */ |
501 | | struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa) |
502 | 0 | { |
503 | 0 | return pa ? pa->type : NULL; |
504 | 0 | } |
505 | | |
506 | | /** |
507 | | * fdisk_partition_set_name: |
508 | | * @pa: partition |
509 | | * @name: partition name |
510 | | * |
511 | | * Returns: 0 on success, <0 on error. |
512 | | */ |
513 | | int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name) |
514 | 0 | { |
515 | 0 | if (!pa) |
516 | 0 | return -EINVAL; |
517 | 0 | return strdup_to_struct_member(pa, name, name); |
518 | 0 | } |
519 | | |
520 | | /** |
521 | | * fdisk_partition_get_name: |
522 | | * @pa: partition |
523 | | * |
524 | | * Returns: partition name |
525 | | */ |
526 | | const char *fdisk_partition_get_name(struct fdisk_partition *pa) |
527 | 0 | { |
528 | 0 | return pa ? pa->name : NULL; |
529 | 0 | } |
530 | | |
531 | | /** |
532 | | * fdisk_partition_set_uuid: |
533 | | * @pa: partition |
534 | | * @uuid: UUID of the partition |
535 | | * |
536 | | * Returns: 0 on success, <0 on error. |
537 | | */ |
538 | | int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid) |
539 | 0 | { |
540 | 0 | if (!pa) |
541 | 0 | return -EINVAL; |
542 | 0 | return strdup_to_struct_member(pa, uuid, uuid); |
543 | 0 | } |
544 | | |
545 | | /** |
546 | | * fdisk_partition_has_end: |
547 | | * @pa: partition |
548 | | * |
549 | | * Returns: 1 if the partition has defined last sector |
550 | | */ |
551 | | int fdisk_partition_has_end(struct fdisk_partition *pa) |
552 | 0 | { |
553 | 0 | return pa && !FDISK_IS_UNDEF(pa->start) && !FDISK_IS_UNDEF(pa->size); |
554 | 0 | } |
555 | | |
556 | | /** |
557 | | * fdisk_partition_get_end: |
558 | | * @pa: partition |
559 | | * |
560 | | * This function may returns absolute non-sense, always check |
561 | | * fdisk_partition_has_end(). |
562 | | * |
563 | | * Note that partition end is defined by fdisk_partition_set_start() and |
564 | | * fdisk_partition_set_size(). |
565 | | * |
566 | | * Returns: last partition sector LBA. |
567 | | */ |
568 | | fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa) |
569 | 0 | { |
570 | 0 | return pa->start + pa->size - (pa->size == 0 ? 0 : 1); |
571 | 0 | } |
572 | | |
573 | | /** |
574 | | * fdisk_partition_end_follow_default |
575 | | * @pa: partition |
576 | | * @enable: 0|1 |
577 | | * |
578 | | * When @pa used as a template for fdisk_add_partition() when force label |
579 | | * driver to use all the possible space for the new partition. |
580 | | * |
581 | | * Returns: 0 on success, <0 on error. |
582 | | */ |
583 | | int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable) |
584 | 28.7k | { |
585 | 28.7k | if (!pa) |
586 | 0 | return -EINVAL; |
587 | 28.7k | pa->end_follow_default = enable ? 1 : 0; |
588 | 28.7k | return 0; |
589 | 28.7k | } |
590 | | |
591 | | /** |
592 | | * fdisk_partition_end_is_default: |
593 | | * @pa: partition |
594 | | * |
595 | | * Returns: 1 if the partition follows default |
596 | | */ |
597 | | int fdisk_partition_end_is_default(struct fdisk_partition *pa) |
598 | 0 | { |
599 | 0 | assert(pa); |
600 | 0 | return pa->end_follow_default; |
601 | 0 | } |
602 | | |
603 | | /** |
604 | | * fdisk_partition_get_uuid: |
605 | | * @pa: partition |
606 | | * |
607 | | * Returns: partition UUID as string |
608 | | */ |
609 | | const char *fdisk_partition_get_uuid(struct fdisk_partition *pa) |
610 | 0 | { |
611 | 0 | return pa ? pa->uuid : NULL; |
612 | 0 | } |
613 | | |
614 | | /** |
615 | | * fdisk_partition_get_attrs: |
616 | | * @pa: partition |
617 | | * |
618 | | * Returns: partition attributes in string format |
619 | | */ |
620 | | const char *fdisk_partition_get_attrs(struct fdisk_partition *pa) |
621 | 0 | { |
622 | 0 | return pa ? pa->attrs : NULL; |
623 | 0 | } |
624 | | |
625 | | /** |
626 | | * fdisk_partition_set_attrs: |
627 | | * @pa: partition |
628 | | * @attrs: attributes |
629 | | * |
630 | | * Sets @attrs to @pa. |
631 | | * |
632 | | * Return: 0 on success, <0 on error. |
633 | | */ |
634 | | int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs) |
635 | 0 | { |
636 | 0 | if (!pa) |
637 | 0 | return -EINVAL; |
638 | 0 | return strdup_to_struct_member(pa, attrs, attrs); |
639 | 0 | } |
640 | | |
641 | | /** |
642 | | * fdisk_partition_is_nested: |
643 | | * @pa: partition |
644 | | * |
645 | | * Returns: 1 if the partition is nested (e.g. MBR logical partition) |
646 | | */ |
647 | | int fdisk_partition_is_nested(struct fdisk_partition *pa) |
648 | 0 | { |
649 | 0 | return pa && !FDISK_IS_UNDEF(pa->parent_partno); |
650 | 0 | } |
651 | | |
652 | | /** |
653 | | * fdisk_partition_is_container: |
654 | | * @pa: partition |
655 | | * |
656 | | * Returns: 1 if the partition is container (e.g. MBR extended partition) |
657 | | */ |
658 | | int fdisk_partition_is_container(struct fdisk_partition *pa) |
659 | 0 | { |
660 | 0 | return pa && pa->container; |
661 | 0 | } |
662 | | |
663 | | /** |
664 | | * fdisk_partition_get_parent: |
665 | | * @pa: partition |
666 | | * @parent: parent parno |
667 | | * |
668 | | * Returns: returns devno of the parent |
669 | | */ |
670 | | int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent) |
671 | 0 | { |
672 | 0 | if (pa && parent) |
673 | 0 | *parent = pa->parent_partno; |
674 | 0 | else |
675 | 0 | return -EINVAL; |
676 | 0 | return 0; |
677 | 0 | } |
678 | | |
679 | | /** |
680 | | * fdisk_partition_is_used: |
681 | | * @pa: partition |
682 | | * |
683 | | * Returns: 1 if the partition points to some area |
684 | | */ |
685 | | int fdisk_partition_is_used(struct fdisk_partition *pa) |
686 | 0 | { |
687 | 0 | return pa && pa->used; |
688 | 0 | } |
689 | | |
690 | | /** |
691 | | * fdisk_partition_is_bootable: |
692 | | * @pa: partition |
693 | | * |
694 | | * Returns: 1 if the partition has enabled boot flag |
695 | | */ |
696 | | int fdisk_partition_is_bootable(struct fdisk_partition *pa) |
697 | 18.2k | { |
698 | 18.2k | return pa && pa->boot == 1; |
699 | 18.2k | } |
700 | | |
701 | | /** |
702 | | * fdisk_partition_is_freespace: |
703 | | * @pa: partition |
704 | | * |
705 | | * Returns: 1 if @pa points to freespace |
706 | | */ |
707 | | int fdisk_partition_is_freespace(struct fdisk_partition *pa) |
708 | 0 | { |
709 | 0 | return pa && pa->freespace; |
710 | 0 | } |
711 | | |
712 | | /** |
713 | | * fdisk_partition_is_wholedisk: |
714 | | * @pa: partition |
715 | | * |
716 | | * Returns: 1 if the partition is special whole-disk (e.g. SUN) partition |
717 | | */ |
718 | | int fdisk_partition_is_wholedisk(struct fdisk_partition *pa) |
719 | 0 | { |
720 | 0 | return pa && pa->wholedisk; |
721 | 0 | } |
722 | | |
723 | | /** |
724 | | * fdisk_partition_next_partno: |
725 | | * @pa: partition |
726 | | * @cxt: context |
727 | | * @n: returns partition number |
728 | | * |
729 | | * If @pa specified and partno-follow-default (see fdisk_partition_partno_follow_default()) |
730 | | * enabled then returns next expected partno or -ERANGE on error. |
731 | | * |
732 | | * If @pa is NULL, or @pa does not specify any semantic for the next partno |
733 | | * then use Ask API to ask user for the next partno. In this case returns 1 if |
734 | | * no free partition available. If fdisk dialogs are disabled then returns -EINVAL. |
735 | | * |
736 | | * Returns: 0 on success, <0 on error, or 1 for non-free partno by Ask API. |
737 | | */ |
738 | | int fdisk_partition_next_partno( |
739 | | struct fdisk_partition *pa, |
740 | | struct fdisk_context *cxt, |
741 | | size_t *n) |
742 | 0 | { |
743 | 0 | if (!cxt || !n) |
744 | 0 | return -EINVAL; |
745 | | |
746 | 0 | if (pa && pa->partno_follow_default) { |
747 | 0 | size_t i; |
748 | |
|
749 | 0 | DBG(PART, ul_debugobj(pa, "next partno (follow default)")); |
750 | |
|
751 | 0 | for (i = 0; i < cxt->label->nparts_max; i++) { |
752 | 0 | if (!fdisk_is_partition_used(cxt, i)) { |
753 | 0 | *n = i; |
754 | 0 | return 0; |
755 | 0 | } |
756 | 0 | } |
757 | 0 | return -ERANGE; |
758 | |
|
759 | 0 | } |
760 | | |
761 | 0 | if (pa && fdisk_partition_has_partno(pa)) { |
762 | |
|
763 | 0 | DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno)); |
764 | |
|
765 | 0 | if (pa->partno >= cxt->label->nparts_max || |
766 | 0 | fdisk_is_partition_used(cxt, pa->partno)) |
767 | 0 | return -ERANGE; |
768 | 0 | *n = pa->partno; |
769 | 0 | return 0; |
770 | |
|
771 | 0 | } |
772 | | |
773 | 0 | if (fdisk_has_dialogs(cxt)) |
774 | 0 | return fdisk_ask_partnum(cxt, n, 1); |
775 | | |
776 | 0 | return -EINVAL; |
777 | 0 | } |
778 | | |
779 | | static int probe_partition_content(struct fdisk_context *cxt, struct fdisk_partition *pa) |
780 | 0 | { |
781 | 0 | int rc = 1; /* nothing */ |
782 | |
|
783 | 0 | DBG(PART, ul_debugobj(pa, "start probe #%zu partition [cxt %p] >>>", pa->partno, cxt)); |
784 | | |
785 | | /* zeroize the current setting */ |
786 | 0 | strdup_to_struct_member(pa, fstype, NULL); |
787 | 0 | strdup_to_struct_member(pa, fsuuid, NULL); |
788 | 0 | strdup_to_struct_member(pa, fslabel, NULL); |
789 | |
|
790 | 0 | if (!fdisk_partition_has_start(pa) || |
791 | 0 | !fdisk_partition_has_size(pa)) |
792 | 0 | goto done; |
793 | | |
794 | 0 | #ifdef HAVE_LIBBLKID |
795 | 0 | else { |
796 | 0 | uintmax_t start, size; |
797 | |
|
798 | 0 | blkid_probe pr = blkid_new_probe(); |
799 | 0 | if (!pr) |
800 | 0 | goto done; |
801 | | |
802 | 0 | DBG(PART, ul_debugobj(pa, "blkid prober: %p", pr)); |
803 | |
|
804 | 0 | blkid_probe_enable_superblocks(pr, 1); |
805 | 0 | blkid_probe_set_superblocks_flags(pr, |
806 | 0 | BLKID_SUBLKS_MAGIC | |
807 | 0 | BLKID_SUBLKS_TYPE | |
808 | 0 | BLKID_SUBLKS_LABEL | |
809 | 0 | BLKID_SUBLKS_UUID | |
810 | 0 | BLKID_SUBLKS_BADCSUM); |
811 | |
|
812 | 0 | start = fdisk_partition_get_start(pa) * fdisk_get_sector_size(cxt); |
813 | 0 | size = fdisk_partition_get_size(pa) * fdisk_get_sector_size(cxt); |
814 | |
|
815 | 0 | if (blkid_probe_set_device(pr, cxt->dev_fd, start, size) == 0 |
816 | 0 | && blkid_do_fullprobe(pr) == 0) { |
817 | |
|
818 | 0 | const char *data; |
819 | 0 | rc = 0; |
820 | |
|
821 | 0 | if (!blkid_probe_lookup_value(pr, "TYPE", &data, NULL)) |
822 | 0 | rc = strdup_to_struct_member(pa, fstype, data); |
823 | |
|
824 | 0 | if (!rc && !blkid_probe_lookup_value(pr, "LABEL", &data, NULL)) |
825 | 0 | rc = strdup_to_struct_member(pa, fslabel, data); |
826 | |
|
827 | 0 | if (!rc && !blkid_probe_lookup_value(pr, "UUID", &data, NULL)) |
828 | 0 | rc = strdup_to_struct_member(pa, fsuuid, data); |
829 | 0 | } |
830 | |
|
831 | 0 | blkid_free_probe(pr); |
832 | 0 | pa->fs_probed = 1; |
833 | 0 | } |
834 | 0 | #endif /* HAVE_LIBBLKID */ |
835 | | |
836 | 0 | done: |
837 | 0 | DBG(PART, ul_debugobj(pa, "<<< end probe #%zu partition[cxt %p, rc=%d]", pa->partno, cxt, rc)); |
838 | 0 | return rc; |
839 | 0 | } |
840 | | |
841 | | /** |
842 | | * fdisk_partition_to_string: |
843 | | * @pa: partition |
844 | | * @cxt: context |
845 | | * @id: field (FDISK_FIELD_*) |
846 | | * @data: returns string with allocated data |
847 | | * |
848 | | * Returns info about partition converted to printable string. |
849 | | * |
850 | | * For example |
851 | | * <informalexample> |
852 | | * <programlisting> |
853 | | * struct fdisk_partition *pa; |
854 | | * |
855 | | * fdisk_get_partition(cxt, 0, &pa); |
856 | | * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data); |
857 | | * printf("first partition uuid: %s\n", data); |
858 | | * free(data); |
859 | | * fdisk_unref_partition(pa); |
860 | | * </programlisting> |
861 | | * </informalexample> |
862 | | * |
863 | | * returns UUID for the first partition. |
864 | | * |
865 | | * Returns: 0 on success, otherwise, a corresponding error. |
866 | | */ |
867 | | int fdisk_partition_to_string(struct fdisk_partition *pa, |
868 | | struct fdisk_context *cxt, |
869 | | int id, |
870 | | char **data) |
871 | 0 | { |
872 | 0 | char *p = NULL; |
873 | 0 | int rc = 0; |
874 | 0 | uint64_t x; |
875 | |
|
876 | 0 | if (!pa || !cxt || !data) |
877 | 0 | return -EINVAL; |
878 | | |
879 | 0 | switch (id) { |
880 | 0 | case FDISK_FIELD_DEVICE: |
881 | 0 | if (pa->freespace) |
882 | 0 | p = strdup(_("Free space")); |
883 | 0 | else if (fdisk_partition_has_partno(pa) && cxt->dev_path) { |
884 | 0 | if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO) |
885 | 0 | rc = asprintf(&p, "%c", (int) pa->partno + 'a'); |
886 | 0 | else |
887 | 0 | p = fdisk_partname(cxt->dev_path, pa->partno + 1); |
888 | 0 | } |
889 | 0 | break; |
890 | 0 | case FDISK_FIELD_BOOT: |
891 | 0 | p = fdisk_partition_is_bootable(pa) ? strdup("*") : NULL; |
892 | 0 | break; |
893 | 0 | case FDISK_FIELD_START: |
894 | 0 | if (fdisk_partition_has_start(pa)) { |
895 | 0 | x = fdisk_cround(cxt, pa->start); |
896 | 0 | rc = pa->start_post ? |
897 | 0 | asprintf(&p, "%"PRIu64"%c", x, pa->start_post) : |
898 | 0 | asprintf(&p, "%"PRIu64, x); |
899 | 0 | } |
900 | 0 | break; |
901 | 0 | case FDISK_FIELD_END: |
902 | 0 | if (fdisk_partition_has_end(pa)) { |
903 | 0 | x = fdisk_cround(cxt, fdisk_partition_get_end(pa)); |
904 | 0 | rc = pa->end_post ? |
905 | 0 | asprintf(&p, "%"PRIu64"%c", x, pa->end_post) : |
906 | 0 | asprintf(&p, "%"PRIu64, x); |
907 | 0 | } |
908 | 0 | break; |
909 | 0 | case FDISK_FIELD_SIZE: |
910 | 0 | if (fdisk_partition_has_size(pa)) { |
911 | 0 | uint64_t sz = pa->size * cxt->sector_size; |
912 | |
|
913 | 0 | switch (cxt->sizeunit) { |
914 | 0 | case FDISK_SIZEUNIT_BYTES: |
915 | 0 | rc = asprintf(&p, "%"PRIu64"", sz); |
916 | 0 | break; |
917 | 0 | case FDISK_SIZEUNIT_HUMAN: |
918 | 0 | if (fdisk_is_details(cxt)) |
919 | 0 | rc = pa->size_post ? |
920 | 0 | asprintf(&p, "%"PRIu64"%c", sz, pa->size_post) : |
921 | 0 | asprintf(&p, "%"PRIu64, sz); |
922 | 0 | else { |
923 | 0 | p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz); |
924 | 0 | if (!p) |
925 | 0 | rc = -ENOMEM; |
926 | 0 | } |
927 | 0 | break; |
928 | 0 | } |
929 | 0 | } |
930 | 0 | break; |
931 | 0 | case FDISK_FIELD_CYLINDERS: |
932 | 0 | { |
933 | 0 | uintmax_t sz = fdisk_partition_has_size(pa) ? pa->size : 0; |
934 | 0 | if (sz) |
935 | | /* Why we need to cast that to uintmax_t? */ |
936 | 0 | rc = asprintf(&p, "%ju", (uintmax_t)(sz / (cxt->geom.heads * cxt->geom.sectors)) + 1); |
937 | 0 | break; |
938 | 0 | } |
939 | 0 | case FDISK_FIELD_SECTORS: |
940 | 0 | rc = asprintf(&p, "%ju", |
941 | 0 | fdisk_partition_has_size(pa) ? (uintmax_t) pa->size : 0); |
942 | 0 | break; |
943 | 0 | case FDISK_FIELD_BSIZE: |
944 | 0 | rc = asprintf(&p, "%"PRIu64, pa->bsize); |
945 | 0 | break; |
946 | 0 | case FDISK_FIELD_FSIZE: |
947 | 0 | rc = asprintf(&p, "%"PRIu64, pa->fsize); |
948 | 0 | break; |
949 | 0 | case FDISK_FIELD_CPG: |
950 | 0 | rc = asprintf(&p, "%"PRIu64, pa->cpg); |
951 | 0 | break; |
952 | 0 | case FDISK_FIELD_TYPE: |
953 | 0 | p = pa->type && pa->type->name ? strdup(_(pa->type->name)) : NULL; |
954 | 0 | break; |
955 | 0 | case FDISK_FIELD_TYPEID: |
956 | 0 | if (pa->type && fdisk_parttype_get_string(pa->type)) |
957 | 0 | rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type)); |
958 | 0 | else if (pa->type) |
959 | 0 | rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type)); |
960 | 0 | break; |
961 | 0 | case FDISK_FIELD_UUID: |
962 | 0 | p = pa->uuid && *pa->uuid? strdup(pa->uuid) : NULL; |
963 | 0 | break; |
964 | 0 | case FDISK_FIELD_NAME: |
965 | 0 | p = pa->name && *pa->name ? strdup(pa->name) : NULL; |
966 | 0 | break; |
967 | 0 | case FDISK_FIELD_ATTR: |
968 | 0 | p = pa->attrs && *pa->attrs ? strdup(pa->attrs) : NULL; |
969 | 0 | break; |
970 | 0 | case FDISK_FIELD_SADDR: |
971 | 0 | p = pa->start_chs && *pa->start_chs ? strdup(pa->start_chs) : NULL; |
972 | 0 | break; |
973 | 0 | case FDISK_FIELD_EADDR: |
974 | 0 | p = pa->end_chs && *pa->end_chs? strdup(pa->end_chs) : NULL; |
975 | 0 | break; |
976 | 0 | case FDISK_FIELD_FSUUID: |
977 | 0 | if (pa->fs_probed || probe_partition_content(cxt, pa) == 0) |
978 | 0 | p = pa->fsuuid && *pa->fsuuid ? strdup(pa->fsuuid) : NULL; |
979 | 0 | break; |
980 | 0 | case FDISK_FIELD_FSLABEL: |
981 | 0 | if (pa->fs_probed || probe_partition_content(cxt, pa) == 0) |
982 | 0 | p = pa->fslabel && *pa->fslabel ? strdup(pa->fslabel) : NULL; |
983 | 0 | break; |
984 | 0 | case FDISK_FIELD_FSTYPE: |
985 | 0 | if (pa->fs_probed || probe_partition_content(cxt, pa) == 0) |
986 | 0 | p = pa->fstype && *pa->fstype ? strdup(pa->fstype) : NULL; |
987 | 0 | break; |
988 | 0 | default: |
989 | 0 | return -EINVAL; |
990 | 0 | } |
991 | | |
992 | 0 | if (rc < 0) { |
993 | 0 | rc = -ENOMEM; |
994 | 0 | free(p); |
995 | 0 | p = NULL; |
996 | |
|
997 | 0 | } else if (rc > 0) |
998 | 0 | rc = 0; |
999 | |
|
1000 | 0 | *data = p; |
1001 | |
|
1002 | 0 | return rc; |
1003 | 0 | } |
1004 | | |
1005 | | |
1006 | | /** |
1007 | | * fdisk_get_partition: |
1008 | | * @cxt: context |
1009 | | * @partno: partition number (0 is the first partition) |
1010 | | * @pa: returns data about partition |
1011 | | * |
1012 | | * Reads disklabel and fills in @pa with data about partition @n. |
1013 | | * |
1014 | | * Note that partno may address unused partition and then this function does |
1015 | | * not fill anything to @pa. See fdisk_is_partition_used(). If @pa points to |
1016 | | * NULL then the function allocates a newly allocated fdisk_partition struct, |
1017 | | * use fdisk_unref_partition() to deallocate. |
1018 | | * |
1019 | | * Returns: 0 on success, otherwise, a corresponding error. |
1020 | | */ |
1021 | | int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, |
1022 | | struct fdisk_partition **pa) |
1023 | 0 | { |
1024 | 0 | int rc; |
1025 | 0 | struct fdisk_partition *np = NULL; |
1026 | |
|
1027 | 0 | if (!cxt || !cxt->label || !pa) |
1028 | 0 | return -EINVAL; |
1029 | 0 | if (!cxt->label->op->get_part) |
1030 | 0 | return -ENOSYS; |
1031 | 0 | if (!fdisk_is_partition_used(cxt, partno)) |
1032 | 0 | return -EINVAL; |
1033 | | |
1034 | 0 | if (!*pa) { |
1035 | 0 | np = *pa = fdisk_new_partition(); |
1036 | 0 | if (!*pa) |
1037 | 0 | return -ENOMEM; |
1038 | 0 | } else |
1039 | 0 | fdisk_reset_partition(*pa); |
1040 | | |
1041 | 0 | (*pa)->partno = partno; |
1042 | 0 | rc = cxt->label->op->get_part(cxt, partno, *pa); |
1043 | |
|
1044 | 0 | if (rc) { |
1045 | 0 | if (np) { |
1046 | 0 | fdisk_unref_partition(np); |
1047 | 0 | *pa = NULL; |
1048 | 0 | } else |
1049 | 0 | fdisk_reset_partition(*pa); |
1050 | 0 | } else |
1051 | 0 | (*pa)->size_explicit = 1; |
1052 | 0 | return rc; |
1053 | 0 | } |
1054 | | |
1055 | | static struct fdisk_partition *area_by_offset( |
1056 | | struct fdisk_table *tb, |
1057 | | struct fdisk_partition *cur, |
1058 | | fdisk_sector_t off) |
1059 | 0 | { |
1060 | 0 | struct fdisk_partition *pa = NULL; |
1061 | 0 | struct fdisk_iter itr; |
1062 | |
|
1063 | 0 | fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); |
1064 | |
|
1065 | 0 | while (fdisk_table_next_partition(tb, &itr, &pa) == 0) { |
1066 | 0 | if (!fdisk_partition_has_start(pa) || !fdisk_partition_has_size(pa)) |
1067 | 0 | continue; |
1068 | 0 | if (fdisk_partition_is_nested(cur) && |
1069 | 0 | pa->parent_partno != cur->parent_partno) |
1070 | 0 | continue; |
1071 | 0 | if (off >= pa->start && off < pa->start + pa->size) |
1072 | 0 | return pa; |
1073 | 0 | } |
1074 | | |
1075 | 0 | return NULL; |
1076 | 0 | } |
1077 | | |
1078 | | static int resize_get_first_possible( |
1079 | | struct fdisk_table *tb, |
1080 | | struct fdisk_partition *cur, |
1081 | | fdisk_sector_t *start) |
1082 | 0 | { |
1083 | 0 | struct fdisk_partition *pa = NULL, *first = NULL; |
1084 | 0 | struct fdisk_iter itr; |
1085 | |
|
1086 | 0 | fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); |
1087 | |
|
1088 | 0 | *start = 0; |
1089 | 0 | DBG(TAB, ul_debugobj(tb, "checking first possible before start=%ju", (uintmax_t) cur->start)); |
1090 | | |
1091 | |
|
1092 | 0 | while (fdisk_table_next_partition(tb, &itr, &pa) == 0) { |
1093 | |
|
1094 | 0 | if (pa->start > cur->start || pa == cur) |
1095 | 0 | break; |
1096 | | |
1097 | 0 | DBG(TAB, ul_debugobj(tb, " checking entry %p [partno=%zu start=%ju, end=%ju, size=%ju%s%s%s]", |
1098 | 0 | pa, |
1099 | 0 | fdisk_partition_get_partno(pa), |
1100 | 0 | (uintmax_t) fdisk_partition_get_start(pa), |
1101 | 0 | (uintmax_t) fdisk_partition_get_end(pa), |
1102 | 0 | (uintmax_t) fdisk_partition_get_size(pa), |
1103 | 0 | fdisk_partition_is_freespace(pa) ? " freespace" : "", |
1104 | 0 | fdisk_partition_is_nested(pa) ? " nested" : "", |
1105 | 0 | fdisk_partition_is_container(pa) ? " container" : "")); |
1106 | | |
1107 | |
|
1108 | 0 | if (!fdisk_partition_is_freespace(pa)) { |
1109 | 0 | DBG(TAB, ul_debugobj(tb, " ignored (no freespace)")); |
1110 | 0 | first = NULL; |
1111 | 0 | continue; |
1112 | 0 | } |
1113 | 0 | if (!fdisk_partition_has_start(pa) || !fdisk_partition_has_size(pa)) { |
1114 | 0 | DBG(TAB, ul_debugobj(tb, " ignored (no start/size)")); |
1115 | 0 | first = NULL; |
1116 | 0 | continue; |
1117 | 0 | } |
1118 | | /* The current is nested, free space has to be nested within the same parent */ |
1119 | 0 | if (fdisk_partition_is_nested(cur) |
1120 | 0 | && pa->parent_partno != cur->parent_partno) { |
1121 | 0 | DBG(TAB, ul_debugobj(tb, " ignore (nested required)")); |
1122 | 0 | first = NULL; |
1123 | 0 | continue; |
1124 | 0 | } |
1125 | 0 | if (pa->start + pa->size <= cur->start) { |
1126 | 0 | first = pa; |
1127 | 0 | DBG(TAB, ul_debugobj(tb, " entry usable")); |
1128 | 0 | } |
1129 | 0 | } |
1130 | |
|
1131 | 0 | if (first) |
1132 | 0 | *start = first->start; |
1133 | 0 | else |
1134 | 0 | DBG(PART, ul_debugobj(cur, "resize: nothing usable before %ju", (uintmax_t) cur->start)); |
1135 | |
|
1136 | 0 | return first ? 0 : -1; |
1137 | 0 | } |
1138 | | |
1139 | | /* |
1140 | | * Verify that area addressed by @start is freespace or the @cur[rent] |
1141 | | * partition and continue to the next table entries until it's freespace, and |
1142 | | * counts size of all this space. |
1143 | | * |
1144 | | * This is core of the partition start offset move operation. We can move the |
1145 | | * start within the current partition to another free space. It's |
1146 | | * forbidden to move start of the partition to another already defined |
1147 | | * partition. |
1148 | | */ |
1149 | | static int resize_get_last_possible( |
1150 | | struct fdisk_table *tb, |
1151 | | struct fdisk_partition *cur, |
1152 | | fdisk_sector_t start, |
1153 | | fdisk_sector_t *maxsz) |
1154 | 0 | { |
1155 | 0 | struct fdisk_partition *pa = NULL, *last = NULL; |
1156 | 0 | struct fdisk_iter itr; |
1157 | |
|
1158 | 0 | fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); |
1159 | |
|
1160 | 0 | *maxsz = 0; |
1161 | 0 | DBG(TAB, ul_debugobj(tb, "checking last possible for start=%ju", (uintmax_t) start)); |
1162 | | |
1163 | |
|
1164 | 0 | while (fdisk_table_next_partition(tb, &itr, &pa) == 0) { |
1165 | |
|
1166 | 0 | DBG(TAB, ul_debugobj(tb, " checking entry %p [partno=%zu start=%ju, end=%ju, size=%ju%s%s%s]", |
1167 | 0 | pa, |
1168 | 0 | fdisk_partition_get_partno(pa), |
1169 | 0 | (uintmax_t) fdisk_partition_get_start(pa), |
1170 | 0 | (uintmax_t) fdisk_partition_get_end(pa), |
1171 | 0 | (uintmax_t) fdisk_partition_get_size(pa), |
1172 | 0 | fdisk_partition_is_freespace(pa) ? " freespace" : "", |
1173 | 0 | fdisk_partition_is_nested(pa) ? " nested" : "", |
1174 | 0 | fdisk_partition_is_container(pa) ? " container" : "")); |
1175 | |
|
1176 | 0 | if (!fdisk_partition_has_start(pa) || |
1177 | 0 | !fdisk_partition_has_size(pa) || |
1178 | 0 | (fdisk_partition_is_container(pa) && pa != cur)) { |
1179 | 0 | DBG(TAB, ul_debugobj(tb, " ignored (no start/size or container)")); |
1180 | 0 | continue; |
1181 | 0 | } |
1182 | | |
1183 | 0 | if (fdisk_partition_is_nested(pa) |
1184 | 0 | && fdisk_partition_is_container(cur) |
1185 | 0 | && pa->parent_partno == cur->partno) { |
1186 | 0 | DBG(TAB, ul_debugobj(tb, " ignore (nested child of the current partition)")); |
1187 | 0 | continue; |
1188 | 0 | } |
1189 | | |
1190 | | /* The current is nested, free space has to be nested within the same parent */ |
1191 | 0 | if (fdisk_partition_is_nested(cur) |
1192 | 0 | && pa->parent_partno != cur->parent_partno) { |
1193 | 0 | DBG(TAB, ul_debugobj(tb, " ignore (nested required)")); |
1194 | 0 | continue; |
1195 | 0 | } |
1196 | | |
1197 | 0 | if (!last) { |
1198 | 0 | if (start >= pa->start && start < pa->start + pa->size) { |
1199 | 0 | if (fdisk_partition_is_freespace(pa) || pa == cur) { |
1200 | 0 | DBG(TAB, ul_debugobj(tb, " accepted as last")); |
1201 | 0 | last = pa; |
1202 | 0 | } else { |
1203 | 0 | DBG(TAB, ul_debugobj(tb, " failed to set last")); |
1204 | 0 | break; |
1205 | 0 | } |
1206 | | |
1207 | | |
1208 | 0 | *maxsz = pa->size - (start - pa->start); |
1209 | 0 | DBG(TAB, ul_debugobj(tb, " new max=%ju", (uintmax_t) *maxsz)); |
1210 | 0 | } |
1211 | 0 | } else if (!fdisk_partition_is_freespace(pa) && pa != cur) { |
1212 | 0 | DBG(TAB, ul_debugobj(tb, " no free space behind current")); |
1213 | 0 | break; |
1214 | 0 | } else { |
1215 | 0 | last = pa; |
1216 | 0 | *maxsz = pa->size - (start - pa->start); |
1217 | 0 | DBG(TAB, ul_debugobj(tb, " new max=%ju (last updated)", (uintmax_t) *maxsz)); |
1218 | 0 | } |
1219 | 0 | } |
1220 | |
|
1221 | 0 | if (last) |
1222 | 0 | DBG(PART, ul_debugobj(cur, "resize: max size=%ju", (uintmax_t) *maxsz)); |
1223 | 0 | else |
1224 | 0 | DBG(PART, ul_debugobj(cur, "resize: nothing usable after %ju", (uintmax_t) start)); |
1225 | |
|
1226 | 0 | return last ? 0 : -1; |
1227 | 0 | } |
1228 | | |
1229 | | /* |
1230 | | * Uses template @tpl to recount start and size change of the partition @res. The |
1231 | | * @tpl->size and @tpl->start are interpreted as relative to the current setting. |
1232 | | */ |
1233 | | static int recount_resize( |
1234 | | struct fdisk_context *cxt, size_t partno, |
1235 | | struct fdisk_partition *res, struct fdisk_partition *tpl) |
1236 | 0 | { |
1237 | 0 | fdisk_sector_t start, size, xsize; |
1238 | 0 | struct fdisk_partition *cur = NULL; |
1239 | 0 | struct fdisk_table *tb = NULL; |
1240 | 0 | int rc; |
1241 | |
|
1242 | 0 | DBG(PART, ul_debugobj(tpl, ">>> resize requested")); |
1243 | |
|
1244 | 0 | FDISK_INIT_UNDEF(start); |
1245 | 0 | FDISK_INIT_UNDEF(size); |
1246 | |
|
1247 | 0 | rc = fdisk_get_partitions(cxt, &tb); |
1248 | 0 | if (!rc) { |
1249 | | /* For resize we do not follow grain to detect free-space, but |
1250 | | * we support to resize with very small granulation. */ |
1251 | 0 | unsigned long org = cxt->grain; |
1252 | |
|
1253 | 0 | cxt->grain = cxt->sector_size; |
1254 | 0 | rc = fdisk_get_freespaces(cxt, &tb); |
1255 | 0 | cxt->grain = org; |
1256 | 0 | } |
1257 | 0 | if (rc) { |
1258 | 0 | fdisk_unref_table(tb); |
1259 | 0 | return rc; |
1260 | 0 | } |
1261 | | |
1262 | 0 | fdisk_table_sort_partitions(tb, fdisk_partition_cmp_start); |
1263 | |
|
1264 | 0 | DBG(PART, ul_debugobj(tpl, "resize partition partno=%zu in table:", partno)); |
1265 | 0 | ON_DBG(PART, fdisk_debug_print_table(tb)); |
1266 | |
|
1267 | 0 | cur = fdisk_table_get_partition_by_partno(tb, partno); |
1268 | 0 | if (!cur) { |
1269 | 0 | fdisk_unref_table(tb); |
1270 | 0 | return -EINVAL; |
1271 | 0 | } |
1272 | | |
1273 | | /* 1a) set new start - change relative to the current on-disk setting */ |
1274 | 0 | if (tpl->movestart && fdisk_partition_has_start(tpl)) { |
1275 | 0 | start = fdisk_partition_get_start(cur); |
1276 | 0 | if (tpl->movestart == FDISK_MOVE_DOWN) { |
1277 | 0 | if (fdisk_partition_get_start(tpl) > start) |
1278 | 0 | goto erange; |
1279 | 0 | start -= fdisk_partition_get_start(tpl); |
1280 | 0 | } else |
1281 | 0 | start += fdisk_partition_get_start(tpl); |
1282 | | |
1283 | 0 | DBG(PART, ul_debugobj(tpl, "resize: moving start %s relative, new start: %ju", |
1284 | 0 | tpl->movestart == FDISK_MOVE_DOWN ? "DOWN" : "UP", (uintmax_t)start)); |
1285 | | |
1286 | | /* 1b) set new start - try freespace before the current partition */ |
1287 | 0 | } else if (tpl->movestart == FDISK_MOVE_DOWN) { |
1288 | |
|
1289 | 0 | if (resize_get_first_possible(tb, cur, &start) != 0) |
1290 | 0 | goto erange; |
1291 | | |
1292 | 0 | DBG(PART, ul_debugobj(tpl, "resize: moving start DOWN (first possible), new start: %ju", |
1293 | 0 | (uintmax_t)start)); |
1294 | | |
1295 | | /* 1c) set new start - absolute number */ |
1296 | 0 | } else if (fdisk_partition_has_start(tpl)) { |
1297 | 0 | start = fdisk_partition_get_start(tpl); |
1298 | 0 | DBG(PART, ul_debugobj(tpl, "resize: moving start to absolute offset: %ju", |
1299 | 0 | (uintmax_t)start)); |
1300 | 0 | } |
1301 | | |
1302 | | /* 2) verify that start is within the current partition or any freespace area */ |
1303 | 0 | if (!FDISK_IS_UNDEF(start)) { |
1304 | 0 | struct fdisk_partition *area = area_by_offset(tb, cur, start); |
1305 | |
|
1306 | 0 | if (area == cur) |
1307 | 0 | DBG(PART, ul_debugobj(tpl, "resize: start points to the current partition")); |
1308 | 0 | else if (area && fdisk_partition_is_freespace(area)) |
1309 | 0 | DBG(PART, ul_debugobj(tpl, "resize: start points to freespace")); |
1310 | 0 | else if (!area && start >= cxt->first_lba && start < cxt->first_lba + (cxt->grain / cxt->sector_size)) |
1311 | 0 | DBG(PART, ul_debugobj(tpl, "resize: start points before first partition")); |
1312 | 0 | else { |
1313 | 0 | DBG(PART, ul_debugobj(tpl, "resize: start verification failed")); |
1314 | 0 | goto erange; |
1315 | 0 | } |
1316 | 0 | } else { |
1317 | | /* no change, start points to the current partition */ |
1318 | 0 | DBG(PART, ul_debugobj(tpl, "resize: start unchanged")); |
1319 | 0 | start = fdisk_partition_get_start(cur); |
1320 | 0 | } |
1321 | | |
1322 | | /* 3a) set new size -- reduce */ |
1323 | 0 | if (tpl->resize == FDISK_RESIZE_REDUCE && fdisk_partition_has_size(tpl)) { |
1324 | 0 | DBG(PART, ul_debugobj(tpl, "resize: reduce")); |
1325 | 0 | size = fdisk_partition_get_size(cur); |
1326 | 0 | if (fdisk_partition_get_size(tpl) > size) |
1327 | 0 | goto erange; |
1328 | 0 | size -= fdisk_partition_get_size(tpl); |
1329 | | |
1330 | | /* 3b) set new size -- enlarge */ |
1331 | 0 | } else if (tpl->resize == FDISK_RESIZE_ENLARGE && fdisk_partition_has_size(tpl)) { |
1332 | 0 | DBG(PART, ul_debugobj(tpl, "resize: enlarge")); |
1333 | 0 | size = fdisk_partition_get_size(cur); |
1334 | 0 | size += fdisk_partition_get_size(tpl); |
1335 | | |
1336 | | /* 3c) set new size -- no size specified, enlarge to all freespace */ |
1337 | 0 | } else if (tpl->resize == FDISK_RESIZE_ENLARGE) { |
1338 | 0 | DBG(PART, ul_debugobj(tpl, "resize: enlarge to all possible")); |
1339 | 0 | if (resize_get_last_possible(tb, cur, start, &size)) |
1340 | 0 | goto erange; |
1341 | | |
1342 | | /* 3d) set new size -- absolute number */ |
1343 | 0 | } else if (fdisk_partition_has_size(tpl)) { |
1344 | 0 | DBG(PART, ul_debugobj(tpl, "resize: new absolute size")); |
1345 | 0 | size = fdisk_partition_get_size(tpl); |
1346 | 0 | } |
1347 | | |
1348 | | /* 4) verify that size is within the current partition or next free space */ |
1349 | 0 | xsize = !FDISK_IS_UNDEF(size) ? size : fdisk_partition_get_size(cur); |
1350 | |
|
1351 | 0 | if (fdisk_partition_has_size(cur)) { |
1352 | 0 | fdisk_sector_t maxsz; |
1353 | |
|
1354 | 0 | if (resize_get_last_possible(tb, cur, start, &maxsz)) |
1355 | 0 | goto erange; |
1356 | 0 | DBG(PART, ul_debugobj(tpl, "resize: size=%ju, max=%ju", |
1357 | 0 | (uintmax_t) xsize, (uintmax_t) maxsz)); |
1358 | 0 | if (xsize > maxsz) |
1359 | 0 | goto erange; |
1360 | 0 | } |
1361 | | |
1362 | 0 | if (FDISK_IS_UNDEF(size)) { |
1363 | 0 | DBG(PART, ul_debugobj(tpl, "resize: size unchanged (undefined)")); |
1364 | 0 | } |
1365 | | |
1366 | |
|
1367 | 0 | DBG(PART, ul_debugobj(tpl, "<<< resize: SUCCESS: start %ju->%ju; size %ju->%ju", |
1368 | 0 | (uintmax_t) fdisk_partition_get_start(cur), (uintmax_t) start, |
1369 | 0 | (uintmax_t) fdisk_partition_get_size(cur), (uintmax_t) size)); |
1370 | 0 | res->start = start; |
1371 | 0 | res->size = size; |
1372 | 0 | fdisk_unref_table(tb); |
1373 | 0 | return 0; |
1374 | 0 | erange: |
1375 | 0 | DBG(PART, ul_debugobj(tpl, "<<< resize: FAILED")); |
1376 | 0 | fdisk_warnx(cxt, _("Failed to resize partition #%zu."), partno + 1); |
1377 | 0 | fdisk_unref_table(tb); |
1378 | 0 | return -ERANGE; |
1379 | |
|
1380 | 0 | } |
1381 | | |
1382 | | /** |
1383 | | * fdisk_set_partition: |
1384 | | * @cxt: context |
1385 | | * @partno: partition number (0 is the first partition) |
1386 | | * @pa: new partition setting |
1387 | | * |
1388 | | * Modifies disklabel according to setting with in @pa. |
1389 | | * |
1390 | | * Returns: 0 on success, <0 on error. |
1391 | | */ |
1392 | | int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, |
1393 | | struct fdisk_partition *pa) |
1394 | 0 | { |
1395 | 0 | struct fdisk_partition *xpa = pa, *tmp = NULL; |
1396 | 0 | int rc, wipe = 0; |
1397 | |
|
1398 | 0 | if (!cxt || !cxt->label || !pa) |
1399 | 0 | return -EINVAL; |
1400 | 0 | if (!cxt->label->op->set_part) |
1401 | 0 | return -ENOSYS; |
1402 | | |
1403 | 0 | pa->fs_probed = 0; |
1404 | |
|
1405 | 0 | if (!fdisk_is_partition_used(cxt, partno)) { |
1406 | 0 | pa->partno = partno; |
1407 | 0 | return fdisk_add_partition(cxt, pa, NULL); |
1408 | 0 | } |
1409 | | |
1410 | 0 | if (pa->resize || pa->movestart |
1411 | 0 | || fdisk_partition_has_start(pa) || fdisk_partition_has_size(pa)) { |
1412 | 0 | xpa = __copy_partition(pa); |
1413 | 0 | if (!xpa) { |
1414 | 0 | rc = -ENOMEM; |
1415 | 0 | goto done; |
1416 | 0 | } |
1417 | 0 | xpa->movestart = 0; |
1418 | 0 | xpa->resize = 0; |
1419 | 0 | FDISK_INIT_UNDEF(xpa->size); |
1420 | 0 | FDISK_INIT_UNDEF(xpa->start); |
1421 | |
|
1422 | 0 | rc = recount_resize(cxt, partno, xpa, pa); |
1423 | 0 | if (rc) |
1424 | 0 | goto done; |
1425 | 0 | } |
1426 | | |
1427 | 0 | DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju)", |
1428 | 0 | partno, xpa, |
1429 | 0 | (uintmax_t) fdisk_partition_get_start(xpa), |
1430 | 0 | (uintmax_t) fdisk_partition_get_end(xpa), |
1431 | 0 | (uintmax_t) fdisk_partition_get_size(xpa))); |
1432 | | |
1433 | | /* disable wipe for old offset/size setting */ |
1434 | 0 | if (fdisk_get_partition(cxt, partno, &tmp) == 0 && tmp) { |
1435 | 0 | wipe = fdisk_set_wipe_area(cxt, fdisk_partition_get_start(tmp), |
1436 | 0 | fdisk_partition_get_size(tmp), FALSE); |
1437 | 0 | fdisk_unref_partition(tmp); |
1438 | 0 | } |
1439 | | |
1440 | | /* call label driver */ |
1441 | 0 | rc = cxt->label->op->set_part(cxt, partno, xpa); |
1442 | | |
1443 | | /* enable wipe for new offset/size */ |
1444 | 0 | if (!rc && wipe) |
1445 | 0 | fdisk_wipe_partition(cxt, partno, TRUE); |
1446 | 0 | done: |
1447 | 0 | DBG(CXT, ul_debugobj(cxt, "set_partition() rc=%d", rc)); |
1448 | 0 | if (xpa != pa) |
1449 | 0 | fdisk_unref_partition(xpa); |
1450 | 0 | return rc; |
1451 | 0 | } |
1452 | | |
1453 | | /** |
1454 | | * fdisk_wipe_partition: |
1455 | | * @cxt: fdisk context |
1456 | | * @partno: partition number |
1457 | | * @enable: 0 or 1 |
1458 | | * |
1459 | | * Enable/disable filesystems/RAIDs wiping in area defined by partition start and size. |
1460 | | * |
1461 | | * Returns: <0 in case of error, 0 on success |
1462 | | * Since: 2.29 |
1463 | | */ |
1464 | | int fdisk_wipe_partition(struct fdisk_context *cxt, size_t partno, int enable) |
1465 | 0 | { |
1466 | 0 | struct fdisk_partition *pa = NULL; |
1467 | 0 | int rc; |
1468 | |
|
1469 | 0 | rc = fdisk_get_partition(cxt, partno, &pa); |
1470 | 0 | if (rc) |
1471 | 0 | return rc; |
1472 | | |
1473 | 0 | rc = fdisk_set_wipe_area(cxt, fdisk_partition_get_start(pa), |
1474 | 0 | fdisk_partition_get_size(pa), enable); |
1475 | 0 | fdisk_unref_partition(pa); |
1476 | 0 | return rc < 0 ? rc : 0; |
1477 | 0 | } |
1478 | | |
1479 | | /** |
1480 | | * fdisk_partition_has_wipe: |
1481 | | * @cxt: fdisk context |
1482 | | * @pa: partition |
1483 | | * |
1484 | | * Since: 2.30 |
1485 | | * |
1486 | | * Returns: 1 if the area specified by @pa will be wiped by write command, or 0. |
1487 | | */ |
1488 | | int fdisk_partition_has_wipe(struct fdisk_context *cxt, struct fdisk_partition *pa) |
1489 | 0 | { |
1490 | 0 | return fdisk_has_wipe_area(cxt, fdisk_partition_get_start(pa), |
1491 | 0 | fdisk_partition_get_size(pa)); |
1492 | 0 | } |
1493 | | |
1494 | | |
1495 | | /** |
1496 | | * fdisk_add_partition: |
1497 | | * @cxt: fdisk context |
1498 | | * @pa: template for the partition (or NULL) |
1499 | | * @partno: NULL or returns new partition number |
1500 | | * |
1501 | | * If @pa is not specified or any @pa item is missing the libfdisk will ask by |
1502 | | * fdisk_ask_ API. |
1503 | | * |
1504 | | * The @pa template is important for non-interactive partitioning, |
1505 | | * especially for MBR where is necessary to differentiate between |
1506 | | * primary/logical; this is done by start offset or/and partno. |
1507 | | * The rules for MBR: |
1508 | | * |
1509 | | * A) template specifies start within extended partition: add logical |
1510 | | * B) template specifies start out of extended partition: add primary |
1511 | | * C) template specifies start (or default), partno < 4: add primary |
1512 | | * D) template specifies default start, partno >= 4: add logical |
1513 | | * |
1514 | | * otherwise MBR driver uses Ask-API to get missing information. |
1515 | | * |
1516 | | * Adds a new partition to disklabel. |
1517 | | * |
1518 | | * Returns: 0 on success, <0 on error. |
1519 | | */ |
1520 | | int fdisk_add_partition(struct fdisk_context *cxt, |
1521 | | struct fdisk_partition *pa, |
1522 | | size_t *partno) |
1523 | 0 | { |
1524 | 0 | int rc; |
1525 | |
|
1526 | 0 | if (!cxt || !cxt->label) |
1527 | 0 | return -EINVAL; |
1528 | 0 | if (!cxt->label->op->add_part) |
1529 | 0 | return -ENOSYS; |
1530 | 0 | if (fdisk_missing_geometry(cxt)) |
1531 | 0 | return -EINVAL; |
1532 | | |
1533 | 0 | if (pa) { |
1534 | 0 | pa->fs_probed = 0; |
1535 | 0 | DBG(CXT, ul_debugobj(cxt, "adding new partition %p", pa)); |
1536 | 0 | if (fdisk_partition_has_start(pa)) |
1537 | 0 | DBG(CXT, ul_debugobj(cxt, " start: %ju", (uintmax_t) fdisk_partition_get_start(pa))); |
1538 | 0 | if (fdisk_partition_has_end(pa)) |
1539 | 0 | DBG(CXT, ul_debugobj(cxt, " end: %ju", (uintmax_t) fdisk_partition_get_end(pa))); |
1540 | 0 | if (fdisk_partition_has_size(pa)) |
1541 | 0 | DBG(CXT, ul_debugobj(cxt, " size: %ju", (uintmax_t) fdisk_partition_get_size(pa))); |
1542 | |
|
1543 | 0 | DBG(CXT, ul_debugobj(cxt, " defaults: start=%s, end=%s, partno=%s", |
1544 | 0 | pa->start_follow_default ? "yes" : "no", |
1545 | 0 | pa->end_follow_default ? "yes" : "no", |
1546 | 0 | pa->partno_follow_default ? "yes" : "no")); |
1547 | 0 | } else |
1548 | 0 | DBG(CXT, ul_debugobj(cxt, "adding partition")); |
1549 | |
|
1550 | 0 | rc = cxt->label->op->add_part(cxt, pa, partno); |
1551 | |
|
1552 | 0 | DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc)); |
1553 | 0 | return rc; |
1554 | 0 | } |
1555 | | |
1556 | | /** |
1557 | | * fdisk_delete_partition: |
1558 | | * @cxt: fdisk context |
1559 | | * @partno: partition number to delete (0 is the first partition) |
1560 | | * |
1561 | | * Deletes a @partno partition from disklabel. |
1562 | | * |
1563 | | * Returns: 0 on success, <0 on error |
1564 | | */ |
1565 | | int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno) |
1566 | 0 | { |
1567 | 0 | if (!cxt || !cxt->label) |
1568 | 0 | return -EINVAL; |
1569 | 0 | if (!cxt->label->op->del_part) |
1570 | 0 | return -ENOSYS; |
1571 | | |
1572 | 0 | fdisk_wipe_partition(cxt, partno, 0); |
1573 | |
|
1574 | 0 | DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd", |
1575 | 0 | cxt->label->name, partno)); |
1576 | 0 | return cxt->label->op->del_part(cxt, partno); |
1577 | 0 | } |
1578 | | |
1579 | | /** |
1580 | | * fdisk_delete_all_partitions: |
1581 | | * @cxt: fdisk context |
1582 | | * |
1583 | | * Delete all used partitions from disklabel. |
1584 | | * |
1585 | | * Returns: 0 on success, otherwise, a corresponding error. |
1586 | | */ |
1587 | | int fdisk_delete_all_partitions(struct fdisk_context *cxt) |
1588 | 0 | { |
1589 | 0 | size_t i; |
1590 | 0 | int rc = 0; |
1591 | |
|
1592 | 0 | if (!cxt || !cxt->label) |
1593 | 0 | return -EINVAL; |
1594 | | |
1595 | 0 | for (i = 0; i < cxt->label->nparts_max; i++) { |
1596 | |
|
1597 | 0 | if (!fdisk_is_partition_used(cxt, i)) |
1598 | 0 | continue; |
1599 | 0 | rc = fdisk_delete_partition(cxt, i); |
1600 | 0 | if (rc) |
1601 | 0 | break; |
1602 | 0 | } |
1603 | |
|
1604 | 0 | return rc; |
1605 | 0 | } |
1606 | | |
1607 | | /** |
1608 | | * fdisk_is_partition_used: |
1609 | | * @cxt: context |
1610 | | * @n: partition number (0 is the first partition) |
1611 | | * |
1612 | | * Check if the partition number @n is used by partition table. This function |
1613 | | * does not check if the device is used (e.g. mounted) by system! |
1614 | | * |
1615 | | * This is faster than fdisk_get_partition() + fdisk_partition_is_used(). |
1616 | | * |
1617 | | * Returns: 0 or 1 |
1618 | | */ |
1619 | | int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n) |
1620 | 0 | { |
1621 | 0 | if (!cxt || !cxt->label) |
1622 | 0 | return -EINVAL; |
1623 | 0 | if (!cxt->label->op->part_is_used) |
1624 | 0 | return -ENOSYS; |
1625 | | |
1626 | 0 | return cxt->label->op->part_is_used(cxt, n); |
1627 | 0 | } |
1628 | | |
1629 | | |
1630 | | /** |
1631 | | * fdisk_partition_max_size: |
1632 | | * @cxt: context |
1633 | | * @n: partition number (0 is the first partition) |
1634 | | * @maxsz: returns maximum size of partition |
1635 | | * |
1636 | | * Find maximum size the partition can be resized to. |
1637 | | * Takes into account free space between this partition and the next one. |
1638 | | * |
1639 | | * Returns: 0 on success, <0 on error. |
1640 | | */ |
1641 | | int fdisk_partition_get_max_size(struct fdisk_context *cxt, size_t n, |
1642 | | fdisk_sector_t *maxsz) |
1643 | 0 | { |
1644 | 0 | struct fdisk_partition *cur = NULL; |
1645 | 0 | struct fdisk_table *tb = NULL; |
1646 | 0 | int rc; |
1647 | |
|
1648 | 0 | rc = fdisk_get_partitions(cxt, &tb); |
1649 | 0 | if (rc) |
1650 | 0 | goto out; |
1651 | | |
1652 | 0 | rc = fdisk_get_freespaces(cxt, &tb); |
1653 | 0 | if (rc) |
1654 | 0 | goto out; |
1655 | | |
1656 | 0 | rc = fdisk_table_sort_partitions(tb, fdisk_partition_cmp_start); |
1657 | 0 | if (rc) |
1658 | 0 | goto out; |
1659 | | |
1660 | 0 | cur = fdisk_table_get_partition_by_partno(tb, n); |
1661 | 0 | if (!cur) |
1662 | 0 | goto einval; |
1663 | | |
1664 | 0 | if (!fdisk_partition_has_start(cur)) |
1665 | 0 | goto einval; |
1666 | | |
1667 | 0 | if (resize_get_last_possible(tb, cur, |
1668 | 0 | fdisk_partition_get_start(cur), maxsz)) |
1669 | 0 | goto einval; |
1670 | | |
1671 | 0 | out: |
1672 | 0 | fdisk_unref_partition(cur); |
1673 | 0 | fdisk_unref_table(tb); |
1674 | |
|
1675 | 0 | return rc; |
1676 | | |
1677 | 0 | einval: |
1678 | | rc = -EINVAL; |
1679 | 0 | goto out; |
1680 | 0 | } |