This page hosts a formal specification of ext2 filesystem using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
<?php
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
namespace {
class Ext2 extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Kaitai\Struct\Struct $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
}
protected $_m_bg1;
public function bg1() {
if ($this->_m_bg1 !== null)
return $this->_m_bg1;
$_pos = $this->_io->pos();
$this->_io->seek(1024);
$this->_m_bg1 = new \Ext2\BlockGroup($this->_io, $this, $this->_root);
$this->_io->seek($_pos);
return $this->_m_bg1;
}
protected $_m_rootDir;
public function rootDir() {
if ($this->_m_rootDir !== null)
return $this->_m_rootDir;
$this->_m_rootDir = $this->bg1()->blockGroups()[0]->inodes()[1]->asDir();
return $this->_m_rootDir;
}
}
}
namespace Ext2 {
class SuperBlockStruct extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2\BlockGroup $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m_inodesCount = $this->_io->readU4le();
$this->_m_blocksCount = $this->_io->readU4le();
$this->_m_rBlocksCount = $this->_io->readU4le();
$this->_m_freeBlocksCount = $this->_io->readU4le();
$this->_m_freeInodesCount = $this->_io->readU4le();
$this->_m_firstDataBlock = $this->_io->readU4le();
$this->_m_logBlockSize = $this->_io->readU4le();
$this->_m_logFragSize = $this->_io->readU4le();
$this->_m_blocksPerGroup = $this->_io->readU4le();
$this->_m_fragsPerGroup = $this->_io->readU4le();
$this->_m_inodesPerGroup = $this->_io->readU4le();
$this->_m_mtime = $this->_io->readU4le();
$this->_m_wtime = $this->_io->readU4le();
$this->_m_mntCount = $this->_io->readU2le();
$this->_m_maxMntCount = $this->_io->readU2le();
$this->_m_magic = $this->_io->readBytes(2);
if (!($this->magic() == "\x53\xEF")) {
throw new \Kaitai\Struct\Error\ValidationNotEqualError("\x53\xEF", $this->magic(), $this->_io(), "/types/super_block_struct/seq/15");
}
$this->_m_state = $this->_io->readU2le();
$this->_m_errors = $this->_io->readU2le();
$this->_m_minorRevLevel = $this->_io->readU2le();
$this->_m_lastcheck = $this->_io->readU4le();
$this->_m_checkinterval = $this->_io->readU4le();
$this->_m_creatorOs = $this->_io->readU4le();
$this->_m_revLevel = $this->_io->readU4le();
$this->_m_defResuid = $this->_io->readU2le();
$this->_m_defResgid = $this->_io->readU2le();
$this->_m_firstIno = $this->_io->readU4le();
$this->_m_inodeSize = $this->_io->readU2le();
$this->_m_blockGroupNr = $this->_io->readU2le();
$this->_m_featureCompat = $this->_io->readU4le();
$this->_m_featureIncompat = $this->_io->readU4le();
$this->_m_featureRoCompat = $this->_io->readU4le();
$this->_m_uuid = $this->_io->readBytes(16);
$this->_m_volumeName = $this->_io->readBytes(16);
$this->_m_lastMounted = $this->_io->readBytes(64);
$this->_m_algoBitmap = $this->_io->readU4le();
$this->_m_preallocBlocks = $this->_io->readU1();
$this->_m_preallocDirBlocks = $this->_io->readU1();
$this->_m_padding1 = $this->_io->readBytes(2);
$this->_m_journalUuid = $this->_io->readBytes(16);
$this->_m_journalInum = $this->_io->readU4le();
$this->_m_journalDev = $this->_io->readU4le();
$this->_m_lastOrphan = $this->_io->readU4le();
$this->_m_hashSeed = [];
$n = 4;
for ($i = 0; $i < $n; $i++) {
$this->_m_hashSeed[] = $this->_io->readU4le();
}
$this->_m_defHashVersion = $this->_io->readU1();
}
protected $_m_blockSize;
public function blockSize() {
if ($this->_m_blockSize !== null)
return $this->_m_blockSize;
$this->_m_blockSize = (1024 << $this->logBlockSize());
return $this->_m_blockSize;
}
protected $_m_blockGroupCount;
public function blockGroupCount() {
if ($this->_m_blockGroupCount !== null)
return $this->_m_blockGroupCount;
$this->_m_blockGroupCount = intval($this->blocksCount() / $this->blocksPerGroup());
return $this->_m_blockGroupCount;
}
protected $_m_inodesCount;
protected $_m_blocksCount;
protected $_m_rBlocksCount;
protected $_m_freeBlocksCount;
protected $_m_freeInodesCount;
protected $_m_firstDataBlock;
protected $_m_logBlockSize;
protected $_m_logFragSize;
protected $_m_blocksPerGroup;
protected $_m_fragsPerGroup;
protected $_m_inodesPerGroup;
protected $_m_mtime;
protected $_m_wtime;
protected $_m_mntCount;
protected $_m_maxMntCount;
protected $_m_magic;
protected $_m_state;
protected $_m_errors;
protected $_m_minorRevLevel;
protected $_m_lastcheck;
protected $_m_checkinterval;
protected $_m_creatorOs;
protected $_m_revLevel;
protected $_m_defResuid;
protected $_m_defResgid;
protected $_m_firstIno;
protected $_m_inodeSize;
protected $_m_blockGroupNr;
protected $_m_featureCompat;
protected $_m_featureIncompat;
protected $_m_featureRoCompat;
protected $_m_uuid;
protected $_m_volumeName;
protected $_m_lastMounted;
protected $_m_algoBitmap;
protected $_m_preallocBlocks;
protected $_m_preallocDirBlocks;
protected $_m_padding1;
protected $_m_journalUuid;
protected $_m_journalInum;
protected $_m_journalDev;
protected $_m_lastOrphan;
protected $_m_hashSeed;
protected $_m_defHashVersion;
public function inodesCount() { return $this->_m_inodesCount; }
public function blocksCount() { return $this->_m_blocksCount; }
public function rBlocksCount() { return $this->_m_rBlocksCount; }
public function freeBlocksCount() { return $this->_m_freeBlocksCount; }
public function freeInodesCount() { return $this->_m_freeInodesCount; }
public function firstDataBlock() { return $this->_m_firstDataBlock; }
public function logBlockSize() { return $this->_m_logBlockSize; }
public function logFragSize() { return $this->_m_logFragSize; }
public function blocksPerGroup() { return $this->_m_blocksPerGroup; }
public function fragsPerGroup() { return $this->_m_fragsPerGroup; }
public function inodesPerGroup() { return $this->_m_inodesPerGroup; }
public function mtime() { return $this->_m_mtime; }
public function wtime() { return $this->_m_wtime; }
public function mntCount() { return $this->_m_mntCount; }
public function maxMntCount() { return $this->_m_maxMntCount; }
public function magic() { return $this->_m_magic; }
public function state() { return $this->_m_state; }
public function errors() { return $this->_m_errors; }
public function minorRevLevel() { return $this->_m_minorRevLevel; }
public function lastcheck() { return $this->_m_lastcheck; }
public function checkinterval() { return $this->_m_checkinterval; }
public function creatorOs() { return $this->_m_creatorOs; }
public function revLevel() { return $this->_m_revLevel; }
public function defResuid() { return $this->_m_defResuid; }
public function defResgid() { return $this->_m_defResgid; }
public function firstIno() { return $this->_m_firstIno; }
public function inodeSize() { return $this->_m_inodeSize; }
public function blockGroupNr() { return $this->_m_blockGroupNr; }
public function featureCompat() { return $this->_m_featureCompat; }
public function featureIncompat() { return $this->_m_featureIncompat; }
public function featureRoCompat() { return $this->_m_featureRoCompat; }
public function uuid() { return $this->_m_uuid; }
public function volumeName() { return $this->_m_volumeName; }
public function lastMounted() { return $this->_m_lastMounted; }
public function algoBitmap() { return $this->_m_algoBitmap; }
public function preallocBlocks() { return $this->_m_preallocBlocks; }
public function preallocDirBlocks() { return $this->_m_preallocDirBlocks; }
public function padding1() { return $this->_m_padding1; }
public function journalUuid() { return $this->_m_journalUuid; }
public function journalInum() { return $this->_m_journalInum; }
public function journalDev() { return $this->_m_journalDev; }
public function lastOrphan() { return $this->_m_lastOrphan; }
public function hashSeed() { return $this->_m_hashSeed; }
public function defHashVersion() { return $this->_m_defHashVersion; }
}
}
namespace Ext2\SuperBlockStruct {
class StateEnum {
const VALID_FS = 1;
const ERROR_FS = 2;
}
}
namespace Ext2\SuperBlockStruct {
class ErrorsEnum {
const ACT_CONTINUE = 1;
const ACT_RO = 2;
const ACT_PANIC = 3;
}
}
namespace Ext2 {
class DirEntry extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2\Dir $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m_inodePtr = $this->_io->readU4le();
$this->_m_recLen = $this->_io->readU2le();
$this->_m_nameLen = $this->_io->readU1();
$this->_m_fileType = $this->_io->readU1();
$this->_m_name = \Kaitai\Struct\Stream::bytesToStr($this->_io->readBytes($this->nameLen()), "UTF-8");
$this->_m_padding = $this->_io->readBytes((($this->recLen() - $this->nameLen()) - 8));
}
protected $_m_inode;
public function inode() {
if ($this->_m_inode !== null)
return $this->_m_inode;
$this->_m_inode = $this->_root()->bg1()->blockGroups()[intval(($this->inodePtr() - 1) / $this->_root()->bg1()->superBlock()->inodesPerGroup())]->inodes()[\Kaitai\Struct\Stream::mod(($this->inodePtr() - 1), $this->_root()->bg1()->superBlock()->inodesPerGroup())];
return $this->_m_inode;
}
protected $_m_inodePtr;
protected $_m_recLen;
protected $_m_nameLen;
protected $_m_fileType;
protected $_m_name;
protected $_m_padding;
public function inodePtr() { return $this->_m_inodePtr; }
public function recLen() { return $this->_m_recLen; }
public function nameLen() { return $this->_m_nameLen; }
public function fileType() { return $this->_m_fileType; }
public function name() { return $this->_m_name; }
public function padding() { return $this->_m_padding; }
}
}
namespace Ext2\DirEntry {
class FileTypeEnum {
const UNKNOWN = 0;
const REG_FILE = 1;
const DIR = 2;
const CHRDEV = 3;
const BLKDEV = 4;
const FIFO = 5;
const SOCK = 6;
const SYMLINK = 7;
}
}
namespace Ext2 {
class Inode extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2\Bgd $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m_mode = $this->_io->readU2le();
$this->_m_uid = $this->_io->readU2le();
$this->_m_size = $this->_io->readU4le();
$this->_m_atime = $this->_io->readU4le();
$this->_m_ctime = $this->_io->readU4le();
$this->_m_mtime = $this->_io->readU4le();
$this->_m_dtime = $this->_io->readU4le();
$this->_m_gid = $this->_io->readU2le();
$this->_m_linksCount = $this->_io->readU2le();
$this->_m_blocks = $this->_io->readU4le();
$this->_m_flags = $this->_io->readU4le();
$this->_m_osd1 = $this->_io->readU4le();
$this->_m_block = [];
$n = 15;
for ($i = 0; $i < $n; $i++) {
$this->_m_block[] = new \Ext2\BlockPtr($this->_io, $this, $this->_root);
}
$this->_m_generation = $this->_io->readU4le();
$this->_m_fileAcl = $this->_io->readU4le();
$this->_m_dirAcl = $this->_io->readU4le();
$this->_m_faddr = $this->_io->readU4le();
$this->_m_osd2 = $this->_io->readBytes(12);
}
protected $_m_asDir;
public function asDir() {
if ($this->_m_asDir !== null)
return $this->_m_asDir;
$io = $this->block()[0]->body()->_io();
$_pos = $io->pos();
$io->seek(0);
$this->_m_asDir = new \Ext2\Dir($io, $this, $this->_root);
$io->seek($_pos);
return $this->_m_asDir;
}
protected $_m_mode;
protected $_m_uid;
protected $_m_size;
protected $_m_atime;
protected $_m_ctime;
protected $_m_mtime;
protected $_m_dtime;
protected $_m_gid;
protected $_m_linksCount;
protected $_m_blocks;
protected $_m_flags;
protected $_m_osd1;
protected $_m_block;
protected $_m_generation;
protected $_m_fileAcl;
protected $_m_dirAcl;
protected $_m_faddr;
protected $_m_osd2;
public function mode() { return $this->_m_mode; }
public function uid() { return $this->_m_uid; }
public function size() { return $this->_m_size; }
public function atime() { return $this->_m_atime; }
public function ctime() { return $this->_m_ctime; }
public function mtime() { return $this->_m_mtime; }
public function dtime() { return $this->_m_dtime; }
public function gid() { return $this->_m_gid; }
public function linksCount() { return $this->_m_linksCount; }
public function blocks() { return $this->_m_blocks; }
public function flags() { return $this->_m_flags; }
public function osd1() { return $this->_m_osd1; }
public function block() { return $this->_m_block; }
public function generation() { return $this->_m_generation; }
public function fileAcl() { return $this->_m_fileAcl; }
public function dirAcl() { return $this->_m_dirAcl; }
public function faddr() { return $this->_m_faddr; }
public function osd2() { return $this->_m_osd2; }
}
}
namespace Ext2 {
class BlockPtr extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2\Inode $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m_ptr = $this->_io->readU4le();
}
protected $_m_body;
public function body() {
if ($this->_m_body !== null)
return $this->_m_body;
$_pos = $this->_io->pos();
$this->_io->seek(($this->ptr() * $this->_root()->bg1()->superBlock()->blockSize()));
$this->_m__raw_body = $this->_io->readBytes($this->_root()->bg1()->superBlock()->blockSize());
$_io__raw_body = new \Kaitai\Struct\Stream($this->_m__raw_body);
$this->_m_body = new \Ext2\RawBlock($_io__raw_body, $this, $this->_root);
$this->_io->seek($_pos);
return $this->_m_body;
}
protected $_m_ptr;
protected $_m__raw_body;
public function ptr() { return $this->_m_ptr; }
public function _raw_body() { return $this->_m__raw_body; }
}
}
namespace Ext2 {
class Dir extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2\Inode $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m_entries = [];
$i = 0;
while (!$this->_io->isEof()) {
$this->_m_entries[] = new \Ext2\DirEntry($this->_io, $this, $this->_root);
$i++;
}
}
protected $_m_entries;
public function entries() { return $this->_m_entries; }
}
}
namespace Ext2 {
class BlockGroup extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2 $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m__raw_superBlock = $this->_io->readBytes(1024);
$_io__raw_superBlock = new \Kaitai\Struct\Stream($this->_m__raw_superBlock);
$this->_m_superBlock = new \Ext2\SuperBlockStruct($_io__raw_superBlock, $this, $this->_root);
$this->_m_blockGroups = [];
$n = $this->superBlock()->blockGroupCount();
for ($i = 0; $i < $n; $i++) {
$this->_m_blockGroups[] = new \Ext2\Bgd($this->_io, $this, $this->_root);
}
}
protected $_m_superBlock;
protected $_m_blockGroups;
protected $_m__raw_superBlock;
public function superBlock() { return $this->_m_superBlock; }
public function blockGroups() { return $this->_m_blockGroups; }
public function _raw_superBlock() { return $this->_m__raw_superBlock; }
}
}
namespace Ext2 {
class Bgd extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2\BlockGroup $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m_blockBitmapBlock = $this->_io->readU4le();
$this->_m_inodeBitmapBlock = $this->_io->readU4le();
$this->_m_inodeTableBlock = $this->_io->readU4le();
$this->_m_freeBlocksCount = $this->_io->readU2le();
$this->_m_freeInodesCount = $this->_io->readU2le();
$this->_m_usedDirsCount = $this->_io->readU2le();
$this->_m_padReserved = $this->_io->readBytes((2 + 12));
}
protected $_m_blockBitmap;
public function blockBitmap() {
if ($this->_m_blockBitmap !== null)
return $this->_m_blockBitmap;
$_pos = $this->_io->pos();
$this->_io->seek(($this->blockBitmapBlock() * $this->_root()->bg1()->superBlock()->blockSize()));
$this->_m_blockBitmap = $this->_io->readBytes(1024);
$this->_io->seek($_pos);
return $this->_m_blockBitmap;
}
protected $_m_inodeBitmap;
public function inodeBitmap() {
if ($this->_m_inodeBitmap !== null)
return $this->_m_inodeBitmap;
$_pos = $this->_io->pos();
$this->_io->seek(($this->inodeBitmapBlock() * $this->_root()->bg1()->superBlock()->blockSize()));
$this->_m_inodeBitmap = $this->_io->readBytes(1024);
$this->_io->seek($_pos);
return $this->_m_inodeBitmap;
}
protected $_m_inodes;
public function inodes() {
if ($this->_m_inodes !== null)
return $this->_m_inodes;
$_pos = $this->_io->pos();
$this->_io->seek(($this->inodeTableBlock() * $this->_root()->bg1()->superBlock()->blockSize()));
$this->_m_inodes = [];
$n = $this->_root()->bg1()->superBlock()->inodesPerGroup();
for ($i = 0; $i < $n; $i++) {
$this->_m_inodes[] = new \Ext2\Inode($this->_io, $this, $this->_root);
}
$this->_io->seek($_pos);
return $this->_m_inodes;
}
protected $_m_blockBitmapBlock;
protected $_m_inodeBitmapBlock;
protected $_m_inodeTableBlock;
protected $_m_freeBlocksCount;
protected $_m_freeInodesCount;
protected $_m_usedDirsCount;
protected $_m_padReserved;
public function blockBitmapBlock() { return $this->_m_blockBitmapBlock; }
public function inodeBitmapBlock() { return $this->_m_inodeBitmapBlock; }
public function inodeTableBlock() { return $this->_m_inodeTableBlock; }
public function freeBlocksCount() { return $this->_m_freeBlocksCount; }
public function freeInodesCount() { return $this->_m_freeInodesCount; }
public function usedDirsCount() { return $this->_m_usedDirsCount; }
public function padReserved() { return $this->_m_padReserved; }
}
}
namespace Ext2 {
class RawBlock extends \Kaitai\Struct\Struct {
public function __construct(\Kaitai\Struct\Stream $_io, \Ext2\BlockPtr $_parent = null, \Ext2 $_root = null) {
parent::__construct($_io, $_parent, $_root);
$this->_read();
}
private function _read() {
$this->_m_body = $this->_io->readBytes($this->_root()->bg1()->superBlock()->blockSize());
}
protected $_m_body;
public function body() { return $this->_m_body; }
}
}