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.
All parsing code for C# generated by Kaitai Struct depends on the C# runtime library. You have to install it before you can parse data.
The C# runtime library is available in the NuGet Gallery. Installation instructions can also be found there.
Parse a local file and get structure in memory:
var data = Ext2.FromFile("path/to/local/file.bin");
Or parse structure from a byte array:
byte[] someArray = new byte[] { ... };
var data = new Ext2(new KaitaiStream(someArray));
After that, one can get various attributes from the structure by accessing properties like:
data.Bg1 // => get bg1
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
using System.Collections.Generic;
namespace Kaitai
{
public partial class Ext2 : KaitaiStruct
{
public static Ext2 FromFile(string fileName)
{
return new Ext2(new KaitaiStream(fileName));
}
public Ext2(KaitaiStream p__io, KaitaiStruct p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root ?? this;
f_bg1 = false;
f_rootDir = false;
_read();
}
private void _read()
{
}
public partial class SuperBlockStruct : KaitaiStruct
{
public static SuperBlockStruct FromFile(string fileName)
{
return new SuperBlockStruct(new KaitaiStream(fileName));
}
public enum StateEnum
{
ValidFs = 1,
ErrorFs = 2,
}
public enum ErrorsEnum
{
ActContinue = 1,
ActRo = 2,
ActPanic = 3,
}
public SuperBlockStruct(KaitaiStream p__io, Ext2.BlockGroup p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_blockSize = false;
f_blockGroupCount = false;
_read();
}
private void _read()
{
_inodesCount = m_io.ReadU4le();
_blocksCount = m_io.ReadU4le();
_rBlocksCount = m_io.ReadU4le();
_freeBlocksCount = m_io.ReadU4le();
_freeInodesCount = m_io.ReadU4le();
_firstDataBlock = m_io.ReadU4le();
_logBlockSize = m_io.ReadU4le();
_logFragSize = m_io.ReadU4le();
_blocksPerGroup = m_io.ReadU4le();
_fragsPerGroup = m_io.ReadU4le();
_inodesPerGroup = m_io.ReadU4le();
_mtime = m_io.ReadU4le();
_wtime = m_io.ReadU4le();
_mntCount = m_io.ReadU2le();
_maxMntCount = m_io.ReadU2le();
_magic = m_io.ReadBytes(2);
if (!((KaitaiStream.ByteArrayCompare(Magic, new byte[] { 83, 239 }) == 0)))
{
throw new ValidationNotEqualError(new byte[] { 83, 239 }, Magic, M_Io, "/types/super_block_struct/seq/15");
}
_state = ((StateEnum) m_io.ReadU2le());
_errors = ((ErrorsEnum) m_io.ReadU2le());
_minorRevLevel = m_io.ReadU2le();
_lastcheck = m_io.ReadU4le();
_checkinterval = m_io.ReadU4le();
_creatorOs = m_io.ReadU4le();
_revLevel = m_io.ReadU4le();
_defResuid = m_io.ReadU2le();
_defResgid = m_io.ReadU2le();
_firstIno = m_io.ReadU4le();
_inodeSize = m_io.ReadU2le();
_blockGroupNr = m_io.ReadU2le();
_featureCompat = m_io.ReadU4le();
_featureIncompat = m_io.ReadU4le();
_featureRoCompat = m_io.ReadU4le();
_uuid = m_io.ReadBytes(16);
_volumeName = m_io.ReadBytes(16);
_lastMounted = m_io.ReadBytes(64);
_algoBitmap = m_io.ReadU4le();
_preallocBlocks = m_io.ReadU1();
_preallocDirBlocks = m_io.ReadU1();
_padding1 = m_io.ReadBytes(2);
_journalUuid = m_io.ReadBytes(16);
_journalInum = m_io.ReadU4le();
_journalDev = m_io.ReadU4le();
_lastOrphan = m_io.ReadU4le();
_hashSeed = new List<uint>();
for (var i = 0; i < 4; i++)
{
_hashSeed.Add(m_io.ReadU4le());
}
_defHashVersion = m_io.ReadU1();
}
private bool f_blockSize;
private int _blockSize;
public int BlockSize
{
get
{
if (f_blockSize)
return _blockSize;
_blockSize = (int) ((1024 << LogBlockSize));
f_blockSize = true;
return _blockSize;
}
}
private bool f_blockGroupCount;
private int _blockGroupCount;
public int BlockGroupCount
{
get
{
if (f_blockGroupCount)
return _blockGroupCount;
_blockGroupCount = (int) ((BlocksCount / BlocksPerGroup));
f_blockGroupCount = true;
return _blockGroupCount;
}
}
private uint _inodesCount;
private uint _blocksCount;
private uint _rBlocksCount;
private uint _freeBlocksCount;
private uint _freeInodesCount;
private uint _firstDataBlock;
private uint _logBlockSize;
private uint _logFragSize;
private uint _blocksPerGroup;
private uint _fragsPerGroup;
private uint _inodesPerGroup;
private uint _mtime;
private uint _wtime;
private ushort _mntCount;
private ushort _maxMntCount;
private byte[] _magic;
private StateEnum _state;
private ErrorsEnum _errors;
private ushort _minorRevLevel;
private uint _lastcheck;
private uint _checkinterval;
private uint _creatorOs;
private uint _revLevel;
private ushort _defResuid;
private ushort _defResgid;
private uint _firstIno;
private ushort _inodeSize;
private ushort _blockGroupNr;
private uint _featureCompat;
private uint _featureIncompat;
private uint _featureRoCompat;
private byte[] _uuid;
private byte[] _volumeName;
private byte[] _lastMounted;
private uint _algoBitmap;
private byte _preallocBlocks;
private byte _preallocDirBlocks;
private byte[] _padding1;
private byte[] _journalUuid;
private uint _journalInum;
private uint _journalDev;
private uint _lastOrphan;
private List<uint> _hashSeed;
private byte _defHashVersion;
private Ext2 m_root;
private Ext2.BlockGroup m_parent;
public uint InodesCount { get { return _inodesCount; } }
public uint BlocksCount { get { return _blocksCount; } }
public uint RBlocksCount { get { return _rBlocksCount; } }
public uint FreeBlocksCount { get { return _freeBlocksCount; } }
public uint FreeInodesCount { get { return _freeInodesCount; } }
public uint FirstDataBlock { get { return _firstDataBlock; } }
public uint LogBlockSize { get { return _logBlockSize; } }
public uint LogFragSize { get { return _logFragSize; } }
public uint BlocksPerGroup { get { return _blocksPerGroup; } }
public uint FragsPerGroup { get { return _fragsPerGroup; } }
public uint InodesPerGroup { get { return _inodesPerGroup; } }
public uint Mtime { get { return _mtime; } }
public uint Wtime { get { return _wtime; } }
public ushort MntCount { get { return _mntCount; } }
public ushort MaxMntCount { get { return _maxMntCount; } }
public byte[] Magic { get { return _magic; } }
public StateEnum State { get { return _state; } }
public ErrorsEnum Errors { get { return _errors; } }
public ushort MinorRevLevel { get { return _minorRevLevel; } }
public uint Lastcheck { get { return _lastcheck; } }
public uint Checkinterval { get { return _checkinterval; } }
public uint CreatorOs { get { return _creatorOs; } }
public uint RevLevel { get { return _revLevel; } }
public ushort DefResuid { get { return _defResuid; } }
public ushort DefResgid { get { return _defResgid; } }
public uint FirstIno { get { return _firstIno; } }
public ushort InodeSize { get { return _inodeSize; } }
public ushort BlockGroupNr { get { return _blockGroupNr; } }
public uint FeatureCompat { get { return _featureCompat; } }
public uint FeatureIncompat { get { return _featureIncompat; } }
public uint FeatureRoCompat { get { return _featureRoCompat; } }
public byte[] Uuid { get { return _uuid; } }
public byte[] VolumeName { get { return _volumeName; } }
public byte[] LastMounted { get { return _lastMounted; } }
public uint AlgoBitmap { get { return _algoBitmap; } }
public byte PreallocBlocks { get { return _preallocBlocks; } }
public byte PreallocDirBlocks { get { return _preallocDirBlocks; } }
public byte[] Padding1 { get { return _padding1; } }
public byte[] JournalUuid { get { return _journalUuid; } }
public uint JournalInum { get { return _journalInum; } }
public uint JournalDev { get { return _journalDev; } }
public uint LastOrphan { get { return _lastOrphan; } }
public List<uint> HashSeed { get { return _hashSeed; } }
public byte DefHashVersion { get { return _defHashVersion; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2.BlockGroup M_Parent { get { return m_parent; } }
}
public partial class DirEntry : KaitaiStruct
{
public static DirEntry FromFile(string fileName)
{
return new DirEntry(new KaitaiStream(fileName));
}
public enum FileTypeEnum
{
Unknown = 0,
RegFile = 1,
Dir = 2,
Chrdev = 3,
Blkdev = 4,
Fifo = 5,
Sock = 6,
Symlink = 7,
}
public DirEntry(KaitaiStream p__io, Ext2.Dir p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_inode = false;
_read();
}
private void _read()
{
_inodePtr = m_io.ReadU4le();
_recLen = m_io.ReadU2le();
_nameLen = m_io.ReadU1();
_fileType = ((FileTypeEnum) m_io.ReadU1());
_name = System.Text.Encoding.GetEncoding("UTF-8").GetString(m_io.ReadBytes(NameLen));
_padding = m_io.ReadBytes(((RecLen - NameLen) - 8));
}
private bool f_inode;
private Inode _inode;
public Inode Inode
{
get
{
if (f_inode)
return _inode;
_inode = (Inode) (M_Root.Bg1.BlockGroups[((InodePtr - 1) / M_Root.Bg1.SuperBlock.InodesPerGroup)].Inodes[KaitaiStream.Mod((InodePtr - 1), M_Root.Bg1.SuperBlock.InodesPerGroup)]);
f_inode = true;
return _inode;
}
}
private uint _inodePtr;
private ushort _recLen;
private byte _nameLen;
private FileTypeEnum _fileType;
private string _name;
private byte[] _padding;
private Ext2 m_root;
private Ext2.Dir m_parent;
public uint InodePtr { get { return _inodePtr; } }
public ushort RecLen { get { return _recLen; } }
public byte NameLen { get { return _nameLen; } }
public FileTypeEnum FileType { get { return _fileType; } }
public string Name { get { return _name; } }
public byte[] Padding { get { return _padding; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2.Dir M_Parent { get { return m_parent; } }
}
public partial class Inode : KaitaiStruct
{
public static Inode FromFile(string fileName)
{
return new Inode(new KaitaiStream(fileName));
}
public Inode(KaitaiStream p__io, Ext2.Bgd p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_asDir = false;
_read();
}
private void _read()
{
_mode = m_io.ReadU2le();
_uid = m_io.ReadU2le();
_size = m_io.ReadU4le();
_atime = m_io.ReadU4le();
_ctime = m_io.ReadU4le();
_mtime = m_io.ReadU4le();
_dtime = m_io.ReadU4le();
_gid = m_io.ReadU2le();
_linksCount = m_io.ReadU2le();
_blocks = m_io.ReadU4le();
_flags = m_io.ReadU4le();
_osd1 = m_io.ReadU4le();
_block = new List<BlockPtr>();
for (var i = 0; i < 15; i++)
{
_block.Add(new BlockPtr(m_io, this, m_root));
}
_generation = m_io.ReadU4le();
_fileAcl = m_io.ReadU4le();
_dirAcl = m_io.ReadU4le();
_faddr = m_io.ReadU4le();
_osd2 = m_io.ReadBytes(12);
}
private bool f_asDir;
private Dir _asDir;
public Dir AsDir
{
get
{
if (f_asDir)
return _asDir;
KaitaiStream io = Block[0].Body.M_Io;
long _pos = io.Pos;
io.Seek(0);
_asDir = new Dir(io, this, m_root);
io.Seek(_pos);
f_asDir = true;
return _asDir;
}
}
private ushort _mode;
private ushort _uid;
private uint _size;
private uint _atime;
private uint _ctime;
private uint _mtime;
private uint _dtime;
private ushort _gid;
private ushort _linksCount;
private uint _blocks;
private uint _flags;
private uint _osd1;
private List<BlockPtr> _block;
private uint _generation;
private uint _fileAcl;
private uint _dirAcl;
private uint _faddr;
private byte[] _osd2;
private Ext2 m_root;
private Ext2.Bgd m_parent;
public ushort Mode { get { return _mode; } }
public ushort Uid { get { return _uid; } }
public uint Size { get { return _size; } }
public uint Atime { get { return _atime; } }
public uint Ctime { get { return _ctime; } }
public uint Mtime { get { return _mtime; } }
public uint Dtime { get { return _dtime; } }
public ushort Gid { get { return _gid; } }
public ushort LinksCount { get { return _linksCount; } }
public uint Blocks { get { return _blocks; } }
public uint Flags { get { return _flags; } }
public uint Osd1 { get { return _osd1; } }
public List<BlockPtr> Block { get { return _block; } }
public uint Generation { get { return _generation; } }
public uint FileAcl { get { return _fileAcl; } }
public uint DirAcl { get { return _dirAcl; } }
public uint Faddr { get { return _faddr; } }
public byte[] Osd2 { get { return _osd2; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2.Bgd M_Parent { get { return m_parent; } }
}
public partial class BlockPtr : KaitaiStruct
{
public static BlockPtr FromFile(string fileName)
{
return new BlockPtr(new KaitaiStream(fileName));
}
public BlockPtr(KaitaiStream p__io, Ext2.Inode p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_body = false;
_read();
}
private void _read()
{
_ptr = m_io.ReadU4le();
}
private bool f_body;
private RawBlock _body;
public RawBlock Body
{
get
{
if (f_body)
return _body;
long _pos = m_io.Pos;
m_io.Seek((Ptr * M_Root.Bg1.SuperBlock.BlockSize));
__raw_body = m_io.ReadBytes(M_Root.Bg1.SuperBlock.BlockSize);
var io___raw_body = new KaitaiStream(__raw_body);
_body = new RawBlock(io___raw_body, this, m_root);
m_io.Seek(_pos);
f_body = true;
return _body;
}
}
private uint _ptr;
private Ext2 m_root;
private Ext2.Inode m_parent;
private byte[] __raw_body;
public uint Ptr { get { return _ptr; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2.Inode M_Parent { get { return m_parent; } }
public byte[] M_RawBody { get { return __raw_body; } }
}
public partial class Dir : KaitaiStruct
{
public static Dir FromFile(string fileName)
{
return new Dir(new KaitaiStream(fileName));
}
public Dir(KaitaiStream p__io, Ext2.Inode p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_entries = new List<DirEntry>();
{
var i = 0;
while (!m_io.IsEof) {
_entries.Add(new DirEntry(m_io, this, m_root));
i++;
}
}
}
private List<DirEntry> _entries;
private Ext2 m_root;
private Ext2.Inode m_parent;
public List<DirEntry> Entries { get { return _entries; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2.Inode M_Parent { get { return m_parent; } }
}
public partial class BlockGroup : KaitaiStruct
{
public static BlockGroup FromFile(string fileName)
{
return new BlockGroup(new KaitaiStream(fileName));
}
public BlockGroup(KaitaiStream p__io, Ext2 p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
__raw_superBlock = m_io.ReadBytes(1024);
var io___raw_superBlock = new KaitaiStream(__raw_superBlock);
_superBlock = new SuperBlockStruct(io___raw_superBlock, this, m_root);
_blockGroups = new List<Bgd>();
for (var i = 0; i < SuperBlock.BlockGroupCount; i++)
{
_blockGroups.Add(new Bgd(m_io, this, m_root));
}
}
private SuperBlockStruct _superBlock;
private List<Bgd> _blockGroups;
private Ext2 m_root;
private Ext2 m_parent;
private byte[] __raw_superBlock;
public SuperBlockStruct SuperBlock { get { return _superBlock; } }
public List<Bgd> BlockGroups { get { return _blockGroups; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2 M_Parent { get { return m_parent; } }
public byte[] M_RawSuperBlock { get { return __raw_superBlock; } }
}
public partial class Bgd : KaitaiStruct
{
public static Bgd FromFile(string fileName)
{
return new Bgd(new KaitaiStream(fileName));
}
public Bgd(KaitaiStream p__io, Ext2.BlockGroup p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_blockBitmap = false;
f_inodeBitmap = false;
f_inodes = false;
_read();
}
private void _read()
{
_blockBitmapBlock = m_io.ReadU4le();
_inodeBitmapBlock = m_io.ReadU4le();
_inodeTableBlock = m_io.ReadU4le();
_freeBlocksCount = m_io.ReadU2le();
_freeInodesCount = m_io.ReadU2le();
_usedDirsCount = m_io.ReadU2le();
_padReserved = m_io.ReadBytes((2 + 12));
}
private bool f_blockBitmap;
private byte[] _blockBitmap;
public byte[] BlockBitmap
{
get
{
if (f_blockBitmap)
return _blockBitmap;
long _pos = m_io.Pos;
m_io.Seek((BlockBitmapBlock * M_Root.Bg1.SuperBlock.BlockSize));
_blockBitmap = m_io.ReadBytes(1024);
m_io.Seek(_pos);
f_blockBitmap = true;
return _blockBitmap;
}
}
private bool f_inodeBitmap;
private byte[] _inodeBitmap;
public byte[] InodeBitmap
{
get
{
if (f_inodeBitmap)
return _inodeBitmap;
long _pos = m_io.Pos;
m_io.Seek((InodeBitmapBlock * M_Root.Bg1.SuperBlock.BlockSize));
_inodeBitmap = m_io.ReadBytes(1024);
m_io.Seek(_pos);
f_inodeBitmap = true;
return _inodeBitmap;
}
}
private bool f_inodes;
private List<Inode> _inodes;
public List<Inode> Inodes
{
get
{
if (f_inodes)
return _inodes;
long _pos = m_io.Pos;
m_io.Seek((InodeTableBlock * M_Root.Bg1.SuperBlock.BlockSize));
_inodes = new List<Inode>();
for (var i = 0; i < M_Root.Bg1.SuperBlock.InodesPerGroup; i++)
{
_inodes.Add(new Inode(m_io, this, m_root));
}
m_io.Seek(_pos);
f_inodes = true;
return _inodes;
}
}
private uint _blockBitmapBlock;
private uint _inodeBitmapBlock;
private uint _inodeTableBlock;
private ushort _freeBlocksCount;
private ushort _freeInodesCount;
private ushort _usedDirsCount;
private byte[] _padReserved;
private Ext2 m_root;
private Ext2.BlockGroup m_parent;
public uint BlockBitmapBlock { get { return _blockBitmapBlock; } }
public uint InodeBitmapBlock { get { return _inodeBitmapBlock; } }
public uint InodeTableBlock { get { return _inodeTableBlock; } }
public ushort FreeBlocksCount { get { return _freeBlocksCount; } }
public ushort FreeInodesCount { get { return _freeInodesCount; } }
public ushort UsedDirsCount { get { return _usedDirsCount; } }
public byte[] PadReserved { get { return _padReserved; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2.BlockGroup M_Parent { get { return m_parent; } }
}
public partial class RawBlock : KaitaiStruct
{
public static RawBlock FromFile(string fileName)
{
return new RawBlock(new KaitaiStream(fileName));
}
public RawBlock(KaitaiStream p__io, Ext2.BlockPtr p__parent = null, Ext2 p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_body = m_io.ReadBytes(M_Root.Bg1.SuperBlock.BlockSize);
}
private byte[] _body;
private Ext2 m_root;
private Ext2.BlockPtr m_parent;
public byte[] Body { get { return _body; } }
public Ext2 M_Root { get { return m_root; } }
public Ext2.BlockPtr M_Parent { get { return m_parent; } }
}
private bool f_bg1;
private BlockGroup _bg1;
public BlockGroup Bg1
{
get
{
if (f_bg1)
return _bg1;
long _pos = m_io.Pos;
m_io.Seek(1024);
_bg1 = new BlockGroup(m_io, this, m_root);
m_io.Seek(_pos);
f_bg1 = true;
return _bg1;
}
}
private bool f_rootDir;
private Dir _rootDir;
public Dir RootDir
{
get
{
if (f_rootDir)
return _rootDir;
_rootDir = (Dir) (Bg1.BlockGroups[0].Inodes[1].AsDir);
f_rootDir = true;
return _rootDir;
}
}
private Ext2 m_root;
private KaitaiStruct m_parent;
public Ext2 M_Root { get { return m_root; } }
public KaitaiStruct M_Parent { get { return m_parent; } }
}
}