1/*
2* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
3* All rights reserved. Distributed under the terms of the MIT License.
4*/
5
6#include "xfs.h"
7
8#include "Inode.h"
9
10
11uint8
12XfsSuperBlock::Flags() const
13{
14	return sb_flags;
15}
16
17
18bool
19XfsSuperBlock::IsValidVersion() const
20{
21	// Version 5 is supported
22	if ((Version() & XFS_SB_VERSION_NUMBITS) == 5) {
23		return true;
24	}
25
26	// Version below 4 are not supported
27	if ((Version() & XFS_SB_VERSION_NUMBITS) < 4) {
28		ERROR("xfs version below 4 is not supported");
29		return false;
30	}
31
32	// V4 filesystems need v2 directories and unwritten extents
33	if (!(Version() & XFS_SB_VERSION_DIRV2BIT)) {
34		ERROR("xfs version 4 uses version 2 directories");
35		return false;
36	}
37	if (!(Version() & XFS_SB_VERSION_EXTFLGBIT)) {
38		ERROR("xfs version 4 uses unwritten extents");
39		return false;
40	}
41
42	// V4 should not have any unknown v4 feature bits set
43	if ((Version()  & ~XFS_SB_VERSION_OKBITS) ||
44	    ((Version()  & XFS_SB_VERSION_MOREBITSBIT) &&
45	     (Features2() & ~XFS_SB_VERSION2_OKBITS))) {
46		ERROR("xfs version 4 unknown feature bit detected");
47		return false;
48	}
49
50	// Valid V4 filesytem
51	return true;
52}
53
54
55bool
56XfsSuperBlock::IsValidFeatureMask() const
57{
58	// Version 5 superblock feature mask validation
59	if(sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN) {
60		ERROR("Superblock has unknown compatible features enabled");
61		ERROR("Use more recent kernal");
62	}
63
64    // We cannot have write support if this is set
65	if(sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN) {
66		ERROR("Superblock has unknown read-only compatible features enabled");
67		ERROR("Filesystem is read-only");
68	}
69
70	// check for incompatible features
71	if(sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN) {
72		ERROR("Superblock has unknown incompatible features enabled");
73		return false;
74	}
75
76	return true;
77}
78
79
80bool
81XfsSuperBlock::IsValid() const
82{
83	if (sb_magicnum != XFS_SB_MAGIC) {
84		ERROR("Invalid Superblock");
85		return false;
86	}
87
88	// For version 4
89	if (XFS_MIN_BLOCKSIZE > sb_blocksize) {
90		ERROR("Basic block is less than 512 bytes!");
91		return false;
92	}
93
94	// Checking correct version of filesystem
95	if(!(IsValidVersion())) {
96		return false;
97	}
98
99	if ((Version() & XFS_SB_VERSION_NUMBITS) == 4) {
100
101		if(sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
102				XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
103			ERROR("V4 Superblock has XFS_{P|G}QUOTA_{ENFD|CHKD} bits");
104			return false;
105		}
106
107		return true;
108	}
109
110	if(!(IsValidFeatureMask())) {
111		return false;
112	}
113
114	// For V5
115    if (XFS_MIN_CRC_BLOCKSIZE > sb_blocksize) {
116		ERROR("Basic block is less than 1024 bytes!");
117		return false;
118	}
119
120	// V5 has a separate project quota inode
121	if (sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
122		ERROR("Version 5 of Super block has XFS_OQUOTA bits");
123		return false;
124	}
125
126	/*TODO: check if full Inode chunks are aligned to
127			inode chunk size when sparse inodes are
128			enabled to support the sparse chunk allocation
129			algorithm and prevent overlapping inode record.
130	*/
131
132	// Sanity Checking
133	if(sb_agcount <= 0
134		||	sb_sectsize < XFS_MIN_SECTORSIZE
135	    ||	sb_sectsize > XFS_MAX_SECTORSIZE
136	    ||	sb_sectlog < XFS_MIN_SECTORSIZE_LOG
137	    ||	sb_sectlog > XFS_MAX_SECTORSIZE_LOG
138	    ||	sb_sectsize != (1 << sb_sectlog)
139	    ||	sb_blocksize < XFS_MIN_BLOCKSIZE
140	    ||	sb_blocksize > XFS_MAX_BLOCKSIZE
141	    ||	sb_blocklog < XFS_MIN_BLOCKSIZE_LOG
142	    ||	sb_blocklog > XFS_MAX_BLOCKSIZE_LOG
143	    ||	sb_blocksize != (uint32)(1 << sb_blocklog)
144	    ||	sb_dirblklog + sb_blocklog > XFS_MAX_BLOCKSIZE_LOG
145	    ||	sb_inodesize < INODE_MIN_SIZE
146	    ||	sb_inodesize > INODE_MAX_SIZE
147	    ||	sb_inodelog < INODE_MINSIZE_LOG
148	    ||	sb_inodelog > INODE_MAXSIZE_LOG
149	    ||	sb_inodesize != (1 << sb_inodelog)) {
150
151		ERROR("Sanity checking failed");
152		return false;
153	}
154
155	// Valid V5 Superblock
156	return true;
157}
158
159
160bool
161XfsSuperBlock::IsVersion5() const
162{
163	return (Version() & XFS_SB_VERSION_NUMBITS) == 5;
164}
165
166
167bool
168XfsSuperBlock::XfsHasIncompatFeature() const
169{
170	return (sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE) != 0;
171}
172
173
174uint16
175XfsSuperBlock::Version() const
176{
177	return sb_versionnum;
178}
179
180
181uint32
182XfsSuperBlock::Features2() const
183{
184	return sb_features2;
185}
186
187
188uint32
189XfsSuperBlock::BlockSize() const
190{
191	return sb_blocksize;
192}
193
194
195uint32
196XfsSuperBlock::DirBlockLog() const
197{
198	return sb_dirblklog;
199}
200
201
202uint8
203XfsSuperBlock::BlockLog() const
204{
205	return sb_blocklog;
206}
207
208
209uint32
210XfsSuperBlock::DirBlockSize() const
211{
212	return BlockSize() * (1 << sb_dirblklog);
213}
214
215
216uint8
217XfsSuperBlock::AgInodeBits() const
218{
219	return AgBlocksLog() + InodesPerBlkLog();
220}
221
222
223uint8
224XfsSuperBlock::InodesPerBlkLog() const
225{
226	return sb_inopblog;
227}
228
229
230uint8
231XfsSuperBlock::AgBlocksLog() const
232{
233	return sb_agblklog;
234}
235
236
237uint32
238XfsSuperBlock::Size() const
239{
240	return XFS_SB_MAXSIZE;
241}
242
243
244uint16
245XfsSuperBlock::InodeSize() const
246{
247	return sb_inodesize;
248}
249
250
251xfs_rfsblock_t
252XfsSuperBlock::TotalBlocks() const
253{
254	return sb_dblocks;
255}
256
257
258xfs_rfsblock_t
259XfsSuperBlock::TotalBlocksWithLog() const
260{
261	return TotalBlocks() + sb_logblocks;
262}
263
264
265uint64
266XfsSuperBlock::FreeBlocks() const
267{
268	return sb_fdblocks;
269}
270
271
272uint64
273XfsSuperBlock::UsedBlocks() const
274{
275	return TotalBlocks() - FreeBlocks();
276}
277
278
279const char*
280XfsSuperBlock::Name() const
281{
282	return sb_fname;
283}
284
285
286xfs_ino_t
287XfsSuperBlock::Root() const
288{
289	return sb_rootino;
290}
291
292
293xfs_agnumber_t
294XfsSuperBlock::AgCount() const
295{
296	return sb_agcount;
297}
298
299
300xfs_agblock_t
301XfsSuperBlock::AgBlocks() const
302{
303	return sb_agblocks;
304}
305
306
307uint32
308XfsSuperBlock::Crc() const
309{
310	return sb_crc;
311}
312
313
314uint32
315XfsSuperBlock::MagicNum() const
316{
317	return sb_magicnum;
318}
319
320
321bool
322XfsSuperBlock::UuidEquals(const uuid_t& u1)
323{
324	if((sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID) != 0) {
325		return memcmp(&u1, &sb_meta_uuid, sizeof(uuid_t)) == 0;
326	} else {
327		return memcmp(&u1, &sb_uuid, sizeof(uuid_t)) == 0;
328	}
329	return false;
330}
331
332
333void
334XfsSuperBlock::SwapEndian()
335{
336	sb_magicnum				=	B_BENDIAN_TO_HOST_INT32(sb_magicnum);
337	sb_blocksize			=	B_BENDIAN_TO_HOST_INT32(sb_blocksize);
338	sb_dblocks				=	B_BENDIAN_TO_HOST_INT64(sb_dblocks);
339	sb_rblocks				=	B_BENDIAN_TO_HOST_INT64(sb_rblocks);
340	sb_rextents				=	B_BENDIAN_TO_HOST_INT64(sb_rextents);
341	sb_logstart				=	B_BENDIAN_TO_HOST_INT64(sb_logstart);
342	sb_rootino				=	B_BENDIAN_TO_HOST_INT64(sb_rootino);
343	sb_rbmino				=	B_BENDIAN_TO_HOST_INT64(sb_rbmino);
344	sb_rsumino				=	B_BENDIAN_TO_HOST_INT64(sb_rsumino);
345	sb_rextsize				=	B_BENDIAN_TO_HOST_INT32(sb_rextsize);
346	sb_agblocks				=	B_BENDIAN_TO_HOST_INT32(sb_agblocks);
347	sb_agcount				=	B_BENDIAN_TO_HOST_INT32(sb_agcount);
348	sb_rbmblocks			=	B_BENDIAN_TO_HOST_INT32(sb_rbmblocks);
349	sb_logblocks			=	B_BENDIAN_TO_HOST_INT32(sb_logblocks);
350	sb_versionnum			=	B_BENDIAN_TO_HOST_INT16(sb_versionnum);
351	sb_sectsize				=	B_BENDIAN_TO_HOST_INT16(sb_sectsize);
352	sb_inodesize			=	B_BENDIAN_TO_HOST_INT16(sb_inodesize);
353	sb_inopblock			=	B_BENDIAN_TO_HOST_INT16(sb_inopblock);
354	sb_icount				=	B_BENDIAN_TO_HOST_INT64(sb_icount);
355	sb_ifree				=	B_BENDIAN_TO_HOST_INT64(sb_ifree);
356	sb_fdblocks				=	B_BENDIAN_TO_HOST_INT64(sb_fdblocks);
357	sb_frextents			=	B_BENDIAN_TO_HOST_INT64(sb_frextents);
358	sb_uquotino				=	B_BENDIAN_TO_HOST_INT64(sb_uquotino);
359	sb_gquotino				=	B_BENDIAN_TO_HOST_INT64(sb_gquotino);
360	sb_qflags				=	B_BENDIAN_TO_HOST_INT16(sb_qflags);
361	sb_inoalignmt			=	B_BENDIAN_TO_HOST_INT32(sb_inoalignmt);
362	sb_unit					=	B_BENDIAN_TO_HOST_INT32(sb_unit);
363	sb_width				=	B_BENDIAN_TO_HOST_INT32(sb_width);
364	sb_logsectsize			=	B_BENDIAN_TO_HOST_INT16(sb_logsectsize);
365	sb_logsunit				=	B_BENDIAN_TO_HOST_INT32(sb_logsunit);
366	sb_features2			=	B_BENDIAN_TO_HOST_INT32(sb_features2);
367	sb_bad_features2		=	B_BENDIAN_TO_HOST_INT32(sb_bad_features2);
368	sb_features_compat		=	B_BENDIAN_TO_HOST_INT32(sb_features_compat);
369	sb_features_ro_compat	=	B_BENDIAN_TO_HOST_INT32(sb_features_ro_compat);
370	sb_features_incompat 	=	B_BENDIAN_TO_HOST_INT32(sb_features_incompat);
371	sb_features_log_incompat =	B_BENDIAN_TO_HOST_INT32(sb_features_log_incompat);
372	// crc is only used on disk, not in memory; just init to 0 here
373	sb_crc					=	0;
374	sb_spino_align			=	B_BENDIAN_TO_HOST_INT32(sb_spino_align);
375	sb_pquotino				=	B_BENDIAN_TO_HOST_INT64(sb_pquotino);
376	sb_lsn					=	B_BENDIAN_TO_HOST_INT64(sb_lsn);
377}
378