UBIFS: Go parsing library

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, 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 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).

KS implementation details

License: GPL-2.0-only
Minimal Kaitai Struct required: 0.11

References

This page hosts a formal specification of UBIFS using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse UBIFS

ubifs.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import (
	"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
	"io"
	"bytes"
)


/**
 * 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`).
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h">Git tag "v7.2"</a>
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/key.h">Git tag "v7.2"</a>
 * @see <a href="http://www.linux-mtd.infradead.org/doc/ubifs.pdf">Source</a>
 */

type Ubifs_Compression int
const (
	Ubifs_Compression__NoCompression Ubifs_Compression = 0
	Ubifs_Compression__Lzo Ubifs_Compression = 1
	Ubifs_Compression__Zlib Ubifs_Compression = 2
	Ubifs_Compression__Zstd Ubifs_Compression = 3
)
var values_Ubifs_Compression = map[Ubifs_Compression]struct{}{0: {}, 1: {}, 2: {}, 3: {}}
func (v Ubifs_Compression) isDefined() bool {
	_, ok := values_Ubifs_Compression[v]
	return ok
}

type Ubifs_HashAlgos int
const (
	Ubifs_HashAlgos__Md4 Ubifs_HashAlgos = 0
	Ubifs_HashAlgos__Md5 Ubifs_HashAlgos = 1
	Ubifs_HashAlgos__Sha1 Ubifs_HashAlgos = 2
	Ubifs_HashAlgos__RipeMd160 Ubifs_HashAlgos = 3
	Ubifs_HashAlgos__Sha256 Ubifs_HashAlgos = 4
	Ubifs_HashAlgos__Sha384 Ubifs_HashAlgos = 5
	Ubifs_HashAlgos__Sha512 Ubifs_HashAlgos = 6
	Ubifs_HashAlgos__Sha224 Ubifs_HashAlgos = 7
	Ubifs_HashAlgos__RipeMd128 Ubifs_HashAlgos = 8
	Ubifs_HashAlgos__RipeMd256 Ubifs_HashAlgos = 9
	Ubifs_HashAlgos__RipeMd320 Ubifs_HashAlgos = 10
	Ubifs_HashAlgos__Wp256 Ubifs_HashAlgos = 11
	Ubifs_HashAlgos__Wp384 Ubifs_HashAlgos = 12
	Ubifs_HashAlgos__Wp512 Ubifs_HashAlgos = 13
	Ubifs_HashAlgos__Tgr128 Ubifs_HashAlgos = 14
	Ubifs_HashAlgos__Tgr160 Ubifs_HashAlgos = 15
	Ubifs_HashAlgos__Tgr192 Ubifs_HashAlgos = 16
	Ubifs_HashAlgos__Sm3256 Ubifs_HashAlgos = 17
	Ubifs_HashAlgos__Streebog256 Ubifs_HashAlgos = 18
	Ubifs_HashAlgos__Streebog512 Ubifs_HashAlgos = 19
	Ubifs_HashAlgos__Sha3256 Ubifs_HashAlgos = 20
	Ubifs_HashAlgos__Sha3384 Ubifs_HashAlgos = 21
	Ubifs_HashAlgos__Sha3512 Ubifs_HashAlgos = 22
)
var values_Ubifs_HashAlgos = map[Ubifs_HashAlgos]struct{}{0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {}, 9: {}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}, 15: {}, 16: {}, 17: {}, 18: {}, 19: {}, 20: {}, 21: {}, 22: {}}
func (v Ubifs_HashAlgos) isDefined() bool {
	_, ok := values_Ubifs_HashAlgos[v]
	return ok
}

type Ubifs_Hashes int
const (
	Ubifs_Hashes__R5 Ubifs_Hashes = 0
	Ubifs_Hashes__TestHash Ubifs_Hashes = 1
)
var values_Ubifs_Hashes = map[Ubifs_Hashes]struct{}{0: {}, 1: {}}
func (v Ubifs_Hashes) isDefined() bool {
	_, ok := values_Ubifs_Hashes[v]
	return ok
}

type Ubifs_InodeTypes int
const (
	Ubifs_InodeTypes__Regular Ubifs_InodeTypes = 0
	Ubifs_InodeTypes__Directory Ubifs_InodeTypes = 1
	Ubifs_InodeTypes__Link Ubifs_InodeTypes = 2
	Ubifs_InodeTypes__BlockDevice Ubifs_InodeTypes = 3
	Ubifs_InodeTypes__CharacterDevice Ubifs_InodeTypes = 4
	Ubifs_InodeTypes__Fifo Ubifs_InodeTypes = 5
	Ubifs_InodeTypes__Socket Ubifs_InodeTypes = 6
)
var values_Ubifs_InodeTypes = map[Ubifs_InodeTypes]struct{}{0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}}
func (v Ubifs_InodeTypes) isDefined() bool {
	_, ok := values_Ubifs_InodeTypes[v]
	return ok
}

type Ubifs_KeyFormats int
const (
	Ubifs_KeyFormats__Simple Ubifs_KeyFormats = 0
)
var values_Ubifs_KeyFormats = map[Ubifs_KeyFormats]struct{}{0: {}}
func (v Ubifs_KeyFormats) isDefined() bool {
	_, ok := values_Ubifs_KeyFormats[v]
	return ok
}

type Ubifs_KeyTypes int
const (
	Ubifs_KeyTypes__Inode Ubifs_KeyTypes = 0
	Ubifs_KeyTypes__Data Ubifs_KeyTypes = 1
	Ubifs_KeyTypes__Directory Ubifs_KeyTypes = 2
	Ubifs_KeyTypes__ExtendedAttribute Ubifs_KeyTypes = 3
)
var values_Ubifs_KeyTypes = map[Ubifs_KeyTypes]struct{}{0: {}, 1: {}, 2: {}, 3: {}}
func (v Ubifs_KeyTypes) isDefined() bool {
	_, ok := values_Ubifs_KeyTypes[v]
	return ok
}

type Ubifs_NodeGroupTypes int
const (
	Ubifs_NodeGroupTypes__NoNodeGroup Ubifs_NodeGroupTypes = 0
	Ubifs_NodeGroupTypes__InNodeGroup Ubifs_NodeGroupTypes = 1
	Ubifs_NodeGroupTypes__LastOfNodeGroup Ubifs_NodeGroupTypes = 2
)
var values_Ubifs_NodeGroupTypes = map[Ubifs_NodeGroupTypes]struct{}{0: {}, 1: {}, 2: {}}
func (v Ubifs_NodeGroupTypes) isDefined() bool {
	_, ok := values_Ubifs_NodeGroupTypes[v]
	return ok
}

type Ubifs_NodeTypes int
const (
	Ubifs_NodeTypes__Inode Ubifs_NodeTypes = 0
	Ubifs_NodeTypes__Data Ubifs_NodeTypes = 1
	Ubifs_NodeTypes__Directory Ubifs_NodeTypes = 2
	Ubifs_NodeTypes__ExtendedAttribute Ubifs_NodeTypes = 3
	Ubifs_NodeTypes__Truncation Ubifs_NodeTypes = 4
	Ubifs_NodeTypes__Padding Ubifs_NodeTypes = 5
	Ubifs_NodeTypes__Superblock Ubifs_NodeTypes = 6
	Ubifs_NodeTypes__Master Ubifs_NodeTypes = 7
	Ubifs_NodeTypes__Reference Ubifs_NodeTypes = 8
	Ubifs_NodeTypes__Index Ubifs_NodeTypes = 9
	Ubifs_NodeTypes__CommitStart Ubifs_NodeTypes = 10
	Ubifs_NodeTypes__Orphan Ubifs_NodeTypes = 11
	Ubifs_NodeTypes__Authentication Ubifs_NodeTypes = 12
	Ubifs_NodeTypes__Signature Ubifs_NodeTypes = 13
)
var values_Ubifs_NodeTypes = map[Ubifs_NodeTypes]struct{}{0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {}, 9: {}, 10: {}, 11: {}, 12: {}, 13: {}}
func (v Ubifs_NodeTypes) isDefined() bool {
	_, ok := values_Ubifs_NodeTypes[v]
	return ok
}
type Ubifs struct {
	_io *kaitai.Stream
	_root *Ubifs
	_parent kaitai.Struct
	_raw_index []byte
	_raw_master1 []byte
	_raw_master2 []byte
	_f_index bool
	index *Ubifs_Dummy
	_f_indexRoot bool
	indexRoot *Ubifs_IndexBlock
	_f_lebs bool
	lebs [][]byte
	_f_lenImage bool
	lenImage int
	_f_master1 bool
	master1 *Ubifs_MasterblockNode
	_f_master2 bool
	master2 *Ubifs_MasterblockNode
	_f_superblock bool
	superblock *Ubifs_SuperblockNode
}
func NewUbifs() *Ubifs {
	return &Ubifs{
	}
}

