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