📜 ⬆️ ⬇️

How ZFS Stores Data

Zfs is a fairly popular file system for long-term data storage. In addition, it ensures the integrity of the recorded data, keeping together with the data and their checksums. The mechanism of checksums allows you to identify, and in the presence of redundancy to recover, damaged data.

In this article, a practical example analyzes how and where zfs saves data.

Directly for data access, we will not use the zdb utility, but try using radare2 to look directly at the bytes that are written on the disk.

About zfs


Zfs (Zettabyte File System) is a COW (copy on write) file system created by Sun for the Solaris operating system.
')
One of the main advantages of this file system is the use of checksums not only for metadata but also for user data.

Zfs disk structure


For a more detailed analysis of zfs components, it is recommended to refer to the official ZFS On-Disk Specification documentation from Sun.

Virtual devices


The zfs pool consists of virtual devices (hereinafter referred to as vdev). We do not need more detailed information now, so we go further. We don’t need more detailed information right now, so we’re going to go further; we’ll just note that vdev has two types of logical and physical virtual devices.

Tag


Four physical labels are stored on each physical virtual device (in Figure L0, L1, L2, and L3).

Tag

Boot block


Immediately after the L0 and L1 tags, 3.5 MB of space is allocated for future use.

Uberblock reference point


Unlike other zfs objects, the position of the labels is strictly fixed and updated in two steps; first, the labels L0 and L2 are updated, then L1 and L3. For this article, of the data recorded in the label, we will be interested only in uberblock, consider it in more detail.

Uberblock


Uberblock is represented by the following structure:

struct uberblock { uint64_t ub_magic; /* UBERBLOCK_MAGIC */ uint64_t ub_version; /* SPA_VERSION */ uint64_t ub_txg; /* txg of last sync */ uint64_t ub_guid_sum; /* sum of all vdev guids */ uint64_t ub_timestamp; /* UTC time of last sync */ blkptr_t ub_rootbp; /* MOS objset_phys_t */ /* highest SPA_VERSION supported by software that wrote this txg */ uint64_t ub_software_version; }; 

We describe some fields:

ub_txg
Transaction number
ub_timestamp
Contains uberblock write time (in UTC format)
ub_rootbp
The link to the Meta Object Set (In zfs, the links to the blocks are represented by the blkptr_t structure, which will be described below).

Links to blocks (blkptr_t)


References to blocks represent the following structure:

 typedef struct blkptr { dva_t blk_dva[SPA_DVAS_PER_BP]; /* Data Virtual Addresses */ uint64_t blk_prop; /* size, compression, type, etc */ uint64_t blk_pad[2]; /* Extra space for the future */ uint64_t blk_phys_birth; /* txg when block was allocated */ uint64_t blk_birth; /* transaction group at birth */ uint64_t blk_fill; /* fill count */ zio_cksum_t blk_cksum; /* 256-bit checksum */ } blkptr_t; /* * All SPA data is represented by 128-bit data virtual addresses (DVAs). * The members of the dva_t should be considered opaque outside the SPA. */ typedef struct dva { uint64_t dva_word[2]; } dva_t; /* * Each block has a 256-bit checksum -- strong enough for cryptographic hashes. */ typedef struct zio_cksum { uint64_t zc_word[4]; } zio_cksum_t; 

If we represent in the form of an array of bytes, then we get the following image

image

The most important fields
dva_t
Virtual address data. The offset field stores the sector offset (512 bytes).
In the image above, these are lines 0 ~ 5.
blk_prop
Type, size, level of indirection of the block, etc.
type converts to dmu_object_type. And the cksum and comp fields in zio_checksum and zio_compress respectively.

 typedef enum dmu_object_type { DMU_OT_NONE, /* general: */ DMU_OT_OBJECT_DIRECTORY, /* ZAP */ DMU_OT_OBJECT_ARRAY, /* UINT64 */ DMU_OT_PACKED_NVLIST, /* UINT8 (XDR by nvlist_pack/unpack) */ DMU_OT_PACKED_NVLIST_SIZE, /* UINT64 */ DMU_OT_BPOBJ, /* UINT64 */ DMU_OT_BPOBJ_HDR, /* UINT64 */ /* spa: */ DMU_OT_SPACE_MAP_HEADER, /* UINT64 */ DMU_OT_SPACE_MAP, /* UINT64 */ /* zil: */ DMU_OT_INTENT_LOG, /* UINT64 */ /* dmu: */ DMU_OT_DNODE, /* DNODE */ DMU_OT_OBJSET, /* OBJSET */ /* dsl: */ DMU_OT_DSL_DIR, /* UINT64 */ DMU_OT_DSL_DIR_CHILD_MAP, /* ZAP */ DMU_OT_DSL_DS_SNAP_MAP, /* ZAP */ DMU_OT_DSL_PROPS, /* ZAP */ DMU_OT_DSL_DATASET, /* UINT64 */ /* zpl: */ DMU_OT_ZNODE, /* ZNODE */ DMU_OT_OLDACL, /* Old ACL */ DMU_OT_PLAIN_FILE_CONTENTS, /* UINT8 */ DMU_OT_DIRECTORY_CONTENTS, /* ZAP */ DMU_OT_MASTER_NODE, /* ZAP */ DMU_OT_UNLINKED_SET, /* ZAP */ /* zvol: */ DMU_OT_ZVOL, /* UINT8 */ DMU_OT_ZVOL_PROP, /* ZAP */ /* other; for testing only! */ DMU_OT_PLAIN_OTHER, /* UINT8 */ DMU_OT_UINT64_OTHER, /* UINT64 */ DMU_OT_ZAP_OTHER, /* ZAP */ /* new object types: */ DMU_OT_ERROR_LOG, /* ZAP */ DMU_OT_SPA_HISTORY, /* UINT8 */ DMU_OT_SPA_HISTORY_OFFSETS, /* spa_his_phys_t */ DMU_OT_POOL_PROPS, /* ZAP */ DMU_OT_DSL_PERMS, /* ZAP */ DMU_OT_ACL, /* ACL */ DMU_OT_SYSACL, /* SYSACL */ DMU_OT_FUID, /* FUID table (Packed NVLIST UINT8) */ DMU_OT_FUID_SIZE, /* FUID table size UINT64 */ DMU_OT_NEXT_CLONES, /* ZAP */ DMU_OT_SCAN_QUEUE, /* ZAP */ DMU_OT_USERGROUP_USED, /* ZAP */ DMU_OT_USERGROUP_QUOTA, /* ZAP */ DMU_OT_USERREFS, /* ZAP */ DMU_OT_DDT_ZAP, /* ZAP */ DMU_OT_DDT_STATS, /* ZAP */ DMU_OT_SA, /* System attr */ DMU_OT_SA_MASTER_NODE, /* ZAP */ DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */ DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */ DMU_OT_SCAN_XLATE, /* ZAP */ DMU_OT_DEDUP, /* fake dedup BP from ddt_bp_create() */ DMU_OT_DEADLIST, /* ZAP */ DMU_OT_DEADLIST_HDR, /* UINT64 */ DMU_OT_DSL_CLONES, /* ZAP */ DMU_OT_BPOBJ_SUBOBJ, /* UINT64 */ /* * Do not allocate new object types here. Doing so makes the on-disk * format incompatible with any other format that uses the same object * type number. * * When creating an object which does not have one of the above types * use the DMU_OTN_* type with the correct byteswap and metadata * values. * * The DMU_OTN_* types do not have entries in the dmu_ot table, * use the DMU_OT_IS_METDATA() and DMU_OT_BYTESWAP() macros instead * of indexing into dmu_ot directly (this works for both DMU_OT_* types * and DMU_OTN_* types). */ DMU_OT_NUMTYPES, /* * Names for valid types declared with DMU_OT(). */ DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE), DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE), DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE), DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE), DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE), DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE), DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE), DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE), DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE), DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE), } dmu_object_type_t; 

The zio_checksum and zio_compress listings are shown below.

 enum zio_checksum { ZIO_CHECKSUM_INHERIT = 0, ZIO_CHECKSUM_ON, ZIO_CHECKSUM_OFF, ZIO_CHECKSUM_LABEL, ZIO_CHECKSUM_GANG_HEADER, ZIO_CHECKSUM_ZILOG, ZIO_CHECKSUM_FLETCHER_2, ZIO_CHECKSUM_FLETCHER_4, ZIO_CHECKSUM_SHA256, ZIO_CHECKSUM_ZILOG2, ZIO_CHECKSUM_FUNCTIONS }; 

 enum zio_compress { ZIO_COMPRESS_INHERIT = 0, ZIO_COMPRESS_ON, ZIO_COMPRESS_OFF, ZIO_COMPRESS_LZJB, ZIO_COMPRESS_EMPTY, ZIO_COMPRESS_GZIP_1, ZIO_COMPRESS_GZIP_2, ZIO_COMPRESS_GZIP_3, ZIO_COMPRESS_GZIP_4, ZIO_COMPRESS_GZIP_5, ZIO_COMPRESS_GZIP_6, ZIO_COMPRESS_GZIP_7, ZIO_COMPRESS_GZIP_8, ZIO_COMPRESS_GZIP_9, ZIO_COMPRESS_ZLE, ZIO_COMPRESS_LZ4, ZIO_COMPRESS_FUNCTIONS }; 

Object (dnode)


Excluding uberblock, all other entities (metadata and user data) are represented as objects. The dmu_object_type enumeration lists the possible types of objects.

The object is described by the dnode_phys structure presented below:

 typedef struct dnode_phys { uint8_t dn_type; /* dmu_object_type_t */ uint8_t dn_indblkshift; /* ln2(indirect block size) */ uint8_t dn_nlevels; /* 1=dn_blkptr->data blocks */ uint8_t dn_nblkptr; /* length of dn_blkptr */ uint8_t dn_bonustype; /* type of data in bonus buffer */ uint8_t dn_checksum; /* ZIO_CHECKSUM type */ uint8_t dn_compress; /* ZIO_COMPRESS type */ uint8_t dn_flags; /* DNODE_FLAG_* */ uint16_t dn_datablkszsec; /* data block size in 512b sectors */ uint16_t dn_bonuslen; /* length of dn_bonus */ uint8_t dn_pad2[4]; /* accounting is protected by dn_dirty_mtx */ uint64_t dn_maxblkid; /* largest allocated block ID */ uint64_t dn_used; /* bytes (or sectors) of disk space */ uint64_t dn_pad3[4]; union { blkptr_t dn_blkptr[1+DN_MAX_BONUSLEN/sizeof (blkptr_t)]; struct { blkptr_t __dn_ignore1; uint8_t dn_bonus[DN_MAX_BONUSLEN]; }; struct { blkptr_t __dn_ignore2; uint8_t __dn_ignore3[DN_MAX_BONUSLEN-sizeof (blkptr_t)]; blkptr_t dn_spill; }; }; } dnode_phys_t; typedef struct zil_header { uint64_t zh_claim_txg; /* txg in which log blocks were claimed */ uint64_t zh_replay_seq; /* highest replayed sequence number */ blkptr_t zh_log; /* log chain */ uint64_t zh_claim_blk_seq; /* highest claimed block sequence number */ uint64_t zh_flags; /* header flags */ uint64_t zh_claim_lr_seq; /* highest claimed lr sequence number */ uint64_t zh_pad[3]; } zil_header_t; 

Set of objects


Zfs objects can be grouped into so-called object sets (objset), and are represented by the following types:

 typedef enum dmu_objset_type { DMU_OST_NONE, DMU_OST_META, /* MOS */ DMU_OST_ZFS, /* Dataset DMU_OST_ZVOL, /*   zfs (vol) DMU_OST_OTHER, /* For testing only! */ DMU_OST_ANY, /* Be careful! */ DMU_OST_NUMTYPES } dmu_objset_type_t; 

The set of objects itself is represented by such a 2-kilobyte structure:
 typedef struct objset_phys { dnode_phys_t os_meta_dnode; zil_header_t os_zil_header; uint64_t os_type; uint64_t os_flags; char os_pad[OBJSET_PHYS_SIZE - sizeof (dnode_phys_t)*3 - sizeof (zil_header_t) - sizeof (uint64_t)*2]; dnode_phys_t os_userused_dnode; dnode_phys_t os_groupused_dnode; } objset_phys_t; 

We look at bytes


In this article we will use a test pool based on a 101-megabyte file.
Why just 101 MB? The fact is that zfs breaks up free space (minus 4x 256KB tags and 3.5 megabyte boot-block) into fixed blocks (see How ZFS works - part 1: vdev ). For a 100MB disk, the block size is 16MB and for a 100MB disk such blocks fit only 5 and the available capacity will be 80Mb. But for 101MB of such blocks 6 are already accommodated and the available volume increases to 96MB. Although this article is not so important. But for example, for a 4Tb disk, if you completely give it to zfs, then we get a “lost” space larger than 13GB.

The 3725 “binary” GBs are divided into blocks of 16GB each, and the remainder of 13GB is not used.

Create a test pool


# dd if=/dev/zero of=/tmp/test_disk bs=1M count=101
101+0
101+0
105906176 (106 MB, 101 MiB) , 0,0847695 s, 1,2 GB/s

#zpool create test -o ashift=9 /tmp/test_disk

Set recordsize to 512 bytes and add a couple of files.

# zfs set recordsize=512 test

# dd if=/dev/urandom of=/test/0B bs=1 count=0
0+0
0+0
0 , 0,000171206 s, 0,0 kB/s
# dd if=/dev/urandom of=/test/512B bs=512 count=1
1+0
1+0
512 , 0,000215428 s, 2,4 MB/s
# dd if=/dev/urandom of=/test/513B bs=513 count=1
1+0
1+0
513 , 0,00022484 s, 2,3 MB/s


Let's see how much space files occupy on disk.

# du -a --block-size=1
1024 ./512B
512 ./0B
2560 ./513B

From the interesting thing, it is striking that a zero-size file is 512 bytes (compare with ext3 where it has a size of zero bytes). A file of 513 bytes in size does not occupy 1,536 bytes but as much as 2,560 bytes, although it would seem that the recordsize plus the service information would have taken the place equal to twice the size. Let's see why this happens.

Find the active uberblock


To access the raw data, we will use the radare2 utility.
Sort by transaction number.

# r2 /tmp/test_disk
[0x00000000]> pf q @@s:0x20010 0x40000 0x400|sort -k2
0x00020010 = (qword)0x0000000000000000
…
0x00028010 = (qword)0x0000000000000020
0x00028810 = (qword)0x0000000000000022
0x00028c10 = (qword)0x0000000000000023
0x0002e010 = (qword)0x0000000000000038

The active uberblock is located at 0x0002e000 (we subtract 16 bytes from the found offset 0x0002e010).

Read uberblock completely
[0x0003fc10]> 0x0002e000
[0x0002e000]> pf qqqqt:[128].q ub_magic ub_version ub_txg ub_guid_sum ub_timestamp ub_software_version
ub_magic : 0x0002e000 = (qword)0x0000000000bab10c
ub_version : 0x0002e008 = (qword)0x0000000000001388
ub_txg : 0x0002e010 = (qword)0x0000000000000038
ub_guid_sum : 0x0002e018 = (qword)0x667c11fc34e97151
ub_timestamp : 0x0002e020 = Wed Jan 31 07:29:56 2018
ub_software_version : 0x0002e0a8 = (qword)0x0000000000001388


We get ub_rootbp
[0x0002e000]> s+0x28
[0x0002e028]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x0002e028 = (qword)[ 0x0000000000000001, 0x00000000000000ab ]
blk_dva_1 : 0x0002e038 = (qword)[ 0x0000000000000001, 0x00000000000000bc ]
blk_dva_2 : 0x0002e048 = (qword)[ 0x0000000000000001, 0x00000000000000bd ]
blk_prop : 0x0002e058 = (qword)0x800b070f00000003
blk_pad[2] : 0x0002e060 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x0002e070 = (qword)0x0000000000000000
blk_birth : 0x0002e078 = (qword)0x0000000000000038
blk_fill : 0x0002e080 = (qword)0x0000000000000023
blk_cksum : 0x0002e088 = (qword)[ 0x0000000d43174e30, 0x00000513bae6359f, 0x0000ff222817dfe3, 0x00223eedae162ece ]

To parse blkptr parameters (blk_prop) I use MS Excell

image

Judging by the comp (= 15) value, the block is compressed by lz4 and occupies 512 bytes on the disk (PSIZE indicates the number of sectors) and after unpacking it should become 2048 bytes (LSIZE).

Save block to file
Calculate the offset from the beginning of the disc. To do this, the value of the blk_dva [0] .dva_word [1] field (= 0x00000000000000ab) from the blkptr structure is multiplied by 512 (sector size) and add 0x400000 (4MB - L0, L1 tags and the boot block). The result is divided into 512 (we work in blocks of 512 bytes).

[0x0002e028]> ?v 0x00000000000000ab<9+0x400000
0x415600
[0x0002e028]> ? 0x415600/512
8363 0x20ab 020253 8.2K 0000:00ab 8363 "\xab " 0b0010000010101011 8363.0 8363.000000f 8363.000000 0t102110202

# dd if=/tmp/test_disk bs=512 skip=8363 count=1 of=/tmp/mos.objset.bin.lz4


For unpacking use a small program (source at the end of the article).

# zdec mos.objset.bin.lz4 mos.objset.bin 2048
Input: mos.objset.bin.lz4
Output: mos.objset.bin
Out size: 2048
-----------------------------
Input size: 512
Real input size: 187
Decompress result: 0


Let's see what is stored in the MOS object.

# r2 mos.objset.bin
[0x00000000]> pf [512].[192].qq[304].[512].[512]. os_type os_flags
os_type : 0x000002c0 = (qword)0x0000000000000001
os_flags : 0x000002c8 = (qword)0x0000000000000000
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x0a
dn_indblkshift : 0x00000001 = 0x0e
dn_nlevels : 0x00000002 = 0x01
dn_nblkptr : 0x00000003 = 0x03
dn_bonustype : 0x00000004 = 0x00
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x01
dn_datablkszsec : 0x00000008 = 0x0020
dn_bonuslen : 0x0000000a = 0x0000
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000001
dn_used : 0x00000018 = (qword)0x0000000000001e00
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Read the blkptr array (the beginning of the array with offset + 0x40). Blkptr structure size 128 bytes (offset + 0x80)

[0x00000000]> s+0x40
[0x00000040]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000040 = (qword)[ 0x0000000000000004, 0x00000000000000fd ]
blk_dva_1 : 0x00000050 = (qword)[ 0x0000000000000004, 0x0000000000000014 ]
blk_dva_2 : 0x00000060 = (qword)[ 0x0000000000000004, 0x0000000000000018 ]
blk_prop : 0x00000070 = (qword)0x800a070f0003001f
blk_pad[2] : 0x00000078 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000088 = (qword)0x0000000000000000
blk_birth : 0x00000090 = (qword)0x0000000000000038
blk_fill : 0x00000098 = (qword)0x000000000000001f
blk_cksum : 0x000000a0 = (qword)[ 0x0000005b728c5143, 0x00006add456a9057, 0x0046f84e9ebc9fc1, 0x227baf4ccb8d8253 ]
[0x00000040]> s+0x80
[0x000000c0]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x000000c0 = (qword)[ 0x0000000000000001, 0x00000000000000c7 ]
blk_dva_1 : 0x000000d0 = (qword)[ 0x0000000000000001, 0x00000000000000c8 ]
blk_dva_2 : 0x000000e0 = (qword)[ 0x0000000000000001, 0x00000000000000f9 ]
blk_prop : 0x000000f0 = (qword)0x800a070f0000001f
blk_pad[2] : 0x000000f8 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000108 = (qword)0x0000000000000000
blk_birth : 0x00000110 = (qword)0x0000000000000038
blk_fill : 0x00000118 = (qword)0x0000000000000004
blk_cksum : 0x00000120 = (qword)[ 0x000000212e3f6320, 0x000007421d158d58, 0x00012cb9dd4a54c3, 0x0026ea30b4caddc5 ]
[0x000000c0]> s+0x80
[0x00000140]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000140 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00000150 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00000160 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000170 = (qword)0x0000000000000000
blk_pad[2] : 0x00000178 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000188 = (qword)0x0000000000000000
blk_birth : 0x00000190 = (qword)0x0000000000000000
blk_fill : 0x00000198 = (qword)0x0000000000000000
blk_cksum : 0x000001a0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

image

The blocks are compressed with the lz4 algorithm and are 2048 bytes in size and 512 bytes, respectively (and the actual size is 16384 bytes).

Save to file and unpack
# dd if=/tmp/test_disk bs=512 skip=8445 count=4 of=/tmp/dsl.dnode.0.bin.lz4
# dd if=/tmp/test_disk bs=512 skip=8391 count=1 of=/tmp/dsl.dnode.1.bin.lz4
# zdec dsl.dnode.0.bin.lz4 dsl.dnode.0.bin 16384
Input: dsl.dnode.0.bin.lz4
Output: dsl.dnode.0.bin
Out size: 16384
-----------------------------
Input size: 2048
Real input size: 1589
Decompress result: 0
# zdec dsl.dnode.1.bin.lz4 dsl.dnode.1.bin 16384
Input: dsl.dnode.1.bin.lz4
Output: dsl.dnode.1.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 464
Decompress result: 0

Make a list of objects

31 objects
# r2 dsl.dnode.0.bin
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x00
dn_indblkshift : 0x00000001 = 0x00
dn_nlevels : 0x00000002 = 0x00
dn_nblkptr : 0x00000003 = 0x00
dn_bonustype : 0x00000004 = 0x00
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x00
dn_datablkszsec : 0x00000008 = 0x0000
dn_bonuslen : 0x0000000a = 0x0000
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000000
dn_used : 0x00000018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000000]> s+0x200
[0x00000200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000200 = 0x01
dn_indblkshift : 0x00000201 = 0x0e
dn_nlevels : 0x00000202 = 0x01
dn_nblkptr : 0x00000203 = 0x03
dn_bonustype : 0x00000204 = 0x00
dn_checksum : 0x00000205 = 0x00
dn_compress : 0x00000206 = 0x00
dn_flags : 0x00000207 = 0x01
dn_datablkszsec : 0x00000208 = 0x0002
dn_bonuslen : 0x0000020a = 0x0000
dn_pad2[4] : 0x0000020c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000210 = (qword)0x0000000000000000
dn_used : 0x00000218 = (qword)0x0000000000000600
dn_pad3[4] : 0x00000220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000200]> s+0x200
[0x00000400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000400 = 0x0c
dn_indblkshift : 0x00000401 = 0x0e
dn_nlevels : 0x00000402 = 0x01
dn_nblkptr : 0x00000403 = 0x01
dn_bonustype : 0x00000404 = 0x0c
dn_checksum : 0x00000405 = 0x00
dn_compress : 0x00000406 = 0x00
dn_flags : 0x00000407 = 0x00
dn_datablkszsec : 0x00000408 = 0x0001
dn_bonuslen : 0x0000040a = 0x0100
dn_pad2[4] : 0x0000040c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000410 = (qword)0x0000000000000000
dn_used : 0x00000418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000400]> s+0x200
[0x00000600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000600 = 0x0f
dn_indblkshift : 0x00000601 = 0x0e
dn_nlevels : 0x00000602 = 0x01
dn_nblkptr : 0x00000603 = 0x03
dn_bonustype : 0x00000604 = 0x00
dn_checksum : 0x00000605 = 0x00
dn_compress : 0x00000606 = 0x00
dn_flags : 0x00000607 = 0x01
dn_datablkszsec : 0x00000608 = 0x0001
dn_bonuslen : 0x0000060a = 0x0000
dn_pad2[4] : 0x0000060c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000610 = (qword)0x0000000000000000
dn_used : 0x00000618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000600]> s+0x200
[0x00000800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000800 = 0x0d
dn_indblkshift : 0x00000801 = 0x0e
dn_nlevels : 0x00000802 = 0x01
dn_nblkptr : 0x00000803 = 0x03
dn_bonustype : 0x00000804 = 0x00
dn_checksum : 0x00000805 = 0x00
dn_compress : 0x00000806 = 0x00
dn_flags : 0x00000807 = 0x01
dn_datablkszsec : 0x00000808 = 0x0001
dn_bonuslen : 0x0000080a = 0x0000
dn_pad2[4] : 0x0000080c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000810 = (qword)0x0000000000000000
dn_used : 0x00000818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000800]> s+0x200
[0x00000a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000a00 = 0x0c
dn_indblkshift : 0x00000a01 = 0x0e
dn_nlevels : 0x00000a02 = 0x01
dn_nblkptr : 0x00000a03 = 0x01
dn_bonustype : 0x00000a04 = 0x0c
dn_checksum : 0x00000a05 = 0x00
dn_compress : 0x00000a06 = 0x00
dn_flags : 0x00000a07 = 0x00
dn_datablkszsec : 0x00000a08 = 0x0001
dn_bonuslen : 0x00000a0a = 0x0100
dn_pad2[4] : 0x00000a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000a10 = (qword)0x0000000000000000
dn_used : 0x00000a18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000a00]> s+0x200
[0x00000c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000c00 = 0x0f
dn_indblkshift : 0x00000c01 = 0x0e
dn_nlevels : 0x00000c02 = 0x01
dn_nblkptr : 0x00000c03 = 0x03
dn_bonustype : 0x00000c04 = 0x00
dn_checksum : 0x00000c05 = 0x00
dn_compress : 0x00000c06 = 0x00
dn_flags : 0x00000c07 = 0x01
dn_datablkszsec : 0x00000c08 = 0x0001
dn_bonuslen : 0x00000c0a = 0x0000
dn_pad2[4] : 0x00000c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000c10 = (qword)0x0000000000000000
dn_used : 0x00000c18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000c00]> s+0x200
[0x00000e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000e00 = 0x0d
dn_indblkshift : 0x00000e01 = 0x0e
dn_nlevels : 0x00000e02 = 0x01
dn_nblkptr : 0x00000e03 = 0x03
dn_bonustype : 0x00000e04 = 0x00
dn_checksum : 0x00000e05 = 0x00
dn_compress : 0x00000e06 = 0x00
dn_flags : 0x00000e07 = 0x01
dn_datablkszsec : 0x00000e08 = 0x0001
dn_bonuslen : 0x00000e0a = 0x0000
dn_pad2[4] : 0x00000e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000e10 = (qword)0x0000000000000000
dn_used : 0x00000e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000e00]> s+0x200
[0x00001000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001000 = 0x0c
dn_indblkshift : 0x00001001 = 0x0e
dn_nlevels : 0x00001002 = 0x01
dn_nblkptr : 0x00001003 = 0x01
dn_bonustype : 0x00001004 = 0x0c
dn_checksum : 0x00001005 = 0x00
dn_compress : 0x00001006 = 0x00
dn_flags : 0x00001007 = 0x00
dn_datablkszsec : 0x00001008 = 0x0001
dn_bonuslen : 0x0000100a = 0x0100
dn_pad2[4] : 0x0000100c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001010 = (qword)0x0000000000000000
dn_used : 0x00001018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001000]> s+0x200
[0x00001200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001200 = 0x0f
dn_indblkshift : 0x00001201 = 0x0e
dn_nlevels : 0x00001202 = 0x01
dn_nblkptr : 0x00001203 = 0x03
dn_bonustype : 0x00001204 = 0x00
dn_checksum : 0x00001205 = 0x00
dn_compress : 0x00001206 = 0x00
dn_flags : 0x00001207 = 0x01
dn_datablkszsec : 0x00001208 = 0x0001
dn_bonuslen : 0x0000120a = 0x0000
dn_pad2[4] : 0x0000120c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001210 = (qword)0x0000000000000000
dn_used : 0x00001218 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001200]> s+0x200
[0x00001400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001400 = 0x0d
dn_indblkshift : 0x00001401 = 0x0e
dn_nlevels : 0x00001402 = 0x01
dn_nblkptr : 0x00001403 = 0x03
dn_bonustype : 0x00001404 = 0x00
dn_checksum : 0x00001405 = 0x00
dn_compress : 0x00001406 = 0x00
dn_flags : 0x00001407 = 0x01
dn_datablkszsec : 0x00001408 = 0x0001
dn_bonuslen : 0x0000140a = 0x0000
dn_pad2[4] : 0x0000140c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001410 = (qword)0x0000000000000000
dn_used : 0x00001418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001400]> s+0x200
[0x00001600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001600 = 0x05
dn_indblkshift : 0x00001601 = 0x0e
dn_nlevels : 0x00001602 = 0x01
dn_nblkptr : 0x00001603 = 0x03
dn_bonustype : 0x00001604 = 0x06
dn_checksum : 0x00001605 = 0x00
dn_compress : 0x00001606 = 0x00
dn_flags : 0x00001607 = 0x00
dn_datablkszsec : 0x00001608 = 0x0100
dn_bonuslen : 0x0000160a = 0x0030
dn_pad2[4] : 0x0000160c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001610 = (qword)0x0000000000000000
dn_used : 0x00001618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001600]> s+0x200
[0x00001800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001800 = 0x0c
dn_indblkshift : 0x00001801 = 0x0e
dn_nlevels : 0x00001802 = 0x01
dn_nblkptr : 0x00001803 = 0x01
dn_bonustype : 0x00001804 = 0x0c
dn_checksum : 0x00001805 = 0x00
dn_compress : 0x00001806 = 0x00
dn_flags : 0x00001807 = 0x00
dn_datablkszsec : 0x00001808 = 0x0001
dn_bonuslen : 0x0000180a = 0x0100
dn_pad2[4] : 0x0000180c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001810 = (qword)0x0000000000000000
dn_used : 0x00001818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001800]> s+0x200
[0x00001a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001a00 = 0x0f
dn_indblkshift : 0x00001a01 = 0x0e
dn_nlevels : 0x00001a02 = 0x01
dn_nblkptr : 0x00001a03 = 0x03
dn_bonustype : 0x00001a04 = 0x00
dn_checksum : 0x00001a05 = 0x00
dn_compress : 0x00001a06 = 0x00
dn_flags : 0x00001a07 = 0x01
dn_datablkszsec : 0x00001a08 = 0x0001
dn_bonuslen : 0x00001a0a = 0x0000
dn_pad2[4] : 0x00001a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001a10 = (qword)0x0000000000000000
dn_used : 0x00001a18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001a00]> s+0x200
[0x00001c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001c00 = 0x0d
dn_indblkshift : 0x00001c01 = 0x0e
dn_nlevels : 0x00001c02 = 0x01
dn_nblkptr : 0x00001c03 = 0x03
dn_bonustype : 0x00001c04 = 0x00
dn_checksum : 0x00001c05 = 0x00
dn_compress : 0x00001c06 = 0x00
dn_flags : 0x00001c07 = 0x01
dn_datablkszsec : 0x00001c08 = 0x0001
dn_bonuslen : 0x00001c0a = 0x0000
dn_pad2[4] : 0x00001c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001c10 = (qword)0x0000000000000000
dn_used : 0x00001c18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001c00]> s+0x200
[0x00001e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001e00 = 0x10
dn_indblkshift : 0x00001e01 = 0x0e
dn_nlevels : 0x00001e02 = 0x01
dn_nblkptr : 0x00001e03 = 0x01
dn_bonustype : 0x00001e04 = 0x10
dn_checksum : 0x00001e05 = 0x00
dn_compress : 0x00001e06 = 0x00
dn_flags : 0x00001e07 = 0x00
dn_datablkszsec : 0x00001e08 = 0x0001
dn_bonuslen : 0x00001e0a = 0x0140
dn_pad2[4] : 0x00001e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001e10 = (qword)0x0000000000000000
dn_used : 0x00001e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00001e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001e00]> s+0x200
[0x00002000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002000 = 0x0e
dn_indblkshift : 0x00002001 = 0x0e
dn_nlevels : 0x00002002 = 0x01
dn_nblkptr : 0x00002003 = 0x03
dn_bonustype : 0x00002004 = 0x00
dn_checksum : 0x00002005 = 0x00
dn_compress : 0x00002006 = 0x00
dn_flags : 0x00002007 = 0x01
dn_datablkszsec : 0x00002008 = 0x0001
dn_bonuslen : 0x0000200a = 0x0000
dn_pad2[4] : 0x0000200c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002010 = (qword)0x0000000000000000
dn_used : 0x00002018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002000]> s+0x200
[0x00002200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002200 = 0x32
dn_indblkshift : 0x00002201 = 0x0e
dn_nlevels : 0x00002202 = 0x01
dn_nblkptr : 0x00002203 = 0x01
dn_bonustype : 0x00002204 = 0x33
dn_checksum : 0x00002205 = 0x00
dn_compress : 0x00002206 = 0x00
dn_flags : 0x00002207 = 0x01
dn_datablkszsec : 0x00002208 = 0x0001
dn_bonuslen : 0x0000220a = 0x0140
dn_pad2[4] : 0x0000220c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002210 = (qword)0x0000000000000000
dn_used : 0x00002218 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002200]> s+0x200
[0x00002400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002400 = 0x10
dn_indblkshift : 0x00002401 = 0x0e
dn_nlevels : 0x00002402 = 0x01
dn_nblkptr : 0x00002403 = 0x01
dn_bonustype : 0x00002404 = 0x10
dn_checksum : 0x00002405 = 0x00
dn_compress : 0x00002406 = 0x00
dn_flags : 0x00002407 = 0x00
dn_datablkszsec : 0x00002408 = 0x0001
dn_bonuslen : 0x0000240a = 0x0140
dn_pad2[4] : 0x0000240c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002410 = (qword)0x0000000000000000
dn_used : 0x00002418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002400]> s+0x200
[0x00002600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002600 = 0x32
dn_indblkshift : 0x00002601 = 0x0e
dn_nlevels : 0x00002602 = 0x01
dn_nblkptr : 0x00002603 = 0x01
dn_bonustype : 0x00002604 = 0x33
dn_checksum : 0x00002605 = 0x00
dn_compress : 0x00002606 = 0x00
dn_flags : 0x00002607 = 0x01
dn_datablkszsec : 0x00002608 = 0x0001
dn_bonuslen : 0x0000260a = 0x0140
dn_pad2[4] : 0x0000260c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002610 = (qword)0x0000000000000000
dn_used : 0x00002618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002600]> s+0x200
[0x00002800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002800 = 0x05
dn_indblkshift : 0x00002801 = 0x0e
dn_nlevels : 0x00002802 = 0x01
dn_nblkptr : 0x00002803 = 0x03
dn_bonustype : 0x00002804 = 0x06
dn_checksum : 0x00002805 = 0x00
dn_compress : 0x00002806 = 0x00
dn_flags : 0x00002807 = 0x00
dn_datablkszsec : 0x00002808 = 0x0100
dn_bonuslen : 0x0000280a = 0x0030
dn_pad2[4] : 0x0000280c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002810 = (qword)0x0000000000000000
dn_used : 0x00002818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002800]> s+0x200
[0x00002a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002a00 = 0x10
dn_indblkshift : 0x00002a01 = 0x0e
dn_nlevels : 0x00002a02 = 0x01
dn_nblkptr : 0x00002a03 = 0x01
dn_bonustype : 0x00002a04 = 0x10
dn_checksum : 0x00002a05 = 0x00
dn_compress : 0x00002a06 = 0x00
dn_flags : 0x00002a07 = 0x00
dn_datablkszsec : 0x00002a08 = 0x0001
dn_bonuslen : 0x00002a0a = 0x0140
dn_pad2[4] : 0x00002a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002a10 = (qword)0x0000000000000000
dn_used : 0x00002a18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002a00]> s+0x200
[0x00002c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002c00 = 0x0e
dn_indblkshift : 0x00002c01 = 0x0e
dn_nlevels : 0x00002c02 = 0x01
dn_nblkptr : 0x00002c03 = 0x03
dn_bonustype : 0x00002c04 = 0x00
dn_checksum : 0x00002c05 = 0x00
dn_compress : 0x00002c06 = 0x00
dn_flags : 0x00002c07 = 0x01
dn_datablkszsec : 0x00002c08 = 0x0001
dn_bonuslen : 0x00002c0a = 0x0000
dn_pad2[4] : 0x00002c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002c10 = (qword)0x0000000000000000
dn_used : 0x00002c18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002c00]> s+0x200
[0x00002e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00002e00 = 0x32
dn_indblkshift : 0x00002e01 = 0x0e
dn_nlevels : 0x00002e02 = 0x01
dn_nblkptr : 0x00002e03 = 0x01
dn_bonustype : 0x00002e04 = 0x33
dn_checksum : 0x00002e05 = 0x00
dn_compress : 0x00002e06 = 0x00
dn_flags : 0x00002e07 = 0x01
dn_datablkszsec : 0x00002e08 = 0x0001
dn_bonuslen : 0x00002e0a = 0x0140
dn_pad2[4] : 0x00002e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00002e10 = (qword)0x0000000000000000
dn_used : 0x00002e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00002e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00002e00]> s+0x200
[0x00003000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003000 = 0x05
dn_indblkshift : 0x00003001 = 0x0e
dn_nlevels : 0x00003002 = 0x01
dn_nblkptr : 0x00003003 = 0x03
dn_bonustype : 0x00003004 = 0x06
dn_checksum : 0x00003005 = 0x00
dn_compress : 0x00003006 = 0x00
dn_flags : 0x00003007 = 0x00
dn_datablkszsec : 0x00003008 = 0x0100
dn_bonuslen : 0x0000300a = 0x0030
dn_pad2[4] : 0x0000300c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003010 = (qword)0x0000000000000000
dn_used : 0x00003018 = (qword)0x0000000000000000
dn_pad3[4] : 0x00003020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003000]> s+0x200
[0x00003200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003200 = 0x25
dn_indblkshift : 0x00003201 = 0x0e
dn_nlevels : 0x00003202 = 0x01
dn_nblkptr : 0x00003203 = 0x03
dn_bonustype : 0x00003204 = 0x00
dn_checksum : 0x00003205 = 0x00
dn_compress : 0x00003206 = 0x00
dn_flags : 0x00003207 = 0x01
dn_datablkszsec : 0x00003208 = 0x0001
dn_bonuslen : 0x0000320a = 0x0000
dn_pad2[4] : 0x0000320c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003210 = (qword)0x0000000000000000
dn_used : 0x00003218 = (qword)0x0000000000000000
dn_pad3[4] : 0x00003220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003200]> s+0x200
[0x00003400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003400 = 0x34
dn_indblkshift : 0x00003401 = 0x0e
dn_nlevels : 0x00003402 = 0x01
dn_nblkptr : 0x00003403 = 0x03
dn_bonustype : 0x00003404 = 0x00
dn_checksum : 0x00003405 = 0x00
dn_compress : 0x00003406 = 0x00
dn_flags : 0x00003407 = 0x01
dn_datablkszsec : 0x00003408 = 0x0001
dn_bonuslen : 0x0000340a = 0x0000
dn_pad2[4] : 0x0000340c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003410 = (qword)0x0000000000000000
dn_used : 0x00003418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00003420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003400]> s+0x200
[0x00003600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003600 = 0x03
dn_indblkshift : 0x00003601 = 0x0e
dn_nlevels : 0x00003602 = 0x01
dn_nblkptr : 0x00003603 = 0x03
dn_bonustype : 0x00003604 = 0x04
dn_checksum : 0x00003605 = 0x00
dn_compress : 0x00003606 = 0x00
dn_flags : 0x00003607 = 0x01
dn_datablkszsec : 0x00003608 = 0x0020
dn_bonuslen : 0x0000360a = 0x0008
dn_pad2[4] : 0x0000360c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003610 = (qword)0x0000000000000000
dn_used : 0x00003618 = (qword)0x0000000000000c00
dn_pad3[4] : 0x00003620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003600]> s+0x200
[0x00003800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003800 = 0xc4
dn_indblkshift : 0x00003801 = 0x0e
dn_nlevels : 0x00003802 = 0x01
dn_nblkptr : 0x00003803 = 0x03
dn_bonustype : 0x00003804 = 0x00
dn_checksum : 0x00003805 = 0x00
dn_compress : 0x00003806 = 0x00
dn_flags : 0x00003807 = 0x01
dn_datablkszsec : 0x00003808 = 0x0001
dn_bonuslen : 0x0000380a = 0x0000
dn_pad2[4] : 0x0000380c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003810 = (qword)0x0000000000000000
dn_used : 0x00003818 = (qword)0x0000000000000600
dn_pad3[4] : 0x00003820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003800]> s+0x200
[0x00003a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003a00 = 0xc4
dn_indblkshift : 0x00003a01 = 0x0e
dn_nlevels : 0x00003a02 = 0x01
dn_nblkptr : 0x00003a03 = 0x03
dn_bonustype : 0x00003a04 = 0x00
dn_checksum : 0x00003a05 = 0x00
dn_compress : 0x00003a06 = 0x00
dn_flags : 0x00003a07 = 0x01
dn_datablkszsec : 0x00003a08 = 0x0001
dn_bonuslen : 0x00003a0a = 0x0000
dn_pad2[4] : 0x00003a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003a10 = (qword)0x0000000000000000
dn_used : 0x00003a18 = (qword)0x0000000000000600
dn_pad3[4] : 0x00003a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003a00]> s+0x200
[0x00003c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003c00 = 0xc4
dn_indblkshift : 0x00003c01 = 0x0e
dn_nlevels : 0x00003c02 = 0x01
dn_nblkptr : 0x00003c03 = 0x03
dn_bonustype : 0x00003c04 = 0x00
dn_checksum : 0x00003c05 = 0x00
dn_compress : 0x00003c06 = 0x00
dn_flags : 0x00003c07 = 0x01
dn_datablkszsec : 0x00003c08 = 0x0020
dn_bonuslen : 0x00003c0a = 0x0000
dn_pad2[4] : 0x00003c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003c10 = (qword)0x0000000000000001
dn_used : 0x00003c18 = (qword)0x0000000000003600
dn_pad3[4] : 0x00003c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00003c00]> s+0x200
[0x00003e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00003e00 = 0x05
dn_indblkshift : 0x00003e01 = 0x0e
dn_nlevels : 0x00003e02 = 0x01
dn_nblkptr : 0x00003e03 = 0x03
dn_bonustype : 0x00003e04 = 0x06
dn_checksum : 0x00003e05 = 0x00
dn_compress : 0x00003e06 = 0x02
dn_flags : 0x00003e07 = 0x01
dn_datablkszsec : 0x00003e08 = 0x0020
dn_bonuslen : 0x00003e0a = 0x0030
dn_pad2[4] : 0x00003e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00003e10 = (qword)0x0000000000000000
dn_used : 0x00003e18 = (qword)0x0000000000000600
dn_pad3[4] : 0x00003e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]