func (this Ubifs) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs) Read(io *kaitai.Stream, parent kaitai.Struct, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}

/**
 * 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.
 */
func (this *Ubifs) Index() (v *Ubifs_Dummy, err error) {
	if (this._f_index) {
		return this.index, nil
	}
	this._f_index = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	tmp1, err := this.Superblock()
	if err != nil {
		return nil, err
	}
	tmp2, err := this.Master1()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(tmp1.NodeHeader.LebSize * tmp2.NodeHeader.LebRoot), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp3, err := this.Superblock()
	if err != nil {
		return nil, err
	}
	tmp4, err := this._io.ReadBytes(int(tmp3.NodeHeader.LebSize))
	if err != nil {
		return nil, err
	}
	tmp4 = tmp4
	this._raw_index = tmp4
	_io__raw_index := kaitai.NewStream(bytes.NewReader(this._raw_index))
	tmp5 := NewUbifs_Dummy()
	err = tmp5.Read(_io__raw_index, this, this._root)
	if err != nil {
		return nil, err
	}
	this.index = tmp5
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.index, nil
}

/**
 * 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`.
 */
func (this *Ubifs) IndexRoot() (v *Ubifs_IndexBlock, err error) {
	if (this._f_indexRoot) {
		return this.indexRoot, nil
	}
	this._f_indexRoot = true
	tmp6, err := this.Index()
	if err != nil {
		return nil, err
	}
	thisIo := tmp6._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	tmp7, err := this.Master1()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(tmp7.NodeHeader.OfsRoot), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp8 := NewUbifs_IndexBlock()
	err = tmp8.Read(thisIo, this, this._root)
	if err != nil {
		return nil, err
	}
	this.indexRoot = tmp8
	{
		_it := this.indexRoot
		tmp9, err := this.Master1()
		if err != nil {
			return nil, err
		}
		if !(_it.Header.LenFullNode == tmp9.NodeHeader.LenRoot) {
			return nil, kaitai.NewValidationExprError(this.indexRoot, this._io, "/instances/index_root")
		}
	}
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.indexRoot, nil
}

/**
 * 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.
 */
func (this *Ubifs) Lebs() (v [][]byte, err error) {
	if (this._f_lebs) {
		return this.lebs, nil
	}
	this._f_lebs = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp10, err := this.Superblock()
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(tmp10.NodeHeader.NumLebs); i++ {
		_ = i
		tmp11, err := this.Superblock()
		if err != nil {
			return nil, err
		}
		tmp12, err := this._io.ReadBytes(int(tmp11.NodeHeader.LebSize))
		if err != nil {
			return nil, err
		}
		tmp12 = tmp12
		this.lebs = append(this.lebs, tmp12)
	}
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.lebs, nil
}

/**
 * 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`).
 */
func (this *Ubifs) LenImage() (v int, err error) {
	if (this._f_lenImage) {
		return this.lenImage, nil
	}
	this._f_lenImage = true
	tmp13, err := this.Superblock()
	if err != nil {
		return 0, err
	}
	tmp14, err := this.Superblock()
	if err != nil {
		return 0, err
	}
	this.lenImage = int(tmp13.NodeHeader.LebSize * tmp14.NodeHeader.NumLebs)
	return this.lenImage, nil
}

/**
 * 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.
 * @see <a href="https://github.com/sigma-star/mtd-utils/blob/053ee1038e5dedae61a88cadfb7bdfe9894d8bb6/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c#L2627-L2633">Git tag "v2.3.1"</a>
 */
func (this *Ubifs) Master1() (v *Ubifs_MasterblockNode, err error) {
	if (this._f_master1) {
		return this.master1, nil
	}
	this._f_master1 = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	tmp15, err := this.Superblock()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(tmp15.NodeHeader.LebSize), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp16, err := this.Superblock()
	if err != nil {
		return nil, err
	}
	tmp17, err := this._io.ReadBytes(int(tmp16.NodeHeader.LebSize))
	if err != nil {
		return nil, err
	}
	tmp17 = tmp17
	this._raw_master1 = tmp17
	_io__raw_master1 := kaitai.NewStream(bytes.NewReader(this._raw_master1))
	tmp18 := NewUbifs_MasterblockNode()
	err = tmp18.Read(_io__raw_master1, this, this._root)
	if err != nil {
		return nil, err
	}
	this.master1 = tmp18
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.master1, nil
}

/**
 * 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.
 * @see <a href="https://github.com/sigma-star/mtd-utils/blob/053ee1038e5dedae61a88cadfb7bdfe9894d8bb6/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c#L2627-L2633">Git tag "v2.3.1"</a>
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/master.c#L115-L130">Git tag "v7.2"</a>
 */
func (this *Ubifs) Master2() (v *Ubifs_MasterblockNode, err error) {
	if (this._f_master2) {
		return this.master2, nil
	}
	this._f_master2 = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	tmp19, err := this.Superblock()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(tmp19.NodeHeader.LebSize * 2), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp20, err := this.Superblock()
	if err != nil {
		return nil, err
	}
	tmp21, err := this._io.ReadBytes(int(tmp20.NodeHeader.LebSize))
	if err != nil {
		return nil, err
	}
	tmp21 = tmp21
	this._raw_master2 = tmp21
	_io__raw_master2 := kaitai.NewStream(bytes.NewReader(this._raw_master2))
	tmp22 := NewUbifs_MasterblockNode()
	err = tmp22.Read(_io__raw_master2, this, this._root)
	if err != nil {
		return nil, err
	}
	this.master2 = tmp22
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.master2, nil
}

/**
 * The superblock node will always be at the start of
 * the first LEB.
 */
func (this *Ubifs) Superblock() (v *Ubifs_SuperblockNode, err error) {
	if (this._f_superblock) {
		return this.superblock, nil
	}
	this._f_superblock = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(0), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp23 := NewUbifs_SuperblockNode()
	err = tmp23.Read(this._io, this, this._root)
	if err != nil {
		return nil, err
	}
	this.superblock = tmp23
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.superblock, nil
}

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L774-L782">Git tag "v7.2"</a>
 */
type Ubifs_AuthenticationHeader struct {
	Hmac []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
}
func NewUbifs_AuthenticationHeader() *Ubifs_AuthenticationHeader {
	return &Ubifs_AuthenticationHeader{
	}
}

func (this Ubifs_AuthenticationHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_AuthenticationHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp24, err := this._root.Superblock()
	if err != nil {
		return err
	}
	tmp25, err := tmp24.NodeHeader.LenHash()
	if err != nil {
		return err
	}
	tmp26, err := this._io.ReadBytes(int(tmp25))
	if err != nil {
		return err
	}
	tmp26 = tmp26
	this.Hmac = tmp26
	return err
}

/**
 * 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.
 */
type Ubifs_Block struct {
	Header *Ubifs_CommonHeader
	NodeHeader interface{}
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Branch
	_raw_NodeHeader []byte
}
func NewUbifs_Block() *Ubifs_Block {
	return &Ubifs_Block{
	}
}

