Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/unblob/handlers/filesystem/android/erofs.py: 100%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

27 statements  

1import io 

2 

3from unblob.extractors import Command 

4from unblob.file_utils import ( 

5 Endian, 

6 InvalidInputFormat, 

7 snull, 

8) 

9from unblob.models import ( 

10 File, 

11 HandlerDoc, 

12 HandlerType, 

13 HexString, 

14 Reference, 

15 StructHandler, 

16 ValidChunk, 

17) 

18 

19C_DEFINITIONS = r""" 

20 typedef struct erofs_handler{ 

21 uint32_t magic; 

22 uint32_t crc32c; 

23 uint32_t feature_compact; 

24 uint8_t block_size_bs; 

25 uint8_t sb_extslots; 

26 uint16_t root_nid; 

27 uint64_t inos; 

28 uint64_t build_time; 

29 uint32_t build_time_nsec; 

30 uint32_t block_count; 

31 uint32_t meta_blkaddr; 

32 uint32_t xattr_blkaddr; 

33 uint8_t uuid[16]; 

34 char volume_name[16]; 

35 uint32_t feature_incompact; 

36 char reserved[44]; 

37 } erofs_handler_t; 

38""" 

39 

40SUPERBLOCK_OFFSET = 0x400 

41 

42 

43class EROFSHandler(StructHandler): 

44 NAME = "erofs" 

45 PATTERNS = [HexString("e2 e1 f5 e0")] # Magic in little endian 

46 HEADER_STRUCT = "erofs_handler_t" 

47 C_DEFINITIONS = C_DEFINITIONS 

48 EXTRACTOR = Command( 

49 "fsck.erofs", 

50 "--no-preserve", 

51 "--extract={outdir}", 

52 "{inpath}", 

53 ) 

54 PATTERN_MATCH_OFFSET = -SUPERBLOCK_OFFSET 

55 

56 DOC = HandlerDoc( 

57 name="Android EROFS", 

58 description="EROFS (Enhanced Read-Only File System) is a lightweight, high-performance file system designed for read-only use cases, commonly used in Android and Linux. It features compression support, metadata efficiency, and a fixed superblock structure.", 

59 handler_type=HandlerType.FILESYSTEM, 

60 vendor="Google", 

61 references=[ 

62 Reference( 

63 title="EROFS Documentation", 

64 url="https://www.kernel.org/doc/html/latest/filesystems/erofs.html", 

65 ), 

66 Reference( 

67 title="EROFS Wikipedia", 

68 url="https://en.wikipedia.org/wiki/Enhanced_Read-Only_File_System", 

69 ), 

70 ], 

71 limitations=[], 

72 ) 

73 

74 def is_valid_header(self, header) -> bool: 

75 try: 

76 snull(header.volume_name).decode("utf-8") 

77 except UnicodeDecodeError: 

78 return False 

79 return ( 

80 header.block_count >= 1 

81 and header.build_time > 0 

82 and header.build_time_nsec > 0 

83 and header.block_size_bs >= 9 

84 ) 

85 

86 def calculate_chunk(self, file: File, start_offset: int) -> ValidChunk | None: 

87 file.seek(start_offset + SUPERBLOCK_OFFSET, io.SEEK_SET) 

88 header = self.parse_header(file, Endian.LITTLE) 

89 if not self.is_valid_header(header): 

90 raise InvalidInputFormat("Invalid erofs header.") 

91 

92 end_offset = (1 << header.block_size_bs) * header.block_count 

93 return ValidChunk( 

94 start_offset=start_offset, 

95 end_offset=end_offset, 

96 )