1/* 2 * Unsquash a squashfs filesystem. This is a highly compressed read only 3 * filesystem. 4 * 5 * Copyright (c) 2009, 2010 6 * Phillip Lougher <phillip@lougher.demon.co.uk> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 2, 11 * or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 * 22 * unsquash-2.c 23 */ 24 25#include "unsquashfs.h" 26#include "squashfs_compat.h" 27 28static squashfs_fragment_entry_2 *fragment_table; 29 30void read_block_list_2(unsigned int *block_list, char *block_ptr, int blocks) 31{ 32 TRACE("read_block_list: blocks %d\n", blocks); 33 34 if(swap) { 35 unsigned int sblock_list[blocks]; 36 memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int)); 37 SQUASHFS_SWAP_INTS_3(block_list, sblock_list, blocks); 38 } else 39 memcpy(block_list, block_ptr, blocks * sizeof(unsigned int)); 40} 41 42 43int read_fragment_table_2() 44{ 45 int res, i, indexes = SQUASHFS_FRAGMENT_INDEXES_2(sBlk.s.fragments); 46 unsigned int fragment_table_index[indexes]; 47 48 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " 49 "from 0x%llx\n", sBlk.s.fragments, indexes, 50 sBlk.s.fragment_table_start); 51 52 if(sBlk.s.fragments == 0) 53 return TRUE; 54 55 fragment_table = malloc(sBlk.s.fragments * 56 sizeof(squashfs_fragment_entry_2)); 57 if(fragment_table == NULL) 58 EXIT_UNSQUASH("read_fragment_table: failed to allocate " 59 "fragment table\n"); 60 61 if(swap) { 62 unsigned int sfragment_table_index[indexes]; 63 64 res = read_fs_bytes(fd, sBlk.s.fragment_table_start, 65 SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.s.fragments), 66 sfragment_table_index); 67 if(res == FALSE) { 68 ERROR("read_fragment_table: failed to read fragment " 69 "table index\n"); 70 return FALSE; 71 } 72 SQUASHFS_SWAP_FRAGMENT_INDEXES_2(fragment_table_index, 73 sfragment_table_index, indexes); 74 } else { 75 res = read_fs_bytes(fd, sBlk.s.fragment_table_start, 76 SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.s.fragments), 77 fragment_table_index); 78 if(res == FALSE) { 79 ERROR("read_fragment_table: failed to read fragment " 80 "table index\n"); 81 return FALSE; 82 } 83 } 84 85 for(i = 0; i < indexes; i++) { 86 int length = read_block(fd, fragment_table_index[i], NULL, 87 ((char *) fragment_table) + (i * 88 SQUASHFS_METADATA_SIZE)); 89 TRACE("Read fragment table block %d, from 0x%x, length %d\n", i, 90 fragment_table_index[i], length); 91 if(length == FALSE) { 92 ERROR("read_fragment_table: failed to read fragment " 93 "table block\n"); 94 return FALSE; 95 } 96 } 97 98 if(swap) { 99 squashfs_fragment_entry_2 sfragment; 100 for(i = 0; i < sBlk.s.fragments; i++) { 101 SQUASHFS_SWAP_FRAGMENT_ENTRY_2((&sfragment), 102 (&fragment_table[i])); 103 memcpy((char *) &fragment_table[i], (char *) &sfragment, 104 sizeof(squashfs_fragment_entry_2)); 105 } 106 } 107 108 return TRUE; 109} 110 111 112void read_fragment_2(unsigned int fragment, long long *start_block, int *size) 113{ 114 TRACE("read_fragment: reading fragment %d\n", fragment); 115 116 squashfs_fragment_entry_2 *fragment_entry = &fragment_table[fragment]; 117 *start_block = fragment_entry->start_block; 118 *size = fragment_entry->size; 119} 120 121 122struct inode *read_inode_2(unsigned int start_block, unsigned int offset) 123{ 124 static union squashfs_inode_header_2 header; 125 long long start = sBlk.s.inode_table_start + start_block; 126 int bytes = lookup_entry(inode_table_hash, start); 127 char *block_ptr = inode_table + bytes + offset; 128 static struct inode i; 129 130 TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset); 131 132 if(bytes == -1) 133 EXIT_UNSQUASH("read_inode: inode table block %lld not found\n", 134 start); 135 136 if(swap) { 137 squashfs_base_inode_header_2 sinode; 138 memcpy(&sinode, block_ptr, sizeof(header.base)); 139 SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode, 140 sizeof(squashfs_base_inode_header_2)); 141 } else 142 memcpy(&header.base, block_ptr, sizeof(header.base)); 143 144 i.xattr = SQUASHFS_INVALID_XATTR; 145 i.uid = (uid_t) uid_table[header.base.uid]; 146 i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid : 147 (uid_t) guid_table[header.base.guid]; 148 i.mode = lookup_type[header.base.inode_type] | header.base.mode; 149 i.type = header.base.inode_type; 150 i.time = sBlk.s.mkfs_time; 151 i.inode_number = inode_number++; 152 153 switch(header.base.inode_type) { 154 case SQUASHFS_DIR_TYPE: { 155 squashfs_dir_inode_header_2 *inode = &header.dir; 156 157 if(swap) { 158 squashfs_dir_inode_header_2 sinode; 159 memcpy(&sinode, block_ptr, sizeof(header.dir)); 160 SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir, 161 &sinode); 162 } else 163 memcpy(&header.dir, block_ptr, 164 sizeof(header.dir)); 165 166 i.data = inode->file_size; 167 i.offset = inode->offset; 168 i.start = inode->start_block; 169 i.time = inode->mtime; 170 break; 171 } 172 case SQUASHFS_LDIR_TYPE: { 173 squashfs_ldir_inode_header_2 *inode = &header.ldir; 174 175 if(swap) { 176 squashfs_ldir_inode_header_2 sinode; 177 memcpy(&sinode, block_ptr, sizeof(header.ldir)); 178 SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir, 179 &sinode); 180 } else 181 memcpy(&header.ldir, block_ptr, 182 sizeof(header.ldir)); 183 184 i.data = inode->file_size; 185 i.offset = inode->offset; 186 i.start = inode->start_block; 187 i.time = inode->mtime; 188 break; 189 } 190 case SQUASHFS_FILE_TYPE: { 191 squashfs_reg_inode_header_2 *inode = &header.reg; 192 193 if(swap) { 194 squashfs_reg_inode_header_2 sinode; 195 memcpy(&sinode, block_ptr, sizeof(sinode)); 196 SQUASHFS_SWAP_REG_INODE_HEADER_2(inode, 197 &sinode); 198 } else 199 memcpy(inode, block_ptr, sizeof(*inode)); 200 201 i.data = inode->file_size; 202 i.time = inode->mtime; 203 i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG 204 ? 0 : inode->file_size % sBlk.s.block_size; 205 i.fragment = inode->fragment; 206 i.offset = inode->offset; 207 i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? 208 (i.data + sBlk.s.block_size - 1) >> 209 sBlk.s.block_log : i.data >> 210 sBlk.s.block_log; 211 i.start = inode->start_block; 212 i.sparse = 0; 213 i.block_ptr = block_ptr + sizeof(*inode); 214 break; 215 } 216 case SQUASHFS_SYMLINK_TYPE: { 217 squashfs_symlink_inode_header_2 *inodep = 218 &header.symlink; 219 220 if(swap) { 221 squashfs_symlink_inode_header_2 sinodep; 222 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 223 SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, 224 &sinodep); 225 } else 226 memcpy(inodep, block_ptr, sizeof(*inodep)); 227 228 i.symlink = malloc(inodep->symlink_size + 1); 229 if(i.symlink == NULL) 230 EXIT_UNSQUASH("read_inode: failed to malloc " 231 "symlink data\n"); 232 strncpy(i.symlink, block_ptr + 233 sizeof(squashfs_symlink_inode_header_2), 234 inodep->symlink_size); 235 i.symlink[inodep->symlink_size] = '\0'; 236 i.data = inodep->symlink_size; 237 break; 238 } 239 case SQUASHFS_BLKDEV_TYPE: 240 case SQUASHFS_CHRDEV_TYPE: { 241 squashfs_dev_inode_header_2 *inodep = &header.dev; 242 243 if(swap) { 244 squashfs_dev_inode_header_2 sinodep; 245 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 246 SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, 247 &sinodep); 248 } else 249 memcpy(inodep, block_ptr, sizeof(*inodep)); 250 251 i.data = inodep->rdev; 252 break; 253 } 254 case SQUASHFS_FIFO_TYPE: 255 case SQUASHFS_SOCKET_TYPE: 256 i.data = 0; 257 break; 258 default: 259 EXIT_UNSQUASH("Unknown inode type %d in " 260 "read_inode_header_2!\n", 261 header.base.inode_type); 262 } 263 return &i; 264} 265