func (this Ubifs_Block) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_Block) Read(io *kaitai.Stream, parent *Ubifs_Branch, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp27 := NewUbifs_CommonHeader()
	err = tmp27.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header = tmp27
	switch (this.Header.NodeType) {
	case Ubifs_NodeTypes__Authentication:
		tmp28, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp28 = tmp28
		this._raw_NodeHeader = tmp28
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp29 := NewUbifs_AuthenticationHeader()
		err = tmp29.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp29
	case Ubifs_NodeTypes__CommitStart:
		tmp30, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp30 = tmp30
		this._raw_NodeHeader = tmp30
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp31 := NewUbifs_CommitStartHeader()
		err = tmp31.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp31
	case Ubifs_NodeTypes__Data:
		tmp32, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp32 = tmp32
		this._raw_NodeHeader = tmp32
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp33 := NewUbifs_DataHeader()
		err = tmp33.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp33
	case Ubifs_NodeTypes__Directory:
		tmp34, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp34 = tmp34
		this._raw_NodeHeader = tmp34
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp35 := NewUbifs_DirectoryHeader()
		err = tmp35.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp35
	case Ubifs_NodeTypes__ExtendedAttribute:
		tmp36, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp36 = tmp36
		this._raw_NodeHeader = tmp36
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp37 := NewUbifs_DirectoryHeader()
		err = tmp37.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp37
	case Ubifs_NodeTypes__Index:
		tmp38, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp38 = tmp38
		this._raw_NodeHeader = tmp38
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp39 := NewUbifs_IndexHeader()
		err = tmp39.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp39
	case Ubifs_NodeTypes__Inode:
		tmp40, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp40 = tmp40
		this._raw_NodeHeader = tmp40
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp41 := NewUbifs_InodeHeader()
		err = tmp41.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp41
	case Ubifs_NodeTypes__Master:
		tmp42, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp42 = tmp42
		this._raw_NodeHeader = tmp42
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp43 := NewUbifs_MasterHeader()
		err = tmp43.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp43
	case Ubifs_NodeTypes__Orphan:
		tmp44, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp44 = tmp44
		this._raw_NodeHeader = tmp44
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp45 := NewUbifs_OrphanHeader()
		err = tmp45.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp45
	case Ubifs_NodeTypes__Padding:
		tmp46, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp46 = tmp46
		this._raw_NodeHeader = tmp46
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp47 := NewUbifs_PaddingHeader()
		err = tmp47.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp47
	case Ubifs_NodeTypes__Reference:
		tmp48, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp48 = tmp48
		this._raw_NodeHeader = tmp48
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp49 := NewUbifs_ReferenceHeader()
		err = tmp49.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp49
	case Ubifs_NodeTypes__Signature:
		tmp50, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp50 = tmp50
		this._raw_NodeHeader = tmp50
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp51 := NewUbifs_SignatureHeader()
		err = tmp51.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp51
	case Ubifs_NodeTypes__Superblock:
		tmp52, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp52 = tmp52
		this._raw_NodeHeader = tmp52
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp53 := NewUbifs_SuperblockHeader()
		err = tmp53.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp53
	case Ubifs_NodeTypes__Truncation:
		tmp54, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp54 = tmp54
		this._raw_NodeHeader = tmp54
		_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
		tmp55 := NewUbifs_TruncationHeader()
		err = tmp55.Read(_io__raw_NodeHeader, this, this._root)
		if err != nil {
			return err
		}
		this.NodeHeader = tmp55
	default:
		tmp56, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
		if err != nil {
			return err
		}
		tmp56 = tmp56
		this._raw_NodeHeader = tmp56
	}
	return err
}

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L801-L817">Git tag "v7.2"</a>
 */
type Ubifs_Branch struct {
	TargetLeb uint32
	OfsTarget uint32
	LenTarget uint32
	Key *Ubifs_Key
	Hash []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_IndexHeader
	_raw_Key []byte
	_raw_target []byte
	_f_target bool
	target *Ubifs_Block
}
func NewUbifs_Branch() *Ubifs_Branch {
	return &Ubifs_Branch{
	}
}

func (this Ubifs_Branch) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_Branch) Read(io *kaitai.Stream, parent *Ubifs_IndexHeader, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp57, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.TargetLeb = uint32(tmp57)
	tmp58, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsTarget = uint32(tmp58)
	tmp59, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenTarget = uint32(tmp59)
	tmp60, err := this._io.ReadBytes(int(8))
	if err != nil {
		return err
	}
	tmp60 = tmp60
	this._raw_Key = tmp60
	_io__raw_Key := kaitai.NewStream(bytes.NewReader(this._raw_Key))
	tmp61 := NewUbifs_Key()
	err = tmp61.Read(_io__raw_Key, this, this._root)
	if err != nil {
		return err
	}
	this.Key = tmp61
	tmp62, err := this._root.Superblock()
	if err != nil {
		return err
	}
	tmp63, err := tmp62.NodeHeader.LenHash()
	if err != nil {
		return err
	}
	tmp64, err := this._io.ReadBytes(int(tmp63))
	if err != nil {
		return err
	}
	tmp64 = tmp64
	this.Hash = tmp64
	return err
}
func (this *Ubifs_Branch) Target() (v *Ubifs_Block, err error) {
	if (this._f_target) {
		return this.target, nil
	}
	this._f_target = true
	thisIo := this._root._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	tmp65, err := this._root.Superblock()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(tmp65.NodeHeader.LebSize * this.TargetLeb + this.OfsTarget), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp66, err := thisIo.ReadBytes(int(this.LenTarget))
	if err != nil {
		return nil, err
	}
	tmp66 = tmp66
	this._raw_target = tmp66
	_io__raw_target := kaitai.NewStream(bytes.NewReader(this._raw_target))
	tmp67 := NewUbifs_Block()
	err = tmp67.Read(_io__raw_target, this, this._root)
	if err != nil {
		return nil, err
	}
	this.target = tmp67
	{
		_it := this.target
		var tmp68 bool;
		if (this._parent.Level != 0) {
			tmp68 = _it.Header.NodeType == Ubifs_NodeTypes__Index
		} else {
			tmp68 = _it.Header.NodeType == this.Key.Type
		}
		if !( ((_it.Header.LenFullNode == this.LenTarget) && (tmp68)) ) {
			return nil, kaitai.NewValidationExprError(this.target, this._io, "/types/branch/instances/target")
		}
	}
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.target, nil
}

/**
 * LEB number of the target node
 */

/**
 * offset within the LEB `target_leb`
 */

/**
 * target node length
 */

/**
 * Hash of the target node. It is empty in a file system without
 * authentication (see `<superblock_header>.len_hash`).
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs.h#L1642-L1654">Git tag "v7.2"</a>
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L833-L841">Git tag "v7.2"</a>
 */
type Ubifs_CommitStartHeader struct {
	CommitNumber uint64
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
}
func NewUbifs_CommitStartHeader() *Ubifs_CommitStartHeader {
	return &Ubifs_CommitStartHeader{
	}
}

func (this Ubifs_CommitStartHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_CommitStartHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp69, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.CommitNumber = uint64(tmp69)
	return err
}

/**
 * commit number
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L443-L464">Git tag "v7.2"</a>
 */
type Ubifs_CommonHeader struct {
	Magic uint32
	Crc uint32
	SequenceNumber uint64
	LenFullNode uint32
	NodeType Ubifs_NodeTypes
	GroupType Ubifs_NodeGroupTypes
	Padding []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent kaitai.Struct
}
func NewUbifs_CommonHeader() *Ubifs_CommonHeader {
	return &Ubifs_CommonHeader{
	}
}

func (this Ubifs_CommonHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_CommonHeader) Read(io *kaitai.Stream, parent kaitai.Struct, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp70, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Magic = uint32(tmp70)
	if !(this.Magic == 101718065) {
		return kaitai.NewValidationNotEqualError(101718065, this.Magic, this._io, "/types/common_header/seq/0")
	}
	tmp71, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Crc = uint32(tmp71)
	tmp72, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.SequenceNumber = uint64(tmp72)
	tmp73, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenFullNode = uint32(tmp73)
	tmp74, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.NodeType = Ubifs_NodeTypes(tmp74)
	tmp75, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.GroupType = Ubifs_NodeGroupTypes(tmp75)
	tmp76, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp76 = tmp76
	this.Padding = tmp76
	if !(bytes.Equal(this.Padding, []uint8{0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0}, this.Padding, this._io, "/types/common_header/seq/6")
	}
	return err
}

/**
 * UBIFS node magic number (`UBIFS_NODE_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).
 */

/**
 * sequence number
 */

/**
 * full node length
 */

/**
 * node type
 */

/**
 * node group type
 */

/**
 * reserved for future, zeroes
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L567-L584">Git tag "v7.2"</a>
 */
type Ubifs_DataHeader struct {
	Key *Ubifs_Key
	LenUncompressed uint32
	Compression Ubifs_Compression
	LenCompressedData uint16
	Data []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
	_raw_Key []byte
}
func NewUbifs_DataHeader() *Ubifs_DataHeader {
	return &Ubifs_DataHeader{
	}
}

func (this Ubifs_DataHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_DataHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp77, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp77 = tmp77
	this._raw_Key = tmp77
	_io__raw_Key := kaitai.NewStream(bytes.NewReader(this._raw_Key))
	tmp78 := NewUbifs_Key()
	err = tmp78.Read(_io__raw_Key, this, this._root)
	if err != nil {
		return err
	}
	this.Key = tmp78
	tmp79, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenUncompressed = uint32(tmp79)
	if !(this.LenUncompressed >= 1) {
		return kaitai.NewValidationLessThanError(1, this.LenUncompressed, this._io, "/types/data_header/seq/1")
	}
	if !(this.LenUncompressed <= 4096) {
		return kaitai.NewValidationGreaterThanError(4096, this.LenUncompressed, this._io, "/types/data_header/seq/1")
	}
	tmp80, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Compression = Ubifs_Compression(tmp80)
	if !this.Compression.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.Compression, this._io, "/types/data_header/seq/2")
	}
	tmp81, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenCompressedData = uint16(tmp81)
	tmp82, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp82 = tmp82
	this.Data = tmp82
	return err
}

