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

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

32 statements  

1from pyfatfs._exceptions import PyFATException 

2from pyfatfs.PyFat import PyFat 

3from structlog import get_logger 

4 

5from unblob.extractors.command import Command 

6from unblob.file_utils import InvalidInputFormat 

7 

8from ...models import ( 

9 File, 

10 Handler, 

11 HandlerDoc, 

12 HandlerType, 

13 HexString, 

14 Reference, 

15 ValidChunk, 

16) 

17 

18logger = get_logger() 

19 

20 

21class PyFatNoClose(PyFat): 

22 def close(self): 

23 return 

24 

25 

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

27 # see PyFat.get_cluster_chain for context 

28 i = len(fs.fat) 

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

30 i -= 1 

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

32 return fs.get_data_cluster_address(i) 

33 

34 

35class FATHandler(Handler): 

36 NAME = "fat" 

37 

38 PATTERNS = [ 

39 HexString( 

40 """ 

41 // An initial x86 short jump instruction 

42 // OEMName (8 bytes) 

43 // BytesPerSec (2 bytes) 

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

45 // 495 (0x1EF) bytes of whatever 

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

47 // sector size is 512." 

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

49 """ 

50 ) 

51 ] 

52 

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

54 

55 DOC = HandlerDoc( 

56 name="FAT", 

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

58 handler_type=HandlerType.FILESYSTEM, 

59 vendor=None, 

60 references=[ 

61 Reference( 

62 title="FAT Wikipedia", 

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

64 ), 

65 ], 

66 limitations=[], 

67 ) 

68 

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

70 pyfat_fs = PyFatNoClose(offset=start_offset) 

71 try: 

72 pyfat_fs.set_fp(file) # type: ignore 

73 except PyFATException as e: 

74 raise InvalidInputFormat from e 

75 

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

77 total_sectors = max( 

78 pyfat_fs.bpb_header["BPB_TotSec16"], 

79 pyfat_fs.bpb_header["BPB_TotSec32"], 

80 ) 

81 

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

83 file_size = file.size() 

84 if start_offset + size > file_size: 

85 size = get_max_offset(pyfat_fs) 

86 

87 return ValidChunk( 

88 start_offset=start_offset, 

89 end_offset=start_offset + size, 

90 )