99from ctypes import c_uint16
1010from ctypes import sizeof
1111
12+ from collections .abc import Generator
13+
1214from ._compat import override
1315
1416from .struct import Ext4Struct
@@ -152,42 +154,42 @@ class Inode(Ext4Struct):
152154 ("i_projid" , c_uint32 ),
153155 ]
154156
155- def __new__ (cls , volume , offset , i_no ):
157+ def __new__ (cls , volume , offset : int , i_no : int ):
156158 if cls is not Inode :
157159 return super ().__new__ (cls )
158160
159- volume .seek (offset + Inode .i_mode .offset )
161+ _ = volume .seek (offset + Inode .i_mode .offset )
160162 file_type = (
161163 Inode .field_type ("i_mode" ).from_buffer_copy (volume .read (Inode .i_mode .size ))
162164 & 0xF000
163165 )
164166 if file_type == MODE .IFIFO :
165- return Fifo ( volume , offset , i_no )
167+ return super (). __new__ ( Fifo )
166168
167169 if file_type == MODE .IFDIR :
168- return Directory ( volume , offset , i_no )
170+ return super (). __new__ ( Directory )
169171
170172 if file_type == MODE .IFREG :
171- return File ( volume , offset , i_no )
173+ return super (). __new__ ( File )
172174
173175 if file_type == MODE .IFLNK :
174- return SymbolicLink ( volume , offset , i_no )
176+ return super (). __new__ ( SymbolicLink )
175177
176178 if file_type == MODE .IFCHR :
177- return CharacterDevice ( volume , offset , i_no )
179+ return super (). __new__ ( CharacterDevice )
178180
179181 if file_type == MODE .IFBLK :
180- return BlockDevice ( volume , offset , i_no )
182+ return super (). __new__ ( BlockDevice )
181183
182184 if file_type == MODE .IFSOCK :
183- return Socket ( volume , offset , i_no )
185+ return super (). __new__ ( Socket )
184186
185187 raise InodeError (f"Unknown file type 0x{ file_type :X} " )
186188
187- def __init__ (self , volume , offset , i_no ):
188- self .i_no = i_no
189+ def __init__ (self , volume , offset : int , i_no : int ):
190+ self .i_no : int = i_no
189191 super ().__init__ (volume , offset )
190- self .tree = ExtentTree (self )
192+ self .tree : ExtentTree = ExtentTree (self )
191193
192194 @property
193195 def superblock (self ):
@@ -206,27 +208,27 @@ def i_file_acl(self):
206208 return self .osd2 .linux2 .l_i_file_acl_high << 32 | self .i_file_acl_lo
207209
208210 @property
209- def has_hi (self ):
211+ def has_hi (self ) -> bool :
210212 return self .superblock .s_inode_size > self .EXT2_GOOD_OLD_INODE_SIZE
211213
212214 @property
213- def fits_in_hi (self ):
215+ def fits_in_hi (self ) -> bool :
214216 return (
215217 self .has_hi
216218 and self .i_checksum_hi .offset + self .i_checksum_hi .size
217219 <= self .EXT2_GOOD_OLD_INODE_SIZE + self .i_extra_isize
218220 )
219221
220222 @property
221- def seed (self ):
223+ def seed (self ) -> int :
222224 seed = crc32c (self .i_no .to_bytes (4 , "little" ), self .volume .seed )
223225 return crc32c (
224226 self .i_generation .to_bytes (Inode .i_generation .size , "little" ),
225227 seed ,
226228 )
227229
228- @property
229- def checksum (self ):
230+ @Ext4Struct . checksum . getter
231+ def checksum (self ) -> int | None :
230232 if self .superblock .s_creator_os != EXT4_OS .LINUX :
231233 return None
232234
@@ -255,8 +257,8 @@ def checksum(self):
255257
256258 return csum
257259
258- @property
259- def expected_checksum (self ):
260+ @Ext4Struct . expected_checksum . getter
261+ def expected_checksum (self ) -> int | None :
260262 if self .superblock .s_creator_os != EXT4_OS .LINUX :
261263 return None
262264
@@ -267,6 +269,7 @@ def expected_checksum(self):
267269
268270 return provided_csum
269271
272+ @override
270273 def validate (self ):
271274 super ().validate ()
272275 if self .tree is not None :
@@ -299,11 +302,13 @@ def _open(self, mode: str = "rb", encoding: None = None, newline: None = None):
299302
300303 return BlockIO (self )
301304
302- def open (self , mode = "rb" , encoding = None , newline = None ):
305+ def open (self , mode : str = "rb" , encoding = None , newline = None ):
303306 raise NotImplementedError ()
304307
305308 @property
306- def xattrs (self ):
309+ def xattrs (
310+ self ,
311+ ) -> Generator [tuple [str , bytes ], None , None ]:
307312 inline_offset = self .offset + self .EXT2_GOOD_OLD_INODE_SIZE + self .i_extra_isize
308313 inline_size = self .offset + self .superblock .s_inode_size - inline_offset
309314 if inline_size > sizeof (ExtendedAttributeIBodyHeader ):
@@ -359,38 +364,40 @@ def readlink(self):
359364
360365
361366class Directory (Inode ):
362- def __init__ (self , volume , offset , i_no ):
367+ def __init__ (self , volume , offset : int , i_no : int ):
363368 super ().__init__ (volume , offset , i_no )
364- self ._dirents = None
369+ self ._dirents : None | list [ DirectoryEntry | DirectoryEntry2 ] = None
365370 if self .is_htree :
366371 self .htree = DXRoot (self )
367372
373+ @override
368374 def verify (self ):
369375 super ().verify ()
370376 # TODO verify DirectoryEntryHash? Or should this be in validate?
371377
378+ @override
372379 def validate (self ):
373380 super ().validate ()
374381 # TODO validate each directory entry block with DirectoryEntryTail
375382
376383 @property
377- def has_filetype (self ):
384+ def has_filetype (self ) -> bool :
378385 return self .superblock .s_feature_incompat & EXT4_FEATURE_INCOMPAT .FILETYPE != 0
379386
380387 @property
381- def is_htree (self ):
388+ def is_htree (self ) -> bool :
382389 return self .i_flags & EXT4_FL .INDEX != 0
383390
384391 @property
385- def is_casefolded (self ):
392+ def is_casefolded (self ) -> bool :
386393 return self .i_flags & EXT4_FL .CASEFOLD != 0
387394
388395 @property
389- def is_encrypted (self ):
396+ def is_encrypted (self ) -> bool :
390397 return self .i_flags & EXT4_FL .ENCRYPTED != 0
391398
392399 @property
393- def hash_in_dirent (self ):
400+ def hash_in_dirent (self ) -> bool :
394401 return self .is_casefolded and self .is_encrypted
395402
396403 def _opendir (self ):
@@ -401,7 +408,7 @@ def _opendir(self):
401408 return
402409
403410 _type = DirectoryEntry2 if self .has_filetype else DirectoryEntry
404- dirents = []
411+ dirents : list [ DirectoryEntry | DirectoryEntry2 ] = []
405412 offset = 0
406413 data = self ._open ().read ()
407414 while offset < len (data ):
@@ -424,8 +431,8 @@ def _opendir(self):
424431 if dirent .rec_len < expected_rec_len :
425432 warnings .warn (
426433 "Directory entry is too small for name length"
427- f", expected={ expected_rec_len } "
428- f", actual={ dirent .rec_len } " ,
434+ + f", expected={ expected_rec_len } "
435+ + f", actual={ dirent .rec_len } " ,
429436 RuntimeWarning ,
430437 )
431438 break
@@ -437,13 +444,9 @@ def _opendir(self):
437444
438445 self ._dirents = dirents
439446
440- def _get_file_type (self , dirent ):
447+ def _get_file_type (self , dirent : DirectoryEntry | DirectoryEntry2 ):
441448 offset = self .volume .inodes .offset (dirent .inode )
442- self .volume .seek (offset + Inode .i_mode .offset )
443- i_mode = Inode .field_type ("i_mode" ).from_buffer_copy (
444- self .volume .read (Inode .i_mode .size )
445- )
446- self .volume .seek (offset + Inode .i_mode .offset )
449+ _ = self .volume .seek (offset + Inode .i_mode .offset )
447450 i_mode = Inode .field_type ("i_mode" ).from_buffer_copy (
448451 self .volume .read (Inode .i_mode .size )
449452 )
0 commit comments