/**
 * node key
 */

/**
 * uncompressed data size in bytes
 */

/**
 * compression type (`compression::no_compression`, `compression::lzo`,
 * etc.)
 */

/**
 * compressed data size in bytes, only valid when data is encrypted
 */

/**
 * 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.
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L541-L565">Git tag "v7.2"</a>
 */
type Ubifs_DirectoryHeader struct {
	Key *Ubifs_Key
	InodeNumber uint64
	Padding1 []byte
	InodeType Ubifs_InodeTypes
	LenName uint16
	Cookie uint32
	Name []byte
	NameTerminator []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
	_raw_Key []byte
}
func NewUbifs_DirectoryHeader() *Ubifs_DirectoryHeader {
	return &Ubifs_DirectoryHeader{
	}
}

func (this Ubifs_DirectoryHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_DirectoryHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp83, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp83 = tmp83
	this._raw_Key = tmp83
	_io__raw_Key := kaitai.NewStream(bytes.NewReader(this._raw_Key))
	tmp84 := NewUbifs_Key()
	err = tmp84.Read(_io__raw_Key, this, this._root)
	if err != nil {
		return err
	}
	this.Key = tmp84
	{
		_it := this.Key
		if !( ((_it.Type == Ubifs_KeyTypes__Directory) || (_it.Type == Ubifs_KeyTypes__ExtendedAttribute)) ) {
			return kaitai.NewValidationExprError(this.Key, this._io, "/types/directory_header/seq/0")
		}
	}
	tmp85, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.InodeNumber = uint64(tmp85)
	if !(this.InodeNumber <= uint32(4294967295)) {
		return kaitai.NewValidationGreaterThanError(uint32(4294967295), this.InodeNumber, this._io, "/types/directory_header/seq/1")
	}
	tmp86, err := this._io.ReadBytes(int(1))
	if err != nil {
		return err
	}
	tmp86 = tmp86
	this.Padding1 = tmp86
	if !(bytes.Equal(this.Padding1, []uint8{0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0}, this.Padding1, this._io, "/types/directory_header/seq/2")
	}
	tmp87, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.InodeType = Ubifs_InodeTypes(tmp87)
	if !this.InodeType.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.InodeType, this._io, "/types/directory_header/seq/3")
	}
	tmp88, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenName = uint16(tmp88)
	tmp89, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Cookie = uint32(tmp89)
	tmp90, err := this._io.ReadBytes(int(this.LenName))
	if err != nil {
		return err
	}
	tmp90 = tmp90
	this.Name = tmp90
	tmp91, err := this._io.ReadBytes(int(1))
	if err != nil {
		return err
	}
	tmp91 = tmp91
	this.NameTerminator = tmp91
	if !(bytes.Equal(this.NameTerminator, []uint8{0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0}, this.NameTerminator, this._io, "/types/directory_header/seq/7")
	}
	return err
}

/**
 * node key
 */

/**
 * target inode number
 */

/**
 * reserved for future, zeroes
 */

/**
 * type of the target inode (`inode_types::regular`,
 * `inode_types::directory`, etc.)
 */

/**
 * name length
 */

/**
 * A 32bits random number, used to construct a 64bits identifier.
 */

/**
 * 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).
 */

/**
 * Zero byte after `name`, [not counted in
 * `len_name`](https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/replay.c#L487-L489).
 */
type Ubifs_Dummy struct {
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs
}
func NewUbifs_Dummy() *Ubifs_Dummy {
	return &Ubifs_Dummy{
	}
}

func (this Ubifs_Dummy) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_Dummy) Read(io *kaitai.Stream, parent *Ubifs, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	return err
}
type Ubifs_IndexBlock struct {
	Header *Ubifs_CommonHeader
	NodeHeader *Ubifs_IndexHeader
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs
	_raw_NodeHeader []byte
}
func NewUbifs_IndexBlock() *Ubifs_IndexBlock {
	return &Ubifs_IndexBlock{
	}
}

func (this Ubifs_IndexBlock) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_IndexBlock) Read(io *kaitai.Stream, parent *Ubifs, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp92 := NewUbifs_CommonHeader()
	err = tmp92.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header = tmp92
	{
		_it := this.Header
		if !(_it.NodeType == Ubifs_NodeTypes__Index) {
			return kaitai.NewValidationExprError(this.Header, this._io, "/types/index_block/seq/0")
		}
	}
	tmp93, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
	if err != nil {
		return err
	}
	tmp93 = tmp93
	this._raw_NodeHeader = tmp93
	_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
	tmp94 := NewUbifs_IndexHeader()
	err = tmp94.Read(_io__raw_NodeHeader, this, this._root)
	if err != nil {
		return err
	}
	this.NodeHeader = tmp94
	return err
}

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L819-L831">Git tag "v7.2"</a>
 */
type Ubifs_IndexHeader struct {
	NumBranches uint16
	Level uint16
	Branches []*Ubifs_Branch
	_io *kaitai.Stream
	_root *Ubifs
	_parent kaitai.Struct
}
func NewUbifs_IndexHeader() *Ubifs_IndexHeader {
	return &Ubifs_IndexHeader{
	}
}

func (this Ubifs_IndexHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_IndexHeader) Read(io *kaitai.Stream, parent kaitai.Struct, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp95, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.NumBranches = uint16(tmp95)
	tmp96, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Level = uint16(tmp96)
	for i := 0; i < int(this.NumBranches); i++ {
		_ = i
		tmp97 := NewUbifs_Branch()
		err = tmp97.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Branches = append(this.Branches, tmp97)
	}
	return err
}

/**
 * number of child index nodes
 */

/**
 * tree 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.
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/misc.h#L186-L205">Git tag "v7.2"</a>
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L480-L539">Git tag "v7.2"</a>
 */
type Ubifs_InodeHeader struct {
	Key *Ubifs_Key
	CreationSequenceNumber uint64
	LenUncompressed uint64
	AtimeSec uint64
	CtimeSec uint64
	MtimeSec uint64
	AtimeNsec uint32
	CtimeNsec uint32
	MtimeNsec uint32
	NumLinks uint32
	Uid uint32
	Gid uint32
	Mode uint32
	Flags uint32
	LenData uint32
	NumXattrs uint32
	XattrSize uint32
	Padding1 []byte
	XattrNames uint32
	Compression Ubifs_Compression
	Padding2 []byte
	Data []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
	_raw_Key []byte
	_f_append bool
	append bool
	_f_compressed bool
	compressed bool
	_f_dirsync bool
	dirsync bool
	_f_encrypted bool
	encrypted bool
	_f_immutable bool
	immutable bool
	_f_isBlockDevice bool
	isBlockDevice bool
	_f_isCharacterDevice bool
	isCharacterDevice bool
	_f_isDir bool
	isDir bool
	_f_isFifo bool
	isFifo bool
	_f_isLink bool
	isLink bool
	_f_isRegular bool
	isRegular bool
	_f_isSocket bool
	isSocket bool
	_f_synchronous bool
	synchronous bool
	_f_xattr bool
	xattr bool
}
func NewUbifs_InodeHeader() *Ubifs_InodeHeader {
	return &Ubifs_InodeHeader{
	}
}

func (this Ubifs_InodeHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_InodeHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp98, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp98 = tmp98
	this._raw_Key = tmp98
	_io__raw_Key := kaitai.NewStream(bytes.NewReader(this._raw_Key))
	tmp99 := NewUbifs_Key()
	err = tmp99.Read(_io__raw_Key, this, this._root)
	if err != nil {
		return err
	}
	this.Key = tmp99
	tmp100, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.CreationSequenceNumber = uint64(tmp100)
	tmp101, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.LenUncompressed = uint64(tmp101)
	tmp102, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.AtimeSec = uint64(tmp102)
	tmp103, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.CtimeSec = uint64(tmp103)
	tmp104, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.MtimeSec = uint64(tmp104)
	tmp105, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.AtimeNsec = uint32(tmp105)
	tmp106, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.CtimeNsec = uint32(tmp106)
	tmp107, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.MtimeNsec = uint32(tmp107)
	tmp108, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumLinks = uint32(tmp108)
	tmp109, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Uid = uint32(tmp109)
	tmp110, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Gid = uint32(tmp110)
	tmp111, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Mode = uint32(tmp111)
	tmp112, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Flags = uint32(tmp112)
	tmp113, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenData = uint32(tmp113)
	tmp114, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumXattrs = uint32(tmp114)
	tmp115, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.XattrSize = uint32(tmp115)
	tmp116, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp116 = tmp116
	this.Padding1 = tmp116
	if !(bytes.Equal(this.Padding1, []uint8{0, 0, 0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0, 0, 0}, this.Padding1, this._io, "/types/inode_header/seq/17")
	}
	tmp117, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.XattrNames = uint32(tmp117)
	tmp118, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Compression = Ubifs_Compression(tmp118)
	if !this.Compression.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.Compression, this._io, "/types/inode_header/seq/19")
	}
	tmp119, err := this._io.ReadBytes(int(26))
	if err != nil {
		return err
	}
	tmp119 = tmp119
	this.Padding2 = tmp119
	tmp120, err := this._io.ReadBytes(int(this.LenData))
	if err != nil {
		return err
	}
	tmp120 = tmp120
	this.Data = tmp120
	return err
}

