Commit 76569da2 authored by Nikos Skalkotos's avatar Nikos Skalkotos
Browse files

disklabel.py: Use abc.ABCMeta on the base classes

Make PartitionTableBase and DisklabelBase classes abstract by using the
ABCMeta metaclass of the abc module
parent 718713c1
...@@ -26,6 +26,7 @@ import sys ...@@ -26,6 +26,7 @@ import sys
import os import os
import cStringIO import cStringIO
import optparse import optparse
import abc
from collections import namedtuple from collections import namedtuple
from collections import OrderedDict from collections import OrderedDict
...@@ -45,7 +46,7 @@ class MBR(object): ...@@ -45,7 +46,7 @@ class MBR(object):
"""Represents a Master Boot Record.""" """Represents a Master Boot Record."""
class Partition(object): class Partition(object):
"""Represents a partition entry in MBR""" """Represents a partition entry in MBR"""
format = "<B3sB3sLL" fmt = "<B3sB3sLL"
def __init__(self, raw_part): def __init__(self, raw_part):
"""Create a Partition instance""" """Create a Partition instance"""
...@@ -55,11 +56,11 @@ class MBR(object): ...@@ -55,11 +56,11 @@ class MBR(object):
self.end, self.end,
self.first_sector, self.first_sector,
self.sector_count self.sector_count
) = struct.unpack(self.format, raw_part) ) = struct.unpack(self.fmt, raw_part)
def pack(self): def pack(self):
"""Pack the partition values into a binary string""" """Pack the partition values into a binary string"""
return struct.pack(self.format, return struct.pack(self.fmt,
self.status, self.status,
self.start, self.start,
self.type, self.type,
...@@ -70,7 +71,7 @@ class MBR(object): ...@@ -70,7 +71,7 @@ class MBR(object):
@staticmethod @staticmethod
def size(): def size():
"""Returns the size of an MBR partition entry""" """Returns the size of an MBR partition entry"""
return struct.calcsize(MBR.Partition.format) return struct.calcsize(MBR.Partition.fmt)
def __str__(self): def __str__(self):
return "%02Xh %s %02Xh %s %d %d" % (self.status, return "%02Xh %s %02Xh %s %d %d" % (self.status,
...@@ -117,7 +118,7 @@ class MBR(object): ...@@ -117,7 +118,7 @@ class MBR(object):
def __init__(self, block): def __init__(self, block):
"""Create an MBR instance""" """Create an MBR instance"""
self.format = "<444s2x16s16s16s16s2s" self.fmt = "<444s2x16s16s16s16s2s"
raw_part = {} # Offset Length Contents raw_part = {} # Offset Length Contents
(self.code_area, # 0 440(max. 446) code area (self.code_area, # 0 440(max. 446) code area
# 440 2(optional) disk signature # 440 2(optional) disk signature
...@@ -127,7 +128,7 @@ class MBR(object): ...@@ -127,7 +128,7 @@ class MBR(object):
raw_part[2], # 478 16 Partition 2 raw_part[2], # 478 16 Partition 2
raw_part[3], # 494 16 Partition 3 raw_part[3], # 494 16 Partition 3
self.signature # 510 2 MBR signature self.signature # 510 2 MBR signature
) = struct.unpack(self.format, block) ) = struct.unpack(self.fmt, block)
self.part = {} self.part = {}
for i in range(4): for i in range(4):
...@@ -135,11 +136,11 @@ class MBR(object): ...@@ -135,11 +136,11 @@ class MBR(object):
def size(self): def size(self):
"""Return the size of a Master Boot Record.""" """Return the size of a Master Boot Record."""
return struct.calcsize(self.format) return struct.calcsize(self.fmt)
def pack(self): def pack(self):
"""Pack an MBR to a binary string.""" """Pack an MBR to a binary string."""
return struct.pack(self.format, return struct.pack(self.fmt,
self.code_area, self.code_area,
self.part[0].pack(), self.part[0].pack(),
self.part[1].pack(), self.part[1].pack(),
...@@ -235,25 +236,19 @@ class Disk(object): ...@@ -235,25 +236,19 @@ class Disk(object):
class DisklabelBase(object): class DisklabelBase(object):
"""Disklabel base class""" """Disklabel base class"""
__metaclass__ = abc.ABCMeta
def __init__(self, device): def __init__(self, device):
"""Create a Disklabel instance""" """Create a Disklabel instance"""
pass
@property
def format(self):
"""Fields format string"""
raise NotImplementedError
@property # Subclasses need to overwrite this
def field(self): self.field = None
"""Diskalabel Fields data structure""" self.ptable = None
raise NotImplementedError
@property @abc.abstractproperty
def ptable(self): def fmt(self):
"""Partition Table data structure""" """Fields format string for the disklabel fields"""
raise NotImplementedError pass
def pack(self, checksum=None): def pack(self, checksum=None):
"""Return a binary copy of the Disklabel block""" """Return a binary copy of the Disklabel block"""
...@@ -264,7 +259,7 @@ class DisklabelBase(object): ...@@ -264,7 +259,7 @@ class DisklabelBase(object):
else: else:
out = self.field out = self.field
return struct.pack(self.format, * out.values() + [self.ptable.pack()]) return struct.pack(self.fmt, * out.values() + [self.ptable.pack()])
def compute_checksum(self): def compute_checksum(self):
"""Compute the checksum of the disklabel""" """Compute the checksum of the disklabel"""
...@@ -281,10 +276,6 @@ class DisklabelBase(object): ...@@ -281,10 +276,6 @@ class DisklabelBase(object):
return checksum return checksum
def enlarge(self, new_size):
"""Enlarge the disk and return the last useable sector"""
raise NotImplementedError
def write_to(self, device): def write_to(self, device):
"""Write the disklabel to a device""" """Write the disklabel to a device"""
...@@ -292,40 +283,63 @@ class DisklabelBase(object): ...@@ -292,40 +283,63 @@ class DisklabelBase(object):
device.seek(BLOCKSIZE, os.SEEK_CUR) device.seek(BLOCKSIZE, os.SEEK_CUR)
device.write(self.pack()) device.write(self.pack())
def enlarge_last_partition(self): @abc.abstractmethod
"""Enlarge the last partition to consume all the useable space"""
raise NotImplementedError
def get_last_partition_id(self): def get_last_partition_id(self):
"""Get the ID of the last partition""" """Get the ID of the last partition"""
raise NotImplementedError pass
@abc.abstractmethod
def __str__(self): def __str__(self):
"""Print the Disklabel""" """Print the Disklabel"""
raise NotImplementedError pass
class PartitionTableBase(object): class PartitionTableBase(object):
"""Base Class for disklabel partition tables""" """Base Class for disklabel partition tables"""
__metaclass__ = abc.ABCMeta
@property @abc.abstractproperty
def format(self): def fmt(self):
"""Partition table format string""" """Partition fields format string"""
raise NotImplementedError pass
Partition = namedtuple('Partition', '') @abc.abstractproperty
def fields(self):
"""The partition fields"""
pass
@abc.abstractmethod
def setpsize(self, i, size):
"""Set size for partition i"""
pass
@abc.abstractmethod
def getpsize(self, i):
"""Get size for partition i"""
pass
@abc.abstractmethod
def setpoffset(self, i, offset):
"""Set offset for partition i"""
pass
@abc.abstractmethod
def getpoffset(self, i):
"""Get offset for partition i"""
pass
def __init__(self, ptable, pnumber): def __init__(self, ptable, pnumber):
"""Create a Partition Table instance""" """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) raw = cStringIO.StringIO(ptable)
try: try:
for _ in xrange(pnumber): for _ in xrange(pnumber):
self.part.append( self.part.append(
self.Partition(*struct.unpack(self.format, raw.read(size))) self.Partition(*struct.unpack(self.fmt, raw.read(size)))
) )
finally: finally:
raw.close() raw.close()
...@@ -341,7 +355,7 @@ class PartitionTableBase(object): ...@@ -341,7 +355,7 @@ class PartitionTableBase(object):
"""Packs the partition table into a binary string.""" """Packs the partition table into a binary string."""
ret = "" ret = ""
for i in xrange(len(self.part)): 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') return ret + ((364 - len(self.part) * 16) * '\x00')
...@@ -351,16 +365,46 @@ class BSDDisklabel(DisklabelBase): ...@@ -351,16 +365,46 @@ class BSDDisklabel(DisklabelBase):
class PartitionTable(PartitionTableBase): class PartitionTable(PartitionTableBase):
"""Represents a BSD Partition Table""" """Represents a BSD Partition Table"""
format = "<IIIBBH" @property
Partition = namedtuple( def fmt(self):
'Partition', # Offset Length Contents """Partition fields format string"""
['size', # 0 4 Number of sectors in partition return "<IIIBBH"
'offset', # 4 4 Starting sector
'fsize', # 8 4 Filesystem basic fragment size @property
'fstype', # 12 1 Filesystem type def fields(self):
'frag', # 13 1 Filesystem fragments per block """The partition fields"""
'cpg' # 14 2 Filesystem cylinders per group 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
]
def setpsize(self, i, size):
"""Set size for partition i"""
tmp = self.part[i]
self.part[i] = self.Partition(size, tmp.offset, tmp.fsize,
tmp.fstype, tmp.frag, tmp.cpg)
def getpsize(self, i):
"""Get size for partition i"""
return self.part[i].size
def setpoffset(self, i, offset):
"""Set offset for partition i"""
tmp = self.part[i]
self.part[i] = self.Partition(tmp.size, offset, tmp.fsize,
tmp.fstype, tmp.frag, tmp.cpg)
def getpoffset(self, i):
"""Get offset for partition i"""
return self.part[i].offset
@property
def fmt(self):
return "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
def __init__(self, device): def __init__(self, device):
"""Create a BSD DiskLabel instance""" """Create a BSD DiskLabel instance"""
...@@ -371,7 +415,6 @@ class BSDDisklabel(DisklabelBase): ...@@ -371,7 +415,6 @@ class BSDDisklabel(DisklabelBase):
device.seek(BLOCKSIZE, os.SEEK_CUR) device.seek(BLOCKSIZE, os.SEEK_CUR)
sector1 = device.read(BLOCKSIZE) sector1 = device.read(BLOCKSIZE)
self.format = "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s"
d_ = OrderedDict() # Off Len Content d_ = OrderedDict() # Off Len Content
(d_["magic"], # 0 4 Magic (d_["magic"], # 0 4 Magic
d_["dtype"], # 4 2 Drive Type d_["dtype"], # 4 2 Drive Type
...@@ -402,12 +445,21 @@ class BSDDisklabel(DisklabelBase): ...@@ -402,12 +445,21 @@ class BSDDisklabel(DisklabelBase):
d_["bbsize"], # 132 4 size of boot area at sn0, bytes d_["bbsize"], # 132 4 size of boot area at sn0, bytes
d_["sbsize"], # 136 4 Max size of fs superblock, bytes d_["sbsize"], # 136 4 Max size of fs superblock, bytes
ptable_raw # 140 16*16 Partition Table 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" assert d_['magic'] == d_['magic2'] == DISKMAGIC, "Disklabel not valid"
self.ptable = self.PartitionTable(ptable_raw, d_['npartitions']) self.ptable = self.PartitionTable(ptable_raw, d_['npartitions'])
self.field = d_ 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): def __str__(self):
"""Print the Disklabel""" """Print the Disklabel"""
...@@ -455,17 +507,21 @@ class OpenBSDDisklabel(DisklabelBase): ...@@ -455,17 +507,21 @@ class OpenBSDDisklabel(DisklabelBase):
class PartitionTable(PartitionTableBase): class PartitionTable(PartitionTableBase):
"""Reprepsents an OpenBSD Partition Table""" """Reprepsents an OpenBSD Partition Table"""
format = "<IIHHBBH" @property
Partition = namedtuple( def fmt(self):
'Partition', # Offset Length Contents return "<IIHHBBH"
['size', # 0 4 Number of sectors in the partition
'offset', # 4 4 Starting sector @property
'offseth', # 8 2 Starting sector (high part) def fields(self):
'sizeh', # 10 2 Number of sectors (high part) return [ # Offset Length Contents
'fstype', # 12 1 File system type 'size', # 0 4 Number of sectors in the partition
'frag', # 13 1 File system Fragments per block 'offset', # 4 4 Starting sector of the partition
'cpg' # 14 2 File system cylinders per group 'offseth', # 8 2 Starting sector (high part)
]) 'sizeh', # 10 2 Number of sectors (high part)
'fstype', # 12 1 File system type
'frag', # 13 1 File system fragments per block
'cpg' # 14 2 File system cylinders per group
]
def setpsize(self, i, size): def setpsize(self, i, size):
"""Set size for partition i""" """Set size for partition i"""
...@@ -489,6 +545,10 @@ class OpenBSDDisklabel(DisklabelBase): ...@@ -489,6 +545,10 @@ class OpenBSDDisklabel(DisklabelBase):
"""Get offset for partition i""" """Get offset for partition i"""
return (self.part[i].offseth << 32) + self.part[i].offset return (self.part[i].offseth << 32) + self.part[i].offset
@property
def fmt(self):
return "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
def __init__(self, device): def __init__(self, device):
"""Create a DiskLabel instance""" """Create a DiskLabel instance"""
...@@ -498,7 +558,6 @@ class OpenBSDDisklabel(DisklabelBase): ...@@ -498,7 +558,6 @@ class OpenBSDDisklabel(DisklabelBase):
device.seek(BLOCKSIZE, os.SEEK_CUR) device.seek(BLOCKSIZE, os.SEEK_CUR)
sector1 = device.read(BLOCKSIZE) sector1 = device.read(BLOCKSIZE)
self.format = "<IHH16s16sIIIIII8sIHHIII20sHH16sIHHII364s"
d_ = OrderedDict() # Off Len Content d_ = OrderedDict() # Off Len Content
(d_["magic"], # 0 4 Magic (d_["magic"], # 0 4 Magic
d_["dtype"], # 4 2 Drive Type d_["dtype"], # 4 2 Drive Type
...@@ -528,7 +587,7 @@ class OpenBSDDisklabel(DisklabelBase): ...@@ -528,7 +587,7 @@ class OpenBSDDisklabel(DisklabelBase):
d_["bbsize"], # 132 4 size of boot area at sn0, bytes d_["bbsize"], # 132 4 size of boot area at sn0, bytes
d_["sbsize"], # 136 4 Max size of fs superblock, bytes d_["sbsize"], # 136 4 Max size of fs superblock, bytes
ptable_raw # 140 16*16 Partition Table 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" assert d_['magic'] == d_['magic2'] == DISKMAGIC, "Disklabel not valid"
self.ptable = self.PartitionTable(ptable_raw, d_['npartitions']) self.ptable = self.PartitionTable(ptable_raw, d_['npartitions'])
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment