1 /* 2 * Unsquash a squashfs filesystem. This is a highly compressed read only 3 * filesystem. 4 * 5 * Copyright (c) 2009, 2010, 2013 6 * Phillip Lougher <phillip (at) squashfs.org.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 28 static squashfs_fragment_entry_2 *fragment_table; 29 30 void 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 43 int read_fragment_table_2(long long *directory_table_end) 44 { 45 int res, i; 46 int bytes = SQUASHFS_FRAGMENT_BYTES_2(sBlk.s.fragments); 47 int indexes = SQUASHFS_FRAGMENT_INDEXES_2(sBlk.s.fragments); 48 unsigned int fragment_table_index[indexes]; 49 50 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " 51 "from 0x%llx\n", sBlk.s.fragments, indexes, 52 sBlk.s.fragment_table_start); 53 54 if(sBlk.s.fragments == 0) { 55 *directory_table_end = sBlk.s.fragment_table_start; 56 return TRUE; 57 } 58 59 fragment_table = malloc(bytes); 60 if(fragment_table == NULL) 61 EXIT_UNSQUASH("read_fragment_table: failed to allocate " 62 "fragment table\n"); 63 64 if(swap) { 65 unsigned int sfragment_table_index[indexes]; 66 67 res = read_fs_bytes(fd, sBlk.s.fragment_table_start, 68 SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.s.fragments), 69 sfragment_table_index); 70 if(res == FALSE) { 71 ERROR("read_fragment_table: failed to read fragment " 72 "table index\n"); 73 return FALSE; 74 } 75 SQUASHFS_SWAP_FRAGMENT_INDEXES_2(fragment_table_index, 76 sfragment_table_index, indexes); 77 } else { 78 res = read_fs_bytes(fd, sBlk.s.fragment_table_start, 79 SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.s.fragments), 80 fragment_table_index); 81 if(res == FALSE) { 82 ERROR("read_fragment_table: failed to read fragment " 83 "table index\n"); 84 return FALSE; 85 } 86 } 87 88 for(i = 0; i < indexes; i++) { 89 int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : 90 bytes & (SQUASHFS_METADATA_SIZE - 1); 91 int length = read_block(fd, fragment_table_index[i], NULL, 92 expected, ((char *) fragment_table) + (i * 93 SQUASHFS_METADATA_SIZE)); 94 TRACE("Read fragment table block %d, from 0x%x, length %d\n", i, 95 fragment_table_index[i], length); 96 if(length == FALSE) { 97 ERROR("read_fragment_table: failed to read fragment " 98 "table block\n"); 99 return FALSE; 100 } 101 } 102 103 if(swap) { 104 squashfs_fragment_entry_2 sfragment; 105 for(i = 0; i < sBlk.s.fragments; i++) { 106 SQUASHFS_SWAP_FRAGMENT_ENTRY_2((&sfragment), 107 (&fragment_table[i])); 108 memcpy((char *) &fragment_table[i], (char *) &sfragment, 109 sizeof(squashfs_fragment_entry_2)); 110 } 111 } 112 113 *directory_table_end = fragment_table_index[0]; 114 return TRUE; 115 } 116 117 118 void read_fragment_2(unsigned int fragment, long long *start_block, int *size) 119 { 120 TRACE("read_fragment: reading fragment %d\n", fragment); 121 122 squashfs_fragment_entry_2 *fragment_entry = &fragment_table[fragment]; 123 *start_block = fragment_entry->start_block; 124 *size = fragment_entry->size; 125 } 126 127 128 struct inode *read_inode_2(unsigned int start_block, unsigned int offset) 129 { 130 static union squashfs_inode_header_2 header; 131 long long start = sBlk.s.inode_table_start + start_block; 132 int bytes = lookup_entry(inode_table_hash, start); 133 char *block_ptr = inode_table + bytes + offset; 134 static struct inode i; 135 136 TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset); 137 138 if(bytes == -1) 139 EXIT_UNSQUASH("read_inode: inode table block %lld not found\n", 140 start); 141 142 if(swap) { 143 squashfs_base_inode_header_2 sinode; 144 memcpy(&sinode, block_ptr, sizeof(header.base)); 145 SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode, 146 sizeof(squashfs_base_inode_header_2)); 147 } else 148 memcpy(&header.base, block_ptr, sizeof(header.base)); 149 150 i.xattr = SQUASHFS_INVALID_XATTR; 151 i.uid = (uid_t) uid_table[header.base.uid]; 152 i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid : 153 (uid_t) guid_table[header.base.guid]; 154 i.mode = lookup_type[header.base.inode_type] | header.base.mode; 155 i.type = header.base.inode_type; 156 i.time = sBlk.s.mkfs_time; 157 i.inode_number = inode_number++; 158 159 switch(header.base.inode_type) { 160 case SQUASHFS_DIR_TYPE: { 161 squashfs_dir_inode_header_2 *inode = &header.dir; 162 163 if(swap) { 164 squashfs_dir_inode_header_2 sinode; 165 memcpy(&sinode, block_ptr, sizeof(header.dir)); 166 SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir, 167 &sinode); 168 } else 169 memcpy(&header.dir, block_ptr, 170 sizeof(header.dir)); 171 172 i.data = inode->file_size; 173 i.offset = inode->offset; 174 i.start = inode->start_block; 175 i.time = inode->mtime; 176 break; 177 } 178 case SQUASHFS_LDIR_TYPE: { 179 squashfs_ldir_inode_header_2 *inode = &header.ldir; 180 181 if(swap) { 182 squashfs_ldir_inode_header_2 sinode; 183 memcpy(&sinode, block_ptr, sizeof(header.ldir)); 184 SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir, 185 &sinode); 186 } else 187 memcpy(&header.ldir, block_ptr, 188 sizeof(header.ldir)); 189 190 i.data = inode->file_size; 191 i.offset = inode->offset; 192 i.start = inode->start_block; 193 i.time = inode->mtime; 194 break; 195 } 196 case SQUASHFS_FILE_TYPE: { 197 squashfs_reg_inode_header_2 *inode = &header.reg; 198 199 if(swap) { 200 squashfs_reg_inode_header_2 sinode; 201 memcpy(&sinode, block_ptr, sizeof(sinode)); 202 SQUASHFS_SWAP_REG_INODE_HEADER_2(inode, 203 &sinode); 204 } else 205 memcpy(inode, block_ptr, sizeof(*inode)); 206 207 i.data = inode->file_size; 208 i.time = inode->mtime; 209 i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG 210 ? 0 : inode->file_size % sBlk.s.block_size; 211 i.fragment = inode->fragment; 212 i.offset = inode->offset; 213 i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? 214 (i.data + sBlk.s.block_size - 1) >> 215 sBlk.s.block_log : i.data >> 216 sBlk.s.block_log; 217 i.start = inode->start_block; 218 i.sparse = 0; 219 i.block_ptr = block_ptr + sizeof(*inode); 220 break; 221 } 222 case SQUASHFS_SYMLINK_TYPE: { 223 squashfs_symlink_inode_header_2 *inodep = 224 &header.symlink; 225 226 if(swap) { 227 squashfs_symlink_inode_header_2 sinodep; 228 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 229 SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, 230 &sinodep); 231 } else 232 memcpy(inodep, block_ptr, sizeof(*inodep)); 233 234 i.symlink = malloc(inodep->symlink_size + 1); 235 if(i.symlink == NULL) 236 EXIT_UNSQUASH("read_inode: failed to malloc " 237 "symlink data\n"); 238 strncpy(i.symlink, block_ptr + 239 sizeof(squashfs_symlink_inode_header_2), 240 inodep->symlink_size); 241 i.symlink[inodep->symlink_size] = '\0'; 242 i.data = inodep->symlink_size; 243 break; 244 } 245 case SQUASHFS_BLKDEV_TYPE: 246 case SQUASHFS_CHRDEV_TYPE: { 247 squashfs_dev_inode_header_2 *inodep = &header.dev; 248 249 if(swap) { 250 squashfs_dev_inode_header_2 sinodep; 251 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 252 SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, 253 &sinodep); 254 } else 255 memcpy(inodep, block_ptr, sizeof(*inodep)); 256 257 i.data = inodep->rdev; 258 break; 259 } 260 case SQUASHFS_FIFO_TYPE: 261 case SQUASHFS_SOCKET_TYPE: 262 i.data = 0; 263 break; 264 default: 265 EXIT_UNSQUASH("Unknown inode type %d in " 266 "read_inode_header_2!\n", 267 header.base.inode_type); 268 } 269 return &i; 270 } 271