/**
 * writes to the inode may only append data
 */
func (this *Ubifs_InodeHeader) Append() (v bool, err error) {
	if (this._f_append) {
		return this.append, nil
	}
	this._f_append = true
	this.append = bool(this.Flags & 8 != 0)
	return this.append, nil
}

/**
 * use compression for this inode
 */
func (this *Ubifs_InodeHeader) Compressed() (v bool, err error) {
	if (this._f_compressed) {
		return this.compressed, nil
	}
	this._f_compressed = true
	this.compressed = bool(this.Flags & 1 != 0)
	return this.compressed, nil
}

/**
 * I/O on this directory inode has to be synchronous
 */
func (this *Ubifs_InodeHeader) Dirsync() (v bool, err error) {
	if (this._f_dirsync) {
		return this.dirsync, nil
	}
	this._f_dirsync = true
	this.dirsync = bool(this.Flags & 16 != 0)
	return this.dirsync, nil
}

/**
 * use encryption for this inode
 */
func (this *Ubifs_InodeHeader) Encrypted() (v bool, err error) {
	if (this._f_encrypted) {
		return this.encrypted, nil
	}
	this._f_encrypted = true
	this.encrypted = bool(this.Flags & 64 != 0)
	return this.encrypted, nil
}

/**
 * inode is immutable
 */
func (this *Ubifs_InodeHeader) Immutable() (v bool, err error) {
	if (this._f_immutable) {
		return this.immutable, nil
	}
	this._f_immutable = true
	this.immutable = bool(this.Flags & 4 != 0)
	return this.immutable, nil
}
func (this *Ubifs_InodeHeader) IsBlockDevice() (v bool, err error) {
	if (this._f_isBlockDevice) {
		return this.isBlockDevice, nil
	}
	this._f_isBlockDevice = true
	this.isBlockDevice = bool(this.Mode & 61440 == 24576)
	return this.isBlockDevice, nil
}
func (this *Ubifs_InodeHeader) IsCharacterDevice() (v bool, err error) {
	if (this._f_isCharacterDevice) {
		return this.isCharacterDevice, nil
	}
	this._f_isCharacterDevice = true
	this.isCharacterDevice = bool(this.Mode & 61440 == 8192)
	return this.isCharacterDevice, nil
}
func (this *Ubifs_InodeHeader) IsDir() (v bool, err error) {
	if (this._f_isDir) {
		return this.isDir, nil
	}
	this._f_isDir = true
	this.isDir = bool(this.Mode & 61440 == 16384)
	return this.isDir, nil
}
func (this *Ubifs_InodeHeader) IsFifo() (v bool, err error) {
	if (this._f_isFifo) {
		return this.isFifo, nil
	}
	this._f_isFifo = true
	this.isFifo = bool(this.Mode & 61440 == 4096)
	return this.isFifo, nil
}
func (this *Ubifs_InodeHeader) IsLink() (v bool, err error) {
	if (this._f_isLink) {
		return this.isLink, nil
	}
	this._f_isLink = true
	this.isLink = bool(this.Mode & 61440 == 40960)
	return this.isLink, nil
}
func (this *Ubifs_InodeHeader) IsRegular() (v bool, err error) {
	if (this._f_isRegular) {
		return this.isRegular, nil
	}
	this._f_isRegular = true
	this.isRegular = bool(this.Mode & 61440 == 32768)
	return this.isRegular, nil
}
func (this *Ubifs_InodeHeader) IsSocket() (v bool, err error) {
	if (this._f_isSocket) {
		return this.isSocket, nil
	}
	this._f_isSocket = true
	this.isSocket = bool(this.Mode & 61440 == 49152)
	return this.isSocket, nil
}

/**
 * I/O on this inode has to be synchronous
 */
func (this *Ubifs_InodeHeader) Synchronous() (v bool, err error) {
	if (this._f_synchronous) {
		return this.synchronous, nil
	}
	this._f_synchronous = true
	this.synchronous = bool(this.Flags & 2 != 0)
	return this.synchronous, nil
}

/**
 * this inode is the inode for an extended attribute value
 */
func (this *Ubifs_InodeHeader) Xattr() (v bool, err error) {
	if (this._f_xattr) {
		return this.xattr, nil
	}
	this._f_xattr = true
	this.xattr = bool(this.Flags & 32 != 0)
	return this.xattr, nil
}

/**
 * node key
 */

/**
 * sequence number at time of creation
 */

/**
 * inode size in bytes (amount of uncompressed data)
 */

/**
 * access time seconds
 */

/**
 * status change time seconds
 */

/**
 * modification time seconds
 */

/**
 * access time nanoseconds
 */

/**
 * status change time nanoseconds
 */

/**
 * modification time nanoseconds
 */

/**
 * number of hard links
 */

/**
 * owner ID
 */

/**
 * group ID
 */

/**
 * file type and permissions, as in `st_mode` (see the `is_*`
 * instances for the file type)
 */

/**
 * per-inode flags (see the instances `compressed`, `synchronous`,
 * etc.)
 */

/**
 * inode data length
 */

/**
 * count of extended attributes this inode has
 */

/**
 * summarized size of all extended attributes in bytes
 */

/**
 * sum of lengths of all extended attribute names belonging
 * to this inode
 */

/**
 * compression type used for this inode
 */

/**
 * reserved for future, zeroes
 */

/**
 * 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.
 */

/**
 * 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).
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/key.h#L16-L22">Git tag "v7.2"</a>
 */
type Ubifs_Key struct {
	InodeNumber uint32
	Value uint64
	Type Ubifs_KeyTypes
	Unused []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent kaitai.Struct
}
func NewUbifs_Key() *Ubifs_Key {
	return &Ubifs_Key{
	}
}

func (this Ubifs_Key) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_Key) Read(io *kaitai.Stream, parent kaitai.Struct, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp121, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.InodeNumber = uint32(tmp121)
	tmp122, err := this._io.ReadBitsIntLe(29)
	if err != nil {
		return err
	}
	this.Value = tmp122
	tmp123, err := this._io.ReadBitsIntLe(3)
	if err != nil {
		return err
	}
	this.Type = Ubifs_KeyTypes(tmp123)
	if !this.Type.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.Type, this._io, "/types/key/seq/2")
	}
	this._io.AlignToByte()
	tmp124, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp124 = tmp124
	this.Unused = tmp124
	return err
}

/**
 * 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.
 */

/**
 * 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.
 */

/**
 * Type of the key, which matches the type of the node.
 */

/**
 * Rest of the field holding the key: 8 zero bytes in `inode_header`,
 * `directory_header` and `data_header`, empty in `branch`.
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L685-L756">Git tag "v7.2"</a>
 */
type Ubifs_MasterHeader struct {
	HighestInum uint64
	CommitNumber uint64
	Flags uint32
	LebLog uint32
	LebRoot uint32
	OfsRoot uint32
	LenRoot uint32
	LebGarbageCollect uint32
	LebIndexHead uint32
	OfsIndexHead uint32
	LenIndex uint64
	TotalFree uint64
	TotalDirty uint64
	TotalUsed uint64
	TotalDead uint64
	TotalDark uint64
	LebLpt uint32
	OfsLpt uint32
	LebNhead uint32
	OfsNhead uint32
	LebLpropsTable uint32
	OfsLpropsTable uint32
	LebSaveTable uint32
	OfsSaveTable uint32
	LebLastLptScan uint32
	NumEmptyLebs uint32
	NumIndexLebs uint32
	NumLebs uint32
	HashRootIndex []byte
	HashLpt []byte
	Hmac []byte
	Padding []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent kaitai.Struct
	_f_dirty bool
	dirty bool
	_f_noOrphans bool
	noOrphans bool
	_f_recovery bool
	recovery bool
}
func NewUbifs_MasterHeader() *Ubifs_MasterHeader {
	return &Ubifs_MasterHeader{
	}
}