4 objects
# r2 dsl.dnode.1.bin
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x1d
dn_indblkshift : 0x00000001 = 0x0e
dn_nlevels : 0x00000002 = 0x01
dn_nblkptr : 0x00000003 = 0x03
dn_bonustype : 0x00000004 = 0x1e
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x01
dn_datablkszsec : 0x00000008 = 0x0100
dn_bonuslen : 0x0000000a = 0x0028
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000000
dn_used : 0x00000018 = (qword)0x0000000000001200
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000000]> s+0x200
[0x00000200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000200 = 0xc4
dn_indblkshift : 0x00000201 = 0x0e
dn_nlevels : 0x00000202 = 0x01
dn_nblkptr : 0x00000203 = 0x03
dn_bonustype : 0x00000204 = 0x00
dn_checksum : 0x00000205 = 0x00
dn_compress : 0x00000206 = 0x00
dn_flags : 0x00000207 = 0x01
dn_datablkszsec : 0x00000208 = 0x0001
dn_bonuslen : 0x0000020a = 0x0000
dn_pad2[4] : 0x0000020c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000210 = (qword)0x0000000000000000
dn_used : 0x00000218 = (qword)0x0000000000000600
dn_pad3[4] : 0x00000220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000200]> s+0x200
[0x00000400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000400 = 0x02
dn_indblkshift : 0x00000401 = 0x0e
dn_nlevels : 0x00000402 = 0x01
dn_nblkptr : 0x00000403 = 0x03
dn_bonustype : 0x00000404 = 0x00
dn_checksum : 0x00000405 = 0x00
dn_compress : 0x00000406 = 0x00
dn_flags : 0x00000407 = 0x01
dn_datablkszsec : 0x00000408 = 0x0001
dn_bonuslen : 0x0000040a = 0x0000
dn_pad2[4] : 0x0000040c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000410 = (qword)0x0000000000000000
dn_used : 0x00000418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000400]> s+0x200
[0x00000600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000600 = 0x08
dn_indblkshift : 0x00000601 = 0x0e
dn_nlevels : 0x00000602 = 0x01
dn_nblkptr : 0x00000603 = 0x01
dn_bonustype : 0x00000604 = 0x07
dn_checksum : 0x00000605 = 0x00
dn_compress : 0x00000606 = 0x00
dn_flags : 0x00000607 = 0x01
dn_datablkszsec : 0x00000608 = 0x0008
dn_bonuslen : 0x0000060a = 0x0140
dn_pad2[4] : 0x0000060c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000610 = (qword)0x0000000000000000
dn_used : 0x00000618 = (qword)0x0000000000000c00
dn_pad3[4] : 0x00000620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]


