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

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

28 statements  

1import io 

2from typing import Optional 

3 

4from unblob.extractors import Command 

5from unblob.file_utils import ( 

6 Endian, 

7 InvalidInputFormat, 

8 snull, 

9) 

10from unblob.models import ( 

11 File, 

12 HandlerDoc, 

13 HandlerType, 

14 HexString, 

15 Reference, 

16 StructHandler, 

17 ValidChunk, 

18) 

19 

20C_DEFINITIONS = r""" 

21 typedef struct erofs_handler{ 

22 uint32_t magic; 

23 uint32_t crc32c; 

24 uint32_t feature_compact; 

25 uint8_t block_size_bs; 

26 uint8_t sb_extslots; 

27 uint16_t root_nid; 

28 uint64_t inos; 

29 uint64_t build_time; 

30 uint32_t build_time_nsec; 

31 uint32_t block_count; 

32 uint32_t meta_blkaddr; 

33 uint32_t xattr_blkaddr; 

34 uint8_t uuid[16]; 

35 char volume_name[16]; 

36 uint32_t feature_incompact; 

37 char reserved[44]; 

38 } erofs_handler_t; 

39""" 

40 

41SUPERBLOCK_OFFSET = 0x400 

42 

43 

44class EROFSHandler(StructHandler): 

45 NAME = "erofs" 

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

47 HEADER_STRUCT = "erofs_handler_t" 

48 C_DEFINITIONS = C_DEFINITIONS 

49 EXTRACTOR = Command( 

50 "fsck.erofs", 

51 "--no-preserve", 

52 "--extract={outdir}", 

53 "{inpath}", 

54 ) 

55 PATTERN_MATCH_OFFSET = -SUPERBLOCK_OFFSET 

56 

57 DOC = HandlerDoc( 

58 name="Android EROFS", 

59 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.", 

60 handler_type=HandlerType.FILESYSTEM, 

61 vendor="Google", 

62 references=[ 

63 Reference( 

64 title="EROFS Documentation", 

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

66 ), 

67 Reference( 

68 title="EROFS Wikipedia", 

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

70 ), 

71 ], 

72 limitations=[], 

73 ) 

74 

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

76 try: 

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

78 except UnicodeDecodeError: 

79 return False 

80 return ( 

81 header.block_count >= 1 

82 and header.build_time > 0 

83 and header.build_time_nsec > 0 

84 and header.block_size_bs >= 9 

85 ) 

86 

87 def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]: 

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

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

90 if not self.is_valid_header(header): 

91 raise InvalidInputFormat("Invalid erofs header.") 

92 

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

94 return ValidChunk( 

95 start_offset=start_offset, 

96 end_offset=end_offset, 

97 )