func (this Ubifs_MasterHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_MasterHeader) Read(io *kaitai.Stream, parent kaitai.Struct, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp125, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.HighestInum = uint64(tmp125)
	tmp126, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.CommitNumber = uint64(tmp126)
	tmp127, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Flags = uint32(tmp127)
	tmp128, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebLog = uint32(tmp128)
	tmp129, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebRoot = uint32(tmp129)
	tmp130, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsRoot = uint32(tmp130)
	tmp131, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenRoot = uint32(tmp131)
	tmp132, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebGarbageCollect = uint32(tmp132)
	tmp133, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebIndexHead = uint32(tmp133)
	tmp134, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsIndexHead = uint32(tmp134)
	tmp135, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.LenIndex = uint64(tmp135)
	tmp136, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.TotalFree = uint64(tmp136)
	tmp137, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.TotalDirty = uint64(tmp137)
	tmp138, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.TotalUsed = uint64(tmp138)
	tmp139, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.TotalDead = uint64(tmp139)
	tmp140, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.TotalDark = uint64(tmp140)
	tmp141, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebLpt = uint32(tmp141)
	tmp142, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsLpt = uint32(tmp142)
	tmp143, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebNhead = uint32(tmp143)
	tmp144, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsNhead = uint32(tmp144)
	tmp145, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebLpropsTable = uint32(tmp145)
	tmp146, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsLpropsTable = uint32(tmp146)
	tmp147, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebSaveTable = uint32(tmp147)
	tmp148, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsSaveTable = uint32(tmp148)
	tmp149, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebLastLptScan = uint32(tmp149)
	tmp150, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumEmptyLebs = uint32(tmp150)
	tmp151, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumIndexLebs = uint32(tmp151)
	tmp152, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumLebs = uint32(tmp152)
	tmp153, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp153 = tmp153
	this.HashRootIndex = tmp153
	tmp154, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp154 = tmp154
	this.HashLpt = tmp154
	tmp155, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp155 = tmp155
	this.Hmac = tmp155
	tmp156, err := this._io.ReadBytes(int(152))
	if err != nil {
		return err
	}
	tmp156 = tmp156
	this.Padding = tmp156
	return err
}

/**
 * master node is dirty
 */
func (this *Ubifs_MasterHeader) Dirty() (v bool, err error) {
	if (this._f_dirty) {
		return this.dirty, nil
	}
	this._f_dirty = true
	this.dirty = bool(this.Flags & 1 != 0)
	return this.dirty, nil
}

/**
 * no orphan inodes present
 */
func (this *Ubifs_MasterHeader) NoOrphans() (v bool, err error) {
	if (this._f_noOrphans) {
		return this.noOrphans, nil
	}
	this._f_noOrphans = true
	this.noOrphans = bool(this.Flags & 2 != 0)
	return this.noOrphans, nil
}

/**
 * written by recovery
 */
func (this *Ubifs_MasterHeader) Recovery() (v bool, err error) {
	if (this._f_recovery) {
		return this.recovery, nil
	}
	this._f_recovery = true
	this.recovery = bool(this.Flags & 4 != 0)
	return this.recovery, nil
}

/**
 * highest inode number in the committed index
 */

/**
 * commit number
 */

/**
 * various flags (see the instances `dirty`, `no_orphans` and
 * `recovery`)
 */

/**
 * start of the log
 */

/**
 * LEB number of the root indexing node
 */

/**
 * offset within the LEB `leb_root`
 */

/**
 * root indexing node length
 */

/**
 * 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.
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/master.c#L214-L217">Git tag "v7.2"</a>
 */

/**
 * LEB number of index head
 */

/**
 * offset of index head
 */

/**
 * size of index on flash
 */

/**
 * total free space in bytes
 */

/**
 * total dirty space in bytes
 */

/**
 * total used space in bytes (includes only data LEBs)
 */

/**
 * total dead space in bytes (includes only data LEBs)
 */

/**
 * total dark space in bytes (includes only data LEBs)
 */

/**
 * LEB number of LPT root nnode
 */

/**
 * offset of LPT root nnode
 */

/**
 * LEB number of LPT head
 */

/**
 * offset of LPT head
 */

/**
 * LEB number of LPT's own lprops table
 */

/**
 * offset of LPT's own lprops table
 */

/**
 * 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).
 */

/**
 * offset of LPT's save table (only meaningful if
 * `<superblock_header>.biglpt` is set, see `leb_save_table`)
 */

/**
 * LEB number of last LPT scan
 */

/**
 * number of empty logical eraseblocks
 */

/**
 * number of indexing logical eraseblocks
 */

/**
 * count of LEBs used by file-system
 */

/**
 * the hash of the root index node
 */

/**
 * the hash of the LPT
 */

/**
 * HMAC to authenticate the master node
 */

/**
 * reserved for future, zeroes
 */
type Ubifs_MasterblockNode struct {
	Header *Ubifs_CommonHeader
	NodeHeader *Ubifs_MasterHeader
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs
	_raw_NodeHeader []byte
}
func NewUbifs_MasterblockNode() *Ubifs_MasterblockNode {
	return &Ubifs_MasterblockNode{
	}
}

func (this Ubifs_MasterblockNode) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_MasterblockNode) Read(io *kaitai.Stream, parent *Ubifs, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp157 := NewUbifs_CommonHeader()
	err = tmp157.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header = tmp157
	{
		_it := this.Header
		if !(_it.NodeType == Ubifs_NodeTypes__Master) {
			return kaitai.NewValidationExprError(this.Header, this._io, "/types/masterblock_node/seq/0")
		}
	}
	tmp158, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
	if err != nil {
		return err
	}
	tmp158 = tmp158
	this._raw_NodeHeader = tmp158
	_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
	tmp159 := NewUbifs_MasterHeader()
	err = tmp159.Read(_io__raw_NodeHeader, this, this._root)
	if err != nil {
		return err
	}
	this.NodeHeader = tmp159
	return err
}

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L843-L853">Git tag "v7.2"</a>
 */
type Ubifs_OrphanHeader struct {
	CommitNumber uint64
	InodeNumbers []uint64
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
}
func NewUbifs_OrphanHeader() *Ubifs_OrphanHeader {
	return &Ubifs_OrphanHeader{
	}
}

func (this Ubifs_OrphanHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_OrphanHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp160, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.CommitNumber = uint64(tmp160)
	for i := 0;; i++ {
		tmp161, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp161 {
			break
		}
		tmp162, err := this._io.ReadU8le()
		if err != nil {
			return err
		}
		this.InodeNumbers = append(this.InodeNumbers, tmp162)
	}
	return err
}

/**
 * commit number (also top bit is set on the last node of the commit)
 */

/**
 * inode numbers of orphans
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L606-L615">Git tag "v7.2"</a>
 */
type Ubifs_PaddingHeader struct {
	LenPadding uint32
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
}
func NewUbifs_PaddingHeader() *Ubifs_PaddingHeader {
	return &Ubifs_PaddingHeader{
	}
}

func (this Ubifs_PaddingHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_PaddingHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp163, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenPadding = uint32(tmp163)
	return err
}

/**
 * how many bytes after this node are unused (because padded)
 */

/**
 * logical eraseblock reference node.
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L758-L772">Git tag "v7.2"</a>
 */
type Ubifs_ReferenceHeader struct {
	LebNumber uint32
	OfsLeb uint32
	JournalHeadNumber uint32
	Padding []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
}
func NewUbifs_ReferenceHeader() *Ubifs_ReferenceHeader {
	return &Ubifs_ReferenceHeader{
	}
}

func (this Ubifs_ReferenceHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_ReferenceHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp164, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebNumber = uint32(tmp164)
	tmp165, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsLeb = uint32(tmp165)
	tmp166, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.JournalHeadNumber = uint32(tmp166)
	tmp167, err := this._io.ReadBytes(int(28))
	if err != nil {
		return err
	}
	tmp167 = tmp167
	this.Padding = tmp167
	return err
}

/**
 * the referred logical eraseblock number
 */

/**
 * start offset in the referred LEB
 */

/**
 * journal head number
 */

/**
 * reserved for future, zeroes
 */

/**
 * 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.
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L784-L799">Git tag "v7.2"</a>
 */
