// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
using System;
using System.Collections.Generic;
namespace Kaitai
{
///
/// UBIFS is a file system for raw flash memory devices. It works on top of
/// UBI (Unsorted Block Images), which works as an abstraction layer so UBIFS
/// does not need to care about low level details. This specification only covers
/// UBIFS, not UBI.
///
/// A UBIFS image is divided into several Logical Erase Blocks (LEB). The first
/// LEB (LEB0) contains the superblock node, which includes information about LEB
/// size, amongst others. The next two LEBs (LEB1 and LEB2) comprise the so called
/// "master area" and both contain a copy of the master node, which includes
/// information about where to find the root index node, which is then used to
/// access all the files on the file system.
///
/// **Limitations of this Kaitai Struct implementation:**
///
/// 1. It only supports UBIFS images created by `mkfs.ubifs` (such as those in
/// firmware images built by OpenWrt), not file systems modified after
/// creation, e.g. by writing files to them on a running Linux system. The
/// Linux kernel appends a new copy of the master node to LEB1 and LEB2
/// whenever it mounts the file system read-write, unmounts it, or commits
/// changes (updates the index on flash to include them). When mounting, Linux
/// uses the
/// [last copy](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/master.c#L84-L165),
/// whereas this implementation reads the first one (`master_1`), which still
/// describes the file system as it was created. Changes made since then are
/// therefore not visible via `index_root`.
/// 2. Changes that have not been committed yet are not in the index at all, so
/// they are not visible via `index_root` either. Until they are committed,
/// UBIFS keeps them only in the journal. This only matters for file systems
/// that were not unmounted cleanly, because unmounting
/// [commits](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/super.c#L486-L493)
/// all changes.
/// 3. Parsing doesn't advance the stream position. This implementation reads
/// the image only through instances, so that parsing doesn't copy the
/// whole image into memory. To find where the image ends, e.g. when
/// carving it out of a larger file, use `len_image`. For the same reason,
/// parsing doesn't fail if the image is truncated. To detect that, check
/// that the stream is at least `len_image` bytes long
/// (`_io.size >= len_image`).
///
///
/// Reference: Git tag "v7.2"
///
///
/// Reference: Git tag "v7.2"
///
///
/// Reference: Source
///
public partial class Ubifs : KaitaiStruct
{
public static Ubifs FromFile(string fileName)
{
return new Ubifs(new KaitaiStream(fileName));
}
public enum Compression
{
NoCompression = 0,
Lzo = 1,
Zlib = 2,
Zstd = 3,
}
public enum HashAlgos
{
Md4 = 0,
Md5 = 1,
Sha1 = 2,
RipeMd160 = 3,
Sha256 = 4,
Sha384 = 5,
Sha512 = 6,
Sha224 = 7,
RipeMd128 = 8,
RipeMd256 = 9,
RipeMd320 = 10,
Wp256 = 11,
Wp384 = 12,
Wp512 = 13,
Tgr128 = 14,
Tgr160 = 15,
Tgr192 = 16,
Sm3256 = 17,
Streebog256 = 18,
Streebog512 = 19,
Sha3256 = 20,
Sha3384 = 21,
Sha3512 = 22,
}
public enum Hashes
{
R5 = 0,
TestHash = 1,
}
public enum InodeTypes
{
Regular = 0,
Directory = 1,
Link = 2,
BlockDevice = 3,
CharacterDevice = 4,
Fifo = 5,
Socket = 6,
}
public enum KeyFormats
{
Simple = 0,
}
public enum KeyTypes
{
Inode = 0,
Data = 1,
Directory = 2,
ExtendedAttribute = 3,
}
public enum NodeGroupTypes
{
NoNodeGroup = 0,
InNodeGroup = 1,
LastOfNodeGroup = 2,
}
public enum NodeTypes
{
Inode = 0,
Data = 1,
Directory = 2,
ExtendedAttribute = 3,
Truncation = 4,
Padding = 5,
Superblock = 6,
Master = 7,
Reference = 8,
Index = 9,
CommitStart = 10,
Orphan = 11,
Authentication = 12,
Signature = 13,
}
public Ubifs(KaitaiStream p__io, KaitaiStruct p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root ?? this;
f_index = false;
f_indexRoot = false;
f_lebs = false;
f_lenImage = false;
f_master1 = false;
f_master2 = false;
f_superblock = false;
_read();
}
private void _read()
{
}
///
/// Reference: Git tag "v7.2"
///
public partial class AuthenticationHeader : KaitaiStruct
{
public static AuthenticationHeader FromFile(string fileName)
{
return new AuthenticationHeader(new KaitaiStream(fileName));
}
public AuthenticationHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_hmac = m_io.ReadBytes(M_Root.Superblock.NodeHeader.LenHash);
}
private byte[] _hmac;
private Ubifs m_root;
private Ubifs.Block m_parent;
///
/// HMAC authenticating the journal before this node, keyed with the
/// file system's authentication key (which is not stored on flash).
/// The kernel [uses](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/auth.c#L275-L276)
/// HMAC with the hash algorithm in `<superblock_header>.hash_algo`
/// ([checked when mounting](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/sb.c#L575-L580)),
/// so `hmac` is as long as its digest, e.g. 32 bytes for SHA-256.
///
public byte[] Hmac { get { return _hmac; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
}
public partial class Block : KaitaiStruct
{
public static Block FromFile(string fileName)
{
return new Block(new KaitaiStream(fileName));
}
public Block(KaitaiStream p__io, Ubifs.Branch p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_header = new CommonHeader(m_io, this, m_root);
switch (Header.NodeType) {
case Ubifs.NodeTypes.Authentication: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new AuthenticationHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.CommitStart: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new CommitStartHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Data: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new DataHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Directory: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new DirectoryHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.ExtendedAttribute: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new DirectoryHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Index: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new IndexHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Inode: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new InodeHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Master: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new MasterHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Orphan: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new OrphanHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Padding: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new PaddingHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Reference: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new ReferenceHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Signature: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new SignatureHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Superblock: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new SuperblockHeader(io___raw_nodeHeader, this, m_root);
break;
}
case Ubifs.NodeTypes.Truncation: {
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new TruncationHeader(io___raw_nodeHeader, this, m_root);
break;
}
default: {
_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
break;
}
}
}
private CommonHeader _header;
private object _nodeHeader;
private Ubifs m_root;
private Ubifs.Branch m_parent;
private byte[] __raw_nodeHeader;
public CommonHeader Header { get { return _header; } }
public object NodeHeader { get { return _nodeHeader; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Branch M_Parent { get { return m_parent; } }
public byte[] M_RawNodeHeader { get { return __raw_nodeHeader; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class Branch : KaitaiStruct
{
public static Branch FromFile(string fileName)
{
return new Branch(new KaitaiStream(fileName));
}
public Branch(KaitaiStream p__io, Ubifs.IndexHeader p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_target = false;
_read();
}
private void _read()
{
_targetLeb = m_io.ReadU4le();
_ofsTarget = m_io.ReadU4le();
_lenTarget = m_io.ReadU4le();
__raw_key = m_io.ReadBytes(8);
var io___raw_key = new KaitaiStream(__raw_key);
_key = new Key(io___raw_key, this, m_root);
_hash = m_io.ReadBytes(M_Root.Superblock.NodeHeader.LenHash);
}
private bool f_target;
private Block _target;
public Block Target
{
get
{
if (f_target)
return _target;
f_target = true;
KaitaiStream io = M_Root.M_Io;
long _pos = io.Pos;
io.Seek(M_Root.Superblock.NodeHeader.LebSize * TargetLeb + OfsTarget);
__raw_target = io.ReadBytes(LenTarget);
var io___raw_target = new KaitaiStream(__raw_target);
_target = new Block(io___raw_target, this, m_root);
{
Block M_ = _target;
if (!( ((M_.Header.LenFullNode == LenTarget) && ((M_Parent.Level != 0 ? M_.Header.NodeType == Ubifs.NodeTypes.Index : ((int) M_.Header.NodeType) == ((int) Key.Type)))) ))
{
throw new ValidationExprError(_target, m_io, "/types/branch/instances/target");
}
}
io.Seek(_pos);
return _target;
}
}
private uint _targetLeb;
private uint _ofsTarget;
private uint _lenTarget;
private Key _key;
private byte[] _hash;
private Ubifs m_root;
private Ubifs.IndexHeader m_parent;
private byte[] __raw_key;
private byte[] __raw_target;
///
/// LEB number of the target node
///
public uint TargetLeb { get { return _targetLeb; } }
///
/// offset within the LEB `target_leb`
///
public uint OfsTarget { get { return _ofsTarget; } }
///
/// target node length
///
public uint LenTarget { get { return _lenTarget; } }
public Key Key { get { return _key; } }
///
/// Hash of the target node. It is empty in a file system without
/// authentication (see `<superblock_header>.len_hash`).
///
///
/// Reference: Git tag "v7.2"
///
public byte[] Hash { get { return _hash; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.IndexHeader M_Parent { get { return m_parent; } }
public byte[] M_RawKey { get { return __raw_key; } }
public byte[] M_RawTarget { get { return __raw_target; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class CommitStartHeader : KaitaiStruct
{
public static CommitStartHeader FromFile(string fileName)
{
return new CommitStartHeader(new KaitaiStream(fileName));
}
public CommitStartHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_commitNumber = m_io.ReadU8le();
}
private ulong _commitNumber;
private Ubifs m_root;
private Ubifs.Block m_parent;
///
/// commit number
///
public ulong CommitNumber { get { return _commitNumber; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class CommonHeader : KaitaiStruct
{
public static CommonHeader FromFile(string fileName)
{
return new CommonHeader(new KaitaiStream(fileName));
}
public CommonHeader(KaitaiStream p__io, KaitaiStruct p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_magic = m_io.ReadU4le();
if (!(_magic == 101718065))
{
throw new ValidationNotEqualError(101718065, _magic, m_io, "/types/common_header/seq/0");
}
_crc = m_io.ReadU4le();
_sequenceNumber = m_io.ReadU8le();
_lenFullNode = m_io.ReadU4le();
_nodeType = ((Ubifs.NodeTypes) m_io.ReadU1());
_groupType = ((Ubifs.NodeGroupTypes) m_io.ReadU1());
_padding = m_io.ReadBytes(2);
if (!((KaitaiStream.ByteArrayCompare(_padding, new byte[] { 0, 0 }) == 0)))
{
throw new ValidationNotEqualError(new byte[] { 0, 0 }, _padding, m_io, "/types/common_header/seq/6");
}
}
private uint _magic;
private uint _crc;
private ulong _sequenceNumber;
private uint _lenFullNode;
private NodeTypes _nodeType;
private NodeGroupTypes _groupType;
private byte[] _padding;
private Ubifs m_root;
private KaitaiStruct m_parent;
///
/// UBIFS node magic number (`UBIFS_NODE_MAGIC`)
///
public uint Magic { get { return _magic; } }
///
/// CRC-32 checksum of the whole node except `magic` and `crc` (i.e.
/// starting at offset 8). It is computed with an initial register value
/// of 0xFFFFFFFF and no final XOR, so it is the bitwise NOT of a standard
/// CRC-32 (e.g.
/// [`zlib.crc32()`](https://docs.python.org/3/library/zlib.html#zlib.crc32)
/// in Python).
///
public uint Crc { get { return _crc; } }
///
/// sequence number
///
public ulong SequenceNumber { get { return _sequenceNumber; } }
///
/// full node length
///
public uint LenFullNode { get { return _lenFullNode; } }
///
/// node type
///
public NodeTypes NodeType { get { return _nodeType; } }
///
/// node group type
///
public NodeGroupTypes GroupType { get { return _groupType; } }
///
/// reserved for future, zeroes
///
public byte[] Padding { get { return _padding; } }
public Ubifs M_Root { get { return m_root; } }
public KaitaiStruct M_Parent { get { return m_parent; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class DataHeader : KaitaiStruct
{
public static DataHeader FromFile(string fileName)
{
return new DataHeader(new KaitaiStream(fileName));
}
public DataHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
__raw_key = m_io.ReadBytes(16);
var io___raw_key = new KaitaiStream(__raw_key);
_key = new Key(io___raw_key, this, m_root);
_lenUncompressed = m_io.ReadU4le();
if (!(_lenUncompressed >= 1))
{
throw new ValidationLessThanError(1, _lenUncompressed, m_io, "/types/data_header/seq/1");
}
if (!(_lenUncompressed <= 4096))
{
throw new ValidationGreaterThanError(4096, _lenUncompressed, m_io, "/types/data_header/seq/1");
}
_compression = ((Ubifs.Compression) m_io.ReadU2le());
if (!Enum.IsDefined(typeof(Compression), _compression))
{
throw new ValidationNotInEnumError(_compression, m_io, "/types/data_header/seq/2");
}
_lenCompressedData = m_io.ReadU2le();
_data = m_io.ReadBytesFull();
}
private Key _key;
private uint _lenUncompressed;
private Compression _compression;
private ushort _lenCompressedData;
private byte[] _data;
private Ubifs m_root;
private Ubifs.Block m_parent;
private byte[] __raw_key;
///
/// node key
///
public Key Key { get { return _key; } }
///
/// uncompressed data size in bytes
///
public uint LenUncompressed { get { return _lenUncompressed; } }
///
/// compression type (`compression::no_compression`, `compression::lzo`,
/// etc.)
///
public Compression Compression { get { return _compression; } }
///
/// compressed data size in bytes, only valid when data is encrypted
///
public ushort LenCompressedData { get { return _lenCompressedData; } }
///
/// One block (up to 4096 bytes) of the file, block number `key.value`,
/// compressed as given by `compression`. Blocks missing from the index
/// are holes (zeros). In an encrypted inode, the compressed data is
/// padded
/// and [encrypted](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/crypto.c#L38-L59),
/// and `len_compressed_data` is the length of the compressed data
/// before padding.
///
public byte[] Data { get { return _data; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
public byte[] M_RawKey { get { return __raw_key; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class DirectoryHeader : KaitaiStruct
{
public static DirectoryHeader FromFile(string fileName)
{
return new DirectoryHeader(new KaitaiStream(fileName));
}
public DirectoryHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
__raw_key = m_io.ReadBytes(16);
var io___raw_key = new KaitaiStream(__raw_key);
_key = new Key(io___raw_key, this, m_root);
{
Key M_ = _key;
if (!( ((M_.Type == Ubifs.KeyTypes.Directory) || (M_.Type == Ubifs.KeyTypes.ExtendedAttribute)) ))
{
throw new ValidationExprError(_key, m_io, "/types/directory_header/seq/0");
}
}
_inodeNumber = m_io.ReadU8le();
if (!(_inodeNumber <= 4294967295))
{
throw new ValidationGreaterThanError(4294967295, _inodeNumber, m_io, "/types/directory_header/seq/1");
}
_padding1 = m_io.ReadBytes(1);
if (!((KaitaiStream.ByteArrayCompare(_padding1, new byte[] { 0 }) == 0)))
{
throw new ValidationNotEqualError(new byte[] { 0 }, _padding1, m_io, "/types/directory_header/seq/2");
}
_inodeType = ((Ubifs.InodeTypes) m_io.ReadU1());
if (!Enum.IsDefined(typeof(InodeTypes), _inodeType))
{
throw new ValidationNotInEnumError(_inodeType, m_io, "/types/directory_header/seq/3");
}
_lenName = m_io.ReadU2le();
_cookie = m_io.ReadU4le();
_name = m_io.ReadBytes(LenName);
_nameTerminator = m_io.ReadBytes(1);
if (!((KaitaiStream.ByteArrayCompare(_nameTerminator, new byte[] { 0 }) == 0)))
{
throw new ValidationNotEqualError(new byte[] { 0 }, _nameTerminator, m_io, "/types/directory_header/seq/7");
}
}
private Key _key;
private ulong _inodeNumber;
private byte[] _padding1;
private InodeTypes _inodeType;
private ushort _lenName;
private uint _cookie;
private byte[] _name;
private byte[] _nameTerminator;
private Ubifs m_root;
private Ubifs.Block m_parent;
private byte[] __raw_key;
///
/// node key
///
public Key Key { get { return _key; } }
///
/// target inode number
///
public ulong InodeNumber { get { return _inodeNumber; } }
///
/// reserved for future, zeroes
///
public byte[] Padding1 { get { return _padding1; } }
///
/// type of the target inode (`inode_types::regular`,
/// `inode_types::directory`, etc.)
///
public InodeTypes InodeType { get { return _inodeType; } }
///
/// name length
///
public ushort LenName { get { return _lenName; } }
///
/// A 32bits random number, used to construct a 64bits identifier.
///
public uint Cookie { get { return _cookie; } }
///
/// Name of the entry.
///
/// It is kept as bytes rather than decoded as a string: names in a
/// directory whose inode has `<inode_header>.encrypted` set are
/// ciphertext, which may contain any bytes, including zeros.
///
/// Unencrypted names, including all names of extended attributes, contain
/// no zero bytes, because Linux can't create such names. They aren't
/// necessarily valid UTF-8, though, as UBIFS doesn't enforce any encoding
/// of file names. A zero byte in such a name means that the image was
/// crafted, since an accidental corruption would most likely fail the
/// node's
/// [CRC check](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/io.c#L287-L293).
///
public byte[] Name { get { return _name; } }
///
/// Zero byte after `name`, [not counted in
/// `len_name`](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/replay.c#L487-L489).
///
public byte[] NameTerminator { get { return _nameTerminator; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
public byte[] M_RawKey { get { return __raw_key; } }
}
public partial class Dummy : KaitaiStruct
{
public static Dummy FromFile(string fileName)
{
return new Dummy(new KaitaiStream(fileName));
}
public Dummy(KaitaiStream p__io, Ubifs p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
}
private Ubifs m_root;
private Ubifs m_parent;
public Ubifs M_Root { get { return m_root; } }
public Ubifs M_Parent { get { return m_parent; } }
}
public partial class IndexBlock : KaitaiStruct
{
public static IndexBlock FromFile(string fileName)
{
return new IndexBlock(new KaitaiStream(fileName));
}
public IndexBlock(KaitaiStream p__io, Ubifs p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_header = new CommonHeader(m_io, this, m_root);
{
CommonHeader M_ = _header;
if (!(M_.NodeType == Ubifs.NodeTypes.Index))
{
throw new ValidationExprError(_header, m_io, "/types/index_block/seq/0");
}
}
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new IndexHeader(io___raw_nodeHeader, this, m_root);
}
private CommonHeader _header;
private IndexHeader _nodeHeader;
private Ubifs m_root;
private Ubifs m_parent;
private byte[] __raw_nodeHeader;
public CommonHeader Header { get { return _header; } }
public IndexHeader NodeHeader { get { return _nodeHeader; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs M_Parent { get { return m_parent; } }
public byte[] M_RawNodeHeader { get { return __raw_nodeHeader; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class IndexHeader : KaitaiStruct
{
public static IndexHeader FromFile(string fileName)
{
return new IndexHeader(new KaitaiStream(fileName));
}
public IndexHeader(KaitaiStream p__io, KaitaiStruct p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_numBranches = m_io.ReadU2le();
_level = m_io.ReadU2le();
_branches = new List();
for (var i = 0; i < NumBranches; i++)
{
_branches.Add(new Branch(m_io, this, m_root));
}
}
private ushort _numBranches;
private ushort _level;
private List _branches;
private Ubifs m_root;
private KaitaiStruct m_parent;
///
/// number of child index nodes
///
public ushort NumBranches { get { return _numBranches; } }
///
/// tree level
///
public ushort Level { get { return _level; } }
///
/// LEB number / offset / length / key branches
///
/// All branches have the same size, which is 20 bytes (with the simple
/// key format) plus the hash length in an authenticated file system.
///
///
/// Reference: Git tag "v7.2"
///
public List Branches { get { return _branches; } }
public Ubifs M_Root { get { return m_root; } }
public KaitaiStruct M_Parent { get { return m_parent; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class InodeHeader : KaitaiStruct
{
public static InodeHeader FromFile(string fileName)
{
return new InodeHeader(new KaitaiStream(fileName));
}
public InodeHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_append = false;
f_compressed = false;
f_dirsync = false;
f_encrypted = false;
f_immutable = false;
f_isBlockDevice = false;
f_isCharacterDevice = false;
f_isDir = false;
f_isFifo = false;
f_isLink = false;
f_isRegular = false;
f_isSocket = false;
f_synchronous = false;
f_xattr = false;
_read();
}
private void _read()
{
__raw_key = m_io.ReadBytes(16);
var io___raw_key = new KaitaiStream(__raw_key);
_key = new Key(io___raw_key, this, m_root);
_creationSequenceNumber = m_io.ReadU8le();
_lenUncompressed = m_io.ReadU8le();
_atimeSec = m_io.ReadU8le();
_ctimeSec = m_io.ReadU8le();
_mtimeSec = m_io.ReadU8le();
_atimeNsec = m_io.ReadU4le();
_ctimeNsec = m_io.ReadU4le();
_mtimeNsec = m_io.ReadU4le();
_numLinks = m_io.ReadU4le();
_uid = m_io.ReadU4le();
_gid = m_io.ReadU4le();
_mode = m_io.ReadU4le();
_flags = m_io.ReadU4le();
_lenData = m_io.ReadU4le();
_numXattrs = m_io.ReadU4le();
_xattrSize = m_io.ReadU4le();
_padding1 = m_io.ReadBytes(4);
if (!((KaitaiStream.ByteArrayCompare(_padding1, new byte[] { 0, 0, 0, 0 }) == 0)))
{
throw new ValidationNotEqualError(new byte[] { 0, 0, 0, 0 }, _padding1, m_io, "/types/inode_header/seq/17");
}
_xattrNames = m_io.ReadU4le();
_compression = ((Ubifs.Compression) m_io.ReadU2le());
if (!Enum.IsDefined(typeof(Compression), _compression))
{
throw new ValidationNotInEnumError(_compression, m_io, "/types/inode_header/seq/19");
}
_padding2 = m_io.ReadBytes(26);
_data = m_io.ReadBytes(LenData);
}
private bool f_append;
private bool _append;
///
/// writes to the inode may only append data
///
public bool Append
{
get
{
if (f_append)
return _append;
f_append = true;
_append = (bool) ((Flags & 8) != 0);
return _append;
}
}
private bool f_compressed;
private bool _compressed;
///
/// use compression for this inode
///
public bool Compressed
{
get
{
if (f_compressed)
return _compressed;
f_compressed = true;
_compressed = (bool) ((Flags & 1) != 0);
return _compressed;
}
}
private bool f_dirsync;
private bool _dirsync;
///
/// I/O on this directory inode has to be synchronous
///
public bool Dirsync
{
get
{
if (f_dirsync)
return _dirsync;
f_dirsync = true;
_dirsync = (bool) ((Flags & 16) != 0);
return _dirsync;
}
}
private bool f_encrypted;
private bool _encrypted;
///
/// use encryption for this inode
///
public bool Encrypted
{
get
{
if (f_encrypted)
return _encrypted;
f_encrypted = true;
_encrypted = (bool) ((Flags & 64) != 0);
return _encrypted;
}
}
private bool f_immutable;
private bool _immutable;
///
/// inode is immutable
///
public bool Immutable
{
get
{
if (f_immutable)
return _immutable;
f_immutable = true;
_immutable = (bool) ((Flags & 4) != 0);
return _immutable;
}
}
private bool f_isBlockDevice;
private bool _isBlockDevice;
public bool IsBlockDevice
{
get
{
if (f_isBlockDevice)
return _isBlockDevice;
f_isBlockDevice = true;
_isBlockDevice = (bool) ((Mode & 61440) == 24576);
return _isBlockDevice;
}
}
private bool f_isCharacterDevice;
private bool _isCharacterDevice;
public bool IsCharacterDevice
{
get
{
if (f_isCharacterDevice)
return _isCharacterDevice;
f_isCharacterDevice = true;
_isCharacterDevice = (bool) ((Mode & 61440) == 8192);
return _isCharacterDevice;
}
}
private bool f_isDir;
private bool _isDir;
public bool IsDir
{
get
{
if (f_isDir)
return _isDir;
f_isDir = true;
_isDir = (bool) ((Mode & 61440) == 16384);
return _isDir;
}
}
private bool f_isFifo;
private bool _isFifo;
public bool IsFifo
{
get
{
if (f_isFifo)
return _isFifo;
f_isFifo = true;
_isFifo = (bool) ((Mode & 61440) == 4096);
return _isFifo;
}
}
private bool f_isLink;
private bool _isLink;
public bool IsLink
{
get
{
if (f_isLink)
return _isLink;
f_isLink = true;
_isLink = (bool) ((Mode & 61440) == 40960);
return _isLink;
}
}
private bool f_isRegular;
private bool _isRegular;
public bool IsRegular
{
get
{
if (f_isRegular)
return _isRegular;
f_isRegular = true;
_isRegular = (bool) ((Mode & 61440) == 32768);
return _isRegular;
}
}
private bool f_isSocket;
private bool _isSocket;
public bool IsSocket
{
get
{
if (f_isSocket)
return _isSocket;
f_isSocket = true;
_isSocket = (bool) ((Mode & 61440) == 49152);
return _isSocket;
}
}
private bool f_synchronous;
private bool _synchronous;
///
/// I/O on this inode has to be synchronous
///
public bool Synchronous
{
get
{
if (f_synchronous)
return _synchronous;
f_synchronous = true;
_synchronous = (bool) ((Flags & 2) != 0);
return _synchronous;
}
}
private bool f_xattr;
private bool _xattr;
///
/// this inode is the inode for an extended attribute value
///
public bool Xattr
{
get
{
if (f_xattr)
return _xattr;
f_xattr = true;
_xattr = (bool) ((Flags & 32) != 0);
return _xattr;
}
}
private Key _key;
private ulong _creationSequenceNumber;
private ulong _lenUncompressed;
private ulong _atimeSec;
private ulong _ctimeSec;
private ulong _mtimeSec;
private uint _atimeNsec;
private uint _ctimeNsec;
private uint _mtimeNsec;
private uint _numLinks;
private uint _uid;
private uint _gid;
private uint _mode;
private uint _flags;
private uint _lenData;
private uint _numXattrs;
private uint _xattrSize;
private byte[] _padding1;
private uint _xattrNames;
private Compression _compression;
private byte[] _padding2;
private byte[] _data;
private Ubifs m_root;
private Ubifs.Block m_parent;
private byte[] __raw_key;
///
/// node key
///
public Key Key { get { return _key; } }
///
/// sequence number at time of creation
///
public ulong CreationSequenceNumber { get { return _creationSequenceNumber; } }
///
/// inode size in bytes (amount of uncompressed data)
///
public ulong LenUncompressed { get { return _lenUncompressed; } }
///
/// access time seconds
///
public ulong AtimeSec { get { return _atimeSec; } }
///
/// status change time seconds
///
public ulong CtimeSec { get { return _ctimeSec; } }
///
/// modification time seconds
///
public ulong MtimeSec { get { return _mtimeSec; } }
///
/// access time nanoseconds
///
public uint AtimeNsec { get { return _atimeNsec; } }
///
/// status change time nanoseconds
///
public uint CtimeNsec { get { return _ctimeNsec; } }
///
/// modification time nanoseconds
///
public uint MtimeNsec { get { return _mtimeNsec; } }
///
/// number of hard links
///
public uint NumLinks { get { return _numLinks; } }
///
/// owner ID
///
public uint Uid { get { return _uid; } }
///
/// group ID
///
public uint Gid { get { return _gid; } }
///
/// file type and permissions, as in `st_mode` (see the `is_*`
/// instances for the file type)
///
public uint Mode { get { return _mode; } }
///
/// per-inode flags (see the instances `compressed`, `synchronous`,
/// etc.)
///
public uint Flags { get { return _flags; } }
///
/// inode data length
///
public uint LenData { get { return _lenData; } }
///
/// count of extended attributes this inode has
///
public uint NumXattrs { get { return _numXattrs; } }
///
/// summarized size of all extended attributes in bytes
///
public uint XattrSize { get { return _xattrSize; } }
public byte[] Padding1 { get { return _padding1; } }
///
/// sum of lengths of all extended attribute names belonging
/// to this inode
///
public uint XattrNames { get { return _xattrNames; } }
///
/// compression type used for this inode
///
public Compression Compression { get { return _compression; } }
///
/// reserved for future, zeroes
///
public byte[] Padding2 { get { return _padding2; } }
///
/// Target of a [symbolic link](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/dir.c#L1220-L1241),
/// (encrypted if the inode is encrypted), device number of a device node
/// ([`union ubifs_dev_desc`](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L466-L478):
/// 4 bytes from Linux, 8 from `mkfs.ubifs`), or value of an
/// [extended attribute](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/xattr.c#L115-L121)
/// (in its own inode, see `xattr`). Empty otherwise.
///
public byte[] Data { get { return _data; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
public byte[] M_RawKey { get { return __raw_key; } }
}
///
/// Inode nodes (`inode_header`), directory and extended attribute entry
/// nodes (`directory_header`) and data nodes (`data_header`) store keys in a
/// 16-byte field (`UBIFS_MAX_KEY_LEN`). The simple key format, the only one
/// there is (see `<superblock_header>.key_fmt`), uses only the first 8
/// bytes, and Linux (v7.2)
/// [zeroes](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/key.h#L432-L440)
/// the rest. Branches of index nodes (`branch`)
/// [store only these 8 bytes](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/key.h#L448-L455).
///
///
/// Reference: Git tag "v7.2"
///
public partial class Key : KaitaiStruct
{
public static Key FromFile(string fileName)
{
return new Key(new KaitaiStream(fileName));
}
public Key(KaitaiStream p__io, KaitaiStruct p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_inodeNumber = m_io.ReadU4le();
_value = m_io.ReadBitsIntLe(29);
_type = ((Ubifs.KeyTypes) m_io.ReadBitsIntLe(3));
if (!Enum.IsDefined(typeof(KeyTypes), _type))
{
throw new ValidationNotInEnumError(_type, m_io, "/types/key/seq/2");
}
m_io.AlignToByte();
_unused = m_io.ReadBytesFull();
}
private uint _inodeNumber;
private ulong _value;
private KeyTypes _type;
private byte[] _unused;
private Ubifs m_root;
private KaitaiStruct m_parent;
///
/// Number of the inode that the node belongs to: the parent directory
/// for a directory entry, the inode that the attribute belongs to for an
/// extended attribute entry.
///
public uint InodeNumber { get { return _inodeNumber; } }
///
/// Block number for a data node, hash of the name (see
/// `<superblock_header>.key_hash`) for a directory or extended
/// attribute entry, 0 for an inode node.
///
public ulong Value { get { return _value; } }
///
/// Type of the key, which matches the type of the node.
///
public KeyTypes Type { get { return _type; } }
///
/// Rest of the field holding the key: 8 zero bytes in `inode_header`,
/// `directory_header` and `data_header`, empty in `branch`.
///
public byte[] Unused { get { return _unused; } }
public Ubifs M_Root { get { return m_root; } }
public KaitaiStruct M_Parent { get { return m_parent; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class MasterHeader : KaitaiStruct
{
public static MasterHeader FromFile(string fileName)
{
return new MasterHeader(new KaitaiStream(fileName));
}
public MasterHeader(KaitaiStream p__io, KaitaiStruct p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_dirty = false;
f_noOrphans = false;
f_recovery = false;
_read();
}
private void _read()
{
_highestInum = m_io.ReadU8le();
_commitNumber = m_io.ReadU8le();
_flags = m_io.ReadU4le();
_lebLog = m_io.ReadU4le();
_lebRoot = m_io.ReadU4le();
_ofsRoot = m_io.ReadU4le();
_lenRoot = m_io.ReadU4le();
_lebGarbageCollect = m_io.ReadU4le();
_lebIndexHead = m_io.ReadU4le();
_ofsIndexHead = m_io.ReadU4le();
_lenIndex = m_io.ReadU8le();
_totalFree = m_io.ReadU8le();
_totalDirty = m_io.ReadU8le();
_totalUsed = m_io.ReadU8le();
_totalDead = m_io.ReadU8le();
_totalDark = m_io.ReadU8le();
_lebLpt = m_io.ReadU4le();
_ofsLpt = m_io.ReadU4le();
_lebNhead = m_io.ReadU4le();
_ofsNhead = m_io.ReadU4le();
_lebLpropsTable = m_io.ReadU4le();
_ofsLpropsTable = m_io.ReadU4le();
_lebSaveTable = m_io.ReadU4le();
_ofsSaveTable = m_io.ReadU4le();
_lebLastLptScan = m_io.ReadU4le();
_numEmptyLebs = m_io.ReadU4le();
_numIndexLebs = m_io.ReadU4le();
_numLebs = m_io.ReadU4le();
_hashRootIndex = m_io.ReadBytes(64);
_hashLpt = m_io.ReadBytes(64);
_hmac = m_io.ReadBytes(64);
_padding = m_io.ReadBytes(152);
}
private bool f_dirty;
private bool _dirty;
///
/// master node is dirty
///
public bool Dirty
{
get
{
if (f_dirty)
return _dirty;
f_dirty = true;
_dirty = (bool) ((Flags & 1) != 0);
return _dirty;
}
}
private bool f_noOrphans;
private bool _noOrphans;
///
/// no orphan inodes present
///
public bool NoOrphans
{
get
{
if (f_noOrphans)
return _noOrphans;
f_noOrphans = true;
_noOrphans = (bool) ((Flags & 2) != 0);
return _noOrphans;
}
}
private bool f_recovery;
private bool _recovery;
///
/// written by recovery
///
public bool Recovery
{
get
{
if (f_recovery)
return _recovery;
f_recovery = true;
_recovery = (bool) ((Flags & 4) != 0);
return _recovery;
}
}
private ulong _highestInum;
private ulong _commitNumber;
private uint _flags;
private uint _lebLog;
private uint _lebRoot;
private uint _ofsRoot;
private uint _lenRoot;
private uint _lebGarbageCollect;
private uint _lebIndexHead;
private uint _ofsIndexHead;
private ulong _lenIndex;
private ulong _totalFree;
private ulong _totalDirty;
private ulong _totalUsed;
private ulong _totalDead;
private ulong _totalDark;
private uint _lebLpt;
private uint _ofsLpt;
private uint _lebNhead;
private uint _ofsNhead;
private uint _lebLpropsTable;
private uint _ofsLpropsTable;
private uint _lebSaveTable;
private uint _ofsSaveTable;
private uint _lebLastLptScan;
private uint _numEmptyLebs;
private uint _numIndexLebs;
private uint _numLebs;
private byte[] _hashRootIndex;
private byte[] _hashLpt;
private byte[] _hmac;
private byte[] _padding;
private Ubifs m_root;
private KaitaiStruct m_parent;
///
/// highest inode number in the committed index
///
public ulong HighestInum { get { return _highestInum; } }
///
/// commit number
///
public ulong CommitNumber { get { return _commitNumber; } }
///
/// various flags (see the instances `dirty`, `no_orphans` and
/// `recovery`)
///
public uint Flags { get { return _flags; } }
///
/// start of the log
///
public uint LebLog { get { return _lebLog; } }
///
/// LEB number of the root indexing node
///
public uint LebRoot { get { return _lebRoot; } }
///
/// offset within the LEB `leb_root`
///
public uint OfsRoot { get { return _ofsRoot; } }
///
/// root indexing node length
///
public uint LenRoot { get { return _lenRoot; } }
///
/// LEB reserved for garbage collection, which must be in the main area.
///
/// The [comment above `struct ubifs_mst_node`](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L695-L696)
/// says that -1 (`0xffff_ffff`) means the LEB was not reserved and should
/// be reserved on mount. However, Linux refuses to mount a file system
/// with -1. Linux
/// [stores](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/master.c#L362)
/// the field in an
/// [`int`](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs.h#L1424),
/// so `0xffff_ffff` becomes -1. Then -1 is rejected by the condition
/// `c->gc_lnum < c->main_first`, because the main area
/// [starts](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/sb.c#L775-L777)
/// after the superblock, master, log, LPT and orphan areas.
///
///
/// Reference: Git tag "v7.2"
///
public uint LebGarbageCollect { get { return _lebGarbageCollect; } }
///
/// LEB number of index head
///
public uint LebIndexHead { get { return _lebIndexHead; } }
///
/// offset of index head
///
public uint OfsIndexHead { get { return _ofsIndexHead; } }
///
/// size of index on flash
///
public ulong LenIndex { get { return _lenIndex; } }
///
/// total free space in bytes
///
public ulong TotalFree { get { return _totalFree; } }
///
/// total dirty space in bytes
///
public ulong TotalDirty { get { return _totalDirty; } }
///
/// total used space in bytes (includes only data LEBs)
///
public ulong TotalUsed { get { return _totalUsed; } }
///
/// total dead space in bytes (includes only data LEBs)
///
public ulong TotalDead { get { return _totalDead; } }
///
/// total dark space in bytes (includes only data LEBs)
///
public ulong TotalDark { get { return _totalDark; } }
///
/// LEB number of LPT root nnode
///
public uint LebLpt { get { return _lebLpt; } }
///
/// offset of LPT root nnode
///
public uint OfsLpt { get { return _ofsLpt; } }
///
/// LEB number of LPT head
///
public uint LebNhead { get { return _lebNhead; } }
///
/// offset of LPT head
///
public uint OfsNhead { get { return _ofsNhead; } }
///
/// LEB number of LPT's own lprops table
///
public uint LebLpropsTable { get { return _lebLpropsTable; } }
///
/// offset of LPT's own lprops table
///
public uint OfsLpropsTable { get { return _ofsLpropsTable; } }
///
/// LEB number of LPT's save table. Present in every master node, but
/// only meaningful if `<superblock_header>.biglpt` is set: only then
/// does Linux [check the location of the save table](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/master.c#L252-L256).
///
public uint LebSaveTable { get { return _lebSaveTable; } }
///
/// offset of LPT's save table (only meaningful if
/// `<superblock_header>.biglpt` is set, see `leb_save_table`)
///
public uint OfsSaveTable { get { return _ofsSaveTable; } }
///
/// LEB number of last LPT scan
///
public uint LebLastLptScan { get { return _lebLastLptScan; } }
///
/// number of empty logical eraseblocks
///
public uint NumEmptyLebs { get { return _numEmptyLebs; } }
///
/// number of indexing logical eraseblocks
///
public uint NumIndexLebs { get { return _numIndexLebs; } }
///
/// count of LEBs used by file-system
///
public uint NumLebs { get { return _numLebs; } }
///
/// the hash of the root index node
///
public byte[] HashRootIndex { get { return _hashRootIndex; } }
///
/// the hash of the LPT
///
public byte[] HashLpt { get { return _hashLpt; } }
///
/// HMAC to authenticate the master node
///
public byte[] Hmac { get { return _hmac; } }
///
/// reserved for future, zeroes
///
public byte[] Padding { get { return _padding; } }
public Ubifs M_Root { get { return m_root; } }
public KaitaiStruct M_Parent { get { return m_parent; } }
}
public partial class MasterblockNode : KaitaiStruct
{
public static MasterblockNode FromFile(string fileName)
{
return new MasterblockNode(new KaitaiStream(fileName));
}
public MasterblockNode(KaitaiStream p__io, Ubifs p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_header = new CommonHeader(m_io, this, m_root);
{
CommonHeader M_ = _header;
if (!(M_.NodeType == Ubifs.NodeTypes.Master))
{
throw new ValidationExprError(_header, m_io, "/types/masterblock_node/seq/0");
}
}
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new MasterHeader(io___raw_nodeHeader, this, m_root);
}
private CommonHeader _header;
private MasterHeader _nodeHeader;
private Ubifs m_root;
private Ubifs m_parent;
private byte[] __raw_nodeHeader;
public CommonHeader Header { get { return _header; } }
public MasterHeader NodeHeader { get { return _nodeHeader; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs M_Parent { get { return m_parent; } }
public byte[] M_RawNodeHeader { get { return __raw_nodeHeader; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class OrphanHeader : KaitaiStruct
{
public static OrphanHeader FromFile(string fileName)
{
return new OrphanHeader(new KaitaiStream(fileName));
}
public OrphanHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_commitNumber = m_io.ReadU8le();
_inodeNumbers = new List();
{
var i = 0;
while (!m_io.IsEof) {
_inodeNumbers.Add(m_io.ReadU8le());
i++;
}
}
}
private ulong _commitNumber;
private List _inodeNumbers;
private Ubifs m_root;
private Ubifs.Block m_parent;
///
/// commit number (also top bit is set on the last node of the commit)
///
public ulong CommitNumber { get { return _commitNumber; } }
///
/// inode numbers of orphans
///
public List InodeNumbers { get { return _inodeNumbers; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class PaddingHeader : KaitaiStruct
{
public static PaddingHeader FromFile(string fileName)
{
return new PaddingHeader(new KaitaiStream(fileName));
}
public PaddingHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_lenPadding = m_io.ReadU4le();
}
private uint _lenPadding;
private Ubifs m_root;
private Ubifs.Block m_parent;
///
/// how many bytes after this node are unused (because padded)
///
public uint LenPadding { get { return _lenPadding; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
}
///
/// logical eraseblock reference node.
///
///
/// Reference: Git tag "v7.2"
///
public partial class ReferenceHeader : KaitaiStruct
{
public static ReferenceHeader FromFile(string fileName)
{
return new ReferenceHeader(new KaitaiStream(fileName));
}
public ReferenceHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_lebNumber = m_io.ReadU4le();
_ofsLeb = m_io.ReadU4le();
_journalHeadNumber = m_io.ReadU4le();
_padding = m_io.ReadBytes(28);
}
private uint _lebNumber;
private uint _ofsLeb;
private uint _journalHeadNumber;
private byte[] _padding;
private Ubifs m_root;
private Ubifs.Block m_parent;
///
/// the referred logical eraseblock number
///
public uint LebNumber { get { return _lebNumber; } }
///
/// start offset in the referred LEB
///
public uint OfsLeb { get { return _ofsLeb; } }
///
/// journal head number
///
public uint JournalHeadNumber { get { return _journalHeadNumber; } }
///
/// reserved for future, zeroes
///
public byte[] Padding { get { return _padding; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
}
///
/// Signature of the superblock node of a file system signed when it was
/// created (`mkfs.ubifs` with a key). Linux
/// [expects it](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/auth.c#L198-L216)
/// as the first node after the superblock node in LEB0.
///
///
/// Reference: Git tag "v7.2"
///
public partial class SignatureHeader : KaitaiStruct
{
public static SignatureHeader FromFile(string fileName)
{
return new SignatureHeader(new KaitaiStream(fileName));
}
public SignatureHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_type = m_io.ReadU4le();
if (!(_type == 1))
{
throw new ValidationNotEqualError(1, _type, m_io, "/types/signature_header/seq/0");
}
_lenSignature = m_io.ReadU4le();
_padding = m_io.ReadBytes(32);
_signature = m_io.ReadBytes(LenSignature);
}
private uint _type;
private uint _lenSignature;
private byte[] _padding;
private byte[] _signature;
private Ubifs m_root;
private Ubifs.Block m_parent;
///
/// type of the signature
///
public uint Type { get { return _type; } }
///
/// length of `signature` in bytes
///
public uint LenSignature { get { return _lenSignature; } }
///
/// reserved for future, zeroes
///
public byte[] Padding { get { return _padding; } }
///
/// [PKCS #7 signature](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/auth.c#L233-L236)
/// of the whole superblock node (4096 bytes, including the common
/// header)
///
public byte[] Signature { get { return _signature; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
}
///
/// Reference: Git tag "v7.2"
///
public partial class SuperblockHeader : KaitaiStruct
{
public static SuperblockHeader FromFile(string fileName)
{
return new SuperblockHeader(new KaitaiStream(fileName));
}
public SuperblockHeader(KaitaiStream p__io, KaitaiStruct p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
f_authenticated = false;
f_biglpt = false;
f_doubleHash = false;
f_encrypted = false;
f_lenHash = false;
f_spaceFixup = false;
_read();
}
private void _read()
{
_padding0 = m_io.ReadBytes(2);
if (!((KaitaiStream.ByteArrayCompare(_padding0, new byte[] { 0, 0 }) == 0)))
{
throw new ValidationNotEqualError(new byte[] { 0, 0 }, _padding0, m_io, "/types/superblock_header/seq/0");
}
_keyHash = ((Ubifs.Hashes) m_io.ReadU1());
if (!Enum.IsDefined(typeof(Hashes), _keyHash))
{
throw new ValidationNotInEnumError(_keyHash, m_io, "/types/superblock_header/seq/1");
}
_keyFmt = ((Ubifs.KeyFormats) m_io.ReadU1());
if (!(_keyFmt == Ubifs.KeyFormats.Simple))
{
throw new ValidationNotEqualError(Ubifs.KeyFormats.Simple, _keyFmt, m_io, "/types/superblock_header/seq/2");
}
_flags = m_io.ReadU4le();
_minIoSize = m_io.ReadU4le();
_lebSize = m_io.ReadU4le();
_numLebs = m_io.ReadU4le();
_maxNumLebs = m_io.ReadU4le();
if (!(_maxNumLebs >= NumLebs))
{
throw new ValidationLessThanError(NumLebs, _maxNumLebs, m_io, "/types/superblock_header/seq/7");
}
_maxBudBytes = m_io.ReadU8le();
_numLogLebs = m_io.ReadU4le();
if (!(_numLogLebs >= 2))
{
throw new ValidationLessThanError(2, _numLogLebs, m_io, "/types/superblock_header/seq/9");
}
_numLptLebs = m_io.ReadU4le();
if (!(_numLptLebs >= 2))
{
throw new ValidationLessThanError(2, _numLptLebs, m_io, "/types/superblock_header/seq/10");
}
_numOrphanLebs = m_io.ReadU4le();
if (!(_numOrphanLebs >= 1))
{
throw new ValidationLessThanError(1, _numOrphanLebs, m_io, "/types/superblock_header/seq/11");
}
_numJournalHeads = m_io.ReadU4le();
_fanout = m_io.ReadU4le();
_numSaveTableEntries = m_io.ReadU4le();
_fmtVersion = m_io.ReadU4le();
if (!(_fmtVersion >= 4))
{
throw new ValidationLessThanError(4, _fmtVersion, m_io, "/types/superblock_header/seq/15");
}
_defaultCompression = ((Ubifs.Compression) m_io.ReadU2le());
if (!Enum.IsDefined(typeof(Compression), _defaultCompression))
{
throw new ValidationNotInEnumError(_defaultCompression, m_io, "/types/superblock_header/seq/16");
}
_padding1 = m_io.ReadBytes(2);
if (!((KaitaiStream.ByteArrayCompare(_padding1, new byte[] { 0, 0 }) == 0)))
{
throw new ValidationNotEqualError(new byte[] { 0, 0 }, _padding1, m_io, "/types/superblock_header/seq/17");
}
_reservePoolUid = m_io.ReadU4le();
_reservePoolGid = m_io.ReadU4le();
_reservePoolSize = m_io.ReadU8le();
_timeGranularity = m_io.ReadU4le();
if (!(_timeGranularity >= 1))
{
throw new ValidationLessThanError(1, _timeGranularity, m_io, "/types/superblock_header/seq/21");
}
if (!(_timeGranularity <= 1000000000))
{
throw new ValidationGreaterThanError(1000000000, _timeGranularity, m_io, "/types/superblock_header/seq/21");
}
_uuid = m_io.ReadBytes(16);
_roCompatVersion = m_io.ReadU4le();
_hmac = m_io.ReadBytes(64);
_hmacWkm = m_io.ReadBytes(64);
if (Authenticated) {
_hashAlgo = ((Ubifs.HashAlgos) m_io.ReadU2le());
if (!Enum.IsDefined(typeof(HashAlgos), _hashAlgo))
{
throw new ValidationNotInEnumError(_hashAlgo, m_io, "/types/superblock_header/seq/26");
}
}
if (!(Authenticated)) {
_hashAlgoUnused = m_io.ReadU2le();
}
_hashMst = m_io.ReadBytes(64);
_padding2 = m_io.ReadBytes(3774);
}
private bool f_authenticated;
private bool _authenticated;
///
/// this filesystem contains hashes for authentication
///
public bool Authenticated
{
get
{
if (f_authenticated)
return _authenticated;
f_authenticated = true;
_authenticated = (bool) ((Flags & 32) != 0);
return _authenticated;
}
}
private bool f_biglpt;
private bool _biglpt;
///
/// if "big" LPT model is used if set
///
public bool Biglpt
{
get
{
if (f_biglpt)
return _biglpt;
f_biglpt = true;
_biglpt = (bool) ((Flags & 2) != 0);
return _biglpt;
}
}
private bool f_doubleHash;
private bool _doubleHash;
///
/// store a 32bit cookie in directory entry nodes to
/// support 64bit cookies for lookups by hash
///
public bool DoubleHash
{
get
{
if (f_doubleHash)
return _doubleHash;
f_doubleHash = true;
_doubleHash = (bool) ((Flags & 8) != 0);
return _doubleHash;
}
}
private bool f_encrypted;
private bool _encrypted;
///
/// filesystem contains encrypted files
///
public bool Encrypted
{
get
{
if (f_encrypted)
return _encrypted;
f_encrypted = true;
_encrypted = (bool) ((Flags & 16) != 0);
return _encrypted;
}
}
private bool f_lenHash;
private int _lenHash;
///
/// Length in bytes of the hash of a node (`c->hash_len` in Linux), e.g.
/// in each branch of an index node. In an authenticated file system, it
/// is determined by `hash_algo`. Otherwise, it is 0.
///
public int LenHash
{
get
{
if (f_lenHash)
return _lenHash;
f_lenHash = true;
_lenHash = (int) ((!(Authenticated) ? 0 : ( ((HashAlgo == Ubifs.HashAlgos.Md4) || (HashAlgo == Ubifs.HashAlgos.Md5) || (HashAlgo == Ubifs.HashAlgos.RipeMd128) || (HashAlgo == Ubifs.HashAlgos.Tgr128)) ? 16 : ( ((HashAlgo == Ubifs.HashAlgos.Sha1) || (HashAlgo == Ubifs.HashAlgos.RipeMd160) || (HashAlgo == Ubifs.HashAlgos.Tgr160)) ? 20 : (HashAlgo == Ubifs.HashAlgos.Tgr192 ? 24 : (HashAlgo == Ubifs.HashAlgos.Sha224 ? 28 : ( ((HashAlgo == Ubifs.HashAlgos.Sha256) || (HashAlgo == Ubifs.HashAlgos.RipeMd256) || (HashAlgo == Ubifs.HashAlgos.Wp256) || (HashAlgo == Ubifs.HashAlgos.Sm3256) || (HashAlgo == Ubifs.HashAlgos.Streebog256) || (HashAlgo == Ubifs.HashAlgos.Sha3256)) ? 32 : (HashAlgo == Ubifs.HashAlgos.RipeMd320 ? 40 : ( ((HashAlgo == Ubifs.HashAlgos.Sha384) || (HashAlgo == Ubifs.HashAlgos.Wp384) || (HashAlgo == Ubifs.HashAlgos.Sha3384)) ? 48 : ( ((HashAlgo == Ubifs.HashAlgos.Sha512) || (HashAlgo == Ubifs.HashAlgos.Wp512) || (HashAlgo == Ubifs.HashAlgos.Streebog512) || (HashAlgo == Ubifs.HashAlgos.Sha3512)) ? 64 : -1))))))))));
return _lenHash;
}
}
private bool f_spaceFixup;
private bool _spaceFixup;
///
/// first-mount "fixup" of free space within LEBs needed
///
public bool SpaceFixup
{
get
{
if (f_spaceFixup)
return _spaceFixup;
f_spaceFixup = true;
_spaceFixup = (bool) ((Flags & 4) != 0);
return _spaceFixup;
}
}
private byte[] _padding0;
private Hashes _keyHash;
private KeyFormats _keyFmt;
private uint _flags;
private uint _minIoSize;
private uint _lebSize;
private uint _numLebs;
private uint _maxNumLebs;
private ulong _maxBudBytes;
private uint _numLogLebs;
private uint _numLptLebs;
private uint _numOrphanLebs;
private uint _numJournalHeads;
private uint _fanout;
private uint _numSaveTableEntries;
private uint _fmtVersion;
private Compression _defaultCompression;
private byte[] _padding1;
private uint _reservePoolUid;
private uint _reservePoolGid;
private ulong _reservePoolSize;
private uint _timeGranularity;
private byte[] _uuid;
private uint _roCompatVersion;
private byte[] _hmac;
private byte[] _hmacWkm;
private HashAlgos _hashAlgo;
private ushort? _hashAlgoUnused;
private byte[] _hashMst;
private byte[] _padding2;
private Ubifs m_root;
private KaitaiStruct m_parent;
///
/// reserved for future, zeroes
///
public byte[] Padding0 { get { return _padding0; } }
///
/// type of hash function used in keys
///
public Hashes KeyHash { get { return _keyHash; } }
///
/// format of the key
///
public KeyFormats KeyFmt { get { return _keyFmt; } }
///
/// file-system flags (see the instances `biglpt`, `space_fixup`, etc.)
///
public uint Flags { get { return _flags; } }
///
/// minimal input/output unit size
///
public uint MinIoSize { get { return _minIoSize; } }
///
/// logical eraseblock size in bytes
///
public uint LebSize { get { return _lebSize; } }
///
/// count of LEBs used by file-system
///
public uint NumLebs { get { return _numLebs; } }
///
/// maximum count of LEBs used by file-system
///
public uint MaxNumLebs { get { return _maxNumLebs; } }
///
/// maximum amount of data stored in buds
///
public ulong MaxBudBytes { get { return _maxBudBytes; } }
///
/// log size in logical eraseblocks
///
public uint NumLogLebs { get { return _numLogLebs; } }
///
/// number of LEBs used for lprops table
///
public uint NumLptLebs { get { return _numLptLebs; } }
///
/// number of LEBs used for recording orphans
///
public uint NumOrphanLebs { get { return _numOrphanLebs; } }
///
/// count of journal heads
///
public uint NumJournalHeads { get { return _numJournalHeads; } }
///
/// tree fanout (max. number of links per indexing node)
///
public uint Fanout { get { return _fanout; } }
///
/// number of LEB numbers in LPT's save table
///
public uint NumSaveTableEntries { get { return _numSaveTableEntries; } }
///
/// UBIFS on-flash format version
///
public uint FmtVersion { get { return _fmtVersion; } }
///
/// default compression algorithm (`compression::lzo`, etc.)
///
public Compression DefaultCompression { get { return _defaultCompression; } }
///
/// reserved for future, zeroes
///
public byte[] Padding1 { get { return _padding1; } }
///
/// reserve pool UID
///
public uint ReservePoolUid { get { return _reservePoolUid; } }
///
/// reserve pool GID
///
public uint ReservePoolGid { get { return _reservePoolGid; } }
///
/// size of the reserved pool in bytes
///
public ulong ReservePoolSize { get { return _reservePoolSize; } }
///
/// time granularity in nanoseconds
///
public uint TimeGranularity { get { return _timeGranularity; } }
///
/// UUID generated when the file system image was created
///
public byte[] Uuid { get { return _uuid; } }
///
/// UBIFS R/O compatibility version
///
public uint RoCompatVersion { get { return _roCompatVersion; } }
///
/// HMAC to authenticate the superblock node
///
public byte[] Hmac { get { return _hmac; } }
///
/// HMAC of a well known message (the string "UBIFS") as a convenience
/// to the user to check if the correct key is passed
///
public byte[] HmacWkm { get { return _hmacWkm; } }
///
/// The hash algo used for this filesystem
///
///
/// Reference: Git tag "v7.2"
///
public HashAlgos HashAlgo { get { return _hashAlgo; } }
///
/// Unused field (would only be meaningful in an authenticated file
/// system, see `hash_algo`). The kernel writes it as 0xffff, `mkfs.ubifs`
/// writes it as 0.
///
///
/// Reference: Git tag "v7.2"
///
public ushort? HashAlgoUnused { get { return _hashAlgoUnused; } }
///
/// hash of the master node, only valid for signed images in which the
/// master node does not contain a hmac
///
public byte[] HashMst { get { return _hashMst; } }
///
/// reserved for future, zeroes
///
public byte[] Padding2 { get { return _padding2; } }
public Ubifs M_Root { get { return m_root; } }
public KaitaiStruct M_Parent { get { return m_parent; } }
}
public partial class SuperblockNode : KaitaiStruct
{
public static SuperblockNode FromFile(string fileName)
{
return new SuperblockNode(new KaitaiStream(fileName));
}
public SuperblockNode(KaitaiStream p__io, Ubifs p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_header = new CommonHeader(m_io, this, m_root);
{
CommonHeader M_ = _header;
if (!(M_.NodeType == Ubifs.NodeTypes.Superblock))
{
throw new ValidationExprError(_header, m_io, "/types/superblock_node/seq/0");
}
}
__raw_nodeHeader = m_io.ReadBytes(Header.LenFullNode - 24);
var io___raw_nodeHeader = new KaitaiStream(__raw_nodeHeader);
_nodeHeader = new SuperblockHeader(io___raw_nodeHeader, this, m_root);
}
private CommonHeader _header;
private SuperblockHeader _nodeHeader;
private Ubifs m_root;
private Ubifs m_parent;
private byte[] __raw_nodeHeader;
public CommonHeader Header { get { return _header; } }
public SuperblockHeader NodeHeader { get { return _nodeHeader; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs M_Parent { get { return m_parent; } }
public byte[] M_RawNodeHeader { get { return __raw_nodeHeader; } }
}
///
/// This node exists only in the journal and never goes to the main area.
///
///
/// Reference: Git tag "v7.2"
///
public partial class TruncationHeader : KaitaiStruct
{
public static TruncationHeader FromFile(string fileName)
{
return new TruncationHeader(new KaitaiStream(fileName));
}
public TruncationHeader(KaitaiStream p__io, Ubifs.Block p__parent = null, Ubifs p__root = null) : base(p__io)
{
m_parent = p__parent;
m_root = p__root;
_read();
}
private void _read()
{
_inodeNumber = m_io.ReadU4le();
_padding = m_io.ReadBytes(12);
_oldSize = m_io.ReadU8le();
if (!(_oldSize >= 1))
{
throw new ValidationLessThanError(1, _oldSize, m_io, "/types/truncation_header/seq/2");
}
_newSize = m_io.ReadU8le();
if (!(_newSize <= OldSize - 1))
{
throw new ValidationGreaterThanError(OldSize - 1, _newSize, m_io, "/types/truncation_header/seq/3");
}
}
private uint _inodeNumber;
private byte[] _padding;
private ulong _oldSize;
private ulong _newSize;
private Ubifs m_root;
private Ubifs.Block m_parent;
///
/// truncated inode number
///
public uint InodeNumber { get { return _inodeNumber; } }
///
/// reserved for future, zeroes
///
public byte[] Padding { get { return _padding; } }
///
/// size before truncation
///
public ulong OldSize { get { return _oldSize; } }
///
/// size after truncation
///
public ulong NewSize { get { return _newSize; } }
public Ubifs M_Root { get { return m_root; } }
public Ubifs.Block M_Parent { get { return m_parent; } }
}
private bool f_index;
private Dummy _index;
///
/// The LEB containing the root index node, as given by `leb_root` in
/// `master_1`.
///
/// This instance only provides the substream for `index_root`, which can then
/// use `ofs_root` (an offset within the LEB) as its `pos` directly.
///
public Dummy Index
{
get
{
if (f_index)
return _index;
f_index = true;
long _pos = m_io.Pos;
m_io.Seek(Superblock.NodeHeader.LebSize * Master1.NodeHeader.LebRoot);
__raw_index = m_io.ReadBytes(Superblock.NodeHeader.LebSize);
var io___raw_index = new KaitaiStream(__raw_index);
_index = new Dummy(io___raw_index, this, m_root);
m_io.Seek(_pos);
return _index;
}
}
private bool f_indexRoot;
private IndexBlock _indexRoot;
///
/// The root index node, in the `index` LEB at the offset given by
/// `ofs_root` in `master_1`. All other index nodes, and through them all
/// the files, are reached from it by recursively following the `target` of
/// each of the `branches`.
///
public IndexBlock IndexRoot
{
get
{
if (f_indexRoot)
return _indexRoot;
f_indexRoot = true;
KaitaiStream io = Index.M_Io;
long _pos = io.Pos;
io.Seek(Master1.NodeHeader.OfsRoot);
_indexRoot = new IndexBlock(io, this, m_root);
{
IndexBlock M_ = _indexRoot;
if (!(M_.Header.LenFullNode == Master1.NodeHeader.LenRoot))
{
throw new ValidationExprError(_indexRoot, m_io, "/instances/index_root");
}
}
io.Seek(_pos);
return _indexRoot;
}
}
private bool f_lebs;
private List _lebs;
///
/// All LEBs of the file system: `lebs[n]` is LEB number `n`, which starts
/// at offset `n * <superblock_header>.leb_size`.
///
/// Accessing this instance reads the whole image into memory. To get a
/// single LEB, it's cheaper to read `<superblock_header>.leb_size` bytes
/// at the offset of that LEB.
///
public List Lebs
{
get
{
if (f_lebs)
return _lebs;
f_lebs = true;
long _pos = m_io.Pos;
m_io.Seek(0);
_lebs = new List();
for (var i = 0; i < Superblock.NodeHeader.NumLebs; i++)
{
_lebs.Add(m_io.ReadBytes(Superblock.NodeHeader.LebSize));
}
m_io.Seek(_pos);
return _lebs;
}
}
private bool f_lenImage;
private int _lenImage;
///
/// Length of the file system image in bytes:
/// `<superblock_header>.num_lebs` LEBs of `<superblock_header>.leb_size`
/// bytes each. Use it to find where the image ends and to detect a
/// truncated image (see the top-level `doc`).
///
public int LenImage
{
get
{
if (f_lenImage)
return _lenImage;
f_lenImage = true;
_lenImage = (int) (Superblock.NodeHeader.LebSize * Superblock.NodeHeader.NumLebs);
return _lenImage;
}
}
private bool f_master1;
private MasterblockNode _master1;
///
/// The first copy of the master node in LEB1. This Kaitai Struct
/// implementation uses it to locate `index_root`. In an image created by
/// `mkfs.ubifs`, it is the only copy in LEB1.
///
///
/// Reference: Git tag "v2.3.1"
///
public MasterblockNode Master1
{
get
{
if (f_master1)
return _master1;
f_master1 = true;
long _pos = m_io.Pos;
m_io.Seek(Superblock.NodeHeader.LebSize);
__raw_master1 = m_io.ReadBytes(Superblock.NodeHeader.LebSize);
var io___raw_master1 = new KaitaiStream(__raw_master1);
_master1 = new MasterblockNode(io___raw_master1, this, m_root);
m_io.Seek(_pos);
return _master1;
}
}
private bool f_master2;
private MasterblockNode _master2;
///
/// The first copy of the master node in LEB2. In an image created by
/// `mkfs.ubifs`, it is the same as `master_1` except for the sequence
/// number and CRC in the common header. Linux keeps the master node in both
/// LEB1 and LEB2 for redundancy, and when mounting, it checks that the
/// copies in both match.
///
///
/// Reference: Git tag "v2.3.1"
///
///
/// Reference: Git tag "v7.2"
///
public MasterblockNode Master2
{
get
{
if (f_master2)
return _master2;
f_master2 = true;
long _pos = m_io.Pos;
m_io.Seek(Superblock.NodeHeader.LebSize * 2);
__raw_master2 = m_io.ReadBytes(Superblock.NodeHeader.LebSize);
var io___raw_master2 = new KaitaiStream(__raw_master2);
_master2 = new MasterblockNode(io___raw_master2, this, m_root);
m_io.Seek(_pos);
return _master2;
}
}
private bool f_superblock;
private SuperblockNode _superblock;
///
/// The superblock node will always be at the start of
/// the first LEB.
///
public SuperblockNode Superblock
{
get
{
if (f_superblock)
return _superblock;
f_superblock = true;
long _pos = m_io.Pos;
m_io.Seek(0);
_superblock = new SuperblockNode(m_io, this, m_root);
m_io.Seek(_pos);
return _superblock;
}
}
private Ubifs m_root;
private KaitaiStruct m_parent;
private byte[] __raw_index;
private byte[] __raw_master1;
private byte[] __raw_master2;
public Ubifs M_Root { get { return m_root; } }
public KaitaiStruct M_Parent { get { return m_parent; } }
public byte[] M_RawIndex { get { return __raw_index; } }
public byte[] M_RawMaster1 { get { return __raw_master1; } }
public byte[] M_RawMaster2 { get { return __raw_master2; } }
}
}