From 0d75161c43b468542503ae32bda6dabc20dabfdf Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Wed, 5 Aug 2020 06:19:17 +0300 Subject: [PATCH 01/15] Add outline of SquashFS superblock --- filesystem/squashfs_superblock.ksy | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 filesystem/squashfs_superblock.ksy diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy new file mode 100644 index 000000000..6288dc04b --- /dev/null +++ b/filesystem/squashfs_superblock.ksy @@ -0,0 +1,54 @@ +meta: + id: squashfs_superblock + title: SquashFS superblock + file-extension: + - squashfs + - snap + endian: le + license: CC-0 +doc-ref: https://github.com/AgentD/squashfs-tools-ng/blob/master/doc/format.txt +seq: + - id: superblock + type: superblock +types: + superblock: + seq: + - id: magic + contents: 'hsqs' + - id: inode_count + type: u4 + - id: mod_time + type: u4 + - id: block_size + type: u4 + - id: frag_count + type: u4 + - id: compressor + type: u2 + - id: block_log + type: u2 + - id: flags + type: u2 + - id: id_count + type: u2 + - id: version_major + contents: [ 4, 0 ] + - id: version_minor + contents: [ 0, 0 ] + - id: root_inode_ref + type: u8 + - id: bytes_used + type: u8 + - id: id_table_start + type: u8 + - id: xattr_id_table_start + type: u8 + - id: inode_table_start + type: u8 + - id: directory_table_start + type: u8 + - id: fragment_table_start + type: u8 + - id: export_table_start + type: u8 + \ No newline at end of file From 113eeb396fb5be3a2179016b489e13d8d522a05d Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Wed, 5 Aug 2020 10:55:29 +0300 Subject: [PATCH 02/15] Wikidata xref by @KOLANICH --- filesystem/squashfs_superblock.ksy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index 6288dc04b..d81ab668d 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -6,6 +6,8 @@ meta: - snap endian: le license: CC-0 + xref: + wikidata: Q389314 doc-ref: https://github.com/AgentD/squashfs-tools-ng/blob/master/doc/format.txt seq: - id: superblock From cc5f2b89b700e60cc13e9d6637689aedb16aa4d5 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Wed, 5 Aug 2020 12:24:46 +0300 Subject: [PATCH 03/15] Add doc to `block_log` --- filesystem/squashfs_superblock.ksy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index d81ab668d..3db03fe46 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -29,6 +29,9 @@ types: type: u2 - id: block_log type: u2 + doc: | + The log2 of the block size. If the two fields do not agree, the + archive is considered corrupted. - id: flags type: u2 - id: id_count @@ -53,4 +56,3 @@ types: type: u8 - id: export_table_start type: u8 - \ No newline at end of file From 5ee51ff38c97de7686481efb4ee25f01be27861c Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Wed, 5 Aug 2020 15:57:07 +0300 Subject: [PATCH 04/15] Add docs to fields and made compressor a enum --- filesystem/squashfs_superblock.ksy | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index 3db03fe46..98787dc62 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -12,6 +12,14 @@ doc-ref: https://github.com/AgentD/squashfs-tools-ng/blob/master/doc/format.txt seq: - id: superblock type: superblock +enums: + compressor: + 1: gzip + 2: lzo + 3: lzma + 4: xz + 5: lz4 + 6: zstd types: superblock: seq: @@ -21,12 +29,19 @@ types: type: u4 - id: mod_time type: u4 + doc: Unix times of last modification. - id: block_size type: u4 + doc: | + The size of a data block in bytes. Must be a power of two between + 4096 (4k) and 1048576 (1 MiB). - id: frag_count type: u4 + doc: The number of entries in the fragment table. - id: compressor type: u2 + enum: compressor + doc: Compressor used for both data and meta data blocks. - id: block_log type: u2 doc: | @@ -36,14 +51,20 @@ types: type: u2 - id: id_count type: u2 + doc: The number of entries in the ID lookup table. - id: version_major contents: [ 4, 0 ] - id: version_minor contents: [ 0, 0 ] - id: root_inode_ref type: u8 + doc: A reference to the inode of the root directory. - id: bytes_used type: u8 + doc: | + The number of bytes used by the archive. Because SquashFS + archives must be padded to a multiple of the underlying device + block size, this can be less than the actual file size. - id: id_table_start type: u8 - id: xattr_id_table_start From 46763e81c9ff70622d8b78693d300a7ba3ac9b0c Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Wed, 5 Aug 2020 21:08:41 +0300 Subject: [PATCH 05/15] Map `flags` to bit in SquashFS superblock --- filesystem/squashfs_superblock.ksy | 32 +++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index 98787dc62..f1ffa6eb6 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -21,6 +21,36 @@ enums: 5: lz4 6: zstd types: + flags: + seq: + # bit count starts from the largest, byte count form the smallest + - id: nfs_export_table + type: b1 + - id: data_deduplicated + type: b1 + - id: fragments_always_generated + type: b1 + - id: fragments_not_used + type: b1 + - id: fragments_uncompresed + type: b1 + - type: b1 + doc: 0x0004 bit is unused. + - id: data_blocks_uncompresed + type: b1 + - id: inodes_uncompresed + type: b1 + # bits 0x0100 are below, starting from the largest + - type: b4 + doc: bits 11110000 are unused + - id: id_table_uncompresed + type: b1 + - id: compressor_options_present + type: b1 + - id: xattrs_absent + type: b1 + - id: xattrs_uncompressed + type: b1 superblock: seq: - id: magic @@ -48,7 +78,7 @@ types: The log2 of the block size. If the two fields do not agree, the archive is considered corrupted. - id: flags - type: u2 + type: flags - id: id_count type: u2 doc: The number of entries in the ID lookup table. From 0f5147d85b62d53942432c11680fe2a7824c9a52 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Thu, 6 Aug 2020 20:13:16 +0300 Subject: [PATCH 06/15] Add description about what SquashFS is --- filesystem/squashfs_superblock.ksy | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index f1ffa6eb6..67261bde3 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -8,6 +8,11 @@ meta: license: CC-0 xref: wikidata: Q389314 +doc: | + SquashFS is a compressed filesystem in a file, that can be read-only + accessed from low memory devices. It is popular for booting LiveCDs and + packing self-contained binaries. SquashFS format is used by Ubuntu .snap + packages. SquashFS is natively supported by Linux Kernel. doc-ref: https://github.com/AgentD/squashfs-tools-ng/blob/master/doc/format.txt seq: - id: superblock From 85fc125b65ef154d129ab026543755ba63ec1612 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Fri, 7 Aug 2020 12:16:37 +0300 Subject: [PATCH 07/15] Add bitmask `0x` comments to `flags` --- filesystem/squashfs_superblock.ksy | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index 67261bde3..7626186e4 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -29,32 +29,30 @@ types: flags: seq: # bit count starts from the largest, byte count form the smallest - - id: nfs_export_table + - id: nfs_export_table # 0x0080 type: b1 - - id: data_deduplicated + - id: data_deduplicated # 0x0040 type: b1 - - id: fragments_always_generated + - id: fragments_always_generated # 0x0020 type: b1 - - id: fragments_not_used + - id: fragments_not_used # 0x0010 type: b1 - - id: fragments_uncompresed + - id: fragments_uncompresed # 0x0008 type: b1 - - type: b1 - doc: 0x0004 bit is unused. - - id: data_blocks_uncompresed + - type: b1 # 0x0004 bit is unused + - id: data_blocks_uncompresed # 0x0002 type: b1 - - id: inodes_uncompresed + - id: inodes_uncompresed # 0x0001 type: b1 # bits 0x0100 are below, starting from the largest - - type: b4 - doc: bits 11110000 are unused - - id: id_table_uncompresed + - type: b4 # bits 11110000 are unused + - id: id_table_uncompresed # 0x0800 type: b1 - - id: compressor_options_present + - id: compressor_options_present # 0x0400 type: b1 - - id: xattrs_absent + - id: xattrs_absent # 0x0200 type: b1 - - id: xattrs_uncompressed + - id: xattrs_uncompressed # 0x0100 type: b1 superblock: seq: From 98354695c29e2af861d97925db924f8c338dd8ab Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Sat, 2 Jan 2021 17:56:26 +0300 Subject: [PATCH 08/15] s/CC-0/CC0-1.0/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Petr Pučil --- filesystem/squashfs_superblock.ksy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index 7626186e4..fa7d93768 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -5,7 +5,7 @@ meta: - squashfs - snap endian: le - license: CC-0 + license: CC0-1.0 xref: wikidata: Q389314 doc: | From 6791fef0fd7f9ec30f8602ad66e9c5cad2f22153 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Sat, 2 Jan 2021 18:01:03 +0300 Subject: [PATCH 09/15] squashfs: Use `valid` instead of `contents` This reflects the field size in spec as agreed in review comments . --- filesystem/squashfs_superblock.ksy | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index fa7d93768..a7e561205 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -86,9 +86,13 @@ types: type: u2 doc: The number of entries in the ID lookup table. - id: version_major - contents: [ 4, 0 ] + type: u2 + valid: + eq: 4 - id: version_minor - contents: [ 0, 0 ] + type: u2 + valid: + eq: 0 - id: root_inode_ref type: u8 doc: A reference to the inode of the root directory. From 86188692d27c60f1d227a13585eb69ff4d51e006 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Mon, 15 Mar 2021 23:50:50 +0300 Subject: [PATCH 10/15] Add .sqfs as possible file-extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Petr Pučil --- filesystem/squashfs_superblock.ksy | 1 + 1 file changed, 1 insertion(+) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs_superblock.ksy index a7e561205..feaa2a029 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs_superblock.ksy @@ -4,6 +4,7 @@ meta: file-extension: - squashfs - snap + - sqfs endian: le license: CC0-1.0 xref: From e0236ce1ee9ad7c3d2b37821bcf03d96ebb17877 Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Sun, 3 Apr 2022 15:29:24 +0200 Subject: [PATCH 11/15] renamed squashfs_superblock to squashfs --- filesystem/{squashfs_superblock.ksy => squashfs.ksy} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename filesystem/{squashfs_superblock.ksy => squashfs.ksy} (98%) diff --git a/filesystem/squashfs_superblock.ksy b/filesystem/squashfs.ksy similarity index 98% rename from filesystem/squashfs_superblock.ksy rename to filesystem/squashfs.ksy index feaa2a029..f9f65658d 100644 --- a/filesystem/squashfs_superblock.ksy +++ b/filesystem/squashfs.ksy @@ -1,6 +1,6 @@ meta: - id: squashfs_superblock - title: SquashFS superblock + id: squashfs + title: SquashFS file-extension: - squashfs - snap From 73aff0198666de61c5182b72c66ee01c7ce9bbfc Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Sun, 3 Apr 2022 15:32:05 +0200 Subject: [PATCH 12/15] added support for reading metadata, inodes, directory entries and data blocks --- filesystem/squashfs.ksy | 349 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 345 insertions(+), 4 deletions(-) diff --git a/filesystem/squashfs.ksy b/filesystem/squashfs.ksy index f9f65658d..a907868d6 100644 --- a/filesystem/squashfs.ksy +++ b/filesystem/squashfs.ksy @@ -6,6 +6,7 @@ meta: - snap - sqfs endian: le + bit-endian: be license: CC0-1.0 xref: wikidata: Q389314 @@ -20,12 +21,60 @@ seq: type: superblock enums: compressor: - 1: gzip - 2: lzo - 3: lzma + 1: zlib + 2: lzma + 3: lzo 4: xz 5: lz4 6: zstd + inode_type: + 1: basic_directory + 2: basic_file + 3: basic_symlink + 4: basic_block_device + 5: basic_character_device + 6: basic_named_pipe + 7: basic_socket + 8: extended_directory + 9: extended_file + 10: extended_symlink + 11: extended_block_device + 12: extended_character_device + 13: extended_named_pipe + 14: extended_socket +instances: + id_table: + io: _root._io + pos: superblock.id_table_start + type: metablock_reference_list((superblock.bytes_used-superblock.id_table_start)/8) + xattr_id_table: + if: superblock.xattr_id_table_start != 18446744073709551615 + io: _root._io + pos: superblock.xattr_id_table_start + type: metablock_list + inode_table: + io: _root._io + pos: superblock.inode_table_start + type: inode_table + size: (superblock.directory_table_start-superblock.inode_table_start) + directory_table: + io: _root._io + pos: superblock.directory_table_start + type: directory_table + size: (superblock.fragment_table_start-superblock.directory_table_start) + fragment_table: + io: _root._io + pos: superblock.fragment_table_start + # ceil(frag_count*8/8192) + type: "metablock_reference_list((superblock.frag_count%1024 >0) ? 1 : 0 + superblock.frag_count*1024)" + export_table: + io: _root._io + pos: superblock.export_table_start + # ceil(inode_count*8/8192) + type: "metablock_reference_list((superblock.inode_count%1024 >0) ? 1 : 0 + superblock.inode_count*1024)" + fragments: + io: _root.fragment_table.data._io + type: fragments types: flags: seq: @@ -95,7 +144,7 @@ types: valid: eq: 0 - id: root_inode_ref - type: u8 + type: inode_reference doc: A reference to the inode of the root directory. - id: bytes_used type: u8 @@ -115,3 +164,295 @@ types: type: u8 - id: export_table_start type: u8 + inode_reference: + instances: + inode_block_start: + value: (raw >> 16) & 0xFFFFFFFF + block_offset: + value: raw & 0xFFFF + inode_table: + io: _root._io + pos: _root.superblock.inode_table_start + inode_block_start + type: inode_table_entry(block_offset) + size: (_root.superblock.directory_table_start-_root.superblock.inode_table_start-inode_block_start) + seq: + - id: raw + type: u8 + inode_table_entry: + params: + - id: offset + type: u2 + instances: + inode_header: + io: inodes._io + pos: offset + type: inode_header + seq: + - id: metablock_list + type: metablock_list + - id: inodes + # we want to concatenate the data of all metablocks, so we fake a 0-sized entry here. the decode method will be called with an empty array, but the constructor has the needed netablocks + size: 0 + process: concat(metablock_list) + type: block_content + inode_table: + seq: + - id: metablock_list + type: metablock_list + - id: inodes + # we want to concatenate the data of all metablocks, so we fake a 0-sized entry here. the decode method will be called with an empty array, but the constructor has the needed netablocks + size: 0 + process: concat(metablock_list) + type: inode_headers + directory_table: + seq: + - id: metablock_list + type: metablock_list + - id: directory + # we want to concatenate the data of all metablocks, so we fake a 0-sized entry here. the decode method will be called with an empty array, but the constructor has the needed netablocks + size: 0 + process: concat(metablock_list) + type: block_content + metablock_list: + seq: + - id: metablock + type: metablock + repeat: eos + metablock_reference_list: + params: + - id: count + type: u8 + seq: + - id: metablock_reference + type: metablock_reference(_index) + repeat: expr + repeat-expr: count + - id: data + # we want to concatenate the data of all metablocks, so we fake a 0-sized entry here. the decode method will be called with an empty array, but the constructor has the needed netablocks + size: 0 + process: concat(metablock_reference) + type: block_content + metablock_reference: + params: + - id: index + type: u4 + instances: + metablock: + io: _root._io + pos: position + type: metablock + seq: + - id: position + type: u8 + metablock: + instances: + compression: + value: (compression_and_len&0x8000)==0 + size: + value: compression_and_len&0x7FFF + seq: + - id: compression_and_len + type: u2 + - id: data + size: size + type: uncompressed_data(compression, 8192, false) + uncompressed_data: + params: + - id: compression + type: b1 + - id: max_size + type: u4 + - id: padded + type: b1 + seq: + - id: data + size-eos: true + process: decompress(compression, _root.superblock.compressor, max_size, padded) + block_content: + seq: + - id: dummy + size: 0 + directory: + seq: + - id: directory_header + type: directory_header + repeat: eos + directory_header: + seq: + - id: count + type: u4 + - id: start + type: u4 + - id: inode_number + type: s4 + - id: directory_entry + type: directory_entry + # sanity check + if: count < 256 + repeat: expr + repeat-expr: count + 1 + directory_entry: + seq: + - id: offset + type: u2 + - id: inode_offset + type: s2 + - id: type + type: u2 + - id: name_size + type: u2 + - id: name + type: str + size: name_size + 1 + encoding: 'ASCII' + inode_headers: + seq: + - id: inode_header + type: inode_header + repeat: expr + repeat-expr: _root.superblock.inode_count + inode_header: + seq: + - id: type + type: u2 + enum: inode_type + - id: permissions + type: u2 + - id: uid + type: u2 + - id: gid + type: u2 + - id: mtime + type: u4 + - id: inode_number + type: u4 + - id: header + type: + switch-on: type + cases: + 'inode_type::basic_directory': inode_header_basic_directory + 'inode_type::extended_directory': inode_header_extended_directory + 'inode_type::basic_file': inode_header_basic_file + inode_header_basic_directory: + instances: + directory_table: + io: _root._io + pos: _root.superblock.directory_table_start + dir_block_start + type: directory_table + size: (_root.superblock.fragment_table_start - _root.superblock.directory_table_start - dir_block_start) + dir: + io: directory_table.directory._io + pos: block_offset + size: file_size - 3 + type: directory + seq: + - id: dir_block_start + type: u4 + - id: hard_link_count + type: u4 + - id: file_size + type: u2 + - id: block_offset + type: u2 + - id: parent_inode_number + type: u4 + inode_header_extended_directory: + instances: + directory_table: + io: _root._io + pos: _root.superblock.directory_table_start + dir_block_start + type: directory_table + size: (_root.superblock.fragment_table_start - _root.superblock.directory_table_start - dir_block_start) + dir: + io: directory_table.directory._io + pos: block_offset + size: file_size - 3 + type: directory + seq: + - id: hard_link_count + type: u4 + - id: file_size + type: u4 + - id: dir_block_start + type: u4 + - id: parent_inode_number + type: u4 + - id: index_count + type: u2 + - id: block_offset + type: u2 + - id: xattr_idx + type: u4 + - id: index + type: directory_index + repeat: expr + repeat-expr: index_count + directory_index: + seq: + - id: index + type: u4 + - id: start + type: u4 + - id: name_size + type: u4 + - id: name + type: str + size: name_size + 1 + encoding: 'ASCII' + inode_header_basic_file: + instances: + fragment: + value: _root.fragments.fragments[frag_index] + if: frag_index!=0xFFFFFFFF + seq: + - id: blocks_start + type: u4 + - id: frag_index + type: u4 + - id: block_offset + type: u4 + - id: file_size + type: u4 + - id: block_sizes + type: u4 + repeat: expr + repeat-expr: "file_size / _root.superblock.block_size + (frag_index==0xFFFFFFFF ? 1 : 0)" + - id: blocks + size: 0 + type: data_block(_index==0?blocks_start:blocks[_index-1].start+blocks[_index-1].size, block_sizes[_index], _index!=block_sizes.size-1) + repeat: expr + repeat-expr: block_sizes.size + data_block: + params: + - id: start + type: u4 + - id: compression_and_len + type: u4 + - id: padded + type: b1 + instances: + compression: + value: (compression_and_len&0x1000000)==0 + size: + value: compression_and_len&0xFFFFFF + data: + io: _root._io + pos: start + size: size + type: uncompressed_data(compression, _root.superblock.block_size, padded) + fragments: + seq: + - id: fragments + type: fragment + repeat: eos + fragment: + seq: + - id: start + type: u8 + - id: compression_and_len + type: u4 + - id: unused + type: u4 + - id: block + size: 0 + type: data_block(start, compression_and_len, false) From 2f8e2aaaeed5744a0ceb57d901889f46bf7ec608 Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Sun, 3 Apr 2022 22:10:41 +0200 Subject: [PATCH 13/15] fix fragment_table metablock count calculation --- filesystem/squashfs.ksy | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/filesystem/squashfs.ksy b/filesystem/squashfs.ksy index a907868d6..69dc61012 100644 --- a/filesystem/squashfs.ksy +++ b/filesystem/squashfs.ksy @@ -65,13 +65,13 @@ instances: fragment_table: io: _root._io pos: superblock.fragment_table_start - # ceil(frag_count*8/8192) - type: "metablock_reference_list((superblock.frag_count%1024 >0) ? 1 : 0 + superblock.frag_count*1024)" + # ceil(frag_count*8/16384) + type: "metablock_reference_list(((superblock.frag_count%512 >0) ? 1 : 0) + superblock.frag_count/512)" export_table: io: _root._io pos: superblock.export_table_start # ceil(inode_count*8/8192) - type: "metablock_reference_list((superblock.inode_count%1024 >0) ? 1 : 0 + superblock.inode_count*1024)" + type: "metablock_reference_list(((superblock.inode_count%1024 >0) ? 1 : 0) + superblock.inode_count/1024)" fragments: io: _root.fragment_table.data._io type: fragments @@ -444,7 +444,8 @@ types: seq: - id: fragments type: fragment - repeat: eos + repeat: expr + repeat-expr: _root.superblock.frag_count fragment: seq: - id: start From 06c365f5e578b5f0a197d37f5db18812c0d1c5fd Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Wed, 20 Apr 2022 20:40:47 +0200 Subject: [PATCH 14/15] Update filesystem/squashfs.ksy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Petr Pučil --- filesystem/squashfs.ksy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filesystem/squashfs.ksy b/filesystem/squashfs.ksy index 69dc61012..fc6fd8993 100644 --- a/filesystem/squashfs.ksy +++ b/filesystem/squashfs.ksy @@ -48,7 +48,7 @@ instances: pos: superblock.id_table_start type: metablock_reference_list((superblock.bytes_used-superblock.id_table_start)/8) xattr_id_table: - if: superblock.xattr_id_table_start != 18446744073709551615 + if: superblock.xattr_id_table_start != 0xffff_ffff_ffff_ffff io: _root._io pos: superblock.xattr_id_table_start type: metablock_list From 0d109dd7e4dad08c38d4309494f273a6a22ac099 Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Tue, 26 Jul 2022 10:36:11 +0200 Subject: [PATCH 15/15] added uid/gid table support fixed kaitai compiler warnings added extended file support fixed data block count calculation --- filesystem/squashfs.ksy | 74 +++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/filesystem/squashfs.ksy b/filesystem/squashfs.ksy index fc6fd8993..a62bf076b 100644 --- a/filesystem/squashfs.ksy +++ b/filesystem/squashfs.ksy @@ -46,7 +46,8 @@ instances: id_table: io: _root._io pos: superblock.id_table_start - type: metablock_reference_list((superblock.bytes_used-superblock.id_table_start)/8) + # ceil(id_count/2048) + type: "metablock_reference_list(((superblock.id_count%2048 >0) ? 1 : 0) + superblock.id_count/2048)" xattr_id_table: if: superblock.xattr_id_table_start != 0xffff_ffff_ffff_ffff io: _root._io @@ -75,6 +76,9 @@ instances: fragments: io: _root.fragment_table.data._io type: fragments + uid_gid_entries: + io: _root.id_table.data._io + type: uid_gid_entries types: flags: seq: @@ -220,13 +224,13 @@ types: repeat: eos metablock_reference_list: params: - - id: count + - id: num_metablock_reference type: u8 seq: - id: metablock_reference type: metablock_reference(_index) repeat: expr - repeat-expr: count + repeat-expr: num_metablock_reference - id: data # we want to concatenate the data of all metablocks, so we fake a 0-sized entry here. the decode method will be called with an empty array, but the constructor has the needed netablocks size: 0 @@ -248,13 +252,13 @@ types: instances: compression: value: (compression_and_len&0x8000)==0 - size: + len_data: value: compression_and_len&0x7FFF seq: - id: compression_and_len type: u2 - id: data - size: size + size: len_data type: uncompressed_data(compression, 8192, false) uncompressed_data: params: @@ -333,6 +337,7 @@ types: 'inode_type::basic_directory': inode_header_basic_directory 'inode_type::extended_directory': inode_header_extended_directory 'inode_type::basic_file': inode_header_basic_file + 'inode_type::extended_file': inode_header_extended_file inode_header_basic_directory: instances: directory_table: @@ -377,7 +382,7 @@ types: type: u4 - id: parent_inode_number type: u4 - - id: index_count + - id: num_index type: u2 - id: block_offset type: u2 @@ -386,7 +391,7 @@ types: - id: index type: directory_index repeat: expr - repeat-expr: index_count + repeat-expr: num_index directory_index: seq: - id: index @@ -416,10 +421,47 @@ types: - id: block_sizes type: u4 repeat: expr - repeat-expr: "file_size / _root.superblock.block_size + (frag_index==0xFFFFFFFF ? 1 : 0)" + doc: | + A list of block sizes. If this file ends in a fragment, the size of this list is the number of full data + blocks needed to store file_size bytes. If this file does not have a fragment, the size of the list is the + number of blocks needed to store file_size bytes, rounded up. + repeat-expr: "file_size / _root.superblock.block_size + (frag_index==0xFFFFFFFF and (file_size.as / _root.superblock.block_size.as) > file_size / _root.superblock.block_size ? 1 : 0)" - id: blocks size: 0 - type: data_block(_index==0?blocks_start:blocks[_index-1].start+blocks[_index-1].size, block_sizes[_index], _index!=block_sizes.size-1) + type: data_block(_index==0?blocks_start:blocks[_index-1].start+blocks[_index-1].len_data, block_sizes[_index], _index!=block_sizes.size-1) + repeat: expr + repeat-expr: block_sizes.size + inode_header_extended_file: + instances: + fragment: + value: _root.fragments.fragments[frag_index] + if: frag_index!=0xFFFFFFFF + seq: + - id: blocks_start + type: u8 + - id: file_size + type: u8 + - id: sparse + type: u8 + - id: hardlink_count + type: u4 + - id: frag_index + type: u4 + - id: block_offset + type: u4 + - id: xattr_idx + type: u4 + - id: block_sizes + type: u4 + repeat: expr + doc: | + A list of block sizes. If this file ends in a fragment, the size of this list is the number of full data + blocks needed to store file_size bytes. If this file does not have a fragment, the size of the list is the + number of blocks needed to store file_size bytes, rounded up. + repeat-expr: "file_size / _root.superblock.block_size + (frag_index==0xFFFFFFFF and (file_size.as / _root.superblock.block_size.as) > file_size / _root.superblock.block_size ? 1 : 0)" + - id: blocks + size: 0 + type: data_block(_index==0?blocks_start:blocks[_index-1].start+blocks[_index-1].len_data, block_sizes[_index], _index!=block_sizes.size-1) repeat: expr repeat-expr: block_sizes.size data_block: @@ -433,12 +475,12 @@ types: instances: compression: value: (compression_and_len&0x1000000)==0 - size: + len_data: value: compression_and_len&0xFFFFFF data: io: _root._io pos: start - size: size + size: len_data type: uncompressed_data(compression, _root.superblock.block_size, padded) fragments: seq: @@ -457,3 +499,13 @@ types: - id: block size: 0 type: data_block(start, compression_and_len, false) + uid_gid_entries: + seq: + - id: uid_gid_entries + type: uid_gid_entry + repeat: expr + repeat-expr: _root.superblock.id_count + uid_gid_entry: + seq: + - id: uid_gid + type: u4