return 1;
}
+static int get_maximum_partition_size(
+ int fd,
+ struct fdisk_partition *p,
+ uint64_t *ret_maximum_partition_size) {
+
+ _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
+ uint64_t start_lba, start, last_lba, end;
+ int r;
+
+ assert(fd >= 0);
+ assert(p);
+ assert(ret_maximum_partition_size);
+
+ c = fdisk_new_context();
+ if (!c)
+ return log_oom();
+
+ r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(fd), 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open device: %m");
+
+ start_lba = fdisk_partition_get_start(p);
+ assert(start_lba <= UINT64_MAX/512);
+ start = start_lba * 512;
+
+ last_lba = fdisk_get_last_lba(c); /* One sector before boundary where usable space ends */
+ assert(last_lba < UINT64_MAX/512);
+ end = DISK_SIZE_ROUND_DOWN((last_lba + 1) * 512); /* Round down to multiple of 4K */
+
+ if (start > end)
+ return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Last LBA is before partition start.");
+
+ *ret_maximum_partition_size = DISK_SIZE_ROUND_DOWN(end - start);
+
+ return 1;
+}
+
static int ask_cb(struct fdisk_context *c, struct fdisk_ask *ask, void *userdata) {
char *result;
setup->partition_offset + setup->partition_size > old_image_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Old partition doesn't fit in backing storage, refusing.");
+ /* Get target partition information in here for new_partition_size calculation */
+ r = prepare_resize_partition(
+ image_fd,
+ setup->partition_offset,
+ setup->partition_size,
+ &disk_uuid,
+ &table,
+ &partition);
+ if (r < 0)
+ return r;
+
if (S_ISREG(st.st_mode)) {
uint64_t partition_table_extra, largest_size;
new_partition_size = 0;
intention = INTENTION_SHRINK;
} else {
- uint64_t new_partition_size_rounded;
+ uint64_t new_partition_size_rounded = DISK_SIZE_ROUND_DOWN(h->disk_size);
- new_partition_size_rounded = DISK_SIZE_ROUND_DOWN(h->disk_size);
+ if (h->disk_size == UINT64_MAX && partition) {
+ r = get_maximum_partition_size(image_fd, partition, &new_partition_size_rounded);
+ if (r < 0)
+ return r;
+ }
if (setup->partition_size >= new_partition_size_rounded &&
setup->partition_size <= h->disk_size) {
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
FORMAT_BYTES(new_fs_size));
- r = prepare_resize_partition(
- image_fd,
- setup->partition_offset,
- setup->partition_size,
- &disk_uuid,
- &table,
- &partition);
- if (r < 0)
- return r;
-
if (new_fs_size > old_fs_size) { /* → Grow */
if (S_ISREG(st.st_mode)) {