At the moment we are interested in objects 15, 18, 21.
indexdn_typedn_bonustypedn_bonuslen
150x10DMU_OT_DSL_DATASET0x10DMU_OT_DSL_DATASET0x0140
180x10DMU_OT_DSL_DATASET0x10DMU_OT_DSL_DATASET0x0140
210x10DMU_OT_DSL_DATASET0x10DMU_OT_DSL_DATASET0x0140


For objects of type DMU_OT_DSL_DATASET, the dsl_dataset_phys structure is stored in the bonus buffer of the dnode structure.
 typedef struct dsl_dataset_phys { uint64_t ds_dir_obj; /* DMU_OT_DSL_DIR */ uint64_t ds_prev_snap_obj; /* DMU_OT_DSL_DATASET */ uint64_t ds_prev_snap_txg; uint64_t ds_next_snap_obj; /* DMU_OT_DSL_DATASET */ uint64_t ds_snapnames_zapobj; /* DMU_OT_DSL_DS_SNAP_MAP 0 for snaps */ uint64_t ds_num_children; /* clone/snap children; ==0 for head */ uint64_t ds_creation_time; /* seconds since 1970 */ uint64_t ds_creation_txg; uint64_t ds_deadlist_obj; /* DMU_OT_DEADLIST */ /* * ds_referenced_bytes, ds_compressed_bytes, and ds_uncompressed_bytes * include all blocks referenced by this dataset, including those * shared with any other datasets. */ uint64_t ds_referenced_bytes; uint64_t ds_compressed_bytes; uint64_t ds_uncompressed_bytes; uint64_t ds_unique_bytes; /* only relevant to snapshots */ /* * The ds_fsid_guid is a 56-bit ID that can change to avoid * collisions. The ds_guid is a 64-bit ID that will never * change, so there is a small probability that it will collide. */ uint64_t ds_fsid_guid; uint64_t ds_guid; uint64_t ds_flags; /* DS_FLAG_* */ blkptr_t ds_bp; uint64_t ds_next_clones_obj; /* DMU_OT_DSL_CLONES */ uint64_t ds_props_obj; /* DMU_OT_DSL_PROPS for snaps */ uint64_t ds_userrefs_obj; /* DMU_OT_USERREFS */ uint64_t ds_pad[5]; /* pad out to 320 bytes for good measure */ } dsl_dataset_phys_t; 


Read object 15

# r2 dsl.dnode.0.bin
-- Change the size of the file with the 'r' (resize) command
[0x00000000]> 0x00001e00
[0x00001e00]> s+0x40
[0x00001e40]> s+0x80
[0x00001ec0]> pf qqqqqqt:qqqqqqqqqb[127].qqq[5]q ds_dir_obj ds_prev_snap_obj ds_prev_snap_txg ds_next_snap_obj ds_snapnames_zapobj ds_num_children ds_creation_time ds_creation_txg ds_deadlist_obj ds_referenced_bytes ds_compressed_bytes ds_uncompressed_bytes ds_unique_bytes ds_fsid_guid ds_guid ds_flags ds_bp ds_next_clones_obj ds_props_obj ds_userrefs_obj ds_pad[5]
ds_dir_obj : 0x00001ec0 = (qword)0x000000000000000c
ds_prev_snap_obj : 0x00001ec8 = (qword)0x0000000000000012
ds_prev_snap_txg : 0x00001ed0 = (qword)0x0000000000000001
ds_next_snap_obj : 0x00001ed8 = (qword)0x0000000000000000
ds_snapnames_zapobj : 0x00001ee0 = (qword)0x0000000000000010
ds_num_children : 0x00001ee8 = (qword)0x0000000000000000
ds_creation_time : 0x00001ef0 = Wed Jan 31 07:25:31 2018
ds_creation_txg : 0x00001ef8 = (qword)0x0000000000000001
ds_deadlist_obj : 0x00001f00 = (qword)0x0000000000000013
ds_referenced_bytes : 0x00001f08 = (qword)0x0000000000000000
ds_compressed_bytes : 0x00001f10 = (qword)0x0000000000000000
ds_uncompressed_bytes : 0x00001f18 = (qword)0x0000000000000000
ds_unique_bytes : 0x00001f20 = (qword)0x0000000000000000
ds_fsid_guid : 0x00001f28 = (qword)0x0072595fd26fec77
ds_guid : 0x00001f30 = (qword)0x3723b59bcad0d186
ds_flags : 0x00001f38 = (qword)0x0000000000000004
ds_bp : 0x00001f40 = 0x00
ds_next_clones_obj : 0x00001fc0 = (qword)0x0000000000000000
ds_props_obj : 0x00001fc8 = (qword)0x0000000000000000
ds_userrefs_obj : 0x00001fd0 = (qword)0x0000000000000000
ds_pad[5] : 0x00001fd8 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
0x00001f40
[0x00001f40]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00001f40 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00001f50 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00001f60 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00001f70 = (qword)0x0000000000000000
blk_pad[2] : 0x00001f78 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00001f88 = (qword)0x0000000000000000
blk_birth : 0x00001f90 = (qword)0x0000000000000000
blk_fill : 0x00001f98 = (qword)0x0000000000000000
blk_cksum : 0x00001fa0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Read object 18

0x00002400
[0x00002400]> s+0x40
[0x00002440]> s+0x80
[0x000024c0]> pf qqqqqqt:qqqqqqqqqb[127].qqq[5]q ds_dir_obj ds_prev_snap_obj ds_prev_snap_txg ds_next_snap_obj ds_snapnames_zapobj ds_num_children ds_creation_time ds_creation_txg ds_deadlist_obj ds_referenced_bytes ds_compressed_bytes ds_uncompressed_bytes ds_unique_bytes ds_fsid_guid ds_guid ds_flags ds_bp ds_next_clones_obj ds_props_obj ds_userrefs_obj ds_pad[5]
ds_dir_obj : 0x000024c0 = (qword)0x000000000000000c
ds_prev_snap_obj : 0x000024c8 = (qword)0x0000000000000000
ds_prev_snap_txg : 0x000024d0 = (qword)0x0000000000000000
ds_next_snap_obj : 0x000024d8 = (qword)0x000000000000000f
ds_snapnames_zapobj : 0x000024e0 = (qword)0x0000000000000000
ds_num_children : 0x000024e8 = (qword)0x0000000000000002
ds_creation_time : 0x000024f0 = Wed Jan 31 07:25:31 2018
ds_creation_txg : 0x000024f8 = (qword)0x0000000000000001
ds_deadlist_obj : 0x00002500 = (qword)0x0000000000000011
ds_referenced_bytes : 0x00002508 = (qword)0x0000000000000000
ds_compressed_bytes : 0x00002510 = (qword)0x0000000000000000
ds_uncompressed_bytes : 0x00002518 = (qword)0x0000000000000000
ds_unique_bytes : 0x00002520 = (qword)0x0000000000000000
ds_fsid_guid : 0x00002528 = (qword)0x007551fa166ccbaf
ds_guid : 0x00002530 = (qword)0x107a852b04f9f01f
ds_flags : 0x00002538 = (qword)0x0000000000000004
ds_bp : 0x00002540 = 0x00
ds_next_clones_obj : 0x000025c0 = (qword)0x0000000000000019
ds_props_obj : 0x000025c8 = (qword)0x0000000000000000
ds_userrefs_obj : 0x000025d0 = (qword)0x0000000000000000
ds_pad[5] : 0x000025d8 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
0x00002540
[0x00002540]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00002540 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00002550 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00002560 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00002570 = (qword)0x0000000000000000
blk_pad[2] : 0x00002578 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00002588 = (qword)0x0000000000000000
blk_birth : 0x00002590 = (qword)0x0000000000000000
blk_fill : 0x00002598 = (qword)0x0000000000000000
blk_cksum : 0x000025a0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

Read object 21

0x00002a00
[0x00002a00]> s+0x40
[0x00002a40]> s+0x80
[0x00002ac0]> pf qqqqqqt:qqqqqqqqqb[127].qqq[5]q ds_dir_obj ds_prev_snap_obj ds_prev_snap_txg ds_next_snap_obj ds_snapnames_zapobj ds_num_children ds_creation_time ds_creation_txg ds_deadlist_obj ds_referenced_bytes ds_compressed_bytes ds_uncompressed_bytes ds_unique_bytes ds_fsid_guid ds_guid ds_flags ds_bp ds_next_clones_obj ds_props_obj ds_userrefs_obj ds_pad[5]
ds_dir_obj : 0x00002ac0 = (qword)0x0000000000000002
ds_prev_snap_obj : 0x00002ac8 = (qword)0x0000000000000012
ds_prev_snap_txg : 0x00002ad0 = (qword)0x0000000000000001
ds_next_snap_obj : 0x00002ad8 = (qword)0x0000000000000000
ds_snapnames_zapobj : 0x00002ae0 = (qword)0x0000000000000016
ds_num_children : 0x00002ae8 = (qword)0x0000000000000000
ds_creation_time : 0x00002af0 = Wed Jan 31 07:25:31 2018
ds_creation_txg : 0x00002af8 = (qword)0x0000000000000001
ds_deadlist_obj : 0x00002b00 = (qword)0x0000000000000017
ds_referenced_bytes : 0x00002b08 = (qword)0x0000000000005600
ds_compressed_bytes : 0x00002b10 = (qword)0x0000000000002e00
ds_uncompressed_bytes : 0x00002b18 = (qword)0x0000000000002e00
ds_unique_bytes : 0x00002b20 = (qword)0x0000000000005600
ds_fsid_guid : 0x00002b28 = (qword)0x00aca2eec566a5b9
ds_guid : 0x00002b30 = (qword)0x6994c8e8b2452f06
ds_flags : 0x00002b38 = (qword)0x0000000000000004
ds_bp : 0x00002b40 = 0x01
ds_next_clones_obj : 0x00002bc0 = (qword)0x0000000000000000
ds_props_obj : 0x00002bc8 = (qword)0x0000000000000000
ds_userrefs_obj : 0x00002bd0 = (qword)0x0000000000000000
ds_pad[5] : 0x00002bd8 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
0x00002b40
[0x00002b40]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00002b40 = (qword)[ 0x0000000000000001, 0x0000000000000057 ]
blk_dva_1 : 0x00002b50 = (qword)[ 0x0000000000000001, 0x0000000000000058 ]
blk_dva_2 : 0x00002b60 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00002b70 = (qword)0x800b070f00000003
blk_pad[2] : 0x00002b78 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00002b88 = (qword)0x0000000000000000
blk_birth : 0x00002b90 = (qword)0x0000000000000038
blk_fill : 0x00002b98 = (qword)0x0000000000000009
blk_cksum : 0x00002ba0 = (qword)[ 0x0000000efd4a0466, 0x000005ded369f382, 0x00012e169b3aebd5, 0x00298598c4f3c9d9 ]

