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 11 uint8 12 XfsSuperBlock::Flags() const 13 { 14 return sb_flags; 15 } 16 17 18 bool 19 XfsSuperBlock::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 55 bool 56 XfsSuperBlock::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 80 bool 81 XfsSuperBlock::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 160 bool 161 XfsSuperBlock::IsVersion5() const 162 { 163 return (Version() & XFS_SB_VERSION_NUMBITS) == 5; 164 } 165 166 167 bool 168 XfsSuperBlock::XfsHasIncompatFeature() const 169 { 170 return (sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE) != 0; 171 } 172 173 174 uint16 175 XfsSuperBlock::Version() const 176 { 177 return sb_versionnum; 178 } 179 180 181 uint32 182 XfsSuperBlock::Features2() const 183 { 184 return sb_features2; 185 } 186 187 188 uint32 189 XfsSuperBlock::BlockSize() const 190 { 191 return sb_blocksize; 192 } 193 194 195 uint32 196 XfsSuperBlock::DirBlockLog() const 197 { 198 return sb_dirblklog; 199 } 200 201 202 uint8 203 XfsSuperBlock::BlockLog() const 204 { 205 return sb_blocklog; 206 } 207 208 209 uint32 210 XfsSuperBlock::DirBlockSize() const 211 { 212 return BlockSize() * (1 << sb_dirblklog); 213 } 214 215 216 uint8 217 XfsSuperBlock::AgInodeBits() const 218 { 219 return AgBlocksLog() + InodesPerBlkLog(); 220 } 221 222 223 uint8 224 XfsSuperBlock::InodesPerBlkLog() const 225 { 226 return sb_inopblog; 227 } 228 229 230 uint8 231 XfsSuperBlock::AgBlocksLog() const 232 { 233 return sb_agblklog; 234 } 235 236 237 uint32 238 XfsSuperBlock::Size() const 239 { 240 return XFS_SB_MAXSIZE; 241 } 242 243 244 uint16 245 XfsSuperBlock::InodeSize() const 246 { 247 return sb_inodesize; 248 } 249 250 251 xfs_rfsblock_t 252 XfsSuperBlock::TotalBlocks() const 253 { 254 return sb_dblocks; 255 } 256 257 258 xfs_rfsblock_t 259 XfsSuperBlock::TotalBlocksWithLog() const 260 { 261 return TotalBlocks() + sb_logblocks; 262 } 263 264 265 uint64 266 XfsSuperBlock::FreeBlocks() const 267 { 268 return sb_fdblocks; 269 } 270 271 272 uint64 273 XfsSuperBlock::UsedBlocks() const 274 { 275 return TotalBlocks() - FreeBlocks(); 276 } 277 278 279 const char* 280 XfsSuperBlock::Name() const 281 { 282 return sb_fname; 283 } 284 285 286 xfs_ino_t 287 XfsSuperBlock::Root() const 288 { 289 return sb_rootino; 290 } 291 292 293 xfs_agnumber_t 294 XfsSuperBlock::AgCount() const 295 { 296 return sb_agcount; 297 } 298 299 300 xfs_agblock_t 301 XfsSuperBlock::AgBlocks() const 302 { 303 return sb_agblocks; 304 } 305 306 307 uint32 308 XfsSuperBlock::Crc() const 309 { 310 return sb_crc; 311 } 312 313 314 uint32 315 XfsSuperBlock::MagicNum() const 316 { 317 return sb_magicnum; 318 } 319 320 321 bool 322 XfsSuperBlock::UuidEquals(const uuid_t *u1) 323 { 324 if((sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID) != 0) { 325 uuid_t *u2 = &sb_meta_uuid; 326 return memcmp(u1, u2, sizeof(uuid_t)) == 0; 327 } else { 328 uuid_t *u2 = &sb_uuid; 329 return memcmp(u1, u2, sizeof(uuid_t)) == 0; 330 } 331 return false; 332 } 333 334 335 void 336 XfsSuperBlock::SwapEndian() 337 { 338 sb_magicnum = B_BENDIAN_TO_HOST_INT32(sb_magicnum); 339 sb_blocksize = B_BENDIAN_TO_HOST_INT32(sb_blocksize); 340 sb_dblocks = B_BENDIAN_TO_HOST_INT64(sb_dblocks); 341 sb_rblocks = B_BENDIAN_TO_HOST_INT64(sb_rblocks); 342 sb_rextents = B_BENDIAN_TO_HOST_INT64(sb_rextents); 343 sb_logstart = B_BENDIAN_TO_HOST_INT64(sb_logstart); 344 sb_rootino = B_BENDIAN_TO_HOST_INT64(sb_rootino); 345 sb_rbmino = B_BENDIAN_TO_HOST_INT64(sb_rbmino); 346 sb_rsumino = B_BENDIAN_TO_HOST_INT64(sb_rsumino); 347 sb_rextsize = B_BENDIAN_TO_HOST_INT32(sb_rextsize); 348 sb_agblocks = B_BENDIAN_TO_HOST_INT32(sb_agblocks); 349 sb_agcount = B_BENDIAN_TO_HOST_INT32(sb_agcount); 350 sb_rbmblocks = B_BENDIAN_TO_HOST_INT32(sb_rbmblocks); 351 sb_logblocks = B_BENDIAN_TO_HOST_INT32(sb_logblocks); 352 sb_versionnum = B_BENDIAN_TO_HOST_INT16(sb_versionnum); 353 sb_sectsize = B_BENDIAN_TO_HOST_INT16(sb_sectsize); 354 sb_inodesize = B_BENDIAN_TO_HOST_INT16(sb_inodesize); 355 sb_inopblock = B_BENDIAN_TO_HOST_INT16(sb_inopblock); 356 sb_icount = B_BENDIAN_TO_HOST_INT64(sb_icount); 357 sb_ifree = B_BENDIAN_TO_HOST_INT64(sb_ifree); 358 sb_fdblocks = B_BENDIAN_TO_HOST_INT64(sb_fdblocks); 359 sb_frextents = B_BENDIAN_TO_HOST_INT64(sb_frextents); 360 sb_uquotino = B_BENDIAN_TO_HOST_INT64(sb_uquotino); 361 sb_gquotino = B_BENDIAN_TO_HOST_INT64(sb_gquotino); 362 sb_qflags = B_BENDIAN_TO_HOST_INT16(sb_qflags); 363 sb_inoalignmt = B_BENDIAN_TO_HOST_INT32(sb_inoalignmt); 364 sb_unit = B_BENDIAN_TO_HOST_INT32(sb_unit); 365 sb_width = B_BENDIAN_TO_HOST_INT32(sb_width); 366 sb_logsectsize = B_BENDIAN_TO_HOST_INT16(sb_logsectsize); 367 sb_logsunit = B_BENDIAN_TO_HOST_INT32(sb_logsunit); 368 sb_features2 = B_BENDIAN_TO_HOST_INT32(sb_features2); 369 sb_bad_features2 = B_BENDIAN_TO_HOST_INT32(sb_bad_features2); 370 sb_features_compat = B_BENDIAN_TO_HOST_INT32(sb_features_compat); 371 sb_features_ro_compat = B_BENDIAN_TO_HOST_INT32(sb_features_ro_compat); 372 sb_features_incompat = B_BENDIAN_TO_HOST_INT32(sb_features_incompat); 373 sb_features_log_incompat = B_BENDIAN_TO_HOST_INT32(sb_features_log_incompat); 374 // crc is only used on disk, not in memory; just init to 0 here 375 sb_crc = 0; 376 sb_spino_align = B_BENDIAN_TO_HOST_INT32(sb_spino_align); 377 sb_pquotino = B_BENDIAN_TO_HOST_INT64(sb_pquotino); 378 sb_lsn = B_BENDIAN_TO_HOST_INT64(sb_lsn); 379 } 380