1""" 2@copyright: 2009 Bastian Blank <waldi@debian.org> 3@license: GNU GPL-3 4""" 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License version 3 as 7# published by the Free Software Foundation. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17import struct 18 19from .general import DescriptorTag, ExtentAD 20 21 22class AnchorVolumeDescriptorPointer(object): 23 _struct = struct.Struct('<16x20s20s') 24 25 def __init__(self, tag, buf): 26 self.tag = tag 27 if tag.identifier != 2: 28 raise RuntimeError('Anchor Volume Descriptor Pointer illegal') 29 30 data = self._struct.unpack(buf[:56]) 31 self.main_descriptor_extent = ExtentAD(data[0]) 32 self.reserve_descriptor_extent = ExtentAD(data[1]) 33 34 35def _DescriptorSequence(media, location, length): 36 buf = media.read_sector(location, length) 37 38 cur = 0 39 while cur < length: 40 tag = DescriptorTag(buf[cur:cur + 16]) 41 if tag.identifier == 8: 42 break 43 44 yield tag, buf[cur:cur + 2048] 45 46 cur += 2048 47 48 49class Volume(object): 50 _lazy = 'partitions', 51 52 def __init__(self, media): 53 self._media = media 54 55 buf = media.read_sector(256) 56 tag = DescriptorTag(buf) 57 self.anchor = AnchorVolumeDescriptorPointer(tag, buf) 58 59 def __getattr__(self, key): 60 if key in self._lazy: 61 self._populate() 62 return super().__getattribute__(key) 63 64 def _read_descriptors(self, extent): 65 seq = _DescriptorSequence(self._media, extent.location, extent.length) 66 67 partitions = {} 68 69 for tag, buf in seq: 70 if tag.identifier == 5: 71 p = Partition(self._media, self, tag, buf) 72 partitions[p.number] = p 73 elif tag.identifier == 6: 74 # TODO 75 pass 76 77 if partitions: 78 return partitions 79 raise RuntimeError 80 81 def _populate(self): 82 try: 83 data = self._read_descriptors(self.anchor.main_descriptor_extent) 84 except RuntimeError: 85 data = self._read_descriptors(self.anchor.reserve_descriptor_extent) 86 self.partitions = data 87 88 89class Partition(object): 90 _lazy = 'fileset' 91 _struct = struct.Struct('<16x4xHH164xII316x') 92 93 def __init__(self, media, volume, tag, buf): 94 self._media = media 95 self._volume = volume 96 97 self.tag = tag 98 if tag.identifier != 5: 99 raise RuntimeError('Partition Descriptor illegal') 100 101 data = self._struct.unpack(buf[:512]) 102 self.flags, self.number, self.location, self.length = data 103 104 def __getattr__(self, key): 105 if key in self._lazy: 106 self._populate() 107 return super().__getattribute__(key) 108 109 def _populate(self): 110 from .filesystem import FileSet 111 112 seq = _DescriptorSequence(self._media, self.location, self.length) 113 114 for tag, buf in seq: 115 if tag.identifier == 256: 116 self.fileset = FileSet(self._media, self._volume, self.number, tag, buf) 117