image
Only this object stores data, then we will work with it.

Save to file and unpack

# dd if=/tmp/test_disk bs=512 skip=8279 count=1 of=/tmp/os.dataset.bin.lz4
# zdec os.dataset.bin.lz4 os.dataset.bin 2048
Input: os.dataset.bin.lz4
Output: os.dataset.bin
Out size: 2048
-----------------------------
Input size: 512
Real input size: 201
Decompress result: 0

Look at the contents of objset

# r2 os.dataset.bin
[0x00000000]> pf [512].[192].qq[304].[512].[512]. os_type os_flags
os_type : 0x000002c0 = (qword)0x0000000000000002
os_flags : 0x000002c8 = (qword)0x0000000000000001
[0x00000000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000000 = 0x0a
dn_indblkshift : 0x00000001 = 0x0e
dn_nlevels : 0x00000002 = 0x07
dn_nblkptr : 0x00000003 = 0x03
dn_bonustype : 0x00000004 = 0x00
dn_checksum : 0x00000005 = 0x00
dn_compress : 0x00000006 = 0x00
dn_flags : 0x00000007 = 0x01
dn_datablkszsec : 0x00000008 = 0x0020
dn_bonuslen : 0x0000000a = 0x0000
dn_pad2[4] : 0x0000000c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000010 = (qword)0x0000000000000000
dn_used : 0x00000018 = (qword)0x0000000000002000
dn_pad3[4] : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000000]> s+0x40
[0x00000040]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000040 = (qword)[ 0x0000000000000001, 0x000000000000010c ]
blk_dva_1 : 0x00000050 = (qword)[ 0x0000000000000001, 0x000000000000010d ]
blk_dva_2 : 0x00000060 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000070 = (qword)0x860a070f0000001f
blk_pad[2] : 0x00000078 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000088 = (qword)0x0000000000000000
blk_birth : 0x00000090 = (qword)0x0000000000000038
blk_fill : 0x00000098 = (qword)0x0000000000000009
blk_cksum : 0x000000a0 = (qword)[ 0x0000001353eb3bd1, 0x000007c5fce654db, 0x000196a4bd5ee712, 0x00384d0db7501d91 ]

image

This is a link to an indirect block of level 6; we will consistently dig to the zero level.

L6
# dd if=/tmp/test_disk bs=512 skip=8460 count=1 of=/tmp/os.dataset.dnode.l6.bin.lz4
# zdec os.dataset.dnode.l6.bin.lz4 os.dataset.dnode.l6.bin 16384
Input: os.dataset.dnode.l6.bin.lz4
Output: os.dataset.dnode.l6.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l6.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x00000000000000b6 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x000000000000010b ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x850a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x00000012eaa1fd11, 0x000007989478980e, 0x00018c88e386c191, 0x0036c2a7102bf2c2 ]


L5
[0x00000000]> "? 0x400000/512 + 0x00000000000000b6"
8374 0x20b6 020266 8.2K 0000:00b6 8374 "\xb6 " 0b0010000010110110 8374.0 8374.000000f 8374.000000 0t102111011
# dd if=/tmp/test_disk bs=512 skip=8374 count=1 of=/tmp/os.dataset.dnode.l5.bin.lz4
# zdec os.dataset.dnode.l5.bin.lz4 os.dataset.dnode.l5.bin 16384
Input: os.dataset.dnode.l5.bin.lz4
Output: os.dataset.dnode.l5.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 149
Decompress result: 0
# r2 os.dataset.dnode.l5.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x00000000000000b4 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x00000000000000b5 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x840a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x000000135bd403fd, 0x000007c79b2ed6a0, 0x0001969b589bf00e, 0x00383d2f2da4c77e ]


L4
[0x00000000]> "? 0x400000/512 + 0x00000000000000b4"
8372 0x20b4 020264 8.2K 0000:00b4 8372 "\xb4 " 0b0010000010110100 8372.0 8372.000000f 8372.000000 0t102111002
# dd if=/tmp/test_disk bs=512 skip=8372 count=1 of=/tmp/os.dataset.dnode.l4.bin.lz4
# zdec os.dataset.dnode.l4.bin.lz4 os.dataset.dnode.l4.bin 16384
Input: os.dataset.dnode.l4.bin.lz4
Output: os.dataset.dnode.l4.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l4.bin
-- Execute a command every time a breakpoint is hit with 'e cmd.bp = !my-program'
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x0000000000000081 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x0000000000000082 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x830a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x00000012cee6bcc2, 0x0000078b79b1c147, 0x000189aa5ace3a0a, 0x00365db1d10dc06e ]


L3
[0x00000000]> "? 0x400000/512 + 0x0000000000000081"
8321 0x2081 020201 8.1K 0000:0081 8321 "\x81 " 0b0010000010000001 8321.0 8321.000000f 8321.000000 0t102102012
# dd if=/tmp/test_disk bs=512 skip=8321 count=1 of=/tmp/os.dataset.dnode.l3.bin.lz4
# zdec os.dataset.dnode.l3.bin.lz4 os.dataset.dnode.l3.bin 16384
Input: os.dataset.dnode.l3.bin.lz4
Output: os.dataset.dnode.l3.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l3.bin
-- Use the '[' and ']' keys in visual mode to adjust the screen width
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x00000000000000ea ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x0000000000000080 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x820a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x00000013d660f06c, 0x000007fd7a9a913f, 0x0001a28c7591888d, 0x003a04c5208f66a6 ]


L2
[0x00000000]> "? 0x400000/512 + 0x00000000000000ea"
8426 0x20ea 020352 8.2K 0000:00ea 8426 "\xea " 0b0010000011101010 8426.0 8426.000000f 8426.000000 0t102120002
# dd if=/tmp/test_disk bs=512 skip=8426 count=1 of=/tmp/os.dataset.dnode.l2.bin.lz4
# zdec os.dataset.dnode.l2.bin.lz4 os.dataset.dnode.l2.bin 16384
Input: os.dataset.dnode.l2.bin.lz4
Output: os.dataset.dnode.l2.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l2.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000001, 0x000000000000007e ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000001, 0x00000000000000d8 ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x810a070f0000001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x000000119de2c7aa, 0x00000700d12632b0, 0x000169e2d81be607, 0x00317850a78e8a46 ]


L1
[0x00000000]> "? 0x400000/512 + 0x000000000000007e"
8318 0x207e 020176 8.1K 0000:007e 8318 "~ " 0b0010000001111110 8318.0 8318.000000f 8318.000000 0t102102002
# dd if=/tmp/test_disk bs=512 skip=8318 count=1 of=/tmp/os.dataset.dnode.l1.bin.lz4
# zdec os.dataset.dnode.l1.bin.lz4 os.dataset.dnode.l1.bin 16384
Input: os.dataset.dnode.l1.bin.lz4
Output: os.dataset.dnode.l1.bin
Out size: 16384
-----------------------------
Input size: 512
Real input size: 150
Decompress result: 0
# r2 os.dataset.dnode.l1.bin
[0x00000000]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000000 = (qword)[ 0x0000000000000002, 0x0000000000000105 ]
blk_dva_1 : 0x00000010 = (qword)[ 0x0000000000000002, 0x000000000000007c ]
blk_dva_2 : 0x00000020 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000030 = (qword)0x800a070f0001001f
blk_pad[2] : 0x00000038 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000048 = (qword)0x0000000000000000
blk_birth : 0x00000050 = (qword)0x0000000000000038
blk_fill : 0x00000058 = (qword)0x0000000000000009
blk_cksum : 0x00000060 = (qword)[ 0x0000003e07b9461b, 0x00001c6526d2728c, 0x00097c6c15624af0, 0x0268557731d83b04 ]


L0
[0x00000000]> "? 0x400000/512 + 0x0000000000000105"
8453 0x2105 020405 8.3K 0000:0105 8453 "\x05!" 0b0010000100000101 8453.0 8453.000000f 8453.000000 0t102121002
# dd if=/tmp/test_disk bs=512 skip=8453 count=2 of=/tmp/os.dataset.dnode.l0.bin.lz4
# zdec os.dataset.dnode.l0.bin.lz4 os.dataset.dnode.l0.bin 16384
Input: os.dataset.dnode.l0.bin.lz4
Output: os.dataset.dnode.l0.bin
Out size: 16384
-----------------------------
Input size: 1024
Real input size: 1007
Decompress result: 0

Zero level is directly objset.

Make a list of objects

