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

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

37 statements  

1import io 

2 

3from unblob.file_utils import ( 

4 InvalidInputFormat, 

5) 

6from unblob.models import ( 

7 File, 

8 HandlerDoc, 

9 HandlerType, 

10 HexString, 

11 Reference, 

12 StructHandler, 

13 ValidChunk, 

14) 

15 

16UFS_C_DEFINITION = """ 

17 #define UFS_MAXMNTLEN 512 

18 #define UFS2_MAXMNTLEN 468 

19 #define UFS2_MAXVOLLEN 32 

20 #define UFS_MAXCSBUFS 31 

21 #define UFS2_NOCSPTRS 28 

22 

23 struct ufs_csum { 

24 uint32 cs_ndir; 

25 uint32 cs_nbfree; 

26 uint32 cs_nifree; 

27 uint32 cs_nffree; 

28 }; 

29 

30 struct ufs2_csum_total { 

31 uint64 cs_ndir; 

32 uint64 cs_nbfree; 

33 uint64 cs_nifree; 

34 uint64 cs_nffree; 

35 uint64 cs_numclusters; 

36 uint64 cs_spare[3]; 

37 }; 

38 

39 struct ufs_timeval { 

40 uint32 tv_sec; 

41 uint32 tv_usec; 

42 }; 

43 

44 struct ufs_super_block { 

45 union { 

46 struct { 

47 uint32 fs_link; 

48 } fs_42; 

49 struct { 

50 uint32 fs_state; 

51 } fs_sun; 

52 } fs_u0; 

53 

54 uint32 fs_rlink; 

55 uint32 fs_sblkno; 

56 uint32 fs_cblkno; 

57 uint32 fs_iblkno; 

58 uint32 fs_dblkno; 

59 uint32 fs_cgoffset; 

60 uint32 fs_cgmask; 

61 uint32 fs_time; 

62 uint32 fs_size; 

63 uint32 fs_dsize; 

64 uint32 fs_ncg; 

65 uint32 fs_bsize; 

66 uint32 fs_fsize; 

67 uint32 fs_frag; 

68 uint32 fs_minfree; 

69 uint32 fs_rotdelay; 

70 uint32 fs_rps; 

71 uint32 fs_bmask; 

72 uint32 fs_fmask; 

73 uint32 fs_bshift; 

74 uint32 fs_fshift; 

75 uint32 fs_maxcontig; 

76 uint32 fs_maxbpg; 

77 uint32 fs_fragshift; 

78 uint32 fs_fsbtodb; 

79 uint32 fs_sbsize; 

80 uint32 fs_csmask; 

81 uint32 fs_csshift; 

82 uint32 fs_nindir; 

83 uint32 fs_inopb; 

84 uint32 fs_nspf; 

85 uint32 fs_optim; 

86 

87 union { 

88 struct { 

89 uint32 fs_npsect; 

90 } fs_sun; 

91 struct { 

92 uint32 fs_state; 

93 } fs_sunx86; 

94 } fs_u1; 

95 

96 uint32 fs_interleave; 

97 uint32 fs_trackskew; 

98 uint32 fs_id[2]; 

99 uint32 fs_csaddr; 

100 uint32 fs_cssize; 

101 uint32 fs_cgsize; 

102 uint32 fs_ntrak; 

103 uint32 fs_nsect; 

104 uint32 fs_spc; 

105 uint32 fs_ncyl; 

106 uint32 fs_cpg; 

107 uint32 fs_ipg; 

108 uint32 fs_fpg; 

109 

110 struct ufs_csum fs_cstotal; 

111 

112 int8 fs_fmod; 

113 int8 fs_clean; 

114 int8 fs_ronly; 

115 int8 fs_flags; 

116 

117 union { 

118 struct { 

119 int8 fs_fsmnt[UFS_MAXMNTLEN]; 

120 uint32 fs_cgrotor; 

121 uint32 fs_csp[UFS_MAXCSBUFS]; 

122 uint32 fs_maxcluster; 

123 uint32 fs_cpc; 

124 uint16 fs_opostbl[16][8]; 

125 } fs_u1; 

126 struct { 

127 int8 fs_fsmnt[UFS2_MAXMNTLEN]; 

128 uint8 fs_volname[UFS2_MAXVOLLEN]; 

129 uint64 fs_swuid; 

130 uint32 fs_pad; 

131 uint32 fs_cgrotor; 

132 uint32 fs_ocsp[UFS2_NOCSPTRS]; 

133 uint32 fs_contigdirs; 

134 uint32 fs_csp; 

135 uint32 fs_maxcluster; 

136 uint32 fs_active; 

137 uint32 fs_old_cpc; 

138 uint32 fs_maxbsize; 

139 uint64 fs_sparecon64[17]; 

140 uint64 fs_sblockloc; 

141 struct ufs2_csum_total fs_cstotal; 

142 struct ufs_timeval fs_time; 

143 uint64 fs_size_64; 

144 uint64 fs_dsize; 

145 uint64 fs_csaddr; 

146 uint64 fs_pendingblocks; 

147 uint32 fs_pendinginodes; 

148 } fs_u2; 

149 } fs_u11; 

150 

151 union { 

152 struct { 

153 uint32 fs_sparecon[53]; 

154 uint32 fs_reclaim; 

155 uint32 fs_sparecon2[1]; 

156 uint32 fs_state; 

157 uint32 fs_qbmask[2]; 

158 uint32 fs_qfmask[2]; 

159 } fs_sun; 

160 struct { 

161 uint32 fs_sparecon[53]; 

162 uint32 fs_reclaim; 

163 uint32 fs_sparecon2[1]; 

164 uint32 fs_npsect; 

165 uint32 fs_qbmask[2]; 

166 uint32 fs_qfmask[2]; 

167 } fs_sunx86; 

168 struct { 

169 uint32 fs_sparecon[50]; 

170 uint32 fs_contigsumsize; 

171 uint32 fs_maxsymlinklen; 

172 uint32 fs_inodefmt; 

173 uint32 fs_maxfilesize[2]; 

174 uint32 fs_qbmask[2]; 

175 uint32 fs_qfmask[2]; 

176 uint32 fs_state; 

177 } fs_44; 

178 } fs_u2_arch; 

179 

180 uint32 fs_postblformat; 

181 uint32 fs_nrpos; 

182 uint32 fs_postbloff; 

183 uint32 fs_rotbloff; 

184 uint32 fs_magic; 

185 uint8 

186 fs_space[1]; 

187} ufs_superblock_t; 

188""" 

