You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
6.6 KiB
Python
227 lines
6.6 KiB
Python
1 year ago
|
#!/usr/bin/env python
|
||
|
#############################################################
|
||
|
# ubi_reader/ubi
|
||
|
# (c) 2013 Jason Pruitt (jrspruitt@gmail.com)
|
||
|
#
|
||
|
# This program is free software: you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation, either version 3 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
#############################################################
|
||
|
|
||
|
from ubireader.debug import error
|
||
|
from ubireader.ubi.block import sort, extract_blocks
|
||
|
from ubireader.ubi import display
|
||
|
from ubireader.ubi.image import description as image
|
||
|
from ubireader.ubi.block import layout, rm_old_blocks
|
||
|
|
||
|
class ubi_base(object):
|
||
|
"""UBI Base object
|
||
|
|
||
|
Arguments:
|
||
|
Obj:image -- UBI image object
|
||
|
|
||
|
Attributes:
|
||
|
ubi_file:file -- ubi_file object
|
||
|
Int:block_count -- Number of blocks found.
|
||
|
Int:first_peb_num -- Number of the first UBI PEB in file.
|
||
|
Int:leb_size -- Size of Logical Erase Blocks.
|
||
|
Int:peb_size -- Size of Physical Erase Blocks.
|
||
|
Int:min_io -- Size of min I/O from vid_hdr_offset.
|
||
|
Dict:blocks -- Dict keyed by PEB number of all blocks.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, ubi_file):
|
||
|
self.__name__ = 'UBI'
|
||
|
self._file = ubi_file
|
||
|
self._first_peb_num = 0
|
||
|
self._blocks = extract_blocks(self)
|
||
|
self._block_count = len(self.blocks)
|
||
|
|
||
|
if self._block_count <= 0:
|
||
|
error(self, 'Fatal', 'No blocks found.')
|
||
|
|
||
|
arbitrary_block = next(iter(self.blocks.values()))
|
||
|
self._min_io_size = arbitrary_block.ec_hdr.vid_hdr_offset
|
||
|
self._leb_size = self.file.block_size - arbitrary_block.ec_hdr.data_offset
|
||
|
|
||
|
|
||
|
def _get_file(self):
|
||
|
"""UBI File object
|
||
|
|
||
|
Returns:
|
||
|
Obj -- UBI File object.
|
||
|
"""
|
||
|
return self._file
|
||
|
file = property(_get_file)
|
||
|
|
||
|
|
||
|
def _get_block_count(self):
|
||
|
"""Total amount of UBI blocks in file.
|
||
|
|
||
|
Returns:
|
||
|
Int -- Number of blocks
|
||
|
"""
|
||
|
return self._block_count
|
||
|
block_count = property(_get_block_count)
|
||
|
|
||
|
|
||
|
def _set_first_peb_num(self, i):
|
||
|
self._first_peb_num = i
|
||
|
def _get_first_peb_num(self):
|
||
|
"""First Physical Erase Block with UBI data
|
||
|
|
||
|
Returns:
|
||
|
Int -- Number of the first PEB.
|
||
|
"""
|
||
|
return self._first_peb_num
|
||
|
first_peb_num = property(_get_first_peb_num, _set_first_peb_num)
|
||
|
|
||
|
|
||
|
def _get_leb_size(self):
|
||
|
"""LEB size of UBI blocks in file.
|
||
|
|
||
|
Returns:
|
||
|
Int -- LEB Size.
|
||
|
"""
|
||
|
return self._leb_size
|
||
|
leb_size = property(_get_leb_size)
|
||
|
|
||
|
|
||
|
def _get_peb_size(self):
|
||
|
"""PEB size of UBI blocks in file.
|
||
|
|
||
|
Returns:
|
||
|
Int -- PEB Size.
|
||
|
"""
|
||
|
return self.file.block_size
|
||
|
peb_size = property(_get_peb_size)
|
||
|
|
||
|
|
||
|
def _get_min_io_size(self):
|
||
|
"""Min I/O Size
|
||
|
|
||
|
Returns:
|
||
|
Int -- Min I/O Size.
|
||
|
"""
|
||
|
return self._min_io_size
|
||
|
min_io_size = property(_get_min_io_size)
|
||
|
|
||
|
|
||
|
def _get_blocks(self):
|
||
|
"""Main Dict of UBI Blocks
|
||
|
|
||
|
Passed around for lists of indexes to be made or to be returned
|
||
|
filtered through a list. So there isn't multiple copies of blocks,
|
||
|
as there can be thousands.
|
||
|
"""
|
||
|
return self._blocks
|
||
|
blocks = property(_get_blocks)
|
||
|
|
||
|
|
||
|
class ubi(ubi_base):
|
||
|
"""UBI object
|
||
|
|
||
|
Arguments:
|
||
|
Obj:ubi_file -- UBI file object.
|
||
|
|
||
|
Attributes:
|
||
|
Inherits:ubi_base -- ubi_base attributes.
|
||
|
List:images -- List of UBI image objects.
|
||
|
List:data_blocks_list -- List of all data blocks in file.
|
||
|
List:layout_blocks_list -- List of all layout blocks in file.
|
||
|
List:int_vol_blocks_list -- List of internal volumes minus layout.
|
||
|
List:unknown_blocks_list -- List of blocks with unknown types. *
|
||
|
"""
|
||
|
|
||
|
def __init__(self, ubi_file):
|
||
|
super(ubi, self).__init__(ubi_file)
|
||
|
|
||
|
layout_list, data_list, int_vol_list, unknown_list = sort.by_type(self.blocks)
|
||
|
|
||
|
self._layout_blocks_list = layout_list
|
||
|
self._data_blocks_list = data_list
|
||
|
self._int_vol_blocks_list = int_vol_list
|
||
|
self._unknown_blocks_list = unknown_list
|
||
|
|
||
|
newest_layout_list = rm_old_blocks(self.blocks, self.layout_blocks_list)
|
||
|
|
||
|
if len(newest_layout_list) < 2:
|
||
|
error(self, 'Fatal', 'Less than 2 layout blocks found.')
|
||
|
|
||
|
layout_pairs = layout.group_pairs(self.blocks, newest_layout_list)
|
||
|
|
||
|
layout_infos = layout.associate_blocks(self.blocks, layout_pairs)
|
||
|
|
||
|
self._images = []
|
||
|
for i in range(0, len(layout_infos)):
|
||
|
self._images.append(image(self.blocks, layout_infos[i]))
|
||
|
|
||
|
|
||
|
def _get_images(self):
|
||
|
"""Get UBI images.
|
||
|
|
||
|
Returns:
|
||
|
List -- Of volume objects groupled by image.
|
||
|
"""
|
||
|
return self._images
|
||
|
images = property(_get_images)
|
||
|
|
||
|
|
||
|
def _get_data_blocks_list(self):
|
||
|
"""Get all UBI blocks found in file that are data blocks.
|
||
|
|
||
|
Returns:
|
||
|
List -- List of block objects.
|
||
|
"""
|
||
|
return self._data_blocks_list
|
||
|
data_blocks_list = property(_get_data_blocks_list)
|
||
|
|
||
|
|
||
|
def _get_layout_blocks_list(self):
|
||
|
"""Get all UBI blocks found in file that are layout volume blocks.
|
||
|
|
||
|
Returns:
|
||
|
List -- List of block objects.
|
||
|
"""
|
||
|
return self._layout_blocks_list
|
||
|
layout_blocks_list = property(_get_layout_blocks_list)
|
||
|
|
||
|
|
||
|
def _get_int_vol_blocks_list(self):
|
||
|
"""Get all UBI blocks found in file that are internal volume blocks.
|
||
|
|
||
|
Returns:
|
||
|
List -- List of block objects.
|
||
|
|
||
|
This does not include layout blocks.
|
||
|
"""
|
||
|
return self._int_vol_blocks_list
|
||
|
int_vol_blocks_list = property(_get_int_vol_blocks_list)
|
||
|
|
||
|
|
||
|
def _get_unknown_blocks_list(self):
|
||
|
"""Get all UBI blocks found in file of unknown type..
|
||
|
|
||
|
Returns:
|
||
|
List -- List of block objects.
|
||
|
"""
|
||
|
return self._unknown_blocks_list
|
||
|
unknown_blocks_list = property(_get_unknown_blocks_list)
|
||
|
|
||
|
def display(self, tab=''):
|
||
|
"""Print information about this object.
|
||
|
|
||
|
Argument:
|
||
|
Str:tab -- '\t' for spacing this object.
|
||
|
"""
|
||
|
return display.ubi(self, tab)
|