9 objects
# r2 os.dataset.dnode.l0.bin
[0x00000000]> s+0x200
[0x00000200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000200 = 0x15
dn_indblkshift : 0x00000201 = 0x0e
dn_nlevels : 0x00000202 = 0x01
dn_nblkptr : 0x00000203 = 0x03
dn_bonustype : 0x00000204 = 0x00
dn_checksum : 0x00000205 = 0x00
dn_compress : 0x00000206 = 0x00
dn_flags : 0x00000207 = 0x03
dn_datablkszsec : 0x00000208 = 0x0001
dn_bonuslen : 0x0000020a = 0x0000
dn_pad2[4] : 0x0000020c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000210 = (qword)0x0000000000000000
dn_used : 0x00000218 = (qword)0x0000000000000400
dn_pad3[4] : 0x00000220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000200]> s+0x200
[0x00000400]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000400 = 0x2d
dn_indblkshift : 0x00000401 = 0x0e
dn_nlevels : 0x00000402 = 0x01
dn_nblkptr : 0x00000403 = 0x03
dn_bonustype : 0x00000404 = 0x00
dn_checksum : 0x00000405 = 0x00
dn_compress : 0x00000406 = 0x00
dn_flags : 0x00000407 = 0x03
dn_datablkszsec : 0x00000408 = 0x0001
dn_bonuslen : 0x0000040a = 0x0000
dn_pad2[4] : 0x0000040c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000410 = (qword)0x0000000000000000
dn_used : 0x00000418 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000420 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000400]> s+0x200
[0x00000600]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000600 = 0x16
dn_indblkshift : 0x00000601 = 0x0e
dn_nlevels : 0x00000602 = 0x01
dn_nblkptr : 0x00000603 = 0x03
dn_bonustype : 0x00000604 = 0x00
dn_checksum : 0x00000605 = 0x00
dn_compress : 0x00000606 = 0x00
dn_flags : 0x00000607 = 0x03
dn_datablkszsec : 0x00000608 = 0x0001
dn_bonuslen : 0x0000060a = 0x0000
dn_pad2[4] : 0x0000060c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000610 = (qword)0x0000000000000000
dn_used : 0x00000618 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000620 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000600]> s+0x200
[0x00000800]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000800 = 0x14
dn_indblkshift : 0x00000801 = 0x0e
dn_nlevels : 0x00000802 = 0x01
dn_nblkptr : 0x00000803 = 0x01
dn_bonustype : 0x00000804 = 0x2c
dn_checksum : 0x00000805 = 0x00
dn_compress : 0x00000806 = 0x00
dn_flags : 0x00000807 = 0x03
dn_datablkszsec : 0x00000808 = 0x0001
dn_bonuslen : 0x0000080a = 0x00a8
dn_pad2[4] : 0x0000080c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000810 = (qword)0x0000000000000000
dn_used : 0x00000818 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000820 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000800]> s+0x200
[0x00000a00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000a00 = 0x2e
dn_indblkshift : 0x00000a01 = 0x0e
dn_nlevels : 0x00000a02 = 0x01
dn_nblkptr : 0x00000a03 = 0x03
dn_bonustype : 0x00000a04 = 0x00
dn_checksum : 0x00000a05 = 0x00
dn_compress : 0x00000a06 = 0x00
dn_flags : 0x00000a07 = 0x03
dn_datablkszsec : 0x00000a08 = 0x0003
dn_bonuslen : 0x00000a0a = 0x0000
dn_pad2[4] : 0x00000a0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000a10 = (qword)0x0000000000000000
dn_used : 0x00000a18 = (qword)0x0000000000000400
dn_pad3[4] : 0x00000a20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000a00]> s+0x200
[0x00000c00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000c00 = 0x2f
dn_indblkshift : 0x00000c01 = 0x0e
dn_nlevels : 0x00000c02 = 0x01
dn_nblkptr : 0x00000c03 = 0x03
dn_bonustype : 0x00000c04 = 0x00
dn_checksum : 0x00000c05 = 0x00
dn_compress : 0x00000c06 = 0x00
dn_flags : 0x00000c07 = 0x03
dn_datablkszsec : 0x00000c08 = 0x0020
dn_bonuslen : 0x00000c0a = 0x0000
dn_pad2[4] : 0x00000c0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000c10 = (qword)0x0000000000000001
dn_used : 0x00000c18 = (qword)0x0000000000002000
dn_pad3[4] : 0x00000c20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000c00]> s+0x200
[0x00000e00]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00000e00 = 0x13
dn_indblkshift : 0x00000e01 = 0x0e
dn_nlevels : 0x00000e02 = 0x01
dn_nblkptr : 0x00000e03 = 0x01
dn_bonustype : 0x00000e04 = 0x2c
dn_checksum : 0x00000e05 = 0x00
dn_compress : 0x00000e06 = 0x00
dn_flags : 0x00000e07 = 0x02
dn_datablkszsec : 0x00000e08 = 0x0001
dn_bonuslen : 0x00000e0a = 0x00a8
dn_pad2[4] : 0x00000e0c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00000e10 = (qword)0x0000000000000000
dn_used : 0x00000e18 = (qword)0x0000000000000000
dn_pad3[4] : 0x00000e20 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00000e00]> s+0x200
[0x00001000]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001000 = 0x13
dn_indblkshift : 0x00001001 = 0x0e
dn_nlevels : 0x00001002 = 0x01
dn_nblkptr : 0x00001003 = 0x01
dn_bonustype : 0x00001004 = 0x2c
dn_checksum : 0x00001005 = 0x00
dn_compress : 0x00001006 = 0x00
dn_flags : 0x00001007 = 0x03
dn_datablkszsec : 0x00001008 = 0x0001
dn_bonuslen : 0x0000100a = 0x00a8
dn_pad2[4] : 0x0000100c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001010 = (qword)0x0000000000000000
dn_used : 0x00001018 = (qword)0x0000000000000200
dn_pad3[4] : 0x00001020 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
[0x00001000]> s+0x200
[0x00001200]> pf bbbbbbbbww[4]bqq[4]q dn_type dn_indblkshift dn_nlevels dn_nblkptr dn_bonustype dn_checksum dn_compress dn_flags dn_datablkszsec dn_bonuslen dn_pad2[4] dn_maxblkid dn_used dn_pad3[4]
dn_type : 0x00001200 = 0x13
dn_indblkshift : 0x00001201 = 0x0e
dn_nlevels : 0x00001202 = 0x02
dn_nblkptr : 0x00001203 = 0x01
dn_bonustype : 0x00001204 = 0x2c
dn_checksum : 0x00001205 = 0x00
dn_compress : 0x00001206 = 0x00
dn_flags : 0x00001207 = 0x03
dn_datablkszsec : 0x00001208 = 0x0001
dn_bonuslen : 0x0000120a = 0x00a8
dn_pad2[4] : 0x0000120c = [ 0x00, 0x00, 0x00, 0x00 ]
dn_maxblkid : 0x00001210 = (qword)0x0000000000000001
dn_used : 0x00001218 = (qword)0x0000000000000800
dn_pad3[4] : 0x00001220 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]


indexdn_typedn_bonustypedn_bonuslen
four0x14DMU_OT_DIRECTORY_CONTENTS0x2cDMU_OT_SA0x00a8
70x13DMU_OT_PLAIN_FILE_CONTENTS0x2cDMU_OT_SA0x00a8
eight0x13DMU_OT_PLAIN_FILE_CONTENTS0x2cDMU_OT_SA0x00a8
90x13DMU_OT_PLAIN_FILE_CONTENTS0x2cDMU_OT_SA0x00a8


Objects 7, 8, 9 are our 0B, 512B, 513B files. The number and file correspondence can be obtained from object 4 (DMU_OT_DIRECTORY_CONTENTS).

Consider object 4
# r2 os.dataset.dnode.l0.bin
[0x00001400]> 0x00000800
[0x00000800]> s+0x40
[0x00000840]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000840 = (qword)[ 0x0100032143000000, 0x0cfd073129805300 ]
blk_dva_1 : 0x00000850 = (qword)[ 0x2e07121a00020f00, 0x4230220007801200 ]
blk_dva_2 : 0x00000860 = (qword)[ 0x08121700020f0008, 0x31353f004003002b ]
blk_prop : 0x00000870 = (qword)0x8014008f8c0001ff
blk_pad[2] : 0x00000878 = (qword)[ 0x0040091b1c004232, 0x00020f1c0040331f ]
blk_phys_birth : 0x00000888 = (qword)0x00000000000050e8
blk_birth : 0x00000890 = (qword)0x0000000000000022
blk_fill : 0x00000898 = (qword)0x0000000000000000
blk_cksum : 0x000008a0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

This is an embedded blkptr (bit E), the structure is different from the usual blkptr.
image

Data is stored directly in the structure.

[0x00000840]> pf [48]bq[24]bq[40]b data_1 blk_prob data_2 txg data_3
data_1 : 0x00000840 = [ 0x00, 0x00, 0x00, 0x43, 0x21, 0x03, 0x00, 0x01, 0x00, 0x53, 0x80, 0x29, 0x31, 0x07, 0xfd, 0x0c, 0x00, 0x0f, 0x02, 0x00, 0x1a, 0x12, 0x07, 0x2e, 0x00, 0x12, 0x80, 0x07, 0x00, 0x22, 0x30, 0x42, 0x08, 0x00, 0x0f, 0x02, 0x00, 0x17, 0x12, 0x08, 0x2b, 0x00, 0x03, 0x40, 0x00, 0x3f, 0x35, 0x31 ]
blk_prob : 0x00000870 = (qword)0x8014008f8c0001ff
data_2 : 0x00000878 = [ 0x32, 0x42, 0x00, 0x1c, 0x1b, 0x09, 0x40, 0x00, 0x1f, 0x33, 0x40, 0x00, 0x1c, 0x0f, 0x02, 0x00, 0xe8, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
txg : 0x00000890 = (qword)0x0000000000000022
data_3 : 0x00000898 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]


We consider this data in the file
Consistently copy 48 bytes and skip blk_prob (8 bytes) the remaining 23 bytes (the full size is taken from the PSIZE field).
# dd if=os.dataset.dnode.l0.bin of=/tmp/emb.bin.lz4 bs=1 count=48 skip=2112
# dd if=os.dataset.dnode.l0.bin of=/tmp/emb.bin.lz4 bs=1 seek=48 count=23 skip=2168
# zdec emb.bin.lz4 emb.bin 512
Input: emb.bin.lz4
Output: emb.bin
Out size: 512
-----------------------------
Input size: 71
Real input size: 67
Decompress result: 0

# r2 emb.bin
[0x00000000]> pf qqq[5]qqxwz mz_block_type mz_salt mz_normflags mz_pad[5] mz_chunk[1]_mze_value mz_chunk[1]_mze_cd mz_chunk[1]_mze_pad mz_chunk[1]_mze_name
mz_block_type : 0x00000000 = (qword)0x8000000000000003
mz_salt : 0x00000008 = (qword)0x00000003fd073129
mz_normflags : 0x00000010 = (qword)0x0000000000000000
mz_pad[5] : 0x00000018 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]
mz_chunk[1]_mze_value : 0x00000040 = (qword)0x8000000000000007
mz_chunk[1]_mze_cd : 0x00000048 = 0x00000000
mz_chunk[1]_mze_pad : 0x0000004c = 0x0000
mz_chunk[1]_mze_name : 0x0000004e = 0B
[0x00000000]> s+0x80
[0x00000080]> pf qxwz mze_value mze_cd mze_pad mze_name
mze_value : 0x00000080 = (qword)0x8000000000000008
mze_cd : 0x00000088 = 0x00000000
mze_pad : 0x0000008c = 0x0000
mze_name : 0x0000008e = 512B
[0x00000080]> s+0x40
[0x000000c0]> pf qxwz mze_value mze_cd mze_pad mze_name
mze_value : 0x000000c0 = (qword)0x8000000000000009
mze_cd : 0x000000c8 = 0x00000000
mze_pad : 0x000000cc = 0x0000
mze_name : 0x000000ce = 513B

mze_value : 0x8000000000000007
ZFS_DIRENT_TYPE : 8 // "? (0x8000000000000007>60)&((1<4)-1)" // /* 8 */ "Regular File",
ZFS_DIRENT_OBJ : 7 // "? (0x8000000000000007>0)&((1<48)-1)" // Object id

0B file is number 7
512B file is number 8
513B file is number 9

Consider object 7
# r2 os.dataset.dnode.l0.bin
[0x00000000]> 0x00000e00
[0x00000e00]> s+0x40
[0x00000e40]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00000e40 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_1 : 0x00000e50 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00000e60 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00000e70 = (qword)0x0000000000000000
blk_pad[2] : 0x00000e78 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00000e88 = (qword)0x0000000000000000
blk_birth : 0x00000e90 = (qword)0x0000000000000000
blk_fill : 0x00000e98 = (qword)0x0000000000000000
blk_cksum : 0x00000ea0 = (qword)[ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ]

The file contains no data - blkptr is empty.

Consider object 8
[0x00000e40]> 0x00001000
[0x00001000]> s+0x40
[0x00001040]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00001040 = (qword)[ 0x0000000000000001, 0x00000000000000e9 ]
blk_dva_1 : 0x00001050 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_dva_2 : 0x00001060 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00001070 = (qword)0x8013070200000000
blk_pad[2] : 0x00001078 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00001088 = (qword)0x0000000000000000
blk_birth : 0x00001090 = (qword)0x0000000000000020
blk_fill : 0x00001098 = (qword)0x0000000000000001
blk_cksum : 0x000010a0 = (qword)[ 0x0000003c34e2ea5c, 0x00000f3db2d3ec9f, 0x00029bdcc6458734, 0x005654ddd2b56e82 ]

image

The file occupies one sector on the disk, i.e. 512 bytes

