Class: Ext3::Superblock
- Inherits:
-
Object
- Object
- Ext3::Superblock
- Defined in:
- lib/fs/ext3/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_FLAGS =
Directories use B-Trees (not implemented?).
(ROF_SPARSE | ROF_LARGE_FILES | ROF_BTREES)
- @@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.
Class Method Summary collapse
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.
-
#initialize(stream) ⇒ Superblock
constructor
A new instance of Superblock.
- #inodeNumToGroupNum(inode) ⇒ Object
- #inodeSize ⇒ Object
- #inodesPerGroup ⇒ Object
- #isDynamic? ⇒ Boolean
- #isNewDirEnt? ⇒ Boolean
- #isValidBlock?(block) ⇒ Boolean
- #isValidInode?(inode) ⇒ Boolean
Constructor Details
#initialize(stream) ⇒ Superblock
Returns a new instance of Superblock.
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 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/fs/ext3/superblock.rb', line 162 def initialize(stream) raise "Ext3::Superblock.initialize: Nil stream" if stream.nil? @stream = stream # 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 "Ext3::Superblock.initialize: Invalid signature=[#{@sb['signature']}]" if @sb['signature'] != SUPERBLOCK_SIG raise "Ext3::Superblock.initialize: Invalid file system state" if @sb['fs_state'] > FSS_END if @sb['fs_state'] != FSS_CLEAN $log.warn("Ext3 file system has errors") if $log && gotBit?(@sb['fs_state'], FSS_ERR) $log.warn("Ext3 orphan inodes being recovered") if $log && gotBit?(@sb['fs_state'], FSS_ORPHAN_REC) end raise "Ext3::Superblock.initialize: Invalid error handling method=[#{@sb['err_method']}]" if @sb['err_method'] > EHM_PANIC raise "Ext3::Superblock.initialize: Filesystem has extents (ext4)" if gotBit?(@sb['incompat_flags'], ICF_EXTENTS) @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.
151 152 153 |
# File 'lib/fs/ext3/superblock.rb', line 151 def blockSize @blockSize end |
#fsId ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
150 151 152 |
# File 'lib/fs/ext3/superblock.rb', line 150 def fsId @fsId end |
#numBlocks ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
150 151 152 |
# File 'lib/fs/ext3/superblock.rb', line 150 def numBlocks @numBlocks end |
#numGroups ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
150 151 152 |
# File 'lib/fs/ext3/superblock.rb', line 150 def numGroups @numGroups end |
#numInodes ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
150 151 152 |
# File 'lib/fs/ext3/superblock.rb', line 150 def numInodes @numInodes end |
#sectorSize ⇒ Object (readonly)
Returns the value of attribute sectorSize.
151 152 153 |
# File 'lib/fs/ext3/superblock.rb', line 151 def sectorSize @sectorSize end |
#stream ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
150 151 152 |
# File 'lib/fs/ext3/superblock.rb', line 150 def stream @stream end |
#volName ⇒ Object (readonly)
///////////////////////////////////////////////////////////////////////// // initialize
150 151 152 |
# File 'lib/fs/ext3/superblock.rb', line 150 def volName @volName end |
Class Method Details
.isSuperblock?(buf) ⇒ Boolean
155 156 157 158 159 160 |
# File 'lib/fs/ext3/superblock.rb', line 155 def self.isSuperblock?(buf) sb = SUPERBLOCK_VALIDATE.decode(buf) sb['signature'] == SUPERBLOCK_SIG && sb['fs_state'] <= FSS_END && sb['err_method'] <= EHM_PANIC end |
Instance Method Details
#blockNumToGroupNum(block) ⇒ Object
241 242 243 244 245 246 |
# File 'lib/fs/ext3/superblock.rb', line 241 def blockNumToGroupNum(block) raise "Ext3::Superblock.blockNumToGroupNum: block is nil" if block.nil? group = (block - @sb['block_group_zero']) / @sb['blocks_in_group'] offset = block.modulo(@sb['blocks_in_group']) return group, offset end |
#blocksPerGroup ⇒ Object
221 222 223 |
# File 'lib/fs/ext3/superblock.rb', line 221 def blocksPerGroup @sb['blocks_in_group'] end |
#blockToAddress(block) ⇒ Object
256 257 258 259 260 |
# File 'lib/fs/ext3/superblock.rb', line 256 def blockToAddress(block) address = block * @blockSize address += (SUPERBLOCK_SIZE + GDE_SIZE * @numGroups) if address == SUPERBLOCK_OFFSET address end |
#firstGroupBlockNum(group) ⇒ Object
248 249 250 |
# File 'lib/fs/ext3/superblock.rb', line 248 def firstGroupBlockNum(group) group * @sb['blocks_in_group'] + @sb['block_group_zero'] end |
#fragmentSize ⇒ Object
217 218 219 |
# File 'lib/fs/ext3/superblock.rb', line 217 def fragmentSize 1024 << @sb['fragment_size'] end |
#fragmentsPerGroup ⇒ Object
225 226 227 |
# File 'lib/fs/ext3/superblock.rb', line 225 def fragmentsPerGroup @sb['fragments_in_group'] end |
#freeBytes ⇒ Object
237 238 239 |
# File 'lib/fs/ext3/superblock.rb', line 237 def freeBytes @sb['unallocated_blocks'] * @blockSize end |
#gdt ⇒ Object
//////////////////////////////////////////////////////////////////////////// // Class helpers & accessors.
205 206 207 |
# File 'lib/fs/ext3/superblock.rb', line 205 def gdt @gdt ||= GroupDescriptorTable.new(self) end |
#getBlock(block, _ignore_alloc = false) ⇒ Object
Ignore allocation is for testing only.
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/fs/ext3/superblock.rb', line 289 def getBlock(block, _ignore_alloc = false) raise "Ext3::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.
275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/fs/ext3/superblock.rb', line 275 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)) $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.
310 311 312 |
# File 'lib/fs/ext3/superblock.rb', line 310 def gotBit?(field, bit) field & bit == bit end |
#inodeNumToGroupNum(inode) ⇒ Object
252 253 254 |
# File 'lib/fs/ext3/superblock.rb', line 252 def inodeNumToGroupNum(inode) (inode - 1).divmod(inodesPerGroup) end |
#inodeSize ⇒ Object
233 234 235 |
# File 'lib/fs/ext3/superblock.rb', line 233 def inodeSize isDynamic? ? @sb['inode_size'] : INODE_SIZE end |
#inodesPerGroup ⇒ Object
229 230 231 |
# File 'lib/fs/ext3/superblock.rb', line 229 def inodesPerGroup @sb['inodes_in_group'] end |
#isDynamic? ⇒ Boolean
209 210 211 |
# File 'lib/fs/ext3/superblock.rb', line 209 def isDynamic? @sb['ver_major'] == MV_DYNAMIC end |
#isNewDirEnt? ⇒ Boolean
213 214 215 |
# File 'lib/fs/ext3/superblock.rb', line 213 def isNewDirEnt? gotBit?(@sb['incompat_flags'], ICF_FILE_TYPE) end |
#isValidBlock?(block) ⇒ Boolean
268 269 270 271 272 |
# File 'lib/fs/ext3/superblock.rb', line 268 def isValidBlock?(block) group, offset = blockNumToGroupNum(block) gde = gdt[group] gde.blockAllocBmp[offset] end |
#isValidInode?(inode) ⇒ Boolean
262 263 264 265 266 |
# File 'lib/fs/ext3/superblock.rb', line 262 def isValidInode?(inode) group, offset = inodeNumToGroupNum(inode) gde = gdt[group] gde.inodeAllocBmp[offset] end |