import os
import cStringIO
import optparse
+import abc
from collections import namedtuple
from collections import OrderedDict
"""Represents a Master Boot Record."""
class Partition(object):
"""Represents a partition entry in MBR"""
- format = "<B3sB3sLL"
+ fmt = "<B3sB3sLL"
def __init__(self, raw_part):
"""Create a Partition instance"""
self.end,
self.first_sector,
self.sector_count
- ) = struct.unpack(self.format, raw_part)
+ ) = struct.unpack(self.fmt, raw_part)
def pack(self):
"""Pack the partition values into a binary string"""
- return struct.pack(self.format,
+ return struct.pack(self.fmt,
self.status,
self.start,
self.type,
@staticmethod
def size():
"""Returns the size of an MBR partition entry"""
- return struct.calcsize(MBR.Partition.format)
+ return struct.calcsize(MBR.Partition.fmt)
def __str__(self):
start = self.unpack_chs(self.start)
def __init__(self, block):
"""Create an MBR instance"""
- self.format = "<444s2x16s16s16s16s2s"
+ self.fmt = "<444s2x16s16s16s16s2s"
raw_part = {} # Offset Length Contents
(self.code_area, # 0 440(max. 446) code area
# 440 2(optional) disk signature
raw_part[2], # 478 16 Partition 2
raw_part[3], # 494 16 Partition 3
self.signature # 510 2 MBR signature
- ) = struct.unpack(self.format, block)
+ ) = struct.unpack(self.fmt, block)
self.part = {}
for i in range(4):
def size(self):
"""Return the size of a Master Boot Record."""
- return struct.calcsize(self.format)
+ return struct.calcsize(self.fmt)
def pack(self):
"""Pack an MBR to a binary string."""
- return struct.pack(self.format,
+ return struct.pack(self.fmt,
self.code_area,
self.part[0].pack(),
self.part[1].pack(),
class DisklabelBase(object):
"""Disklabel base class"""
+ __metaclass__ = abc.ABCMeta
def __init__(self, device):
"""Create a Disklabel instance"""
- pass
- @property
- def format(self):
- """Fields format string"""
- raise NotImplementedError
-
- @property
- def field(self):
- """Diskalabel Fields data structure"""
- raise NotImplementedError
+ # Subclasses need to overwrite this
+ self.field = None
+ self.ptable = None
- @property
- def ptable(self):
- """Partition Table data structure"""
- raise NotImplementedError
+ @abc.abstractproperty
+ def fmt(self):
+ """Fields format string for the disklabel fields"""
+ pass
def pack(self, checksum=None):
"""Return a binary copy of the Disklabel block"""
if checksum is not None:
out['checksum'] = checksum
- return struct.pack(self.format, * out.values() + [self.ptable.pack()])
+ return struct.pack(self.fmt, * out.values() + [self.ptable.pack()])
def compute_checksum(self):
"""Compute the checksum of the disklabel"""
return checksum
+ @abc.abstractmethod
def enlarge(self, new_size):
"""Enlarge the disk and return the last usable sector"""
- raise NotImplementedError
+ pass
def write_to(self, device):
"""Write the disklabel to a device"""
device.seek(BLOCKSIZE, os.SEEK_CUR)
device.write(self.pack())
+ @abc.abstractmethod
def enlarge_last_partition(self):
"""Enlarge the last partition to consume all the usable space"""
- raise NotImplementedError
+ pass
+ @abc.abstractmethod
def get_last_partition_id(self):
"""Get the ID of the last partition"""
- raise NotImplementedError
+ pass
+ @abc.abstractmethod
def __str__(self):
"""Print the Disklabel"""
- raise NotImplementedError
+ pass
class PartitionTableBase(object):
"""Base Class for disklabel partition tables"""
+ __metaclass__ = abc.ABCMeta
- @property
- def format(self):
- """Partition table format string"""
- raise NotImplementedError
+ @abc.abstractproperty
+ def fmt(self):
+ """Partition fields format string"""
+ pass
- Partition = namedtuple('Partition', '')
+ @abc.abstractproperty
+ def fields(self):
+ """The partition fields"""
+ pass
def __init__(self, ptable, pnumber):
"""Create a Partition Table instance"""
- self.part = []
- size = struct.calcsize(self.format)
+ self.Partition = namedtuple('Partition', self.fields)
+ self.part = []
+ size = struct.calcsize(self.fmt)
raw = cStringIO.StringIO(ptable)
try:
for _ in xrange(pnumber):
self.part.append(
- self.Partition(*struct.unpack(self.format, raw.read(size)))
+ self.Partition(*struct.unpack(self.fmt, raw.read(size)))
)
finally:
raw.close()
"""Packs the partition table into a binary string."""
ret = ""
for i in xrange(len(self.part)):
- ret += struct.pack(self.format, *self.part[i])
+ ret += struct.pack(self.fmt, *self.part[i])
return ret + ((364 - len(self.part) * 16) * '\x00')
class PartitionTable(PartitionTableBase):
"""Represents a BSD Partition Table"""
- format = "<IIIBBH"
- Partition = namedtuple(
- 'Partition', # Offset Length Contents
- ['size', # 0 4 Number of sectors in partition
- 'offset', # 4 4 Starting sector
- 'fsize', # 8 4 Filesystem basic fragment size
- 'fstype', # 12 1 Filesystem type
- 'frag', # 13 1 Filesystem fragments per block
- 'cpg' # 14 2 Filesystem cylinders per group
- ])
+ @property
+ def fmt(self):
+ """Partition fields format string"""
+ return "<IIIBBH"
+
+ @property
+ def fields(self):
+ """The partition fields"""
+ return [ # Offset Length Contents
+ 'size', # 0 4 Number of sectors in partition
+ 'offset', # 4 4 Starting sector of the partition
+ 'fsize', # 8 4 File system basic fragment size
+ 'fstype', # 12 1 File system type
+ 'frag', # 13 1 File system fragments per block
+ 'cpg' # 14 2 File system cylinders per group
+ ]
+
+ @property
+ def fmt(self):
+ return "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
def __init__(self, device):
"""Create a BSD DiskLabel instance"""
device.seek(BLOCKSIZE, os.SEEK_CUR)
sector1 = device.read(BLOCKSIZE)
- self.format = "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
d_ = OrderedDict() # Off Len Content
(d_["magic"], # 0 4 Magic
d_["dtype"], # 4 2 Drive Type
d_["bbsize"], # 132 4 size of boot area at sn0, bytes
d_["sbsize"], # 136 4 Max size of fs superblock, bytes
ptable_raw # 140 16*16 Partition Table
- ) = struct.unpack(self.format, sector1)
+ ) = struct.unpack(self.fmt, sector1)
assert d_['magic'] == d_['magic2'] == DISKMAGIC, "Disklabel not valid"
self.ptable = self.PartitionTable(ptable_raw, d_['npartitions'])
self.field = d_
+ def enlarge(self, new_size):
+ raise NotImplementedError
+
+ def enlarge_last_partition(self):
+ raise NotImplementedError
+
+ def get_last_partition_id(self):
+ raise NotImplementedError
+
def __str__(self):
"""Print the Disklabel"""
class PartitionTable(PartitionTableBase):
"""Reprepsents an OpenBSD Partition Table"""
- format = "<IIHHBBH"
- Partition = namedtuple(
- 'Partition', # Offset Length Contents
- ['size', # 0 4 Number of sectors in the partition
- 'offset', # 4 4 Starting sector
- 'offseth', # 8 2 Starting sector (high part)
- 'sizeh', # 10 2 Number of sectors (high part)
- 'fstype', # 12 1 Filesystem type
- 'frag', # 13 1 Filesystem Fragments per block
- 'cpg' # 14 2 FS cylinders per group
- ])
+
+ @property
+ def fmt(self):
+ return "<IIHHBBH"
+
+ @property
+ def fields(self):
+ return [ # Offset Length Contents
+ 'size', # 0 4 Number of sectors in the partition
+ 'offset', # 4 4 Starting sector of the partition
+ 'offseth', # 8 2 Starting sector (high part)
+ 'sizeh', # 10 2 Number of sectors (high part)
+ 'fstype', # 12 1 Filesystem type
+ 'frag', # 13 1 Filesystem Fragments per block
+ 'cpg' # 14 2 FS cylinders per group
+ ]
def setpsize(self, i, size):
"""Set size for partition i"""
"""Get offset for partition i"""
return (self.part[i].offseth << 32) + self.part[i].offset
+ @property
+ def fmt(self):
+ return "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
+
def __init__(self, device):
"""Create a DiskLabel instance"""
+
super(OpenBSD_Disklabel, self).__init__(device)
# Disklabel starts at offset one
device.seek(BLOCKSIZE, os.SEEK_CUR)
sector1 = device.read(BLOCKSIZE)
- self.format = "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
d_ = OrderedDict() # Off Len Content
(d_["magic"], # 0 4 Magic
d_["dtype"], # 4 2 Drive Type
d_["bbsize"], # 132 4 size of boot area at sn0, bytes
d_["sbsize"], # 136 4 Max size of fs superblock, bytes
ptable_raw # 140 16*16 Partition Table
- ) = struct.unpack(self.format, sector1)
+ ) = struct.unpack(self.fmt, sector1)
assert d_['magic'] == d_['magic2'] == DISKMAGIC, "Disklabel not valid"
self.ptable = self.PartitionTable(ptable_raw, d_['npartitions'])