Skip to content

Commit 6ed18b0

Browse files
committed
feat: add type hints to ubireader.ubifs
1 parent b1ccaa8 commit 6ed18b0

8 files changed

Lines changed: 285 additions & 80 deletions

File tree

ubireader/ubifs/__init__.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
21+
from typing import TYPE_CHECKING
2022
from ubireader.debug import error, log, verbose_display
2123
from ubireader.ubifs.defines import *
2224
from ubireader.ubifs import nodes, display
23-
from typing import Optional
25+
26+
if TYPE_CHECKING:
27+
from ubireader.ubi_io import ubi_file as UbiFile, leb_virtual_file as LebVirtualFile
2428

2529
class ubifs():
2630
"""UBIFS object
@@ -36,7 +40,7 @@ class ubifs():
3640
Obj:mst_node -- Master Node of UBIFS image LEB1
3741
Obj:mst_node2 -- Master Node 2 of UBIFS image LEB2
3842
"""
39-
def __init__(self, ubifs_file, master_key: Optional[bytes] = None):
43+
def __init__(self, ubifs_file: UbiFile | LebVirtualFile, master_key: bytes | None = None) -> None:
4044
self.__name__ = 'UBIFS'
4145
self._file = ubifs_file
4246
self.master_key = master_key
@@ -59,7 +63,7 @@ def __init__(self, ubifs_file, master_key: Optional[bytes] = None):
5963
except Exception as e:
6064
error(self, 'Fatal', 'Super block error: %s' % e)
6165

62-
self._mst_nodes = [None, None]
66+
self._mst_nodes: list[nodes.mst_node | None] = [None, None]
6367
for i in range(0, 2):
6468
try:
6569
mst_offset = self.leb_size * (UBIFS_MST_LNUM + i)
@@ -88,12 +92,12 @@ def __init__(self, ubifs_file, master_key: Optional[bytes] = None):
8892
log(self , 'Swapping Master Nodes due to bad first node.')
8993

9094

91-
def _get_file(self):
95+
def _get_file(self) -> UbiFile | LebVirtualFile:
9296
return self._file
9397
file = property(_get_file)
9498

9599

96-
def _get_superblock(self):
100+
def _get_superblock(self) -> nodes.sb_node:
97101
""" Superblock Node Object
98102
99103
Returns:
@@ -103,7 +107,7 @@ def _get_superblock(self):
103107
superblock_node = property(_get_superblock)
104108

105109

106-
def _get_master_node(self):
110+
def _get_master_node(self) -> nodes.mst_node | None:
107111
"""Master Node Object
108112
109113
Returns:
@@ -113,7 +117,7 @@ def _get_master_node(self):
113117
master_node = property(_get_master_node)
114118

115119

116-
def _get_master_node2(self):
120+
def _get_master_node2(self) -> nodes.mst_node | None:
117121
"""Master Node Object 2
118122
119123
Returns:
@@ -123,7 +127,7 @@ def _get_master_node2(self):
123127
master_node2 = property(_get_master_node2)
124128

125129

126-
def _get_leb_size(self):
130+
def _get_leb_size(self) -> int:
127131
"""LEB size of UBI blocks in file.
128132
129133
Returns:
@@ -133,7 +137,7 @@ def _get_leb_size(self):
133137
leb_size = property(_get_leb_size)
134138

135139

136-
def _get_min_io_size(self):
140+
def _get_min_io_size(self) -> int:
137141
"""Min I/O Size
138142
139143
Returns:
@@ -142,7 +146,7 @@ def _get_min_io_size(self):
142146
return self._min_io_size
143147
min_io_size = property(_get_min_io_size)
144148

145-
def display(self, tab=''):
149+
def display(self, tab: str = '') -> str:
146150
"""Print information about this object.
147151
148152
Argument:

ubireader/ubifs/decrypt.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1+
from __future__ import annotations
2+
from typing import TYPE_CHECKING
13
from ubireader.ubifs.defines import UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT
24
from ubireader.debug import error
35
from cryptography.hazmat.primitives.ciphers import (
46
Cipher, algorithms, modes
57
)
68

