Zfs является достаточно популярной файловой системой для долговременного хранения данных. Кроме того она обеспечивает целостность записанных данных, сохраняя вместе с данными и их контрольные суммы. Механизм контрольных сумм позволяет выявить, и при наличии избыточности восстановить, поврежденные данные.
В данной статье на практическом примере производится разбор, как и куда zfs сохраняет данные.
Непосредственно для доступа к данным мы не будем использовать утилиту zdb, а попробуем с помощью radare2 посмотреть непосредственно на байты которые записаны на диске.
Zfs(Zettabyte File System) это COW(copy on write) файловая система, созданная в Sun для операционной системы Solaris.
Одним из основных преимуществ этой файловой системы считается использование контрольных сумм не только для метаданных но и для данных пользователя.
Для более подробного разбора компонентов zfs рекомендуется обратится к официальной документации ZFS On-Disk Specification от Sun.
Пул zfs состоит из виртуальных устройств (далее vdev). Более детальная информация нам сейчас не нужна, отметим только что vdev существует два вида логическое и физическое виртуальное устройство.
На каждом физическом виртуальном устройстве хранится четыре метки (на рисунке L0, L1, L2 и L3).
Непосредственно после меток L0 и L1 выделено 3,5 Мб пространства, зарезервированного для будущего использования.
В отличии от остальных объектов zfs положение меток строго фиксировано и обновление их происходит в два шага, сначала обновляются метки L0 и L2 затем L1 и L3. Для данной статьи из данных записанных в метке нас будет интересовать только uberblock, рассмотрим его подробнее.
Uberblock представлен следующей структурой:
Опишем некоторые поля:
ub_txg
Номер транзакции
ub_timestamp
Содержит время записи uberblock (в UTC формате)
ub_rootbp
Ссылка на Meta Object Set (В zfs ссылки на блоки представлены структурой blkptr_t, будет описана ниже).
Ссылки на блоки представляют собой следующую структуру:
Если представить в виде массива байт то получится следующее изображение
Наиболее важные поля
dva_t
Виртуальный адрес данных. В поле offset хранится смещение в секторах (512 байт).
На изображении выше это строки 0~5.
blk_prop
В соответствующих полях записан тип, размер, уровень косвенности блока и т.п.
type преобразеется в перечесление dmu_object_type. А поля cksum и comp в zio_checksum и zio_compress соответственно.
Перечисления zio_checksum и zio_compress представлены ниже.
Исключая uberblock все остальные сущности (метаданные и пользовательские данные) представлены в виде объектов. В перечислении dmu_object_type перечислены возможные типы объектов.
Объект описывается структурой dnode_phys, представленой ниже:
Объекты zfs могут группироваться в так называемые наборы объектов (objset), и представлены следующими типами:
Сам набор объектов представлен такой 2-х килобайтной структурой:
В этой статье мы будем использовать тестовый пул основанный на 101-мегабайтном файле.
Почуму именно 101 Мб? Дело в том что zfs разбивает свободное пространнство (за минусом 4х 256Кб меток и 3.5 мегабайтного boot-блока) на фиксированные блоки (смотри Как работает ZFS — часть 1: vdev). Для 100Мб диска размер блока равняется 16Мб и для 100Мб диска таких блоков поместится только 5 и доступный объем будет равен 80Мб. А вот для 101Мб таких блоков уже вмещается 6 и доступный объем увеличивается до 96Мб. Хотя для данной статьи это не так уж и важно. Но например для 4Тб диска если его полностью отдать zfs то получим «потерянное» пространство размером более 13Гб.
3725 «двоичных» Гб делятся на блоки размером 16Гб каждый и остаток в 13Гб не используется.
Зададим recordsize равным 512 байтам и добавим пару файлов.
Посмотрим сколько места файлы занимают на диске
Из интересного бросается в глаза то что файл нулевого размера занимает 512 байт (сравните с ext3 где он имеет размер ноль байтов). Файл размером 513 байт занимает не 1536 байт а целых 2560 байт, хотя казалось бы должен был бы занять место равное удвоенному размеру recordsize плюс служебная информация. Давайте разбирать почему так происходит.
Для доступа к сырым данным будем использовать утилиту radare2.
Сортируем по номеру транзакции.
Активный uberblock находится по адресу 0x0002e000 (от найденого смещения 0x0002e010 отнимаем 16 байт).
Считываем uberblock полностью
Получаем ub_rootbp
Для разбора параметров blkptr(blk_prop) использую MS Excell
Судя по значению comp (=15) блок сжат lz4 и занимает на диске 512 байт (PSIZE — показывает количество секторов) и после распаковки должен стать 2048 байт(LSIZE).
Сохраним блок в файл
Вычислим смещение от начала диска. Для этого значение поля blk_dva[0].dva_word[1](=0x00000000000000ab) из структуры blkptr умножим на 512(размер сектора) и добавим 0x400000(4Мб — метки L0, L1 и boot-блок). Результат поделим на 512 (работаем блоками по 512 байт).
Для распаковки используем небольшую программку (исходник в конце статьи).
Посмотрим что хранится в MOS объекте
Считываем массив blkptr (начало массива со смещением +0x40). Размер структуры blkptr 128 байт (смещение +0x80)
Блоки сжаты алгоритмом lz4 и имеют размер 2048 байт и 512 байт соответственно (и реальный размер 16384 байт).
Сохраним в файл и распакуем
Составим список из объектов
В данный момент нас интересуют объекты 15, 18, 21.
Для объектов типа DMU_OT_DSL_DATASET в бонус-буфере структуры dnode хранится структура dsl_dataset_phys.
Считываем объект 15
Считываем объект 18
Считываем объект 21
Только этот объект хранит данные, далее будем работать с ним.
Сохраним в файл и распакуем
Смотрим содержимое objset
Это ссылка на косвенный блок 6 уровня, последовательно будем копать до нулевого уровня.
L6
L5
L4
L3
L2
L1
L0
Нулевой уровень это непосредственно objset.
Составим список объектов
Объекты 7, 8, 9 это созданные нами файлы 0B, 512B, 513B. Соответствие номера и файла можно получить из объекта 4 (DMU_OT_DIRECTORY_CONTENTS).
Считаем объект 4
Это Embedded blkptr(бит E), структура отличается от обычного blkptr.
Данные хранятся непосредственно в структуре.
Считаем эти данные в файл
Последовательно копируем 48 байт и пропустив blk_prob (8 байт) оставшиеся 23 байта (полный размер берется из поля PSIZE).
0B файл имеет номер 7
512B файл имеет номер 8
513B файл имеет номер 9
Считаем объект 7
Файл не содержит данных — blkptr пустой.
Считаем объект 8
Файл занимает на диске один сектор, т.е. 512 байт.
Считаем объект 9
Файл размером 513 байт не помещается полностью в recordsize равную 512 байтам и для его хранения задействуется косвенный блок.
Косвенный блок хранится в двух экземплярах (blk_dva_0 и blk_dva_1).
Отсюда размеры файлов на диске:
0B: dnode(512B) = 512 байт
512B: dnode(512B) + данные файла(512B) = 1024 байт
513B: dnode(512B) + 2*косвенных блока(512B) + 2*данные файла(512B) = 2560 байт
В данной статье на практическом примере производится разбор, как и куда zfs сохраняет данные.
Непосредственно для доступа к данным мы не будем использовать утилиту zdb, а попробуем с помощью radare2 посмотреть непосредственно на байты которые записаны на диске.
О zfs
Zfs(Zettabyte File System) это COW(copy on write) файловая система, созданная в Sun для операционной системы Solaris.
Одним из основных преимуществ этой файловой системы считается использование контрольных сумм не только для метаданных но и для данных пользователя.
Дисковая структура zfs
Для более подробного разбора компонентов zfs рекомендуется обратится к официальной документации ZFS On-Disk Specification от Sun.
Виртуальные устройства
Пул zfs состоит из виртуальных устройств (далее vdev). Более детальная информация нам сейчас не нужна, отметим только что vdev существует два вида логическое и физическое виртуальное устройство.
Метка
На каждом физическом виртуальном устройстве хранится четыре метки (на рисунке L0, L1, L2 и L3).
Boot-блок
Непосредственно после меток L0 и L1 выделено 3,5 Мб пространства, зарезервированного для будущего использования.
Точка отсчета uberblock
В отличии от остальных объектов zfs положение меток строго фиксировано и обновление их происходит в два шага, сначала обновляются метки L0 и L2 затем L1 и L3. Для данной статьи из данных записанных в метке нас будет интересовать только uberblock, рассмотрим его подробнее.
Uberblock
Uberblock представлен следующей структурой:
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;
};
Опишем некоторые поля:
ub_txg
Номер транзакции
ub_timestamp
Содержит время записи uberblock (в UTC формате)
ub_rootbp
Ссылка на Meta Object Set (В zfs ссылки на блоки представлены структурой blkptr_t, будет описана ниже).
Ссылки на блоки (blkptr_t)
Ссылки на блоки представляют собой следующую структуру:
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;
Если представить в виде массива байт то получится следующее изображение
Наиболее важные поля
dva_t
Виртуальный адрес данных. В поле offset хранится смещение в секторах (512 байт).
На изображении выше это строки 0~5.
blk_prop
В соответствующих полях записан тип, размер, уровень косвенности блока и т.п.
type преобразеется в перечесление dmu_object_type. А поля cksum и comp в zio_checksum и zio_compress соответственно.
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;
Перечисления zio_checksum и zio_compress представлены ниже.
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
};
Объект (dnode)
Исключая uberblock все остальные сущности (метаданные и пользовательские данные) представлены в виде объектов. В перечислении dmu_object_type перечислены возможные типы объектов.
Объект описывается структурой dnode_phys, представленой ниже:
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;
Набор объектов
Объекты zfs могут группироваться в так называемые наборы объектов (objset), и представлены следующими типами:
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;
Сам набор объектов представлен такой 2-х килобайтной структурой:
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;
Смотрим на байты
В этой статье мы будем использовать тестовый пул основанный на 101-мегабайтном файле.
Почуму именно 101 Мб? Дело в том что zfs разбивает свободное пространнство (за минусом 4х 256Кб меток и 3.5 мегабайтного boot-блока) на фиксированные блоки (смотри Как работает ZFS — часть 1: vdev). Для 100Мб диска размер блока равняется 16Мб и для 100Мб диска таких блоков поместится только 5 и доступный объем будет равен 80Мб. А вот для 101Мб таких блоков уже вмещается 6 и доступный объем увеличивается до 96Мб. Хотя для данной статьи это не так уж и важно. Но например для 4Тб диска если его полностью отдать zfs то получим «потерянное» пространство размером более 13Гб.
3725 «двоичных» Гб делятся на блоки размером 16Гб каждый и остаток в 13Гб не используется.
Создаем тестовый пул
# 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
Зададим recordsize равным 512 байтам и добавим пару файлов.
# 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
Посмотрим сколько места файлы занимают на диске
# du -a --block-size=1
1024 ./512B
512 ./0B
2560 ./513B
Из интересного бросается в глаза то что файл нулевого размера занимает 512 байт (сравните с ext3 где он имеет размер ноль байтов). Файл размером 513 байт занимает не 1536 байт а целых 2560 байт, хотя казалось бы должен был бы занять место равное удвоенному размеру recordsize плюс служебная информация. Давайте разбирать почему так происходит.
Находим активный uberblock
Для доступа к сырым данным будем использовать утилиту radare2.
Сортируем по номеру транзакции.
# 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
Активный uberblock находится по адресу 0x0002e000 (от найденого смещения 0x0002e010 отнимаем 16 байт).
Считываем uberblock полностью
[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
Получаем 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 ]
Для разбора параметров blkptr(blk_prop) использую MS Excell
Судя по значению comp (=15) блок сжат lz4 и занимает на диске 512 байт (PSIZE — показывает количество секторов) и после распаковки должен стать 2048 байт(LSIZE).
Сохраним блок в файл
Вычислим смещение от начала диска. Для этого значение поля blk_dva[0].dva_word[1](=0x00000000000000ab) из структуры blkptr умножим на 512(размер сектора) и добавим 0x400000(4Мб — метки L0, L1 и boot-блок). Результат поделим на 512 (работаем блоками по 512 байт).
[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
Для распаковки используем небольшую программку (исходник в конце статьи).
# 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
Посмотрим что хранится в MOS объекте
# 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 ]
Считываем массив blkptr (начало массива со смещением +0x40). Размер структуры blkptr 128 байт (смещение +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 ]
Блоки сжаты алгоритмом lz4 и имеют размер 2048 байт и 512 байт соответственно (и реальный размер 16384 байт).
Сохраним в файл и распакуем
# 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
Составим список из объектов
31 объект
# 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 объекта
# 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 ]
В данный момент нас интересуют объекты 15, 18, 21.
index | dn_type | dn_bonustype | dn_bonuslen | ||
15 | 0x10 | DMU_OT_DSL_DATASET | 0x10 | DMU_OT_DSL_DATASET | 0x0140 |
18 | 0x10 | DMU_OT_DSL_DATASET | 0x10 | DMU_OT_DSL_DATASET | 0x0140 |
21 | 0x10 | DMU_OT_DSL_DATASET | 0x10 | DMU_OT_DSL_DATASET | 0x0140 |
Для объектов типа DMU_OT_DSL_DATASET в бонус-буфере структуры dnode хранится структура dsl_dataset_phys.
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;
Считываем объект 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 ]
Считываем объект 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 ]
Считываем объект 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 ]
Только этот объект хранит данные, далее будем работать с ним.
Сохраним в файл и распакуем
# 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
Смотрим содержимое 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 ]
Это ссылка на косвенный блок 6 уровня, последовательно будем копать до нулевого уровня.
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
Нулевой уровень это непосредственно objset.
Составим список объектов
9 объектов
# 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 ]
index | dn_type | dn_bonustype | dn_bonuslen | ||
4 | 0x14 | DMU_OT_DIRECTORY_CONTENTS | 0x2c | DMU_OT_SA | 0x00a8 |
7 | 0x13 | DMU_OT_PLAIN_FILE_CONTENTS | 0x2c | DMU_OT_SA | 0x00a8 |
8 | 0x13 | DMU_OT_PLAIN_FILE_CONTENTS | 0x2c | DMU_OT_SA | 0x00a8 |
9 | 0x13 | DMU_OT_PLAIN_FILE_CONTENTS | 0x2c | DMU_OT_SA | 0x00a8 |
Объекты 7, 8, 9 это созданные нами файлы 0B, 512B, 513B. Соответствие номера и файла можно получить из объекта 4 (DMU_OT_DIRECTORY_CONTENTS).
Считаем объект 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 ]
Это Embedded blkptr(бит E), структура отличается от обычного blkptr.
Данные хранятся непосредственно в структуре.
[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 ]
Считаем эти данные в файл
Последовательно копируем 48 байт и пропустив blk_prob (8 байт) оставшиеся 23 байта (полный размер берется из поля PSIZE).
# 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 файл имеет номер 7
512B файл имеет номер 8
513B файл имеет номер 9
Считаем объект 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 ]
Файл не содержит данных — blkptr пустой.
Считаем объект 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 ]
Файл занимает на диске один сектор, т.е. 512 байт.
Считаем объект 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 ]
Файл размером 513 байт не помещается полностью в recordsize равную 512 байтам и для его хранения задействуется косвенный блок.
Косвенный блок хранится в двух экземплярах (blk_dva_0 и blk_dva_1).
Отсюда размеры файлов на диске:
0B: dnode(512B) = 512 байт
512B: dnode(512B) + данные файла(512B) = 1024 байт
513B: dnode(512B) + 2*косвенных блока(512B) + 2*данные файла(512B) = 2560 байт
Программа для распаковки блока сжатого алгоритмом lz4
Представляет собой копию функции LZ4_uncompress_unknownOutputSize из файла lz4.c
#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;
}