From b0376b3fa9916be57a7847467e7f1ac42705d25b Mon Sep 17 00:00:00 2001 From: Nikos Skalkotos Date: Tue, 29 Jan 2013 15:27:54 +0200 Subject: [PATCH] Add support for gpt partitions in bundle_volume --- image_creator/bundle_volume.py | 74 +++++++++++++++++++++------------------- image_creator/gpt.py | 1 + 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/image_creator/bundle_volume.py b/image_creator/bundle_volume.py index f2aa22a..e373f88 100644 --- a/image_creator/bundle_volume.py +++ b/image_creator/bundle_volume.py @@ -34,6 +34,7 @@ import os import re import tempfile +import uuid from collections import namedtuple import parted @@ -43,6 +44,7 @@ from image_creator.util import get_command from image_creator.util import FatalError from image_creator.util import try_fail_repeat from image_creator.util import free_space +from image_creator.gpt import GPTPartitionTable findfs = get_command('findfs') dd = get_command('dd') @@ -128,17 +130,23 @@ class BundleVolume(object): def _create_partition_table(self, image): - if self.disk.type != 'msdos': - raise FatalError('Only msdos partition tables are supported') - # Copy the MBR and the space between the MBR and the first partition. - # In Grub version 1 Stage 1.5 is located there. + # In msdos partitons tables Grub Stage 1.5 is located there. + # In gpt partition tables the Primary GPT Header is there. first_sector = self.disk.getPrimaryPartitions()[0].geometry.start dd('if=%s' % self.disk.device.path, 'of=%s' % image, 'bs=%d' % self.disk.device.sectorSize, 'count=%d' % first_sector, 'conv=notrunc') + if self.disk.type == 'gpt': + # Copy the Secondary GPT Header + table = GPTPartitionTable(self.disk.device.path) + dd('if=%s' % self.disk.device.path, 'of=%s' % image, + 'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc', + 'seek=%d' % table.primary.last_usable_lba, + 'skip=%d' % table.primary.last_usable_lba) + # Create the Extended boot records (EBRs) in the image extended = self.disk.getExtendedPartition() if not extended: @@ -172,8 +180,7 @@ class BundleVolume(object): new_end = self.disk.device.length - image_dev = parted.Device(image) - image_disk = parted.Disk(image_dev) + image_disk = parted.Disk(parted.Device(image)) is_extended = lambda p: p.type == parted.PARTITION_EXTENDED is_logical = lambda p: p.type == parted.PARTITION_LOGICAL @@ -188,19 +195,18 @@ class BundleVolume(object): image_disk.deletePartition( image_disk.getPartitionBySector(last.start)) - image_disk.commit() + image_disk.commitToDevice() if is_logical(last) and last.num == 5: extended = image_disk.getExtendedPartition() image_disk.deletePartition(extended) - image_disk.commit() + image_disk.commitToDevice() partitions.remove(filter(is_extended, partitions)[0]) partitions.remove(last) last = partitions[-1] - # Leave 2048 blocks at the end - new_end = last.end + 2048 + new_end = last.end mount_options = self._get_mount_options( self.disk.getPartitionBySector(last.start).path) @@ -220,30 +226,23 @@ class BundleVolume(object): image_disk.getPartitionBySector(last.start), parted.Constraint(device=image_disk.device), start=last.start, end=part_end) - image_disk.commit() + image_disk.commitToDevice() # Parted may have changed this for better alignment part_end = image_disk.getPartitionBySector(last.start).geometry.end last = last._replace(end=part_end) partitions[-1] = last - # Leave 2048 blocks at the end. - new_end = part_end + 2048 + new_end = part_end if last.type == parted.PARTITION_LOGICAL: # Fix the extended partition - extended = disk.getExtendedPartition() - - image_disk.setPartitionGeometry( - extended, parted.Constraint(device=img_dev), - ext.geometry.start, end=last.end) - image_disk.commit() + image_disk.minimizeExtendedPartition() - # image_dev.destroy() - return new_end + return (new_end, self._get_partitions(image_disk)) def _map_partition(self, dev, num, start, end): - name = os.path.basename(dev) + name = os.path.basename(dev) + "_" + uuid.uuid4().hex tablefd, table = tempfile.mkstemp() try: size = end - start + 1 @@ -321,14 +320,13 @@ class BundleVolume(object): '/boot/grub/menu.lst', '/boot/grub/grub.conf'] - orig = dict(map( - lambda p: ( - p.number, - blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip()), - self.disk.partitions)) + orig = {} + for p in self.disk.partitions: + if p.number in new_uuid.keys(): + orig[p.number] = \ + blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip() for f in map(lambda f: target + f, files): - if not os.path.exists(f): continue @@ -340,13 +338,12 @@ class BundleVolume(object): line = re.sub(orig[i], uuid, line) dest.write(line) - def _create_filesystems(self, image): + def _create_filesystems(self, image, partitions): filesystem = {} for p in self.disk.partitions: filesystem[p.number] = self._get_mount_options(p.path) - partitions = self._get_partitions(parted.Disk(parted.Device(image))) unmounted = filter(lambda p: filesystem[p.num] is None, partitions) mounted = filter(lambda p: filesystem[p.num] is not None, partitions) @@ -429,10 +426,17 @@ class BundleVolume(object): os.close(fd) self._create_partition_table(image) - - end_sector = self._shrink_partitions(image) - - size = (end_sector + 1) * self.disk.device.sectorSize + end_sector, partitions = self._shrink_partitions(image) + + if self.disk.type == 'gpt': + old_size = size + size = (end_sector + 1) * self.disk.device.sectorSize + ptable = GPTPartitionTable(image) + size = ptable.shrink(size, old_size) + else: + # Alighn to 2048 + end_sector = ((end_sector + 2047) // 2048) * 2048 + size = (end_sector + 1) * self.disk.device.sectorSize # Truncate image to the new size. fd = os.open(image, os.O_RDWR) @@ -449,7 +453,7 @@ class BundleVolume(object): dirname) self.out.success("sufficient") - self._create_filesystems(image) + self._create_filesystems(image, partitions) return image diff --git a/image_creator/gpt.py b/image_creator/gpt.py index fa9dbde..98f7cc8 100644 --- a/image_creator/gpt.py +++ b/image_creator/gpt.py @@ -296,6 +296,7 @@ class GPTPartitionTable(object): d.write(self.mbr.pack()) d.write(self.primary.pack()) d.write('\x00' * (BLOCKSIZE - self.primary.size())) + d.write(self.part_entries) d.seek(self.secondary.part_entry_start * BLOCKSIZE) d.write(self.part_entries) d.seek(self.primary.backup_lba * BLOCKSIZE) -- 1.7.10.4