9+
if TYPE_CHECKING:
10+
from collections.abc import Mapping
11+
from ubireader.ubifs import ubifs as Ubifs, nodes
12+
from ubireader.ubifs.walk import Inode
13+
714
AES_BLOCK_SIZE = algorithms.AES.block_size // 8
815

9-
def lookup_inode_nonce(inodes: dict, inode: dict) -> bytes:
16+
def lookup_inode_nonce(inodes: Mapping[int, Inode], inode: Inode) -> bytes | None:
1017
# get the extended attribute 'xent' of the inode
1118
if 'xent' not in inode or not inode['xent']:
1219
raise ValueError(f"No xent found for inode {inode}")
@@ -29,7 +36,7 @@ def derive_key_from_nonce(master_key: bytes, nonce: bytes) -> bytes:
2936
return derived_key
3037

3138

32-
def filename_decrypt(key: bytes, ciphertext: bytes):
39+
def filename_decrypt(key: bytes, ciphertext: bytes) -> bytes:
3340

3441
# using AES CTS-CBC mode not supported by pyca cryptography
3542
if len(ciphertext) > AES_BLOCK_SIZE:
@@ -59,15 +66,15 @@ def filename_decrypt(key: bytes, ciphertext: bytes):
5966
return plaintext.rstrip(b'\x00')
6067

6168

62-
def datablock_decrypt(block_key: bytes, block_iv: bytes, block_data: bytes):
69+
def datablock_decrypt(block_key: bytes, block_iv: bytes, block_data: bytes) -> bytes:
6370
decryptor = Cipher(
6471
algorithms.AES(block_key),
6572
modes.XTS(block_iv),
6673
).decryptor()
6774
return decryptor.update(block_data) + decryptor.finalize()
6875

6976

70-
def decrypt_filenames(ubifs, inodes):
77+
def decrypt_filenames(ubifs: Ubifs, inodes: Mapping[int, Inode]) -> None:
7178
if ubifs.master_key is None:
7279
for inode in inodes.values():
7380
for dent in inode.get('dent', []):
@@ -87,7 +94,7 @@ def decrypt_filenames(ubifs, inodes):
8794
error(decrypt_filenames, 'Error', str(e))
8895

8996

90-
def decrypt_symlink_target(ubifs, inodes, dent_node) -> str:
97+
def decrypt_symlink_target(ubifs: Ubifs, inodes: Mapping[int, Inode], dent_node: nodes.dent_node) -> str:
9198
if ubifs.master_key is None:
9299
return inodes[dent_node.inum]['ino'].data.decode()
93100
inode = inodes[dent_node.inum]

ubireader/ubifs/display.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,22 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
21+
from typing import TYPE_CHECKING
2022
from ubireader.ubifs.defines import PRINT_UBIFS_FLGS, PRINT_UBIFS_MST
2123

22-
def ubifs(ubifs, tab=''):
24+
if TYPE_CHECKING:
25+
from ubireader.ubifs import ubifs as Ubifs
26+
from ubireader.ubifs import nodes
27+
28+
def ubifs(ubifs: Ubifs, tab: str = '') -> str:
2329
buf = '%sUBIFS Image\n' % (tab)
2430
buf += '%s---------------------\n' % (tab)
2531
buf += '%sMin I/O: %s\n' % (tab, ubifs.min_io_size)
2632
buf += '%sLEB Size: %s\n' % (tab, ubifs.leb_size)
2733
return buf
2834

29-
def common_hdr(chdr, tab=''):
35+
def common_hdr(chdr: nodes.common_hdr, tab: str = '') -> str:
3036
buf = '%s%s\n' % (tab, chdr)
3137
buf += '%s---------------------\n' % (tab)
3238
tab += '\t'
@@ -41,7 +47,7 @@ def common_hdr(chdr, tab=''):
4147
buf += '%s%s: %r\n' % (tab, key, value)
4248
return buf
4349

