+ ATTENTION: make sure unmount is called before shrink
+ """
+ get_fstype = lambda p: \
+ self.g.vfs_type("%s%d" % (self.guestfs_device, p['part_num']))
+ is_logical = lambda p: \
+ self.meta['PARTITION_TABLE'] == 'msdos' and p['part_num'] > 4
+ is_extended = lambda p: \
+ self.meta['PARTITION_TABLE'] == 'msdos' and \
+ self.g.part_get_mbr_id(self.guestfs_device, p['part_num']) == 5
+
+ part_add = lambda ptype, start, stop: \
+ self.g.part_add(self.guestfs_device, ptype, start, stop)
+ part_del = lambda p: self.g.part_del(self.guestfs_device, p)
+ part_get_id = lambda p: self.g.part_get_mbr_id(self.guestfs_device, p)
+ part_set_id = lambda p, id: \
+ self.g.part_set_mbr_id(self.guestfs_device, p, id)
+ part_get_bootable = lambda p: \
+ self.g.part_get_bootable(self.guestfs_device, p)
+ part_set_bootable = lambda p, bootable: \
+ self.g.part_set_bootable(self.guestfs_device, p, bootable)
+
+ MB = 2 ** 20
+
+ self.out.output("Shrinking image (this may take a while)...", False)
+
+ sector_size = self.g.blockdev_getss(self.guestfs_device)
+
+ last_part = None
+ fstype = None
+ while True:
+ last_part = self._last_partition()
+ fstype = get_fstype(last_part)
+
+ if fstype == 'swap':
+ self.meta['SWAP'] = "%d:%s" % \
+ (last_part['part_num'],
+ (last_part['part_size'] + MB - 1) // MB)
+ part_del(last_part['part_num'])
+ continue
+ elif is_extended(last_part):
+ part_del(last_part['part_num'])
+ continue
+
+ # Most disk manipulation programs leave 2048 sectors after the last
+ # partition
+ new_size = last_part['part_end'] + 1 + 2048 * sector_size
+ self.size = min(self.size, new_size)
+ break
+
+ if not re.match("ext[234]", fstype):
+ self.out.warn("Don't know how to resize %s partitions." % fstype)
+ return self.size
+
+ part_dev = "%s%d" % (self.guestfs_device, last_part['part_num'])