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

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

33 statements  

1from typing import Optional 

2 

3from pyfatfs._exceptions import PyFATException 

4from pyfatfs.PyFat import PyFat 

5from structlog import get_logger 

6 

7from unblob.extractors.command import Command 

8from unblob.file_utils import InvalidInputFormat 

9 

10from ...models import ( 

11 File, 

12 Handler, 

13 HandlerDoc, 

14 HandlerType, 

15 HexString, 

16 Reference, 

17 ValidChunk, 

18) 

19 

20logger = get_logger() 

21 

22 

23class PyFatNoClose(PyFat): 

24 def close(self): 

25 return 

26 

27 

28def get_max_offset(fs: PyFat) -> int: 

29 # see PyFat.get_cluster_chain for context 

30 i = len(fs.fat) 

31 while i > 0 and fs.fat[i - 1] == 0: 

32 i -= 1 

33 # i - 1 is the last cluster that is part of a filesystem object 

34 return fs.get_data_cluster_address(i) 

35 

36 

37class FATHandler(Handler): 

38 NAME = "fat" 

39 

40 PATTERNS = [ 

41 HexString( 

42 """ 

43 // An initial x86 short jump instruction 

44 // OEMName (8 bytes) 

45 // BytesPerSec (2 bytes) 

46 // SecPerClus (1 byte) "Must be one of 1, 2, 4, 8, 16, 32, 64, 128." 

47 // 495 (0x1EF) bytes of whatever 

48 // 55 AA is the "signature". "This will be the end of the sector only in case the 

49 // sector size is 512." 

50 ( EB | E9 ) [13] ( 01 | 02 | 04 | 08 | 10 | 20 | 40 | 80 ) [495] 55 AA 

51 """ 

52 ) 

53 ] 

54 

55 EXTRACTOR = Command("7z", "x", "-y", "{inpath}", "-o{outdir}") 

56 

57 DOC = HandlerDoc( 

58 name="FAT", 

59 description="FAT (File Allocation Table) is a file system format used for organizing and managing files on storage devices, supporting FAT12, FAT16, and FAT32 variants. It uses a table to map file clusters, enabling efficient file storage and retrieval.", 

60 handler_type=HandlerType.FILESYSTEM, 

61 vendor=None, 

62 references=[ 

63 Reference( 

64 title="FAT Wikipedia", 

65 url="https://en.wikipedia.org/wiki/File_Allocation_Table", 

66 ), 

67 ], 

68 limitations=[], 

69 ) 

70 

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

72 pyfat_fs = PyFatNoClose(offset=start_offset) 

73 try: 

74 pyfat_fs.set_fp(file) # type: ignore 

75 except PyFATException as e: 

76 raise InvalidInputFormat from e 

77 

78 # we have exactly one of these set to non-0, depending on FAT version 

79 total_sectors = max( 

80 pyfat_fs.bpb_header["BPB_TotSec16"], 

81 pyfat_fs.bpb_header["BPB_TotSec32"], 

82 ) 

83 

84 size = total_sectors * pyfat_fs.bpb_header["BPB_BytsPerSec"] 

85 file_size = file.size() 

86 if start_offset + size > file_size: 

87 size = get_max_offset(pyfat_fs) 

88 

89 return ValidChunk( 

90 start_offset=start_offset, 

91 end_offset=start_offset + size, 

92 )