From 948ebd7e91f29efea22bc4987582efb827940294 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 9 Dec 2010 17:06:49 +0100 Subject: [PATCH] Support fragments and chunks for data --- grub-core/fs/squash4.c | 91 +++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c index 1622d3736..6fc2bc11b 100644 --- a/grub-core/fs/squash4.c +++ b/grub-core/fs/squash4.c @@ -28,16 +28,16 @@ #include /* - object format Pointed by - superblock RAW Fixed offset (0) - data RAW ? Fixed offset (60) - inode table Chunk superblock - dir table Chunk superblock - unk3 Chunk unk1 - unk1 RAW, Chunk superblock - unk2 RAW superblock - UID/GID Chunk exttblptr - exttblptr RAW superblock + object format Pointed by + superblock RAW Fixed offset (0) + data RAW ? Fixed offset (60) + inode table Chunk superblock + dir table Chunk superblock + fragment table Chunk unk1 + unk1 RAW, Chunk superblock + unk2 RAW superblock + UID/GID Chunk exttblptr + exttblptr RAW superblock UID/GID table is the array ot uint32_t unk1 contains pointer to unk3 followed by some chunk. @@ -73,8 +73,8 @@ struct grub_squash_inode grub_uint16_t dummy1[3]; grub_uint32_t mtime; grub_uint16_t dummy2[2]; - grub_uint16_t chunk; - grub_uint16_t dummy3[3]; + grub_uint32_t chunk; + grub_uint32_t fragment; grub_uint32_t offset; grub_uint32_t size; } __attribute__ ((packed)); @@ -105,10 +105,30 @@ struct grub_squash_dirent char name[0]; }; +struct grub_squash_frag_desc +{ + grub_uint64_t offset; + grub_uint64_t dummy; +}; + #define SQUASH_CHUNK_SIZE 0x2000 #define SQUASH_CHUNK_FLAGS 0x8000 #define SQUASH_CHUNK_UNCOMPRESSED 0x8000 +struct grub_squash_data +{ + grub_disk_t disk; + struct grub_squash_super sb; + struct grub_squash_inode ino; + grub_uint64_t fragments; +}; + +struct grub_fshelp_node +{ + struct grub_squash_data *data; + struct grub_squash_inode ino; +}; + static grub_err_t read_chunk (grub_disk_t disk, void *buf, grub_size_t len, grub_uint64_t chunk, unsigned nchunk, grub_off_t offset) @@ -161,25 +181,13 @@ read_chunk (grub_disk_t disk, void *buf, grub_size_t len, return GRUB_ERR_NONE; } -struct grub_squash_data -{ - grub_disk_t disk; - struct grub_squash_super sb; - struct grub_squash_inode ino; -}; - -struct grub_fshelp_node -{ - struct grub_squash_data *data; - struct grub_squash_inode ino; -}; - static struct grub_squash_data * squash_mount (grub_disk_t disk) { struct grub_squash_super sb; grub_err_t err; struct grub_squash_data *data; + grub_uint64_t frag; err = grub_disk_read (disk, 0, 0, sizeof (sb), &sb); if (grub_errno == GRUB_ERR_OUT_OF_RANGE) @@ -191,11 +199,22 @@ squash_mount (grub_disk_t disk) grub_error (GRUB_ERR_BAD_FS, "not squash4"); return NULL; } + + err = grub_disk_read (disk, grub_le_to_cpu32 (sb.unk1offset) + >> GRUB_DISK_SECTOR_BITS, + grub_le_to_cpu32 (sb.unk1offset) + & (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_error (GRUB_ERR_BAD_FS, "not a squash4"); + if (err) + return NULL; + data = grub_malloc (sizeof (*data)); if (!data) return NULL; data->sb = sb; data->disk = disk; + data->fragments = frag; return data; } @@ -356,6 +375,7 @@ grub_squash_open (struct grub_file *file, const char *name) file->data = data; data->ino = fdiro->ino; file->size = grub_le_to_cpu32 (fdiro->ino.size); + return GRUB_ERR_NONE; } @@ -366,8 +386,25 @@ grub_squash_read (grub_file_t file, char *buf, grub_size_t len) grub_uint64_t a; struct grub_squash_data *data = file->data; - a = sizeof (struct grub_squash_super) + grub_le_to_cpu32 (data->ino.offset) - + file->offset; + a = grub_le_to_cpu32 (data->ino.offset) + file->offset; + if (grub_le_to_cpu16 (data->ino.fragment) == 0xffff) + { + if (grub_le_to_cpu32 (data->ino.chunk)) + a += grub_le_to_cpu32 (data->ino.chunk); + else + a += sizeof (struct grub_squash_super); + } + else + { + struct grub_squash_frag_desc frag; + err = read_chunk (file->device->disk, &frag, sizeof (frag), + data->fragments, 0, sizeof (frag) + * grub_le_to_cpu16 (data->ino.fragment)); + if (err) + return -1; + a += grub_le_to_cpu64 (frag.offset); + a += grub_le_to_cpu32 (data->ino.chunk); + } err = grub_disk_read (file->device->disk, a >> GRUB_DISK_SECTOR_BITS, a & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);