189 

190MAGIC_OFFSET = 0x55C # relative to SB_OFFSET 

191 

192 

193class _UFSHandler(StructHandler): 

194 HEADER_STRUCT = "ufs_superblock_t" 

195 C_DEFINITIONS = UFS_C_DEFINITION 

196 EXTRACTOR = None 

197 SB_OFFSET = 0 

198 

199 def get_block_size(self, header) -> int: 

200 raise NotImplementedError("Subclasses must implement this function.") 

201 

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

203 return ( 

204 header.fs_frag == (header.fs_bsize // header.fs_fsize) 

205 and self.get_block_size(header) > 0 

206 and header.fs_ncg > 0 

207 ) 

208 

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

210 file.seek( 

211 start_offset + self.SB_OFFSET, io.SEEK_SET 

212 ) # Skip the boot sector to reach the start of UFS superblock 

213 header = self.parse_header(file) 

214 if not self.is_valid_header(header): 

215 raise InvalidInputFormat("Invalid UFS Header") 

216 

217 end_offset = start_offset + (self.get_block_size(header) * header.fs_fsize) 

218 return ValidChunk(start_offset=start_offset, end_offset=end_offset) 

219 

220 

221class UFS1Handler(_UFSHandler): 

222 NAME = "ufs1" 

223 PATTERNS = [HexString("54 19 01")] # UFS1 little endian 

224 SB_OFFSET = 0x2000 

225 PATTERN_MATCH_OFFSET = -SB_OFFSET - MAGIC_OFFSET 

226 DOC = HandlerDoc( 

227 name="ufs1", 

228 description="UFS1 (Unix File System 1) is the original UFS implementation supported by Unix-like operating systems such as FreeBSD and Solaris. It utilizes a hierarchical tree structure and inodes to manage file metadata and data block addresses, with 32-bit block addressing limiting partition sizes to 1TB.", 

229 handler_type=HandlerType.FILESYSTEM, 

230 vendor=None, 

231 references=[ 

232 Reference( 

233 title="Unix File System Wikipedia", 

234 url="https://en.wikipedia.org/wiki/Unix_File_System", 

235 ) 

236 ], 

237 limitations=[ 

238 "File extraction is not yet supported, only carving of the filesystem is currently available." 

239 ], 

240 ) 

241 

242 def get_block_size(self, header) -> int: 

243 return header.fs_size 

244 

245 

246class UFS2Handler(_UFSHandler): 

247 NAME = "ufs2" 

248 PATTERNS = [HexString("19 01 54 19")] 

249 SB_OFFSET = 0x10000 

250 PATTERN_MATCH_OFFSET = -SB_OFFSET - MAGIC_OFFSET 

251 DOC = HandlerDoc( 

252 name="ufs2", 

253 description="UFS2 (Unix File System 2) is an extended version of UFS1 supported by Unix-like operating systems such as FreeBSD and Solaris. It introduces 64-bit block addressing, extended file attributes, and improved performance over UFS1, while retaining the hierarchical tree structure and inodes for file metadata and data block management.", 

254 handler_type=HandlerType.FILESYSTEM, 

255 vendor=None, 

256 references=[ 

257 Reference( 

258 title="Unix File System Wikipedia", 

259 url="https://en.wikipedia.org/wiki/Unix_File_System", 

260 ) 

261 ], 

262 limitations=[ 

263 "File extraction is not yet supported, only carving of the filesystem is currently available." 

264 ], 

265 ) 

266 

267 def get_block_size(self, header) -> int: 

268 return header.fs_u11.fs_u2.fs_size_64