Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 40 additions & 12 deletions ubireader/ubifs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

if TYPE_CHECKING:
from ubireader.ubi_io import ubi_file as UbiFile, leb_virtual_file as LebVirtualFile
from typing import Optional
from zlib import crc32

class ubifs():
"""UBIFS object
Expand Down Expand Up @@ -65,24 +67,50 @@ def __init__(self, ubifs_file: UbiFile | LebVirtualFile, master_key: bytes | Non

self._mst_nodes: list[nodes.mst_node | None] = [None, None]
for i in range(0, 2):
s_mst_offset = self.leb_size * (UBIFS_MST_LNUM + i)
mst_offset = s_mst_offset
mst_nodes = []
try:
mst_offset = self.leb_size * (UBIFS_MST_LNUM + i)
self.file.seek(mst_offset)
mst_chdr = nodes.common_hdr(self.file.read(UBIFS_COMMON_HDR_SZ))
log(self , '%s file addr: %s' % (mst_chdr, self.file.last_read_addr()))
verbose_display(mst_chdr)
while mst_offset < self.leb_size + s_mst_offset:
self.file.seek(mst_offset)
mst_chdr = nodes.common_hdr(self.file.read(UBIFS_COMMON_HDR_SZ))
log(self , '%s file addr: %s' % (mst_chdr, self.file.last_read_addr()))
verbose_display(mst_chdr)
# crc
cpos = self.file.tell()
self.file.seek(mst_offset + 8)
crcdata = self.file.read(mst_chdr.len-8)
self.file.seek(cpos)
crc = (~crc32(crcdata) & 0xFFFFFFFF)

if crc != mst_chdr.crc:
log(self, 'Master node CRC check failed: expected 0x%x got 0x%x' % (crc, mst_chdr.crc))
mst_offset += mst_chdr.len
continue

if mst_chdr.node_type == UBIFS_MST_NODE:
self.file.seek(mst_offset + UBIFS_COMMON_HDR_SZ)
buf = self.file.read(UBIFS_MST_NODE_SZ)
self._mst_nodes[i] = nodes.mst_node(buf, self.file.last_read_addr())
log(self , '%s%s file addr: %s' % (self._mst_nodes[i], i, self.file.last_read_addr()))
verbose_display(self._mst_nodes[i])
else:
raise Exception('Wrong node type.')
if mst_chdr.node_type == UBIFS_MST_NODE:
buf = self.file.read(UBIFS_MST_NODE_SZ)
mst_node = nodes.mst_node(buf, self.file.last_read_addr())
mst_nodes.append(mst_node)
log(self , '%s%s file addr: %s' % (mst_node, i, self.file.last_read_addr()))
verbose_display(mst_node)
elif mst_chdr.node_type == UBIFS_PAD_NODE:
buf = self.file.read(UBIFS_PAD_NODE_SZ)
padnode = nodes.pad_node(buf, self.file.last_read_addr())
mst_offset += padnode.pad_len
log(self , '%s%s file addr: %s' % (padnode, i, self.file.last_read_addr()))
verbose_display(padnode)
else:
raise Exception('Wrong node type.')
mst_offset += mst_chdr.len
except Exception as e:
error(self, 'Warn', 'Master block %s error: %s' % (i, e))

# Get the valid master node with the highest sequence number.
if len(mst_nodes):
self._mst_nodes[i] = max(mst_nodes, key=lambda x: x.cmt_no)

if self._mst_nodes[0] is None and self._mst_nodes[1] is None:
error(self, 'Fatal', 'No valid Master Node found.')

Expand Down
8 changes: 8 additions & 0 deletions ubireader/ubifs/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ def mst_node(node: nodes.mst_node, tab: str = '') -> str:
buf += '%s%s: %r\n' % (tab, key, value)
return buf

def pad_node(node, tab=''):
buf = '%s%s\n' % (tab, node)
buf += '%sFile offset: %s\n' % (tab, node.file_offset)
buf += '%s---------------------\n' % (tab)
tab += '\t'
for key, value in node:
buf += '%s%s: %r\n' % (tab, key, value)
return buf

def dent_node(node: nodes.dent_node, tab: str = '') -> str:
buf = '%s%s\n' % (tab, node)
Expand Down
28 changes: 28 additions & 0 deletions ubireader/ubifs/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,31 @@ def __iter__(self) -> Iterator[tuple[str, Any]]:

def display(self, tab: str = '') -> str:
return display.mst_node(self, tab)

class pad_node(object):
"""Get pad node at given LEB number + offset.

Arguments:
Bin:buf -- Raw data to extract header information from.
Int:offset -- Offset in LEB of data node.

See ubifs/defines.py for object attributes.
"""
def __init__(self, buf, file_offset=-1):
self.file_offset = file_offset
fields = dict(list(zip(UBIFS_PAD_NODE_FIELDS, struct.unpack(UBIFS_PAD_NODE_FORMAT, buf))))
for key in fields:
setattr(self, key, fields[key])

setattr(self, 'errors', [])

def __repr__(self):
return 'UBIFS Pad Node'

def __iter__(self):
for key in dir(self):
if not key.startswith('_'):
yield key, getattr(self, key)

def display(self, tab=''):
return display.pad_node(self, tab)
6 changes: 5 additions & 1 deletion ubireader/ubifs/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,11 @@ def _set_file_perms(path, inode):
verbose_log(_set_file_perms, 'perms:%s, owner: %s.%s, path: %s' % (inode['ino'].mode, inode['ino'].uid, inode['ino'].gid, path))

def _set_file_timestamps(path, inode):
os.utime(path, (inode['ino'].atime_sec, inode['ino'].mtime_sec), follow_symlinks = False)
times = (inode['ino'].atime_sec, inode['ino'].mtime_sec)
if os.utime in os.supports_follow_symlinks:
os.utime(path, times, follow_symlinks=False)
else:
os.utime(path, times)
verbose_log(_set_file_timestamps, 'timestamps: access: %s, modify: %s, path: %s' % (inode['ino'].atime_sec, inode['ino'].mtime_sec, path))

def _write_reg_file(path, data):
Expand Down
Loading