Class: Ext4::Superblock
- Inherits:
-
Object
- Object
- Ext4::Superblock
- Defined in:
- lib/fs/ext4/superblock.rb
Overview
//////////////////////////////////////////////////////////////////////////// // Class.
Constant Summary collapse
- DEF_BLOCK_CACHE_SIZE =
Default cache sizes.
50
- DEF_INODE_CACHE_SIZE =
50
- FSS_CLEAN =
File System State.
0x0001
- FSS_ERR =
File system is clean.
0x0002
- FSS_ORPHAN_REC =
File system has errors.
0x0004
- FSS_END =
NOTE: Recovered NOT by this software but by the ‘NIX kernel. IOW start the VM to repair it.
FSS_CLEAN | FSS_ERR | FSS_ORPHAN_REC
- EHM_CONTINUE =
Error Handling Method.
1
- EHM_RO_REMOUNT =
No action.
2
- EHM_PANIC =
Remount file system as read only.
3
- CO_LINUX =
Creator OS.
0
- CO_GNU_HURD =
NOTE: FS creation tools allow setting this value.
1
- CO_MASIX =
These values are supposedly defined.
2
- CO_FREE_BSD =
3
- CO_LITES =
4
- MV_ORIGINAL =
Major Version.
0
- MV_DYNAMIC =
NOTE: If version is not dynamic, then values from
1
- CFF_PREALLOC_DIR_BLKS =
Compatible Feature Flags.
0x0001
- CFF_AFS_SERVER_INODES =
Preallocate directory blocks to reduce fragmentation.
0x0002
- CFF_JOURNAL =
AFS server inodes exist in system.
0x0004
- CFF_EXTENDED_ATTRIBS =
File system has journal (Ext3).
0x0008
- CFF_BIG_PART =
Inodes have extended attributes.
0x0010
- CFF_HASH_INDEX =
File system can resize itself for larger partitions.
0x0020
- CFF_FLAGS =
Directories use hash index (another modified b-tree).
(CFF_PREALLOC_DIR_BLKS | CFF_AFS_SERVER_INODES | CFF_JOURNAL | CFF_EXTENDED_ATTRIBS | CFF_BIG_PART | CFF_HASH_INDEX)
- ICF_COMPRESSION =
Incompatible Feature flags.
0x0001
- ICF_FILE_TYPE =
Not supported on Linux?
0x0002
- ICF_RECOVER_FS =
Directory entries contain file type field.
0x0004
- ICF_JOURNAL =
File system needs recovery.
0x0008
- ICF_META_BG =
File system uses journal device.
0x0010
- ICF_EXTENTS =
File system uses extents (ext4)
0x0040
- ICF_64BIT =
File system uses 64-bit
0x0080
- ICF_MMP =
0x0100
- ICF_FLEX_BG =
0x0200
- ICF_EA_INODE =
EA in inode
0x0400
- ICF_DIRDATA =
data in dirent
0x1000
- ICF_FLAGS =
(ICF_COMPRESSION | ICF_FILE_TYPE | ICF_RECOVER_FS | ICF_JOURNAL | ICF_META_BG | ICF_EXTENTS | ICF_64BIT | ICF_MMP | ICF_FLEX_BG | ICF_EA_INODE | ICF_DIRDATA)
- ROF_SPARSE =
ReadOnly Feature flags.
0x0001
- ROF_LARGE_FILES =
Sparse superblocks & group descriptor tables.
0x0002
- ROF_BTREES =
File system contains large files (over 4G).
0x0004
- ROF_HUGE_FILE =
Directories use B-Trees (not implemented?).
0x0008
- ROF_GDT_CSUM =
0x0010
- ROF_DIR_NLINK =
0x0020
- ROF_EXTRA_ISIZE =
0x0040
- ROF_FLAGS =
(ROF_SPARSE | ROF_LARGE_FILES | ROF_BTREES | ROF_HUGE_FILE | ROF_GDT_CSUM | ROF_DIR_NLINK | ROF_EXTRA_ISIZE)
- @@track_inodes =
false
Instance Attribute Summary collapse
-
#blockSize ⇒ Object
readonly
Returns the value of attribute blockSize.
-
#fsId ⇒ Object
readonly
///////////////////////////////////////////////////////////////////////// // initialize.
-
#numBlocks ⇒ Object
readonly
///////////////////////////////////////////////////////////////////////// // initialize.
-
#numGroups ⇒ Object
readonly
///////////////////////////////////////////////////////////////////////// // initialize.
-
#numInodes ⇒ Object
readonly
///////////////////////////////////////////////////////////////////////// // initialize.
-
#sectorSize ⇒ Object
readonly
Returns the value of attribute sectorSize.
-
#stream ⇒ Object
readonly
///////////////////////////////////////////////////////////////////////// // initialize.
-
#volName ⇒ Object
readonly
///////////////////////////////////////////////////////////////////////// // initialize.
Instance Method Summary collapse
- #blockNumToGroupNum(block) ⇒ Object
- #blocksPerGroup ⇒ Object
- #blockToAddress(block) ⇒ Object
- #firstGroupBlockNum(group) ⇒ Object
- #fragmentSize ⇒ Object
- #fragmentsPerGroup ⇒ Object
- #freeBytes ⇒ Object
-
#gdt ⇒ Object
//////////////////////////////////////////////////////////////////////////// // Class helpers & accessors.
-
#getBlock(block, _ignore_alloc = false) ⇒ Object
Ignore allocation is for testing only.
-
#getInode(inode, _ignore_alloc = false) ⇒ Object
Ignore allocation is for testing only.
-
#gotBit?(field, bit) ⇒ Boolean
//////////////////////////////////////////////////////////////////////////// // Utility functions.
- #groupDescriptorSize ⇒ Object
-
#initialize(stream) ⇒ Superblock
constructor
A new instance of Superblock.
- #inodeNumToGroupNum(inode) ⇒ Object
- #inodeSize ⇒ Object
- #inodesPerGroup ⇒ Object
- #is_enabled_64_bit? ⇒ Boolean
- #isDynamic? ⇒ Boolean
- #isNewDirEnt? ⇒ Boolean
- #isValidBlock?(block) ⇒ Boolean
- #isValidInode?(inode) ⇒ Boolean
Constructor Details
#initialize(stream) ⇒ Superblock
Returns a new instance of Superblock.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/fs/ext4/superblock.rb', line 150 def initialize(stream) raise "Ext4::Superblock.initialize: Nil stream" if (@stream = stream).nil? # Seek, read & decode the superblock structure @stream.seek(SUPERBLOCK_OFFSET) @sb = SUPERBLOCK.decode(@stream.read(SUPERBLOCK_SIZE)) # Grab some quick facts & make sure there's nothing wrong. Tight qualification. raise "Ext4::Superblock.initialize: Invalid signature=[#{@sb['signature']}]" if @sb['signature'] != SUPERBLOCK_SIG raise "Ext4::Superblock.initialize: Invalid file system state" if @sb['fs_state'] > FSS_END if (state = @sb['fs_state']) != FSS_CLEAN $log.warn("Ext4 file system has errors") if $log && gotBit?(state, FSS_ERR) $log.warn("Ext4 orphan inodes being recovered") if $log && gotBit?(state, FSS_ORPHAN_REC) end raise "Ext4::Superblock.initialize: Invalid error handling method=[#{@sb['err_method']}]" if @sb['err_method'] > EHM_PANIC @blockSize = 1024 << @sb['block_size'] @block_cache = LruHash.new(DEF_BLOCK_CACHE_SIZE) @inode_cache = LruHash.new(DEF_INODE_CACHE_SIZE) # expose for testing. @numBlocks = @sb['num_blocks'] @numInodes = @sb['num_inodes'] # Inode file size members can't be trusted, so use sector count instead. # MiqDisk exposes blockSize, which for our purposes is sectorSize. @sectorSize = @stream.blockSize # Preprocess some members. @sb['vol_name'].delete!("\000") @sb['last_mnt_path'].delete!("\000") @numGroups, @lastGroupBlocks = @sb['num_blocks'].divmod(@sb['blocks_in_group']) @numGroups += 1 if @lastGroupBlocks > 0 @fsId = UUIDTools::UUID.parse_raw(@sb['fs_id']) @volName = @sb['vol_name'] end |
Instance Attribute Details
#blockSize ⇒ Object (readonly)
Returns the value of attribute blockSize.
146 147 148 |
# File 'lib/fs/ext4/superblock.rb', line 146 def blockSize @blockSize end |
#fsId ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
145 146 147 |
# File 'lib/fs/ext4/superblock.rb', line 145 def fsId @fsId end |
#numBlocks ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
145 146 147 |
# File 'lib/fs/ext4/superblock.rb', line 145 def numBlocks @numBlocks end |
#numGroups ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
145 146 147 |
# File 'lib/fs/ext4/superblock.rb', line 145 def numGroups @numGroups end |
#numInodes ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
145 146 147 |
# File 'lib/fs/ext4/superblock.rb', line 145 def numInodes @numInodes end |
#sectorSize ⇒ Object (readonly)
Returns the value of attribute sectorSize.
146 147 148 |
# File 'lib/fs/ext4/superblock.rb', line 146 def sectorSize @sectorSize end |
#stream ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
145 146 147 |
# File 'lib/fs/ext4/superblock.rb', line 145 def stream @stream end |
#volName ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
145 146 147 |
# File 'lib/fs/ext4/superblock.rb', line 145 def volName @volName end |
Instance Method Details
#blockNumToGroupNum(block) ⇒ Object
235 236 237 238 239 240 241 242 243 |
# File 'lib/fs/ext4/superblock.rb', line 235 def blockNumToGroupNum(block) unless block.kind_of?(Numeric) $log.error("Ext4::Superblock.blockNumToGroupNum called from: #{caller.join('\n')}") raise "Ext4::Superblock.blockNumToGroupNum: block is expected to be numeric, but is <#{block.class.name}>" end group = (block - @sb['block_group_zero']) / @sb['blocks_in_group'] offset = block.modulo(@sb['blocks_in_group']) return group, offset end |
#blocksPerGroup ⇒ Object
207 208 209 |
# File 'lib/fs/ext4/superblock.rb', line 207 def blocksPerGroup @sb['blocks_in_group'] end |
#blockToAddress(block) ⇒ Object
253 254 255 256 257 |
# File 'lib/fs/ext4/superblock.rb', line 253 def blockToAddress(block) address = block * @blockSize address += (SUPERBLOCK_SIZE + groupDescriptorSize * @numGroups) if address == SUPERBLOCK_OFFSET address end |
#firstGroupBlockNum(group) ⇒ Object
245 246 247 |
# File 'lib/fs/ext4/superblock.rb', line 245 def firstGroupBlockNum(group) group * @sb['blocks_in_group'] + @sb['block_group_zero'] end |
#fragmentSize ⇒ Object
203 204 205 |
# File 'lib/fs/ext4/superblock.rb', line 203 def fragmentSize 1024 << @sb['fragment_size'] end |
#fragmentsPerGroup ⇒ Object
211 212 213 |
# File 'lib/fs/ext4/superblock.rb', line 211 def fragmentsPerGroup @sb['fragments_in_group'] end |
#freeBytes ⇒ Object
231 232 233 |
# File 'lib/fs/ext4/superblock.rb', line 231 def freeBytes @sb['unallocated_blocks'] * @blockSize end |
#gdt ⇒ Object
//////////////////////////////////////////////////////////////////////////// // Class helpers & accessors.
191 192 193 |
# File 'lib/fs/ext4/superblock.rb', line 191 def gdt @gdt ||= GroupDescriptorTable.new(self) end |
#getBlock(block, _ignore_alloc = false) ⇒ Object
Ignore allocation is for testing only.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/fs/ext4/superblock.rb', line 286 def getBlock(block, _ignore_alloc = false) raise "Ext4::Superblock.getBlock: block is nil" if block.nil? unless @block_cache.key?(block) if block == 0 @block_cache[block] = MemoryBuffer.create(@blockSize) else # raise "Block #{block} is not allocated" if (not gde.blockAllocBmp[offset] and not ignore_alloc) address = blockToAddress(block) # This function will read the block into our cache @stream.seek(address) @block_cache[block] = @stream.read(@blockSize) end end @block_cache[block] end |
#getInode(inode, _ignore_alloc = false) ⇒ Object
Ignore allocation is for testing only.
272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/fs/ext4/superblock.rb', line 272 def getInode(inode, _ignore_alloc = false) unless @inode_cache.key?(inode) group, offset = inodeNumToGroupNum(inode) gde = gdt[group] # raise "Inode #{inode} is not allocated" if (not gde.inodeAllocBmp[offset] and not ignore_alloc) @stream.seek(blockToAddress(gde.inodeTable) + offset * inodeSize) @inode_cache[inode] = Inode.new(@stream.read(inodeSize), self, inode) $log.info "Inode num: #{inode}\n#{@inode_cache[inode].dump}\n\n" if $log && @@track_inodes end @inode_cache[inode] end |
#gotBit?(field, bit) ⇒ Boolean
//////////////////////////////////////////////////////////////////////////// // Utility functions.
307 308 309 |
# File 'lib/fs/ext4/superblock.rb', line 307 def gotBit?(field, bit) field & bit == bit end |
#groupDescriptorSize ⇒ Object
227 228 229 |
# File 'lib/fs/ext4/superblock.rb', line 227 def groupDescriptorSize @groupDescriptorSize ||= is_enabled_64_bit? ? @sb['group_desc_size'] : GDE_SIZE end |
#inodeNumToGroupNum(inode) ⇒ Object
249 250 251 |
# File 'lib/fs/ext4/superblock.rb', line 249 def inodeNumToGroupNum(inode) (inode - 1).divmod(inodesPerGroup) end |
#inodeSize ⇒ Object
219 220 221 |
# File 'lib/fs/ext4/superblock.rb', line 219 def inodeSize isDynamic? ? @sb['inode_size'] : INODE_SIZE end |
#inodesPerGroup ⇒ Object
215 216 217 |
# File 'lib/fs/ext4/superblock.rb', line 215 def inodesPerGroup @sb['inodes_in_group'] end |
#is_enabled_64_bit? ⇒ Boolean
223 224 225 |
# File 'lib/fs/ext4/superblock.rb', line 223 def is_enabled_64_bit? @is_enabled_64_bit ||= gotBit?(@sb['incompat_flags'], ICF_64BIT) end |
#isDynamic? ⇒ Boolean
195 196 197 |
# File 'lib/fs/ext4/superblock.rb', line 195 def isDynamic? @sb['ver_major'] == MV_DYNAMIC end |
#isNewDirEnt? ⇒ Boolean
199 200 201 |
# File 'lib/fs/ext4/superblock.rb', line 199 def isNewDirEnt? gotBit?(@sb['incompat_flags'], ICF_FILE_TYPE) end |
#isValidBlock?(block) ⇒ Boolean
265 266 267 268 269 |
# File 'lib/fs/ext4/superblock.rb', line 265 def isValidBlock?(block) group, offset = blockNumToGroupNum(block) gde = gdt[group] gde.blockAllocBmp[offset] end |
#isValidInode?(inode) ⇒ Boolean
259 260 261 262 263 |
# File 'lib/fs/ext4/superblock.rb', line 259 def isValidInode?(inode) group, offset = inodeNumToGroupNum(inode) gde = gdt[group] gde.inodeAllocBmp[offset] end |