summaryrefslogtreecommitdiff
path: root/lib/sqfs
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2021-07-21 09:41:47 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2021-07-21 09:56:31 +0200
commit248494992442fbde7eb6ca3979a778d82fa86016 (patch)
tree3ba8d5100aef7cf0d1f1aeae9f306fd5e6053503 /lib/sqfs
parent5333fbe46bcbf70b4888bcc6655681f2cd0f161b (diff)
Fix libsquashfs directory writer size accounting
The squashfs readdir() implementation in the Linux kernel returns non-existing "." and ".." entries for offsets 0 and 1, and after that reads from disk. For convenience, it was decided to store an off-by-3 value on disk instead of doing complex primary school math to adjust for this. This didn't show up until now, because the kernel implementation trusts the value from the directory header more than the actual size in the inode and happily reads 3 more than the inode would allow it to. This only showed up with 7-zip which subtracts 3 from the size and expects the result to be exact and bails if the directory headers suggest otherwise. And yes, I did consider making a "Holy Hand Granade of Antioch" reference, but consciously decided not to. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs')
-rw-r--r--lib/sqfs/dir_writer.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/lib/sqfs/dir_writer.c b/lib/sqfs/dir_writer.c
index 908bb01..ad44458 100644
--- a/lib/sqfs/dir_writer.c
+++ b/lib/sqfs/dir_writer.c
@@ -379,7 +379,7 @@ sqfs_inode_generic_t
block_offset = writer->dir_ref & 0xFFFF;
if (xattr != 0xFFFFFFFF || start_block > 0xFFFFFFFFUL ||
- writer->dir_size > 0xFFFF) {
+ writer->dir_size > (0xFFFF - 3)) {
inode->base.type = SQFS_INODE_EXT_DIR;
} else {
inode->base.type = SQFS_INODE_DIR;
@@ -388,12 +388,12 @@ sqfs_inode_generic_t
if (inode->base.type == SQFS_INODE_DIR) {
inode->data.dir.start_block = start_block;
inode->data.dir.nlink = writer->ent_count + hlinks + 2;
- inode->data.dir.size = writer->dir_size;
+ inode->data.dir.size = writer->dir_size + 3;
inode->data.dir.offset = block_offset;
inode->data.dir.parent_inode = parent_ino;
} else {
inode->data.dir_ext.nlink = writer->ent_count + hlinks + 2;
- inode->data.dir_ext.size = writer->dir_size;
+ inode->data.dir_ext.size = writer->dir_size + 3;
inode->data.dir_ext.start_block = start_block;
inode->data.dir_ext.parent_inode = parent_ino;
inode->data.dir_ext.offset = block_offset;