/* * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com * All rights reserved. Distributed under the terms of the MIT License. */ #include "xfs.h" #include "Inode.h" uint8 XfsSuperBlock::Flags() const { return sb_flags; } bool XfsSuperBlock::IsValidVersion() const { // Version 5 is supported if ((Version() & XFS_SB_VERSION_NUMBITS) == 5) { return true; } // Version below 4 are not supported if ((Version() & XFS_SB_VERSION_NUMBITS) < 4) { ERROR("xfs version below 4 is not supported"); return false; } // V4 filesystems need v2 directories and unwritten extents if (!(Version() & XFS_SB_VERSION_DIRV2BIT)) { ERROR("xfs version 4 uses version 2 directories"); return false; } if (!(Version() & XFS_SB_VERSION_EXTFLGBIT)) { ERROR("xfs version 4 uses unwritten extents"); return false; } // V4 should not have any unknown v4 feature bits set if ((Version() & ~XFS_SB_VERSION_OKBITS) || ((Version() & XFS_SB_VERSION_MOREBITSBIT) && (Features2() & ~XFS_SB_VERSION2_OKBITS))) { ERROR("xfs version 4 unknown feature bit detected"); return false; } // Valid V4 filesytem return true; } bool XfsSuperBlock::IsValidFeatureMask() const { // Version 5 superblock feature mask validation if(sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN) { ERROR("Superblock has unknown compatible features enabled"); ERROR("Use more recent kernal"); } // We cannot have write support if this is set if(sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN) { ERROR("Superblock has unknown read-only compatible features enabled"); ERROR("Filesystem is read-only"); } // check for incompatible features if(sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN) { ERROR("Superblock has unknown incompatible features enabled"); return false; } return true; } bool XfsSuperBlock::IsValid() const { if (sb_magicnum != XFS_SB_MAGIC) { ERROR("Invalid Superblock"); return false; } // For version 4 if (XFS_MIN_BLOCKSIZE > sb_blocksize) { ERROR("Basic block is less than 512 bytes!"); return false; } // Checking correct version of filesystem if(!(IsValidVersion())) { return false; } if ((Version() & XFS_SB_VERSION_NUMBITS) == 4) { if(sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) { ERROR("V4 Superblock has XFS_{P|G}QUOTA_{ENFD|CHKD} bits"); return false; } return true; } if(!(IsValidFeatureMask())) { return false; } // For V5 if (XFS_MIN_CRC_BLOCKSIZE > sb_blocksize) { ERROR("Basic block is less than 1024 bytes!"); return false; } // V5 has a separate project quota inode if (sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) { ERROR("Version 5 of Super block has XFS_OQUOTA bits"); return false; } /*TODO: check if full Inode chunks are aligned to inode chunk size when sparse inodes are enabled to support the sparse chunk allocation algorithm and prevent overlapping inode record. */ // Sanity Checking if(sb_agcount <= 0 || sb_sectsize < XFS_MIN_SECTORSIZE || sb_sectsize > XFS_MAX_SECTORSIZE || sb_sectlog < XFS_MIN_SECTORSIZE_LOG || sb_sectlog > XFS_MAX_SECTORSIZE_LOG || sb_sectsize != (1 << sb_sectlog) || sb_blocksize < XFS_MIN_BLOCKSIZE || sb_blocksize > XFS_MAX_BLOCKSIZE || sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || sb_blocksize != (uint32)(1 << sb_blocklog) || sb_dirblklog + sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || sb_inodesize < INODE_MIN_SIZE || sb_inodesize > INODE_MAX_SIZE || sb_inodelog < INODE_MINSIZE_LOG || sb_inodelog > INODE_MAXSIZE_LOG || sb_inodesize != (1 << sb_inodelog)) { ERROR("Sanity checking failed"); return false; } // Valid V5 Superblock return true; } bool XfsSuperBlock::IsVersion5() const { return (Version() & XFS_SB_VERSION_NUMBITS) == 5; } bool XfsSuperBlock::XfsHasIncompatFeature() const { return (sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE) != 0; } uint16 XfsSuperBlock::Version() const { return sb_versionnum; } uint32 XfsSuperBlock::Features2() const { return sb_features2; } uint32 XfsSuperBlock::BlockSize() const { return sb_blocksize; } uint32 XfsSuperBlock::DirBlockLog() const { return sb_dirblklog; } uint8 XfsSuperBlock::BlockLog() const { return sb_blocklog; } uint32 XfsSuperBlock::DirBlockSize() const { return BlockSize() * (1 << sb_dirblklog); } uint8 XfsSuperBlock::AgInodeBits() const { return AgBlocksLog() + InodesPerBlkLog(); } uint8 XfsSuperBlock::InodesPerBlkLog() const { return sb_inopblog; } uint8 XfsSuperBlock::AgBlocksLog() const { return sb_agblklog; } uint32 XfsSuperBlock::Size() const { return XFS_SB_MAXSIZE; } uint16 XfsSuperBlock::InodeSize() const { return sb_inodesize; } xfs_rfsblock_t XfsSuperBlock::TotalBlocks() const { return sb_dblocks; } xfs_rfsblock_t XfsSuperBlock::TotalBlocksWithLog() const { return TotalBlocks() + sb_logblocks; } uint64 XfsSuperBlock::FreeBlocks() const { return sb_fdblocks; } uint64 XfsSuperBlock::UsedBlocks() const { return TotalBlocks() - FreeBlocks(); } const char* XfsSuperBlock::Name() const { return sb_fname; } xfs_ino_t XfsSuperBlock::Root() const { return sb_rootino; } xfs_agnumber_t XfsSuperBlock::AgCount() const { return sb_agcount; } xfs_agblock_t XfsSuperBlock::AgBlocks() const { return sb_agblocks; } uint32 XfsSuperBlock::Crc() const { return sb_crc; } uint32 XfsSuperBlock::MagicNum() const { return sb_magicnum; } bool XfsSuperBlock::UuidEquals(const uuid_t& u1) { if((sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID) != 0) { return memcmp(&u1, &sb_meta_uuid, sizeof(uuid_t)) == 0; } else { return memcmp(&u1, &sb_uuid, sizeof(uuid_t)) == 0; } return false; } void XfsSuperBlock::SwapEndian() { sb_magicnum = B_BENDIAN_TO_HOST_INT32(sb_magicnum); sb_blocksize = B_BENDIAN_TO_HOST_INT32(sb_blocksize); sb_dblocks = B_BENDIAN_TO_HOST_INT64(sb_dblocks); sb_rblocks = B_BENDIAN_TO_HOST_INT64(sb_rblocks); sb_rextents = B_BENDIAN_TO_HOST_INT64(sb_rextents); sb_logstart = B_BENDIAN_TO_HOST_INT64(sb_logstart); sb_rootino = B_BENDIAN_TO_HOST_INT64(sb_rootino); sb_rbmino = B_BENDIAN_TO_HOST_INT64(sb_rbmino); sb_rsumino = B_BENDIAN_TO_HOST_INT64(sb_rsumino); sb_rextsize = B_BENDIAN_TO_HOST_INT32(sb_rextsize); sb_agblocks = B_BENDIAN_TO_HOST_INT32(sb_agblocks); sb_agcount = B_BENDIAN_TO_HOST_INT32(sb_agcount); sb_rbmblocks = B_BENDIAN_TO_HOST_INT32(sb_rbmblocks); sb_logblocks = B_BENDIAN_TO_HOST_INT32(sb_logblocks); sb_versionnum = B_BENDIAN_TO_HOST_INT16(sb_versionnum); sb_sectsize = B_BENDIAN_TO_HOST_INT16(sb_sectsize); sb_inodesize = B_BENDIAN_TO_HOST_INT16(sb_inodesize); sb_inopblock = B_BENDIAN_TO_HOST_INT16(sb_inopblock); sb_icount = B_BENDIAN_TO_HOST_INT64(sb_icount); sb_ifree = B_BENDIAN_TO_HOST_INT64(sb_ifree); sb_fdblocks = B_BENDIAN_TO_HOST_INT64(sb_fdblocks); sb_frextents = B_BENDIAN_TO_HOST_INT64(sb_frextents); sb_uquotino = B_BENDIAN_TO_HOST_INT64(sb_uquotino); sb_gquotino = B_BENDIAN_TO_HOST_INT64(sb_gquotino); sb_qflags = B_BENDIAN_TO_HOST_INT16(sb_qflags); sb_inoalignmt = B_BENDIAN_TO_HOST_INT32(sb_inoalignmt); sb_unit = B_BENDIAN_TO_HOST_INT32(sb_unit); sb_width = B_BENDIAN_TO_HOST_INT32(sb_width); sb_logsectsize = B_BENDIAN_TO_HOST_INT16(sb_logsectsize); sb_logsunit = B_BENDIAN_TO_HOST_INT32(sb_logsunit); sb_features2 = B_BENDIAN_TO_HOST_INT32(sb_features2); sb_bad_features2 = B_BENDIAN_TO_HOST_INT32(sb_bad_features2); sb_features_compat = B_BENDIAN_TO_HOST_INT32(sb_features_compat); sb_features_ro_compat = B_BENDIAN_TO_HOST_INT32(sb_features_ro_compat); sb_features_incompat = B_BENDIAN_TO_HOST_INT32(sb_features_incompat); sb_features_log_incompat = B_BENDIAN_TO_HOST_INT32(sb_features_log_incompat); // crc is only used on disk, not in memory; just init to 0 here sb_crc = 0; sb_spino_align = B_BENDIAN_TO_HOST_INT32(sb_spino_align); sb_pquotino = B_BENDIAN_TO_HOST_INT64(sb_pquotino); sb_lsn = B_BENDIAN_TO_HOST_INT64(sb_lsn); }