""" ReiserFS file system version 3 parser (other version have not been tested). Author: Frederic Weisbecker Creation date: 8 december 2006 Sources: - http://p-nand-q.com/download/rfstool/reiserfs_docs.html - http://homes.cerias.purdue.edu/~florian/reiser/reiserfs.php - file://usr/src/linux-2.6.16.19/include/linux/reiserfs_fs.h NOTES: The most part of the description of the structures, their fields and their comments decribed here comes from the file include/linux/reiserfs_fs.h - written by Hans reiser - located in the Linux kernel 2.6.16.19 and from the Reiserfs explanations in http://p-nand-q.com/download/rfstool/reiserfs_docs.html written by Gerson Kurz. """ from hachoir.parser import Parser from hachoir.field import (FieldSet, Enum, UInt16, UInt32, String, RawBytes, NullBytes, SeekableFieldSet, Bit) from hachoir.core.endian import LITTLE_ENDIAN class BlockState(Bit): """The state (used/free) of a ReiserFs Block""" STATE = { True: "used", False: "free" } block_nb = 0 def __init__(self, parent, name, nb_block): """@param nb_block: Number of the block concerned""" Bit.__init__(self, parent, name) self.block_nb = self.__class__.block_nb self.__class__.block_nb += 1 def createDescription(self): return "State of the block %d" % self.block_nb def createDisplay(self): return self.STATE[Bit.createValue(self)] class BitmapBlock(SeekableFieldSet): """ The bitmap blocks are Reiserfs blocks where each byte contains the state of 8 blocks in the filesystem. So each bit will describe the state of a block to tell if it is used or not. """ def createFields(self): block_size = self["/superblock/blocksize"].value for i in range(0, block_size * 8): yield BlockState(self, "block[]", i) class BitmapBlockGroup(SeekableFieldSet): """The group that manages the Bitmap Blocks""" def createFields(self): block_size = self["/superblock/blocksize"].value nb_bitmap_block = self["/superblock/bmap_nr"].value # Position of the first bitmap block self.seekByte(REISER_FS.SUPERBLOCK_OFFSET + block_size, relative=False) yield BitmapBlock(self, "BitmapBlock[]", "Bitmap blocks tells for each block if it is used") # The other bitmap blocks for i in range(1, nb_bitmap_block): self.seekByte((block_size**2) * 8 * i, relative=False) yield BitmapBlock(self, "BitmapBlock[]", "Bitmap blocks tells for each block if it is used") class Journal_params(FieldSet): static_size = 32 * 8 def createFields(self): yield UInt32(self, "1st_block", "Journal 1st block number") yield UInt32(self, "dev", "Journal device number") yield UInt32(self, "size", "Size of the journal") yield UInt32(self, "trans_max", "Max number of blocks in a transaction") # TODO: Must be explained: it was sb_journal_block_count yield UInt32(self, "magic", "Random value made on fs creation.") yield UInt32(self, "max_batch", "Max number of blocks to batch into a trans") yield UInt32(self, "max_commit_age", "In seconds, how old can an async commit be") yield UInt32(self, "max_trans_age", "In seconds, how old can a transaction be") def createDescription(self): return "Parameters of the journal" class SuperBlock(FieldSet): # static_size = 204*8 UMOUNT_STATE = {1: "unmounted", 2: "not unmounted"} HASH_FUNCTIONS = { 0: "UNSET_HASH", 1: "TEA_HASH", 2: "YURA_HASH", 3: "R5_HASH" } def createFields(self): # TODO: This structure is normally divided in two parts: # _reiserfs_super_block_v1 # _reiserfs_super_block # It will be divided later to easily support older version of the first # part yield UInt32(self, "block_count", "Number of blocks") yield UInt32(self, "free_blocks", "Number of free blocks") yield UInt32(self, "root_block", "Root block number") yield Journal_params(self, "Journal parameters") yield UInt16(self, "blocksize", "Size of a block") yield UInt16(self, "oid_maxsize", "Max size of object id array") yield UInt16(self, "oid_cursize", "Current size of object id array") yield Enum(UInt16(self, "umount_state", "Filesystem umounted or not"), self.UMOUNT_STATE) yield String(self, "magic", 10, "Magic string", strip="\0") # TODO: change the type of s_fs_state in Enum to have more details # about this fsck state yield UInt16(self, "fs_state", "Rebuilding phase of fsck ") yield Enum(UInt32(self, "hash_function", "Hash function to sort names in a directory"), self.HASH_FUNCTIONS) yield UInt16(self, "tree_height", "Height of disk tree") yield UInt16(self, "bmap_nr", "Amount of bitmap blocks needed to address each block of file system") # TODO: find a good description for this field yield UInt16(self, "version", "Field only reliable on filesystem with non-standard journal") yield UInt16(self, "reserved_for_journal", "Size in blocks of journal area on main device") # TODO: same as above yield UInt32(self, "inode_generation", "No description") # TODO: same as above and should be an enum field yield UInt32(self, "flags", "No description") # TODO: Create a special Type to format this id yield RawBytes(self, "uuid", 16, "Filesystem unique identifier") yield String(self, "label", 16, "Filesystem volume label", strip="\0") yield NullBytes(self, "unused", 88) yield NullBytes(self, "Bytes before end of the block", self["blocksize"].value - 204) def createDescription(self): return "Superblock: ReiserFs Filesystem" class REISER_FS(Parser): PARSER_TAGS = { "id": "reiserfs", "category": "file_system", # 130 blocks before the journal + # Minimal size of journal (513 blocks) + # 1 block for the rest # And The Minimal size of a block is 512 bytes "min_size": (130 + 513 + 1) * (512 * 8), "description": "ReiserFS file system" } endian = LITTLE_ENDIAN # Offsets (in bytes) of important information SUPERBLOCK_OFFSET = 64 * 1024 MAGIC_OFFSET = SUPERBLOCK_OFFSET + 52 def validate(self): # Let's look at the magic field in the superblock magic = self.stream.readBytes(self.MAGIC_OFFSET * 8, 9).rstrip(b"\0") if magic in (b"ReIsEr3Fs", b"ReIsErFs", b"ReIsEr2Fs"): return True return "Invalid magic string" def createFields(self): yield NullBytes(self, "padding[]", self.SUPERBLOCK_OFFSET) yield SuperBlock(self, "superblock") yield BitmapBlockGroup(self, "Group of bitmap blocks")