44-
def sb_node(node, tab=''):
50+
def sb_node(node: nodes.sb_node, tab: str = '') -> str:
4551
buf = '%s%s\n' % (tab, node)
4652
buf += '%sFile offset: %s\n' % (tab, node.file_offset)
4753
buf += '%s---------------------\n' % (tab)
@@ -69,7 +75,7 @@ def sb_node(node, tab=''):
6975
return buf
7076

7177

72-
def mst_node(node, tab=''):
78+
def mst_node(node: nodes.mst_node, tab: str = '') -> str:
7379
buf = '%s%s\n' % (tab, node)
7480
buf += '%sFile offset: %s\n' % (tab, node.file_offset)
7581
buf += '%s---------------------\n' % (tab)
@@ -94,7 +100,7 @@ def mst_node(node, tab=''):
94100
return buf
95101

96102

97-
def dent_node(node, tab=''):
103+
def dent_node(node: nodes.dent_node, tab: str = '') -> str:
98104
buf = '%s%s\n' % (tab, node)
99105
buf += '%s---------------------\n' % (tab)
100106
tab += '\t'
@@ -108,7 +114,7 @@ def dent_node(node, tab=''):
108114
return buf
109115

110116

111-
def data_node(node, tab=''):
117+
def data_node(node: nodes.data_node, tab: str = '') -> str:
112118
buf = '%s%s\n' % (tab, node)
113119
buf += '%s---------------------\n' % (tab)
114120
tab += '\t'
@@ -122,7 +128,7 @@ def data_node(node, tab=''):
122128
return buf
123129

124130

125-
def idx_node(node, tab=''):
131+
def idx_node(node: nodes.idx_node, tab: str = '') -> str:
126132
buf = '%s%s\n' % (tab, node)
127133
buf += '%s---------------------\n' % (tab)
128134
tab += '\t'
@@ -136,7 +142,7 @@ def idx_node(node, tab=''):
136142
return buf
137143

138144

139-
def ino_node(node, tab=''):
145+
def ino_node(node: nodes.ino_node, tab: str = '') -> str:
140146
buf = '%s%s\n' % (tab, node)
141147
buf += '%s---------------------\n' % (tab)
142148
tab += '\t'
@@ -150,7 +156,7 @@ def ino_node(node, tab=''):
150156
return buf
151157

152158

153-
def branch(node, tab=''):
159+
def branch(node: nodes.branch, tab: str = '') -> str:
154160
buf = '%s%s\n' % (tab, node)
155161
buf += '%s---------------------\n' % (tab)
156162
tab += '\t'

ubireader/ubifs/list.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,30 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
2021
import os
2122
import time
22-
import struct
23+
from typing import TYPE_CHECKING
2324
from ubireader.ubifs.decrypt import decrypt_symlink_target
2425
from ubireader.ubifs.defines import *
2526
from ubireader.ubifs import walk
2627
from ubireader.ubifs.misc import process_reg_file
2728
from ubireader.debug import error
2829

30+
if TYPE_CHECKING:
31+
from collections.abc import Mapping
32+
from ubireader.ubifs import ubifs as Ubifs, nodes
33+
from ubireader.ubifs.walk import Inode
2934

30-
def list_files(ubifs, list_path):
35+
def list_files(ubifs: Ubifs, list_path: str) -> None:
3136
pathnames = list_path.split("/")
32-
pnames = []
37+
pnames: list[str] = []
3338
for i in pathnames:
3439
if len(i) > 0:
3540
pnames.append(i)
3641
try:
37-
inodes = {}
38-
bad_blocks = []
42+
inodes: dict[int, Inode] = {}
43+
bad_blocks: list[int] = []
3944

4045
walk.index(ubifs, ubifs.master_node.root_lnum, ubifs.master_node.root_offs, inodes, bad_blocks)
4146

@@ -60,18 +65,18 @@ def list_files(ubifs, list_path):
6065
error(list_files, 'Error', '%s' % e)
6166