type Ubifs_SignatureHeader struct {
	Type uint32
	LenSignature uint32
	Padding []byte
	Signature []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
}
func NewUbifs_SignatureHeader() *Ubifs_SignatureHeader {
	return &Ubifs_SignatureHeader{
	}
}

func (this Ubifs_SignatureHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_SignatureHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp168, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Type = uint32(tmp168)
	if !(this.Type == 1) {
		return kaitai.NewValidationNotEqualError(1, this.Type, this._io, "/types/signature_header/seq/0")
	}
	tmp169, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenSignature = uint32(tmp169)
	tmp170, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp170 = tmp170
	this.Padding = tmp170
	tmp171, err := this._io.ReadBytes(int(this.LenSignature))
	if err != nil {
		return err
	}
	tmp171 = tmp171
	this.Signature = tmp171
	return err
}

/**
 * type of the signature
 */

/**
 * length of `signature` in bytes
 */

/**
 * reserved for future, zeroes
 */

/**
 * [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)
 */

/**
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L617-L683">Git tag "v7.2"</a>
 */
type Ubifs_SuperblockHeader struct {
	Padding0 []byte
	KeyHash Ubifs_Hashes
	KeyFmt Ubifs_KeyFormats
	Flags uint32
	MinIoSize uint32
	LebSize uint32
	NumLebs uint32
	MaxNumLebs uint32
	MaxBudBytes uint64
	NumLogLebs uint32
	NumLptLebs uint32
	NumOrphanLebs uint32
	NumJournalHeads uint32
	Fanout uint32
	NumSaveTableEntries uint32
	FmtVersion uint32
	DefaultCompression Ubifs_Compression
	Padding1 []byte
	ReservePoolUid uint32
	ReservePoolGid uint32
	ReservePoolSize uint64
	TimeGranularity uint32
	Uuid []byte
	RoCompatVersion uint32
	Hmac []byte
	HmacWkm []byte
	HashAlgo Ubifs_HashAlgos
	HashAlgoUnused uint16
	HashMst []byte
	Padding2 []byte
	_io *kaitai.Stream
	_root *Ubifs
	_parent kaitai.Struct
	_f_authenticated bool
	authenticated bool
	_f_biglpt bool
	biglpt bool
	_f_doubleHash bool
	doubleHash bool
	_f_encrypted bool
	encrypted bool
	_f_lenHash bool
	lenHash int
	_f_spaceFixup bool
	spaceFixup bool
}
func NewUbifs_SuperblockHeader() *Ubifs_SuperblockHeader {
	return &Ubifs_SuperblockHeader{
	}
}

func (this Ubifs_SuperblockHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_SuperblockHeader) Read(io *kaitai.Stream, parent kaitai.Struct, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp172, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp172 = tmp172
	this.Padding0 = tmp172
	if !(bytes.Equal(this.Padding0, []uint8{0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0}, this.Padding0, this._io, "/types/superblock_header/seq/0")
	}
	tmp173, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.KeyHash = Ubifs_Hashes(tmp173)
	if !this.KeyHash.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.KeyHash, this._io, "/types/superblock_header/seq/1")
	}
	tmp174, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.KeyFmt = Ubifs_KeyFormats(tmp174)
	if !(this.KeyFmt == Ubifs_KeyFormats__Simple) {
		return kaitai.NewValidationNotEqualError(Ubifs_KeyFormats__Simple, this.KeyFmt, this._io, "/types/superblock_header/seq/2")
	}
	tmp175, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Flags = uint32(tmp175)
	tmp176, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.MinIoSize = uint32(tmp176)
	tmp177, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LebSize = uint32(tmp177)
	tmp178, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumLebs = uint32(tmp178)
	tmp179, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.MaxNumLebs = uint32(tmp179)
	if !(this.MaxNumLebs >= this.NumLebs) {
		return kaitai.NewValidationLessThanError(this.NumLebs, this.MaxNumLebs, this._io, "/types/superblock_header/seq/7")
	}
	tmp180, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.MaxBudBytes = uint64(tmp180)
	tmp181, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumLogLebs = uint32(tmp181)
	if !(this.NumLogLebs >= 2) {
		return kaitai.NewValidationLessThanError(2, this.NumLogLebs, this._io, "/types/superblock_header/seq/9")
	}
	tmp182, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumLptLebs = uint32(tmp182)
	if !(this.NumLptLebs >= 2) {
		return kaitai.NewValidationLessThanError(2, this.NumLptLebs, this._io, "/types/superblock_header/seq/10")
	}
	tmp183, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumOrphanLebs = uint32(tmp183)
	if !(this.NumOrphanLebs >= 1) {
		return kaitai.NewValidationLessThanError(1, this.NumOrphanLebs, this._io, "/types/superblock_header/seq/11")
	}
	tmp184, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumJournalHeads = uint32(tmp184)
	tmp185, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Fanout = uint32(tmp185)
	tmp186, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumSaveTableEntries = uint32(tmp186)
	tmp187, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.FmtVersion = uint32(tmp187)
	if !(this.FmtVersion >= 4) {
		return kaitai.NewValidationLessThanError(4, this.FmtVersion, this._io, "/types/superblock_header/seq/15")
	}
	tmp188, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.DefaultCompression = Ubifs_Compression(tmp188)
	if !this.DefaultCompression.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.DefaultCompression, this._io, "/types/superblock_header/seq/16")
	}
	tmp189, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp189 = tmp189
	this.Padding1 = tmp189
	if !(bytes.Equal(this.Padding1, []uint8{0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0}, this.Padding1, this._io, "/types/superblock_header/seq/17")
	}
	tmp190, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.ReservePoolUid = uint32(tmp190)
	tmp191, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.ReservePoolGid = uint32(tmp191)
	tmp192, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.ReservePoolSize = uint64(tmp192)
	tmp193, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.TimeGranularity = uint32(tmp193)
	if !(this.TimeGranularity >= 1) {
		return kaitai.NewValidationLessThanError(1, this.TimeGranularity, this._io, "/types/superblock_header/seq/21")
	}
	if !(this.TimeGranularity <= 1000000000) {
		return kaitai.NewValidationGreaterThanError(1000000000, this.TimeGranularity, this._io, "/types/superblock_header/seq/21")
	}
	tmp194, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp194 = tmp194
	this.Uuid = tmp194
	tmp195, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.RoCompatVersion = uint32(tmp195)
	tmp196, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp196 = tmp196
	this.Hmac = tmp196
	tmp197, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp197 = tmp197
	this.HmacWkm = tmp197
	tmp198, err := this.Authenticated()
	if err != nil {
		return err
	}
	if (tmp198) {
		tmp199, err := this._io.ReadU2le()
		if err != nil {
			return err
		}
		this.HashAlgo = Ubifs_HashAlgos(tmp199)
		if !this.HashAlgo.isDefined() {
			return kaitai.NewValidationNotInEnumError(this.HashAlgo, this._io, "/types/superblock_header/seq/26")
		}
	}
	tmp200, err := this.Authenticated()
	if err != nil {
		return err
	}
	if (!(tmp200)) {
		tmp201, err := this._io.ReadU2le()
		if err != nil {
			return err
		}
		this.HashAlgoUnused = uint16(tmp201)
	}
	tmp202, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp202 = tmp202
	this.HashMst = tmp202
	tmp203, err := this._io.ReadBytes(int(3774))
	if err != nil {
		return err
	}
	tmp203 = tmp203
	this.Padding2 = tmp203
	return err
}

/**
 * this filesystem contains hashes for authentication
 */
func (this *Ubifs_SuperblockHeader) Authenticated() (v bool, err error) {
	if (this._f_authenticated) {
		return this.authenticated, nil
	}
	this._f_authenticated = true
	this.authenticated = bool(this.Flags & 32 != 0)
	return this.authenticated, nil
}

/**
 * if "big" LPT model is used if set
 */
func (this *Ubifs_SuperblockHeader) Biglpt() (v bool, err error) {
	if (this._f_biglpt) {
		return this.biglpt, nil
	}
	this._f_biglpt = true
	this.biglpt = bool(this.Flags & 2 != 0)
	return this.biglpt, nil
}

/**
 * store a 32bit cookie in directory entry nodes to
 * support 64bit cookies for lookups by hash
 */
func (this *Ubifs_SuperblockHeader) DoubleHash() (v bool, err error) {
	if (this._f_doubleHash) {
		return this.doubleHash, nil
	}
	this._f_doubleHash = true
	this.doubleHash = bool(this.Flags & 8 != 0)
	return this.doubleHash, nil
}

/**
 * filesystem contains encrypted files
 */