Consider object 9
[0x00001040]> 0x1200
[0x00001200]> s+0x40
[0x00001240]> pf [2]q[2]q[2]qq[2]qqqq[4]q blk_dva_0 blk_dva_1 blk_dva_2 blk_prop blk_pad[2] blk_phys_birth blk_birth blk_fill blk_cksum
blk_dva_0 : 0x00001240 = (qword)[ 0x0000000000000001, 0x000000000000009d ]
blk_dva_1 : 0x00001250 = (qword)[ 0x0000000000000001, 0x0000000000000059 ]
blk_dva_2 : 0x00001260 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_prop : 0x00001270 = (qword)0x8113070f0000001f
blk_pad[2] : 0x00001278 = (qword)[ 0x0000000000000000, 0x0000000000000000 ]
blk_phys_birth : 0x00001288 = (qword)0x0000000000000000
blk_birth : 0x00001290 = (qword)0x0000000000000022
blk_fill : 0x00001298 = (qword)0x0000000000000002
blk_cksum : 0x000012a0 = (qword)[ 0x0000001427d4c96a, 0x000007e5038b685d, 0x000194254db44203, 0x0037093ef743abcc ]

image

A file of 513 bytes in size does not fit completely into recordsize equal to 512 bytes and an indirect block is used to store it.
The indirect block is stored in duplicate (blk_dva_0 and blk_dva_1).
From here the sizes of files on a disk:
0B: dnode (512B) = 512 bytes
512B: dnode (512B) + file data (512B) = 1024 bytes
513B: dnode (512B) + 2 * indirect blocks (512B) + 2 * file data (512B) = 2560 bytes

Program for unpacking the block compressed by the lz4 algorithm
It is a copy of the LZ4_uncompress_unknownOutputSize function from the lz4.c file .

 #include <iostream> #include <fstream> #include <cstdint> #include <cstring> using namespace std; static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize); #define BE_IN8(xa) \ *((uint8_t *)(xa)) #define BE_IN16(xa) \ (((uint16_t)BE_IN8(xa) << 8) | BE_IN8((uint8_t *)(xa)+1)) #define BE_IN32(xa) \ (((uint32_t)BE_IN16(xa) << 16) | BE_IN16((uint8_t *)(xa)+2)) #define COMPRESSIONLEVEL 12 #define NOTCOMPRESSIBLE_CONFIRMATION 6 /* * * CPU Feature Detection */ /* 32 or 64 bits ? */ #if defined(_LP64) #define LZ4_ARCH64 1 #else #define LZ4_ARCH64 0 #endif /* * Little Endian or Big Endian? * Note: overwrite the below #define if you know your architecture endianess. */ #if defined(_BIG_ENDIAN) #define LZ4_BIG_ENDIAN 1 #else /* * Little Endian assumed. PDP Endian and other very rare endian format * are unsupported. */ #undef LZ4_BIG_ENDIAN #endif /* * Unaligned memory access is automatically enabled for "common" CPU, * such as x86. For others CPU, the compiler will be more cautious, and * insert extra code to ensure aligned access is respected. If you know * your target CPU supports unaligned memory access, you may want to * force this option manually to improve performance */ #if defined(__ARM_FEATURE_UNALIGNED) #define LZ4_FORCE_UNALIGNED_ACCESS 1 #endif /* * Illumos : we can't use GCC's __builtin_ctz family of builtins in the * kernel * Linux : we can use GCC's __builtin_ctz family of builtins in the * kernel */ #undef LZ4_FORCE_SW_BITCOUNT #if defined(__sparc) #define LZ4_FORCE_SW_BITCOUNT #endif /* * Compiler Options */ /* Disable restrict */ #define restrict /* * Linux : GCC_VERSION is defined as of 3.9-rc1, so undefine it. * torvalds/linux@3f3f8d2f48acfd8ed3b8e6b7377935da57b27b16 */ #ifdef GCC_VERSION #undef GCC_VERSION #endif #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) #define expect(expr, value) (__builtin_expect((expr), (value))) #else #define expect(expr, value) (expr) #endif #ifndef likely #define likely(expr) expect((expr) != 0, 1) #endif #ifndef unlikely #define unlikely(expr) expect((expr) != 0, 0) #endif #define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | \ (((x) & 0xffu) << 8))) /* Basic types */ #define BYTE uint8_t #define U16 uint16_t #define U32 uint32_t #define S32 int32_t #define U64 uint64_t #ifndef LZ4_FORCE_UNALIGNED_ACCESS #pragma pack(1) #endif typedef struct _U16_S { U16 v; } U16_S; typedef struct _U32_S { U32 v; } U32_S; typedef struct _U64_S { U64 v; } U64_S; #ifndef LZ4_FORCE_UNALIGNED_ACCESS #pragma pack() #endif #define A64(x) (((U64_S *)(x))->v) #define A32(x) (((U32_S *)(x))->v) #define A16(x) (((U16_S *)(x))->v) /* * Constants */ #define MINMATCH 4 #define HASH_LOG COMPRESSIONLEVEL #define HASHTABLESIZE (1 << HASH_LOG) #define HASH_MASK (HASHTABLESIZE - 1) #define SKIPSTRENGTH (NOTCOMPRESSIBLE_CONFIRMATION > 2 ? \ NOTCOMPRESSIBLE_CONFIRMATION : 2) #define COPYLENGTH 8 #define LASTLITERALS 5 #define MFLIMIT (COPYLENGTH + MINMATCH) #define MINLENGTH (MFLIMIT + 1) #define MAXD_LOG 16 #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) #define ML_BITS 4 #define ML_MASK ((1U<<ML_BITS)-1) #define RUN_BITS (8-ML_BITS) #define RUN_MASK ((1U<<RUN_BITS)-1) /* * Architecture-specific macros */ #if LZ4_ARCH64 #define STEPSIZE 8 #define UARCH U64 #define AARCH A64 #define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d += 8; s += 8; #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d) #define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e) #define HTYPE U32 #define INITBASE(base) const BYTE* const base = ip #else /* !LZ4_ARCH64 */ #define STEPSIZE 4 #define UARCH U32 #define AARCH A32 #define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d += 4; s += 4; #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d); #define LZ4_SECURECOPY LZ4_WILDCOPY #define HTYPE const BYTE * #define INITBASE(base) const int base = 0 #endif /* !LZ4_ARCH64 */ #if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE)) #define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; } #define LZ4_WRITE_LITTLEENDIAN_16(p, i) \ { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; } #else #define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); } #define LZ4_WRITE_LITTLEENDIAN_16(p, v) { A16(p) = v; p += 2; } #endif /* Local structures */ struct refTables { HTYPE hashTable[HASHTABLESIZE]; }; /* Macros */ #define LZ4_HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH * 8) - \ HASH_LOG)) #define LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p)) #define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e); #define LZ4_BLINDCOPY(s, d, l) { BYTE* e = (d) + l; LZ4_WILDCOPY(s, d, e); \ d = e; } static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize) { /* Local Variables */ const BYTE *restrict ip = (const BYTE *) source; const BYTE *const iend = ip + isize; const BYTE *ref; BYTE *op = (BYTE *) dest; BYTE *const oend = op + maxOutputSize; BYTE *cpy; size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; #if LZ4_ARCH64 size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; #endif /* Main Loop */ while (ip < iend) { unsigned token; size_t length; /* get runlength */ token = *ip++; if ((length = (token >> ML_BITS)) == RUN_MASK) { int s = 255; while ((ip < iend) && (s == 255)) { s = *ip++; length += s; } } /* copy literals */ cpy = op + length; /* CORNER-CASE: cpy might overflow. */ if (cpy < op) goto _output_error; /* cpy was overflowed, bail! */ if ((cpy > oend - COPYLENGTH) || (ip + length > iend - COPYLENGTH)) { if (cpy > oend) /* Error: writes beyond output buffer */ goto _output_error; if (ip + length != iend) /* * Error: LZ4 format requires to consume all * input at this stage */ goto _output_error; (void) memcpy(op, ip, length); op += length; /* Necessarily EOF, due to parsing restrictions */ break; } LZ4_WILDCOPY(ip, op, cpy); ip -= (op - cpy); op = cpy; /* get offset */ LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); ip += 2; if (ref < (BYTE * const) dest) /* * Error: offset creates reference outside of * destination buffer */ goto _output_error; /* get matchlength */ if ((length = (token & ML_MASK)) == ML_MASK) { while (ip < iend) { int s = *ip++; length += s; if (s == 255) continue; break; } } /* copy repeated sequence */ if (unlikely(op - ref < STEPSIZE)) { #if LZ4_ARCH64 size_t dec64 = dec64table[op-ref]; #else const int dec64 = 0; #endif op[0] = ref[0]; op[1] = ref[1]; op[2] = ref[2]; op[3] = ref[3]; op += 4; ref += 4; ref -= dec32table[op-ref]; A32(op) = A32(ref); op += STEPSIZE - 4; ref -= dec64; } else { LZ4_COPYSTEP(ref, op); } cpy = op + length - (STEPSIZE - 4); if (cpy > oend - COPYLENGTH) { if (cpy > oend) /* * Error: request to write outside of * destination buffer */ goto _output_error; LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); while (op < cpy) *op++ = *ref++; op = cpy; if (op == oend) /* * Check EOF (should never happen, since * last 5 bytes are supposed to be literals) */ goto _output_error; continue; } LZ4_SECURECOPY(ref, op, cpy); op = cpy; /* correction */ } /* end of decoding */ return (int)(((char *)op) - dest); /* write overflow error detected */ _output_error: return (int)(-(((char *)ip) - source)); } /*ARGSUSED*/ int lz4_decompress_zfs(void *s_start, void *d_start, size_t s_len, size_t d_len, int n) { const char *src = (const char*) s_start; uint32_t bufsiz = BE_IN32(src); /* invalid compressed buffer size encoded at start */ if (bufsiz + sizeof (bufsiz) > s_len) return (1); std::cout << "Real input size: " << bufsiz << std::endl; /* * Returns 0 on success (decompression function returned non-negative) * and non-zero on failure (decompression function returned negative. */ return (LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)], (char*)d_start, bufsiz, d_len) < 0); } int main( int argc, char **argv ) { if (argc < 4) { std::cout << argv[0] << " <in> <out> <out_size>" << std::endl; return 1; } char* szInput = argv[1]; char* szOutput = argv[2]; int nOutSize = atoi(argv[3]); std::cout << "Input: \t\t" << szInput << std::endl; std::cout << "Output: \t" << szOutput << std::endl; std::cout << "Out size: \t" << nOutSize << std::endl; std::cout << "-----------------------------" << std::endl; // READ INPUT fstream fs(szInput, fstream::in); if (!fs.is_open()) { std::cout << "Open error"; return 1; } fs.seekg(0, ios::end); int fileSize = fs.tellg(); std::cout << "Input size: \t" << fileSize << std::endl; char* src = new char[fileSize]; fs.seekg(0, ios::beg); fs.read(src, fileSize); if (!fs) { std::cout << "error: only " << fs.gcount() << " could be read"; fs.close(); return 1; } fs.close(); // END READ INPUT // DECOMPRESS char* dst = new char[nOutSize]; std::memset(dst, 0, nOutSize); int nRes = lz4_decompress_zfs(src, dst, fileSize, nOutSize, 0); std::cout << "Decompress result: " << nRes << std::endl; if (nRes) { std::cout << "Decompress error" << std::endl; // return 1; } // END DECOMPRESS // OUTPUT fstream out(szOutput, fstream::out); if (!out.is_open()) { std::cout << "Open error"; return 1; } out.write(dst, nOutSize); if (!out) { std::cout << "error: only " << out.gcount() << " could be write"; out.close(); return 1; } out.close(); // END OUTPUT delete[] src; delete[] dst; return 0; } 

Source: https://habr.com/ru/post/348354/


All Articles