6267

63-
def copy_file(ubifs, filepath, destpath):
68+
def copy_file(ubifs: Ubifs, filepath: str, destpath: str) -> bool:
6469
pathnames = filepath.split("/")
65-
pnames = []
70+
pnames: list[str] = []
6671
for i in pathnames:
6772
if len(i) > 0:
6873
pnames.append(i)
6974

7075
filename = pnames[len(pnames)-1]
7176
del pnames[-1]
7277

73-
inodes = {}
74-
bad_blocks = []
78+
inodes: dict[int, Inode] = {}
79+
bad_blocks: list[int] = []
7580

7681
walk.index(ubifs, ubifs.master_node.root_lnum, ubifs.master_node.root_offs, inodes, bad_blocks)
7782

@@ -97,7 +102,7 @@ def copy_file(ubifs, filepath, destpath):
97102
return False
98103

99104

100-
def find_dir(inodes, inum, names, idx):
105+
def find_dir(inodes: Mapping[int, Inode], inum: int, names: list[str], idx: int) -> int | None:
101106
if len(names) == 0:
102107
return 1
103108
for dent in inodes[inum]['dent']:
@@ -109,7 +114,7 @@ def find_dir(inodes, inum, names, idx):
109114
return None
110115

111116

112-
def print_dent(ubifs, inodes, dent_node, long=True, longts=False):
117+
def print_dent(ubifs: Ubifs, inodes: Mapping[int, Inode], dent_node: nodes.dent_node, long: bool = True, longts: bool = False) -> None:
113118
inode = inodes[dent_node.inum]
114119
if long:
115120
fl = file_leng(ubifs, inode)
@@ -128,7 +133,7 @@ def print_dent(ubifs, inodes, dent_node, long=True, longts=False):
128133
print(dent_node.name)
129134

130135

131-
def file_leng(ubifs, inode):
136+
def file_leng(ubifs: Ubifs, inode: Inode) -> int:
132137
fl = 0
133138
if 'data' in inode:
134139
compr_type = 0

ubireader/ubifs/misc.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
21+
from typing import TYPE_CHECKING, TypedDict
2022
from lzallright import LZOCompressor
2123
import struct
2224
import zlib
@@ -25,13 +27,22 @@
2527
from ubireader.debug import error
2628
from ubireader.ubifs.decrypt import lookup_inode_nonce, derive_key_from_nonce, datablock_decrypt
2729

30+
if TYPE_CHECKING:
31+
from collections.abc import Mapping
32+
from ubireader.ubifs import ubifs as Ubifs
33+
from ubireader.ubifs.walk import Inode
34+
2835
# For happy printing
2936
ino_types = ['file', 'dir','lnk','blk','chr','fifo','sock']
3037
node_types = ['ino','data','dent','xent','trun','pad','sb','mst','ref','idx','cs','orph']
3138
key_types = ['ino','data','dent','xent']
3239

40+
class ParsedKey(TypedDict):
41+
type: str
42+
ino_num: int
43+
khash: int
3344

34-
def parse_key(key):
45+
def parse_key(key: bytes) -> ParsedKey:
3546
"""Parse node key
3647
3748
Arguments:
@@ -51,7 +62,7 @@ def parse_key(key):
5162
return {'type':key_type, 'ino_num':ino_num, 'khash': khash}
5263

5364

54-
def decompress(ctype, unc_len, data):
65+
def decompress(ctype: int, unc_len: int, data: bytes) -> bytes | None:
5566
"""Decompress data.
5667
5768
Arguments:
@@ -76,7 +87,7 @@ def decompress(ctype, unc_len, data):
7687
return data
7788

7889

79-
def process_reg_file(ubifs, inode, path, inodes):
90+
def process_reg_file(ubifs: Ubifs, inode: Inode, path: str, inodes: Mapping[int, Inode]) -> bytes:
8091
try:
8192
buf = bytearray()
8293
start_key = (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS)

0 commit comments

Comments
 (0)