func (this *Ubifs_SuperblockHeader) Encrypted() (v bool, err error) {
	if (this._f_encrypted) {
		return this.encrypted, nil
	}
	this._f_encrypted = true
	this.encrypted = bool(this.Flags & 16 != 0)
	return this.encrypted, nil
}

/**
 * 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.
 */
func (this *Ubifs_SuperblockHeader) LenHash() (v int, err error) {
	if (this._f_lenHash) {
		return this.lenHash, nil
	}
	this._f_lenHash = true
	var tmp204 int8;
	tmp205, err := this.Authenticated()
	if err != nil {
		return 0, err
	}
	if (!(tmp205)) {
		tmp204 = 0
	} else {
		var tmp206 int8;
		if ( ((this.HashAlgo == Ubifs_HashAlgos__Md4) || (this.HashAlgo == Ubifs_HashAlgos__Md5) || (this.HashAlgo == Ubifs_HashAlgos__RipeMd128) || (this.HashAlgo == Ubifs_HashAlgos__Tgr128)) ) {
			tmp206 = 16
		} else {
			var tmp207 int8;
			if ( ((this.HashAlgo == Ubifs_HashAlgos__Sha1) || (this.HashAlgo == Ubifs_HashAlgos__RipeMd160) || (this.HashAlgo == Ubifs_HashAlgos__Tgr160)) ) {
				tmp207 = 20
			} else {
				var tmp208 int8;
				if (this.HashAlgo == Ubifs_HashAlgos__Tgr192) {
					tmp208 = 24
				} else {
					var tmp209 int8;
					if (this.HashAlgo == Ubifs_HashAlgos__Sha224) {
						tmp209 = 28
					} else {
						var tmp210 int8;
						if ( ((this.HashAlgo == Ubifs_HashAlgos__Sha256) || (this.HashAlgo == Ubifs_HashAlgos__RipeMd256) || (this.HashAlgo == Ubifs_HashAlgos__Wp256) || (this.HashAlgo == Ubifs_HashAlgos__Sm3256) || (this.HashAlgo == Ubifs_HashAlgos__Streebog256) || (this.HashAlgo == Ubifs_HashAlgos__Sha3256)) ) {
							tmp210 = 32
						} else {
							var tmp211 int8;
							if (this.HashAlgo == Ubifs_HashAlgos__RipeMd320) {
								tmp211 = 40
							} else {
								var tmp212 int8;
								if ( ((this.HashAlgo == Ubifs_HashAlgos__Sha384) || (this.HashAlgo == Ubifs_HashAlgos__Wp384) || (this.HashAlgo == Ubifs_HashAlgos__Sha3384)) ) {
									tmp212 = 48
								} else {
									var tmp213 int8;
									if ( ((this.HashAlgo == Ubifs_HashAlgos__Sha512) || (this.HashAlgo == Ubifs_HashAlgos__Wp512) || (this.HashAlgo == Ubifs_HashAlgos__Streebog512) || (this.HashAlgo == Ubifs_HashAlgos__Sha3512)) ) {
										tmp213 = 64
									} else {
										tmp213 = -1
									}
									tmp212 = tmp213
								}
								tmp211 = tmp212
							}
							tmp210 = tmp211
						}
						tmp209 = tmp210
					}
					tmp208 = tmp209
				}
				tmp207 = tmp208
			}
			tmp206 = tmp207
		}
		tmp204 = tmp206
	}
	this.lenHash = int(tmp204)
	return this.lenHash, nil
}

/**
 * first-mount "fixup" of free space within LEBs needed
 */
func (this *Ubifs_SuperblockHeader) SpaceFixup() (v bool, err error) {
	if (this._f_spaceFixup) {
		return this.spaceFixup, nil
	}
	this._f_spaceFixup = true
	this.spaceFixup = bool(this.Flags & 4 != 0)
	return this.spaceFixup, nil
}

/**
 * reserved for future, zeroes
 */

/**
 * type of hash function used in keys
 */

/**
 * format of the key
 */

/**
 * file-system flags (see the instances `biglpt`, `space_fixup`, etc.)
 */

/**
 * minimal input/output unit size
 */

/**
 * logical eraseblock size in bytes
 */

/**
 * count of LEBs used by file-system
 */

/**
 * maximum count of LEBs used by file-system
 */

/**
 * maximum amount of data stored in buds
 */

/**
 * log size in logical eraseblocks
 */

/**
 * number of LEBs used for lprops table
 */

/**
 * number of LEBs used for recording orphans
 */

/**
 * count of journal heads
 */

/**
 * tree fanout (max. number of links per indexing node)
 */

/**
 * number of LEB numbers in LPT's save table
 */

/**
 * UBIFS on-flash format version
 */

/**
 * default compression algorithm (`compression::lzo`, etc.)
 */

/**
 * reserved for future, zeroes
 */

/**
 * reserve pool UID
 */

/**
 * reserve pool GID
 */

/**
 * size of the reserved pool in bytes
 */

/**
 * time granularity in nanoseconds
 */

/**
 * UUID generated when the file system image was created
 */

/**
 * UBIFS R/O compatibility version
 */

/**
 * HMAC to authenticate the superblock node
 */

/**
 * HMAC of a well known message (the string "UBIFS") as a convenience
 * to the user to check if the correct key is passed
 */

/**
 * The hash algo used for this filesystem
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/sb.c#L549-L573">Git tag "v7.2"</a>
 */

/**
 * 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.
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/sb.c#L183-L191">Git tag "v7.2"</a>
 */

/**
 * hash of the master node, only valid for signed images in which the
 * master node does not contain a hmac
 */

/**
 * reserved for future, zeroes
 */
type Ubifs_SuperblockNode struct {
	Header *Ubifs_CommonHeader
	NodeHeader *Ubifs_SuperblockHeader
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs
	_raw_NodeHeader []byte
}
func NewUbifs_SuperblockNode() *Ubifs_SuperblockNode {
	return &Ubifs_SuperblockNode{
	}
}

func (this Ubifs_SuperblockNode) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_SuperblockNode) Read(io *kaitai.Stream, parent *Ubifs, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp214 := NewUbifs_CommonHeader()
	err = tmp214.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header = tmp214
	{
		_it := this.Header
		if !(_it.NodeType == Ubifs_NodeTypes__Superblock) {
			return kaitai.NewValidationExprError(this.Header, this._io, "/types/superblock_node/seq/0")
		}
	}
	tmp215, err := this._io.ReadBytes(int(this.Header.LenFullNode - 24))
	if err != nil {
		return err
	}
	tmp215 = tmp215
	this._raw_NodeHeader = tmp215
	_io__raw_NodeHeader := kaitai.NewStream(bytes.NewReader(this._raw_NodeHeader))
	tmp216 := NewUbifs_SuperblockHeader()
	err = tmp216.Read(_io__raw_NodeHeader, this, this._root)
	if err != nil {
		return err
	}
	this.NodeHeader = tmp216
	return err
}

/**
 * This node exists only in the journal and never goes to the main area.
 * @see <a href="https://github.com/torvalds/linux/blob/8d3ae59288f1e7d58d76558a6ee96d533bc5019f/fs/ubifs/ubifs-media.h#L586-L604">Git tag "v7.2"</a>
 */
type Ubifs_TruncationHeader struct {
	InodeNumber uint32
	Padding []byte
	OldSize uint64
	NewSize uint64
	_io *kaitai.Stream
	_root *Ubifs
	_parent *Ubifs_Block
}
func NewUbifs_TruncationHeader() *Ubifs_TruncationHeader {
	return &Ubifs_TruncationHeader{
	}
}

func (this Ubifs_TruncationHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Ubifs_TruncationHeader) Read(io *kaitai.Stream, parent *Ubifs_Block, root *Ubifs) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp217, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.InodeNumber = uint32(tmp217)
	tmp218, err := this._io.ReadBytes(int(12))
	if err != nil {
		return err
	}
	tmp218 = tmp218
	this.Padding = tmp218
	tmp219, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.OldSize = uint64(tmp219)
	if !(this.OldSize >= 1) {
		return kaitai.NewValidationLessThanError(1, this.OldSize, this._io, "/types/truncation_header/seq/2")
	}
	tmp220, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.NewSize = uint64(tmp220)
	if !(this.NewSize <= this.OldSize - 1) {
		return kaitai.NewValidationGreaterThanError(this.OldSize - 1, this.NewSize, this._io, "/types/truncation_header/seq/3")
	}
	return err
}

/**
 * truncated inode number
 */

/**
 * reserved for future, zeroes
 */

/**
 * size before truncation
 */

/**
 * size after truncation
 */