unsquashfs.c revision 9b5bf8c73c0eaf4f1ba0461615f4ed0d405a30cc
1443c15812032991c98b33b5424b17bcd55fe3575plougher/* 2443c15812032991c98b33b5424b17bcd55fe3575plougher * Unsquash a squashfs filesystem. This is a highly compressed read only filesystem. 3443c15812032991c98b33b5424b17bcd55fe3575plougher * 4769592935b09063a5493ebeb530c599753ece5d2plougher * Copyright (c) 2002, 2003, 2004, 2005, 2006 59b5bf8c73c0eaf4f1ba0461615f4ed0d405a30ccplougher * Phillip Lougher <phillip@lougher.org.uk> 6443c15812032991c98b33b5424b17bcd55fe3575plougher * 7443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is free software; you can redistribute it and/or 8443c15812032991c98b33b5424b17bcd55fe3575plougher * modify it under the terms of the GNU General Public License 9443c15812032991c98b33b5424b17bcd55fe3575plougher * as published by the Free Software Foundation; either version 2, 10443c15812032991c98b33b5424b17bcd55fe3575plougher * or (at your option) any later version. 11443c15812032991c98b33b5424b17bcd55fe3575plougher * 12443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is distributed in the hope that it will be useful, 13443c15812032991c98b33b5424b17bcd55fe3575plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of 14443c15812032991c98b33b5424b17bcd55fe3575plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15443c15812032991c98b33b5424b17bcd55fe3575plougher * GNU General Public License for more details. 16443c15812032991c98b33b5424b17bcd55fe3575plougher * 17443c15812032991c98b33b5424b17bcd55fe3575plougher * You should have received a copy of the GNU General Public License 18443c15812032991c98b33b5424b17bcd55fe3575plougher * along with this program; if not, write to the Free Software 19443c15812032991c98b33b5424b17bcd55fe3575plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20443c15812032991c98b33b5424b17bcd55fe3575plougher * 21443c15812032991c98b33b5424b17bcd55fe3575plougher * unsquash.c 22443c15812032991c98b33b5424b17bcd55fe3575plougher */ 23443c15812032991c98b33b5424b17bcd55fe3575plougher 24443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRUE 1 25443c15812032991c98b33b5424b17bcd55fe3575plougher#define FALSE 0 26443c15812032991c98b33b5424b17bcd55fe3575plougher#include <stdio.h> 27443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/types.h> 28443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/stat.h> 29443c15812032991c98b33b5424b17bcd55fe3575plougher#include <fcntl.h> 30443c15812032991c98b33b5424b17bcd55fe3575plougher#include <errno.h> 31443c15812032991c98b33b5424b17bcd55fe3575plougher#include <string.h> 32443c15812032991c98b33b5424b17bcd55fe3575plougher#include <zlib.h> 33443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/mman.h> 34443c15812032991c98b33b5424b17bcd55fe3575plougher#include <utime.h> 35443c15812032991c98b33b5424b17bcd55fe3575plougher 36443c15812032991c98b33b5424b17bcd55fe3575plougher#ifndef linux 37443c15812032991c98b33b5424b17bcd55fe3575plougher#define __BYTE_ORDER BYTE_ORDER 38443c15812032991c98b33b5424b17bcd55fe3575plougher#define __BIG_ENDIAN BIG_ENDIAN 39443c15812032991c98b33b5424b17bcd55fe3575plougher#define __LITTLE_ENDIAN LITTLE_ENDIAN 40443c15812032991c98b33b5424b17bcd55fe3575plougher#else 41443c15812032991c98b33b5424b17bcd55fe3575plougher#include <endian.h> 42443c15812032991c98b33b5424b17bcd55fe3575plougher#endif 43443c15812032991c98b33b5424b17bcd55fe3575plougher 44443c15812032991c98b33b5424b17bcd55fe3575plougher#include <squashfs_fs.h> 45443c15812032991c98b33b5424b17bcd55fe3575plougher#include "read_fs.h" 46443c15812032991c98b33b5424b17bcd55fe3575plougher#include "global.h" 47443c15812032991c98b33b5424b17bcd55fe3575plougher 48443c15812032991c98b33b5424b17bcd55fe3575plougher#include <stdlib.h> 49443c15812032991c98b33b5424b17bcd55fe3575plougher 50443c15812032991c98b33b5424b17bcd55fe3575plougher#ifdef SQUASHFS_TRACE 51443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRACE(s, args...) do { \ 52443c15812032991c98b33b5424b17bcd55fe3575plougher printf("mksquashfs: "s, ## args); \ 53443c15812032991c98b33b5424b17bcd55fe3575plougher } while(0) 54443c15812032991c98b33b5424b17bcd55fe3575plougher#else 55443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRACE(s, args...) 56443c15812032991c98b33b5424b17bcd55fe3575plougher#endif 57443c15812032991c98b33b5424b17bcd55fe3575plougher 58443c15812032991c98b33b5424b17bcd55fe3575plougher#define ERROR(s, args...) do { \ 59443c15812032991c98b33b5424b17bcd55fe3575plougher fprintf(stderr, s, ## args); \ 60443c15812032991c98b33b5424b17bcd55fe3575plougher } while(0) 61443c15812032991c98b33b5424b17bcd55fe3575plougher 62443c15812032991c98b33b5424b17bcd55fe3575plougher#define EXIT_UNSQUASH(s, args...) do { \ 63443c15812032991c98b33b5424b17bcd55fe3575plougher fprintf(stderr, "FATAL ERROR aborting: "s, ## args); \ 64443c15812032991c98b33b5424b17bcd55fe3575plougher } while(0) 65443c15812032991c98b33b5424b17bcd55fe3575plougher 66443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry { 67443c15812032991c98b33b5424b17bcd55fe3575plougher int start; 68443c15812032991c98b33b5424b17bcd55fe3575plougher int bytes; 69443c15812032991c98b33b5424b17bcd55fe3575plougher struct hash_table_entry *next; 70443c15812032991c98b33b5424b17bcd55fe3575plougher}; 71443c15812032991c98b33b5424b17bcd55fe3575plougher 72443c15812032991c98b33b5424b17bcd55fe3575plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, dev_count = 0, fifo_count = 0; 73443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL; 74443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536]; 75443c15812032991c98b33b5424b17bcd55fe3575plougherint fd; 76443c15812032991c98b33b5424b17bcd55fe3575ploughersquashfs_fragment_entry *fragment_table; 77443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table; 78443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG; 79443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data; 80443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data; 81443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data; 82443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size; 83443c15812032991c98b33b5424b17bcd55fe3575plougherint lsonly = FALSE, info = FALSE; 84443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode; 85443c15812032991c98b33b5424b17bcd55fe3575plougher 86443c15812032991c98b33b5424b17bcd55fe3575plougher#define CALCULATE_HASH(start) (start & 0xffff) 87443c15812032991c98b33b5424b17bcd55fe3575plougher 88443c15812032991c98b33b5424b17bcd55fe3575plougherint add_entry(struct hash_table_entry *hash_table[], int start, int bytes) 89443c15812032991c98b33b5424b17bcd55fe3575plougher{ 90443c15812032991c98b33b5424b17bcd55fe3575plougher int hash = CALCULATE_HASH(start); 91443c15812032991c98b33b5424b17bcd55fe3575plougher struct hash_table_entry *hash_table_entry; 92443c15812032991c98b33b5424b17bcd55fe3575plougher 93443c15812032991c98b33b5424b17bcd55fe3575plougher if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) { 94443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("add_hash: out of memory in malloc\n"); 95443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 96443c15812032991c98b33b5424b17bcd55fe3575plougher } 97443c15812032991c98b33b5424b17bcd55fe3575plougher 98443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table_entry->start = start; 99443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table_entry->bytes = bytes; 100443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table_entry->next = hash_table[hash]; 101443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table[hash] = hash_table_entry; 102443c15812032991c98b33b5424b17bcd55fe3575plougher 103443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 104443c15812032991c98b33b5424b17bcd55fe3575plougher} 105443c15812032991c98b33b5424b17bcd55fe3575plougher 106443c15812032991c98b33b5424b17bcd55fe3575plougher 107443c15812032991c98b33b5424b17bcd55fe3575plougherint lookup_entry(struct hash_table_entry *hash_table[], int start) 108443c15812032991c98b33b5424b17bcd55fe3575plougher{ 109443c15812032991c98b33b5424b17bcd55fe3575plougher int hash = CALCULATE_HASH(start); 110443c15812032991c98b33b5424b17bcd55fe3575plougher struct hash_table_entry *hash_table_entry; 111443c15812032991c98b33b5424b17bcd55fe3575plougher 112443c15812032991c98b33b5424b17bcd55fe3575plougher for(hash_table_entry = hash_table[hash]; hash_table_entry; hash_table_entry = hash_table_entry->next) 113443c15812032991c98b33b5424b17bcd55fe3575plougher if(hash_table_entry->start == start) 114443c15812032991c98b33b5424b17bcd55fe3575plougher return hash_table_entry->bytes; 115443c15812032991c98b33b5424b17bcd55fe3575plougher 116443c15812032991c98b33b5424b17bcd55fe3575plougher return -1; 117443c15812032991c98b33b5424b17bcd55fe3575plougher} 118443c15812032991c98b33b5424b17bcd55fe3575plougher 119443c15812032991c98b33b5424b17bcd55fe3575plougher 120443c15812032991c98b33b5424b17bcd55fe3575plougherint read_bytes(long long byte, int bytes, char *buff) 121443c15812032991c98b33b5424b17bcd55fe3575plougher{ 122443c15812032991c98b33b5424b17bcd55fe3575plougher off_t off = byte; 123443c15812032991c98b33b5424b17bcd55fe3575plougher 124fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); 125fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 126443c15812032991c98b33b5424b17bcd55fe3575plougher if(lseek(fd, off, SEEK_SET) == -1) { 127443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Lseek failed because %s\b", strerror(errno)); 128443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 129443c15812032991c98b33b5424b17bcd55fe3575plougher } 130443c15812032991c98b33b5424b17bcd55fe3575plougher 131443c15812032991c98b33b5424b17bcd55fe3575plougher if(read(fd, buff, bytes) == -1) { 132443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Read on destination failed because %s\n", strerror(errno)); 133443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 134443c15812032991c98b33b5424b17bcd55fe3575plougher } 135443c15812032991c98b33b5424b17bcd55fe3575plougher 136443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 137443c15812032991c98b33b5424b17bcd55fe3575plougher} 138443c15812032991c98b33b5424b17bcd55fe3575plougher 139443c15812032991c98b33b5424b17bcd55fe3575plougher 140443c15812032991c98b33b5424b17bcd55fe3575plougherint read_block(long long start, long long *next, char *block, squashfs_super_block *sBlk) 141443c15812032991c98b33b5424b17bcd55fe3575plougher{ 142443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned short c_byte; 143443c15812032991c98b33b5424b17bcd55fe3575plougher int offset = 2; 144443c15812032991c98b33b5424b17bcd55fe3575plougher 145443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 146443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, 2, block) == FALSE) 147fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 148443c15812032991c98b33b5424b17bcd55fe3575plougher ((unsigned char *) &c_byte)[1] = block[0]; 149443c15812032991c98b33b5424b17bcd55fe3575plougher ((unsigned char *) &c_byte)[0] = block[1]; 150443c15812032991c98b33b5424b17bcd55fe3575plougher } else 151443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, 2, (char *)&c_byte) == FALSE) 152fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 153fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 154fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed"); 155443c15812032991c98b33b5424b17bcd55fe3575plougher 156443c15812032991c98b33b5424b17bcd55fe3575plougher if(SQUASHFS_CHECK_DATA(sBlk->flags)) 157443c15812032991c98b33b5424b17bcd55fe3575plougher offset = 3; 158443c15812032991c98b33b5424b17bcd55fe3575plougher if(SQUASHFS_COMPRESSED(c_byte)) { 159443c15812032991c98b33b5424b17bcd55fe3575plougher char buffer[SQUASHFS_METADATA_SIZE]; 160443c15812032991c98b33b5424b17bcd55fe3575plougher int res; 161443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned long bytes = SQUASHFS_METADATA_SIZE; 162443c15812032991c98b33b5424b17bcd55fe3575plougher 163443c15812032991c98b33b5424b17bcd55fe3575plougher c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); 164443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start + offset, c_byte, buffer) == FALSE) 165fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 166443c15812032991c98b33b5424b17bcd55fe3575plougher 167443c15812032991c98b33b5424b17bcd55fe3575plougher if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) { 168443c15812032991c98b33b5424b17bcd55fe3575plougher if(res == Z_MEM_ERROR) 169443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough memory\n"); 170443c15812032991c98b33b5424b17bcd55fe3575plougher else if(res == Z_BUF_ERROR) 171443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough room in output buffer\n"); 172443c15812032991c98b33b5424b17bcd55fe3575plougher else 173443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, unknown error %d\n", res); 174fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 175443c15812032991c98b33b5424b17bcd55fe3575plougher } 176443c15812032991c98b33b5424b17bcd55fe3575plougher if(next) 177443c15812032991c98b33b5424b17bcd55fe3575plougher *next = start + offset + c_byte; 178443c15812032991c98b33b5424b17bcd55fe3575plougher return bytes; 179443c15812032991c98b33b5424b17bcd55fe3575plougher } else { 180443c15812032991c98b33b5424b17bcd55fe3575plougher c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); 181443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start + offset, c_byte, block) == FALSE) 182fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 183443c15812032991c98b33b5424b17bcd55fe3575plougher if(next) 184443c15812032991c98b33b5424b17bcd55fe3575plougher *next = start + offset + c_byte; 185443c15812032991c98b33b5424b17bcd55fe3575plougher return c_byte; 186443c15812032991c98b33b5424b17bcd55fe3575plougher } 187fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 188fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed: 189fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher return FALSE; 190443c15812032991c98b33b5424b17bcd55fe3575plougher} 191443c15812032991c98b33b5424b17bcd55fe3575plougher 192443c15812032991c98b33b5424b17bcd55fe3575plougher 193443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block) 194443c15812032991c98b33b5424b17bcd55fe3575plougher{ 195443c15812032991c98b33b5424b17bcd55fe3575plougher int res; 196443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned long bytes = block_size; 197443c15812032991c98b33b5424b17bcd55fe3575plougher int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size); 198443c15812032991c98b33b5424b17bcd55fe3575plougher 199fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte), SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed"); 200fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 201443c15812032991c98b33b5424b17bcd55fe3575plougher if(SQUASHFS_COMPRESSED_BLOCK(size)) { 202443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, c_byte, data) == FALSE) 203443c15812032991c98b33b5424b17bcd55fe3575plougher return 0; 204443c15812032991c98b33b5424b17bcd55fe3575plougher 205443c15812032991c98b33b5424b17bcd55fe3575plougher if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte)) != Z_OK) { 206443c15812032991c98b33b5424b17bcd55fe3575plougher if(res == Z_MEM_ERROR) 207443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough memory\n"); 208443c15812032991c98b33b5424b17bcd55fe3575plougher else if(res == Z_BUF_ERROR) 209443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough room in output buffer\n"); 210443c15812032991c98b33b5424b17bcd55fe3575plougher else 211443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, unknown error %d\n", res); 212443c15812032991c98b33b5424b17bcd55fe3575plougher return 0; 213443c15812032991c98b33b5424b17bcd55fe3575plougher } 214443c15812032991c98b33b5424b17bcd55fe3575plougher 215443c15812032991c98b33b5424b17bcd55fe3575plougher return bytes; 216443c15812032991c98b33b5424b17bcd55fe3575plougher } else { 217443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, c_byte, block) == FALSE) 218443c15812032991c98b33b5424b17bcd55fe3575plougher return 0; 219443c15812032991c98b33b5424b17bcd55fe3575plougher 220443c15812032991c98b33b5424b17bcd55fe3575plougher return c_byte; 221443c15812032991c98b33b5424b17bcd55fe3575plougher } 222443c15812032991c98b33b5424b17bcd55fe3575plougher} 223443c15812032991c98b33b5424b17bcd55fe3575plougher 224443c15812032991c98b33b5424b17bcd55fe3575plougher 225443c15812032991c98b33b5424b17bcd55fe3575ploughervoid uncompress_inode_table(long long start, long long end, squashfs_super_block *sBlk) 226443c15812032991c98b33b5424b17bcd55fe3575plougher{ 227443c15812032991c98b33b5424b17bcd55fe3575plougher int size = 0, bytes = 0, res; 228443c15812032991c98b33b5424b17bcd55fe3575plougher 229443c15812032991c98b33b5424b17bcd55fe3575plougher while(start < end) { 230443c15812032991c98b33b5424b17bcd55fe3575plougher if((size - bytes < SQUASHFS_METADATA_SIZE) && 231443c15812032991c98b33b5424b17bcd55fe3575plougher ((inode_table = realloc(inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL)) 232443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n"); 233443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("uncompress_inode_table: reading block 0x%llx\n", start); 234443c15812032991c98b33b5424b17bcd55fe3575plougher add_entry(inode_table_hash, start, bytes); 235443c15812032991c98b33b5424b17bcd55fe3575plougher if((res = read_block(start, &start, inode_table + bytes, sBlk)) == 0) { 236443c15812032991c98b33b5424b17bcd55fe3575plougher free(inode_table); 237443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n"); 238443c15812032991c98b33b5424b17bcd55fe3575plougher } 239443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += res; 240443c15812032991c98b33b5424b17bcd55fe3575plougher } 241443c15812032991c98b33b5424b17bcd55fe3575plougher} 242443c15812032991c98b33b5424b17bcd55fe3575plougher 243443c15812032991c98b33b5424b17bcd55fe3575plougher 244443c15812032991c98b33b5424b17bcd55fe3575plougherint set_attributes(char *pathname, unsigned int mode, unsigned int uid, unsigned int guid, 245443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int mtime, unsigned int set_mode) 246443c15812032991c98b33b5424b17bcd55fe3575plougher{ 247443c15812032991c98b33b5424b17bcd55fe3575plougher struct utimbuf times = { (time_t) mtime, (time_t) mtime }; 248443c15812032991c98b33b5424b17bcd55fe3575plougher 249443c15812032991c98b33b5424b17bcd55fe3575plougher if(utime(pathname, ×) == -1) { 250443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno)); 251443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 252443c15812032991c98b33b5424b17bcd55fe3575plougher } 253443c15812032991c98b33b5424b17bcd55fe3575plougher 254443c15812032991c98b33b5424b17bcd55fe3575plougher if(set_mode && chmod(pathname, (mode_t) mode) == -1) { 255443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno)); 256443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 257443c15812032991c98b33b5424b17bcd55fe3575plougher } 258443c15812032991c98b33b5424b17bcd55fe3575plougher 259443c15812032991c98b33b5424b17bcd55fe3575plougher if(geteuid() == 0) { 260443c15812032991c98b33b5424b17bcd55fe3575plougher uid_t uid_value = (uid_t) uid_table[uid]; 261443c15812032991c98b33b5424b17bcd55fe3575plougher uid_t guid_value = guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[guid]; 262443c15812032991c98b33b5424b17bcd55fe3575plougher 263443c15812032991c98b33b5424b17bcd55fe3575plougher if(chown(pathname, uid_value, guid_value) == -1) { 264443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); 265443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 266443c15812032991c98b33b5424b17bcd55fe3575plougher } 267443c15812032991c98b33b5424b17bcd55fe3575plougher } 268443c15812032991c98b33b5424b17bcd55fe3575plougher 269443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 270443c15812032991c98b33b5424b17bcd55fe3575plougher} 271443c15812032991c98b33b5424b17bcd55fe3575plougher 272443c15812032991c98b33b5424b17bcd55fe3575plougher 273443c15812032991c98b33b5424b17bcd55fe3575ploughervoid read_uids_guids(squashfs_super_block *sBlk) 274443c15812032991c98b33b5424b17bcd55fe3575plougher{ 275443c15812032991c98b33b5424b17bcd55fe3575plougher if((uid_table = malloc((sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int))) == NULL) 276443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("read_uids_guids: failed to allocate uid/gid table\n"); 277443c15812032991c98b33b5424b17bcd55fe3575plougher 278443c15812032991c98b33b5424b17bcd55fe3575plougher guid_table = uid_table + sBlk->no_uids; 279443c15812032991c98b33b5424b17bcd55fe3575plougher 280443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(sBlk->uid_start, (sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int), (char *) uid_table) == 281443c15812032991c98b33b5424b17bcd55fe3575plougher FALSE) 282443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n"); 283443c15812032991c98b33b5424b17bcd55fe3575plougher} 284443c15812032991c98b33b5424b17bcd55fe3575plougher 285443c15812032991c98b33b5424b17bcd55fe3575plougher 286443c15812032991c98b33b5424b17bcd55fe3575ploughervoid read_fragment_table(squashfs_super_block *sBlk) 287443c15812032991c98b33b5424b17bcd55fe3575plougher{ 288443c15812032991c98b33b5424b17bcd55fe3575plougher int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); 289443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_fragment_index fragment_table_index[indexes]; 290443c15812032991c98b33b5424b17bcd55fe3575plougher 291fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start); 292443c15812032991c98b33b5424b17bcd55fe3575plougher if(sBlk->fragments == 0) 293443c15812032991c98b33b5424b17bcd55fe3575plougher return; 294443c15812032991c98b33b5424b17bcd55fe3575plougher 295443c15812032991c98b33b5424b17bcd55fe3575plougher if((fragment_table = (squashfs_fragment_entry *) malloc(sBlk->fragments * sizeof(squashfs_fragment_entry))) == NULL) 296443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n"); 297443c15812032991c98b33b5424b17bcd55fe3575plougher 298443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 299443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_fragment_index sfragment_table_index[indexes]; 300443c15812032991c98b33b5424b17bcd55fe3575plougher 301443c15812032991c98b33b5424b17bcd55fe3575plougher read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) sfragment_table_index); 302443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes); 303443c15812032991c98b33b5424b17bcd55fe3575plougher } else 304443c15812032991c98b33b5424b17bcd55fe3575plougher read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index); 305443c15812032991c98b33b5424b17bcd55fe3575plougher 306443c15812032991c98b33b5424b17bcd55fe3575plougher for(i = 0; i < indexes; i++) { 307443c15812032991c98b33b5424b17bcd55fe3575plougher int length = read_block(fragment_table_index[i], NULL, ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk); 308fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); 309443c15812032991c98b33b5424b17bcd55fe3575plougher } 310443c15812032991c98b33b5424b17bcd55fe3575plougher 311443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 312443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_fragment_entry sfragment; 313443c15812032991c98b33b5424b17bcd55fe3575plougher for(i = 0; i < sBlk->fragments; i++) { 314443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&fragment_table[i])); 315443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy((char *) &fragment_table[i], (char *) &sfragment, sizeof(squashfs_fragment_entry)); 316443c15812032991c98b33b5424b17bcd55fe3575plougher } 317443c15812032991c98b33b5424b17bcd55fe3575plougher } 318443c15812032991c98b33b5424b17bcd55fe3575plougher} 319443c15812032991c98b33b5424b17bcd55fe3575plougher 320443c15812032991c98b33b5424b17bcd55fe3575plougher 321443c15812032991c98b33b5424b17bcd55fe3575plougherchar *read_fragment(unsigned int fragment) 322443c15812032991c98b33b5424b17bcd55fe3575plougher{ 323fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("read_fragment: reading fragment %d\n", fragment); 324fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 325443c15812032991c98b33b5424b17bcd55fe3575plougher if(cached_frag == SQUASHFS_INVALID_FRAG || fragment != cached_frag) { 326443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_fragment_entry *fragment_entry = &fragment_table[fragment]; 327443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_data_block(fragment_entry->start_block, fragment_entry->size, fragment_data) == 0) { 328443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("read_fragment: failed to read fragment %d\n", fragment); 329443c15812032991c98b33b5424b17bcd55fe3575plougher cached_frag = SQUASHFS_INVALID_FRAG; 330443c15812032991c98b33b5424b17bcd55fe3575plougher return NULL; 331443c15812032991c98b33b5424b17bcd55fe3575plougher } 332443c15812032991c98b33b5424b17bcd55fe3575plougher cached_frag = fragment; 333443c15812032991c98b33b5424b17bcd55fe3575plougher } 334443c15812032991c98b33b5424b17bcd55fe3575plougher 335443c15812032991c98b33b5424b17bcd55fe3575plougher return fragment_data; 336443c15812032991c98b33b5424b17bcd55fe3575plougher} 337443c15812032991c98b33b5424b17bcd55fe3575plougher 338443c15812032991c98b33b5424b17bcd55fe3575plougher 339443c15812032991c98b33b5424b17bcd55fe3575plougherint write_file(char *pathname, unsigned int fragment, unsigned int frag_bytes, unsigned int offset, 340443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int blocks, long long start, char *block_ptr, unsigned int mode) 341443c15812032991c98b33b5424b17bcd55fe3575plougher{ 342f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher unsigned int file_fd, bytes, i; 343f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher unsigned int *block_list; 344443c15812032991c98b33b5424b17bcd55fe3575plougher 345443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("write_file: regular file, blocks %d\n", blocks); 346443c15812032991c98b33b5424b17bcd55fe3575plougher 347f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { 348f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher ERROR("write_file: unable to malloc block list\n"); 349f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher return FALSE; 350f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher } 351f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher 352443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 353443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int sblock_list[blocks]; 354443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int)); 355443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); 356443c15812032991c98b33b5424b17bcd55fe3575plougher } else 357443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(block_list, block_ptr, blocks * sizeof(unsigned int)); 358443c15812032991c98b33b5424b17bcd55fe3575plougher 359443c15812032991c98b33b5424b17bcd55fe3575plougher if((file_fd = open(pathname, O_CREAT | O_WRONLY, (mode_t) mode)) == -1) { 360443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("write_file: failed to create file %s, because %s\n", pathname, 361443c15812032991c98b33b5424b17bcd55fe3575plougher strerror(errno)); 362f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher free(block_list); 363443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 364443c15812032991c98b33b5424b17bcd55fe3575plougher } 365443c15812032991c98b33b5424b17bcd55fe3575plougher 366443c15812032991c98b33b5424b17bcd55fe3575plougher for(i = 0; i < blocks; i++) { 367443c15812032991c98b33b5424b17bcd55fe3575plougher if((bytes = read_data_block(start, block_list[i], file_data)) == 0) { 368fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher ERROR("write_file: failed to read data block 0x%llx\n", start); 369443c15812032991c98b33b5424b17bcd55fe3575plougher goto failure; 370443c15812032991c98b33b5424b17bcd55fe3575plougher } 371443c15812032991c98b33b5424b17bcd55fe3575plougher 372443c15812032991c98b33b5424b17bcd55fe3575plougher if(write(file_fd, file_data, bytes) < bytes) { 373fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher ERROR("write_file: failed to write data block 0x%llx\n", start); 374443c15812032991c98b33b5424b17bcd55fe3575plougher goto failure; 375443c15812032991c98b33b5424b17bcd55fe3575plougher } 376443c15812032991c98b33b5424b17bcd55fe3575plougher 377443c15812032991c98b33b5424b17bcd55fe3575plougher start += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); 378443c15812032991c98b33b5424b17bcd55fe3575plougher } 379443c15812032991c98b33b5424b17bcd55fe3575plougher 380443c15812032991c98b33b5424b17bcd55fe3575plougher if(frag_bytes != 0) { 381443c15812032991c98b33b5424b17bcd55fe3575plougher char *fragment_data = read_fragment(fragment); 382443c15812032991c98b33b5424b17bcd55fe3575plougher 383443c15812032991c98b33b5424b17bcd55fe3575plougher if(fragment_data == NULL) 384443c15812032991c98b33b5424b17bcd55fe3575plougher goto failure; 385443c15812032991c98b33b5424b17bcd55fe3575plougher 386443c15812032991c98b33b5424b17bcd55fe3575plougher if(write(file_fd, fragment_data + offset, frag_bytes) < frag_bytes) { 387fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher ERROR("write_file: failed to write fragment %d\n", fragment); 388443c15812032991c98b33b5424b17bcd55fe3575plougher goto failure; 389443c15812032991c98b33b5424b17bcd55fe3575plougher } 390443c15812032991c98b33b5424b17bcd55fe3575plougher } 391443c15812032991c98b33b5424b17bcd55fe3575plougher 392443c15812032991c98b33b5424b17bcd55fe3575plougher close(file_fd); 393443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 394443c15812032991c98b33b5424b17bcd55fe3575plougher 395443c15812032991c98b33b5424b17bcd55fe3575plougherfailure: 396443c15812032991c98b33b5424b17bcd55fe3575plougher close(file_fd); 397f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher free(block_list); 398443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 399443c15812032991c98b33b5424b17bcd55fe3575plougher} 400443c15812032991c98b33b5424b17bcd55fe3575plougher 401443c15812032991c98b33b5424b17bcd55fe3575plougher 402443c15812032991c98b33b5424b17bcd55fe3575plougherint create_inode(char *pathname, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk) 403443c15812032991c98b33b5424b17bcd55fe3575plougher{ 404443c15812032991c98b33b5424b17bcd55fe3575plougher long long start = sBlk->inode_table_start + start_block; 405443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_inode_header header; 406443c15812032991c98b33b5424b17bcd55fe3575plougher char *block_ptr; 407443c15812032991c98b33b5424b17bcd55fe3575plougher int bytes = lookup_entry(inode_table_hash, start), file_fd; 408443c15812032991c98b33b5424b17bcd55fe3575plougher 409fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("create_inode: pathname %s, start 0x%llx, offset %d\n", pathname, start, offset); 410443c15812032991c98b33b5424b17bcd55fe3575plougher 411443c15812032991c98b33b5424b17bcd55fe3575plougher if(bytes == -1) { 412443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: inode block 0x%llx out of range!\n", start); 413443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 414443c15812032991c98b33b5424b17bcd55fe3575plougher } 415443c15812032991c98b33b5424b17bcd55fe3575plougher block_ptr = inode_table + bytes + offset; 416443c15812032991c98b33b5424b17bcd55fe3575plougher 417443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 418443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_base_inode_header sinode; 419443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sinode, block_ptr, sizeof(header.base)); 420443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, &sinode, sizeof(squashfs_base_inode_header)); 421443c15812032991c98b33b5424b17bcd55fe3575plougher } else 422443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&header.base, block_ptr, sizeof(header.base)); 423443c15812032991c98b33b5424b17bcd55fe3575plougher 424443c15812032991c98b33b5424b17bcd55fe3575plougher if(created_inode[header.base.inode_number - 1]) { 425443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: hard link\n"); 426443c15812032991c98b33b5424b17bcd55fe3575plougher if(link(created_inode[header.base.inode_number - 1], pathname) == -1) { 427443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno)); 428443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 429443c15812032991c98b33b5424b17bcd55fe3575plougher } 430443c15812032991c98b33b5424b17bcd55fe3575plougher 431443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 432443c15812032991c98b33b5424b17bcd55fe3575plougher } 433443c15812032991c98b33b5424b17bcd55fe3575plougher 434443c15812032991c98b33b5424b17bcd55fe3575plougher switch(header.base.inode_type) { 435443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_FILE_TYPE: { 436443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int frag_bytes; 437443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int blocks; 438443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int offset; 439443c15812032991c98b33b5424b17bcd55fe3575plougher long long start; 440443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_reg_inode_header *inode = &header.reg; 441443c15812032991c98b33b5424b17bcd55fe3575plougher 442443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 443443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_reg_inode_header sinode; 444443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sinode, block_ptr, sizeof(sinode)); 445443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_REG_INODE_HEADER(inode, &sinode); 446443c15812032991c98b33b5424b17bcd55fe3575plougher } else 447443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(inode, block_ptr, sizeof(*inode)); 448443c15812032991c98b33b5424b17bcd55fe3575plougher 449443c15812032991c98b33b5424b17bcd55fe3575plougher frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size; 450443c15812032991c98b33b5424b17bcd55fe3575plougher offset = inode->offset; 451443c15812032991c98b33b5424b17bcd55fe3575plougher blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size 452443c15812032991c98b33b5424b17bcd55fe3575plougher + sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >> 453443c15812032991c98b33b5424b17bcd55fe3575plougher sBlk->block_log; 454443c15812032991c98b33b5424b17bcd55fe3575plougher start = inode->start_block; 455443c15812032991c98b33b5424b17bcd55fe3575plougher 456443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); 457443c15812032991c98b33b5424b17bcd55fe3575plougher 458443c15812032991c98b33b5424b17bcd55fe3575plougher if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start, 459443c15812032991c98b33b5424b17bcd55fe3575plougher block_ptr + sizeof(*inode), inode->mode)) { 460443c15812032991c98b33b5424b17bcd55fe3575plougher set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE); 461443c15812032991c98b33b5424b17bcd55fe3575plougher file_count ++; 462443c15812032991c98b33b5424b17bcd55fe3575plougher } 463443c15812032991c98b33b5424b17bcd55fe3575plougher break; 464443c15812032991c98b33b5424b17bcd55fe3575plougher } 465443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_LREG_TYPE: { 466443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int frag_bytes; 467443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int blocks; 468443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int offset; 469443c15812032991c98b33b5424b17bcd55fe3575plougher long long start; 470443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_lreg_inode_header *inode = &header.lreg; 471443c15812032991c98b33b5424b17bcd55fe3575plougher 472443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 473443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_lreg_inode_header sinode; 474443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sinode, block_ptr, sizeof(sinode)); 475443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_LREG_INODE_HEADER(inode, &sinode); 476443c15812032991c98b33b5424b17bcd55fe3575plougher } else 477443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(inode, block_ptr, sizeof(*inode)); 478443c15812032991c98b33b5424b17bcd55fe3575plougher 479443c15812032991c98b33b5424b17bcd55fe3575plougher frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size; 480443c15812032991c98b33b5424b17bcd55fe3575plougher offset = inode->offset; 481443c15812032991c98b33b5424b17bcd55fe3575plougher blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size 482443c15812032991c98b33b5424b17bcd55fe3575plougher + sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >> 483443c15812032991c98b33b5424b17bcd55fe3575plougher sBlk->block_log; 484443c15812032991c98b33b5424b17bcd55fe3575plougher start = inode->start_block; 485443c15812032991c98b33b5424b17bcd55fe3575plougher 486443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); 487443c15812032991c98b33b5424b17bcd55fe3575plougher 488443c15812032991c98b33b5424b17bcd55fe3575plougher if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start, 489443c15812032991c98b33b5424b17bcd55fe3575plougher block_ptr + sizeof(*inode), inode->mode)) { 490443c15812032991c98b33b5424b17bcd55fe3575plougher set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE); 491443c15812032991c98b33b5424b17bcd55fe3575plougher file_count ++; 492443c15812032991c98b33b5424b17bcd55fe3575plougher } 493443c15812032991c98b33b5424b17bcd55fe3575plougher break; 494443c15812032991c98b33b5424b17bcd55fe3575plougher } 495443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_SYMLINK_TYPE: { 496443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_symlink_inode_header *inodep = &header.symlink; 497443c15812032991c98b33b5424b17bcd55fe3575plougher char name[65536]; 498443c15812032991c98b33b5424b17bcd55fe3575plougher 499443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 500443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_symlink_inode_header sinodep; 501443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sinodep, block_ptr, sizeof(sinodep)); 502443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, &sinodep); 503443c15812032991c98b33b5424b17bcd55fe3575plougher } else 504443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(inodep, block_ptr, sizeof(*inodep)); 505443c15812032991c98b33b5424b17bcd55fe3575plougher 506443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: symlink, symlink_size %d\n", inodep->symlink_size); 507443c15812032991c98b33b5424b17bcd55fe3575plougher 508443c15812032991c98b33b5424b17bcd55fe3575plougher strncpy(name, block_ptr + sizeof(squashfs_symlink_inode_header), inodep->symlink_size); 509443c15812032991c98b33b5424b17bcd55fe3575plougher name[inodep->symlink_size] = '\0'; 510443c15812032991c98b33b5424b17bcd55fe3575plougher 511443c15812032991c98b33b5424b17bcd55fe3575plougher if(symlink(name, pathname) == -1) { 512443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create symlink %s, because %s\n", pathname, 513443c15812032991c98b33b5424b17bcd55fe3575plougher strerror(errno)); 514443c15812032991c98b33b5424b17bcd55fe3575plougher break; 515443c15812032991c98b33b5424b17bcd55fe3575plougher } 516443c15812032991c98b33b5424b17bcd55fe3575plougher 517443c15812032991c98b33b5424b17bcd55fe3575plougher if(geteuid() == 0) { 518443c15812032991c98b33b5424b17bcd55fe3575plougher uid_t uid_value = (uid_t) uid_table[inodep->uid]; 519443c15812032991c98b33b5424b17bcd55fe3575plougher uid_t guid_value = inodep->guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[inodep->guid]; 520443c15812032991c98b33b5424b17bcd55fe3575plougher 521443c15812032991c98b33b5424b17bcd55fe3575plougher if(lchown(pathname, uid_value, guid_value) == -1) 522443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); 523443c15812032991c98b33b5424b17bcd55fe3575plougher } 524443c15812032991c98b33b5424b17bcd55fe3575plougher 525443c15812032991c98b33b5424b17bcd55fe3575plougher sym_count ++; 526443c15812032991c98b33b5424b17bcd55fe3575plougher break; 527443c15812032991c98b33b5424b17bcd55fe3575plougher } 528443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_BLKDEV_TYPE: 529443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_CHRDEV_TYPE: { 530443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_dev_inode_header *inodep = &header.dev; 531443c15812032991c98b33b5424b17bcd55fe3575plougher 532443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 533443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_dev_inode_header sinodep; 534443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sinodep, block_ptr, sizeof(sinodep)); 535443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, &sinodep); 536443c15812032991c98b33b5424b17bcd55fe3575plougher } else 537443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(inodep, block_ptr, sizeof(*inodep)); 538443c15812032991c98b33b5424b17bcd55fe3575plougher 539443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: dev, rdev 0x%x\n", inodep->rdev); 540443c15812032991c98b33b5424b17bcd55fe3575plougher 541443c15812032991c98b33b5424b17bcd55fe3575plougher if(geteuid() == 0) { 542443c15812032991c98b33b5424b17bcd55fe3575plougher if(mknod(pathname, inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? S_IFCHR : S_IFBLK, 543443c15812032991c98b33b5424b17bcd55fe3575plougher makedev((inodep->rdev >> 8) & 0xff, inodep->rdev & 0xff)) 544443c15812032991c98b33b5424b17bcd55fe3575plougher == -1) { 545443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create %s device %s, because %s\n", 546443c15812032991c98b33b5424b17bcd55fe3575plougher inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", 547443c15812032991c98b33b5424b17bcd55fe3575plougher pathname, strerror(errno)); 548443c15812032991c98b33b5424b17bcd55fe3575plougher break; 549443c15812032991c98b33b5424b17bcd55fe3575plougher } 550443c15812032991c98b33b5424b17bcd55fe3575plougher set_attributes(pathname, inodep->mode, inodep->uid, inodep->guid, inodep->mtime, TRUE); 551443c15812032991c98b33b5424b17bcd55fe3575plougher dev_count ++; 552443c15812032991c98b33b5424b17bcd55fe3575plougher } else 553443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: could not create %s device %s, because you're not superuser!\n", 554443c15812032991c98b33b5424b17bcd55fe3575plougher inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", 555443c15812032991c98b33b5424b17bcd55fe3575plougher pathname, strerror(errno)); 556443c15812032991c98b33b5424b17bcd55fe3575plougher break; 557fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher } 558443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_FIFO_TYPE: 559443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: fifo\n"); 560443c15812032991c98b33b5424b17bcd55fe3575plougher 561443c15812032991c98b33b5424b17bcd55fe3575plougher if(mknod(pathname, S_IFIFO, 0) == -1) { 562443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create fifo %s, because %s\n", 563443c15812032991c98b33b5424b17bcd55fe3575plougher pathname, strerror(errno)); 564443c15812032991c98b33b5424b17bcd55fe3575plougher break; 565443c15812032991c98b33b5424b17bcd55fe3575plougher } 566443c15812032991c98b33b5424b17bcd55fe3575plougher set_attributes(pathname, header.base.mode, header.base.uid, header.base.guid, 567443c15812032991c98b33b5424b17bcd55fe3575plougher header.base.mtime, TRUE); 568443c15812032991c98b33b5424b17bcd55fe3575plougher fifo_count ++; 569443c15812032991c98b33b5424b17bcd55fe3575plougher break; 570443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_SOCKET_TYPE: 571443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: socket\n"); 572443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: socket %s ignored\n", pathname); 573443c15812032991c98b33b5424b17bcd55fe3575plougher break; 574443c15812032991c98b33b5424b17bcd55fe3575plougher default: 575443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Unknown inode type %d in create_inode_table!\n", header.base.inode_type); 576443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 577443c15812032991c98b33b5424b17bcd55fe3575plougher } 578fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 579443c15812032991c98b33b5424b17bcd55fe3575plougher created_inode[header.base.inode_number - 1] = strdup(pathname); 580443c15812032991c98b33b5424b17bcd55fe3575plougher 581443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 582443c15812032991c98b33b5424b17bcd55fe3575plougher} 583443c15812032991c98b33b5424b17bcd55fe3575plougher 584443c15812032991c98b33b5424b17bcd55fe3575plougher 585443c15812032991c98b33b5424b17bcd55fe3575ploughervoid uncompress_directory_table(long long start, long long end, squashfs_super_block *sBlk) 586443c15812032991c98b33b5424b17bcd55fe3575plougher{ 587443c15812032991c98b33b5424b17bcd55fe3575plougher int bytes = 0, size = 0, res; 588443c15812032991c98b33b5424b17bcd55fe3575plougher 589443c15812032991c98b33b5424b17bcd55fe3575plougher while(start < end) { 590443c15812032991c98b33b5424b17bcd55fe3575plougher if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table = realloc(directory_table, size += SQUASHFS_METADATA_SIZE)) == NULL) 591443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n"); 592443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("uncompress_directory_table: reading block 0x%llx\n", start); 593443c15812032991c98b33b5424b17bcd55fe3575plougher add_entry(directory_table_hash, start, bytes); 594443c15812032991c98b33b5424b17bcd55fe3575plougher if((res = read_block(start, &start, directory_table + bytes, sBlk)) == 0) 595443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n"); 596443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += res; 597443c15812032991c98b33b5424b17bcd55fe3575plougher } 598443c15812032991c98b33b5424b17bcd55fe3575plougher} 599443c15812032991c98b33b5424b17bcd55fe3575plougher 600443c15812032991c98b33b5424b17bcd55fe3575plougher 601443c15812032991c98b33b5424b17bcd55fe3575plougher#define DIR_ENT_SIZE 16 602443c15812032991c98b33b5424b17bcd55fe3575plougher 603443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir_ent { 604443c15812032991c98b33b5424b17bcd55fe3575plougher char name[SQUASHFS_NAME_LEN + 1]; 605443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int start_block; 606443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int offset; 607443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int type; 608443c15812032991c98b33b5424b17bcd55fe3575plougher}; 609443c15812032991c98b33b5424b17bcd55fe3575plougher 610443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir { 611443c15812032991c98b33b5424b17bcd55fe3575plougher int dir_count; 612443c15812032991c98b33b5424b17bcd55fe3575plougher int cur_entry; 613443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int mode; 614443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int uid; 615443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int guid; 616443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int mtime; 617443c15812032991c98b33b5424b17bcd55fe3575plougher struct dir_ent *dirs; 618443c15812032991c98b33b5424b17bcd55fe3575plougher}; 619443c15812032991c98b33b5424b17bcd55fe3575plougher 620443c15812032991c98b33b5424b17bcd55fe3575plougher 621443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir *squashfs_openddir(unsigned int block_start, unsigned int offset, squashfs_super_block *sBlk) 622443c15812032991c98b33b5424b17bcd55fe3575plougher{ 623443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_dir_header dirh; 624443c15812032991c98b33b5424b17bcd55fe3575plougher char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; 625443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; 626443c15812032991c98b33b5424b17bcd55fe3575plougher long long start = sBlk->inode_table_start + block_start; 627443c15812032991c98b33b5424b17bcd55fe3575plougher char *block_ptr; 628443c15812032991c98b33b5424b17bcd55fe3575plougher int bytes = lookup_entry(inode_table_hash, start); 629443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_inode_header header; 630443c15812032991c98b33b5424b17bcd55fe3575plougher int dir_count, size; 631443c15812032991c98b33b5424b17bcd55fe3575plougher struct dir_ent *new_dir; 632443c15812032991c98b33b5424b17bcd55fe3575plougher struct dir *dir; 633443c15812032991c98b33b5424b17bcd55fe3575plougher 634fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset); 635443c15812032991c98b33b5424b17bcd55fe3575plougher 636443c15812032991c98b33b5424b17bcd55fe3575plougher if(bytes == -1) { 637fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher ERROR("squashfs_opendir: inode block %d not found!\n", block_start); 638443c15812032991c98b33b5424b17bcd55fe3575plougher return NULL; 639443c15812032991c98b33b5424b17bcd55fe3575plougher } 640443c15812032991c98b33b5424b17bcd55fe3575plougher block_ptr = inode_table + bytes + offset; 641443c15812032991c98b33b5424b17bcd55fe3575plougher 642443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 643443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_dir_inode_header sinode; 644443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sinode, block_ptr, sizeof(header.dir)); 645443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_DIR_INODE_HEADER(&header.dir, &sinode); 646443c15812032991c98b33b5424b17bcd55fe3575plougher } else 647443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&header.dir, block_ptr, sizeof(header.dir)); 648443c15812032991c98b33b5424b17bcd55fe3575plougher 649443c15812032991c98b33b5424b17bcd55fe3575plougher switch(header.dir.inode_type) { 650443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_DIR_TYPE: 651443c15812032991c98b33b5424b17bcd55fe3575plougher block_start = header.dir.start_block; 652443c15812032991c98b33b5424b17bcd55fe3575plougher offset = header.dir.offset; 653443c15812032991c98b33b5424b17bcd55fe3575plougher size = header.dir.file_size; 654443c15812032991c98b33b5424b17bcd55fe3575plougher break; 655443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_LDIR_TYPE: 656443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 657443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_ldir_inode_header sinode; 658443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sinode, block_ptr, sizeof(header.ldir)); 659443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_LDIR_INODE_HEADER(&header.ldir, &sinode); 660443c15812032991c98b33b5424b17bcd55fe3575plougher } else 661443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&header.ldir, block_ptr, sizeof(header.ldir)); 662443c15812032991c98b33b5424b17bcd55fe3575plougher block_start = header.ldir.start_block; 663443c15812032991c98b33b5424b17bcd55fe3575plougher offset = header.ldir.offset; 664443c15812032991c98b33b5424b17bcd55fe3575plougher size = header.ldir.file_size; 665443c15812032991c98b33b5424b17bcd55fe3575plougher break; 666443c15812032991c98b33b5424b17bcd55fe3575plougher default: 667443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("squashfs_opendir: inode not a directory\n"); 668443c15812032991c98b33b5424b17bcd55fe3575plougher return NULL; 669443c15812032991c98b33b5424b17bcd55fe3575plougher } 670443c15812032991c98b33b5424b17bcd55fe3575plougher 671443c15812032991c98b33b5424b17bcd55fe3575plougher start = sBlk->directory_table_start + block_start; 672443c15812032991c98b33b5424b17bcd55fe3575plougher bytes = lookup_entry(directory_table_hash, start); 673443c15812032991c98b33b5424b17bcd55fe3575plougher 674443c15812032991c98b33b5424b17bcd55fe3575plougher if(bytes == -1) { 675fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher ERROR("squashfs_opendir: directory block %d not found!\n", block_start); 676443c15812032991c98b33b5424b17bcd55fe3575plougher return NULL; 677443c15812032991c98b33b5424b17bcd55fe3575plougher } 678443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += offset; 679443c15812032991c98b33b5424b17bcd55fe3575plougher size += bytes - 3; 680443c15812032991c98b33b5424b17bcd55fe3575plougher 681443c15812032991c98b33b5424b17bcd55fe3575plougher if((dir = malloc(sizeof(struct dir))) == NULL) { 682443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("squashfs_opendir: malloc failed!\n"); 683443c15812032991c98b33b5424b17bcd55fe3575plougher return NULL; 684443c15812032991c98b33b5424b17bcd55fe3575plougher } 685443c15812032991c98b33b5424b17bcd55fe3575plougher 686443c15812032991c98b33b5424b17bcd55fe3575plougher dir->dir_count = 0; 687443c15812032991c98b33b5424b17bcd55fe3575plougher dir->cur_entry = 0; 688443c15812032991c98b33b5424b17bcd55fe3575plougher dir->mode = header.dir.mode; 689443c15812032991c98b33b5424b17bcd55fe3575plougher dir->uid = header.dir.uid; 690443c15812032991c98b33b5424b17bcd55fe3575plougher dir->guid = header.dir.guid; 691443c15812032991c98b33b5424b17bcd55fe3575plougher dir->mtime = header.dir.mtime; 692443c15812032991c98b33b5424b17bcd55fe3575plougher dir->dirs = NULL; 693443c15812032991c98b33b5424b17bcd55fe3575plougher 694fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher while(bytes < size) { 695443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 696443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_dir_header sdirh; 697443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); 698443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); 699443c15812032991c98b33b5424b17bcd55fe3575plougher } else 700443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&dirh, directory_table + bytes, sizeof(dirh)); 701fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 702443c15812032991c98b33b5424b17bcd55fe3575plougher dir_count = dirh.count + 1; 703fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count); 704443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += sizeof(dirh); 705443c15812032991c98b33b5424b17bcd55fe3575plougher 706443c15812032991c98b33b5424b17bcd55fe3575plougher while(dir_count--) { 707443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 708443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_dir_entry sdire; 709443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(&sdire, directory_table + bytes, sizeof(sdire)); 710443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); 711443c15812032991c98b33b5424b17bcd55fe3575plougher } else 712443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(dire, directory_table + bytes, sizeof(dire)); 713443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += sizeof(*dire); 714443c15812032991c98b33b5424b17bcd55fe3575plougher 715443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(dire->name, directory_table + bytes, dire->size + 1); 716443c15812032991c98b33b5424b17bcd55fe3575plougher dire->name[dire->size + 1] = '\0'; 717fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type); 718443c15812032991c98b33b5424b17bcd55fe3575plougher if((dir->dir_count % DIR_ENT_SIZE) == 0) { 719443c15812032991c98b33b5424b17bcd55fe3575plougher if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) { 720443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("squashfs_opendir: realloc failed!\n"); 721443c15812032991c98b33b5424b17bcd55fe3575plougher free(dir->dirs); 722443c15812032991c98b33b5424b17bcd55fe3575plougher free(dir); 723443c15812032991c98b33b5424b17bcd55fe3575plougher return NULL; 724443c15812032991c98b33b5424b17bcd55fe3575plougher } 725443c15812032991c98b33b5424b17bcd55fe3575plougher dir->dirs = new_dir; 726443c15812032991c98b33b5424b17bcd55fe3575plougher } 727443c15812032991c98b33b5424b17bcd55fe3575plougher strcpy(dir->dirs[dir->dir_count].name, dire->name); 728443c15812032991c98b33b5424b17bcd55fe3575plougher dir->dirs[dir->dir_count].start_block = dirh.start_block; 729443c15812032991c98b33b5424b17bcd55fe3575plougher dir->dirs[dir->dir_count].offset = dire->offset; 730443c15812032991c98b33b5424b17bcd55fe3575plougher dir->dirs[dir->dir_count].type = dire->type; 731443c15812032991c98b33b5424b17bcd55fe3575plougher dir->dir_count ++; 732443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += dire->size + 1; 733443c15812032991c98b33b5424b17bcd55fe3575plougher } 734443c15812032991c98b33b5424b17bcd55fe3575plougher } 735443c15812032991c98b33b5424b17bcd55fe3575plougher 736443c15812032991c98b33b5424b17bcd55fe3575plougher return dir; 737443c15812032991c98b33b5424b17bcd55fe3575plougher} 738443c15812032991c98b33b5424b17bcd55fe3575plougher 739443c15812032991c98b33b5424b17bcd55fe3575plougher 740443c15812032991c98b33b5424b17bcd55fe3575plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, unsigned int *offset, unsigned int *type) 741443c15812032991c98b33b5424b17bcd55fe3575plougher{ 742443c15812032991c98b33b5424b17bcd55fe3575plougher if(dir->cur_entry == dir->dir_count) 743443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 744443c15812032991c98b33b5424b17bcd55fe3575plougher 745443c15812032991c98b33b5424b17bcd55fe3575plougher *name = dir->dirs[dir->cur_entry].name; 746443c15812032991c98b33b5424b17bcd55fe3575plougher *start_block = dir->dirs[dir->cur_entry].start_block; 747443c15812032991c98b33b5424b17bcd55fe3575plougher *offset = dir->dirs[dir->cur_entry].offset; 748443c15812032991c98b33b5424b17bcd55fe3575plougher *type = dir->dirs[dir->cur_entry].type; 749443c15812032991c98b33b5424b17bcd55fe3575plougher dir->cur_entry ++; 750443c15812032991c98b33b5424b17bcd55fe3575plougher 751443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 752443c15812032991c98b33b5424b17bcd55fe3575plougher} 753443c15812032991c98b33b5424b17bcd55fe3575plougher 754443c15812032991c98b33b5424b17bcd55fe3575plougher 755443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir) 756443c15812032991c98b33b5424b17bcd55fe3575plougher{ 757443c15812032991c98b33b5424b17bcd55fe3575plougher free(dir->dirs); 758443c15812032991c98b33b5424b17bcd55fe3575plougher free(dir); 759443c15812032991c98b33b5424b17bcd55fe3575plougher} 760443c15812032991c98b33b5424b17bcd55fe3575plougher 761443c15812032991c98b33b5424b17bcd55fe3575plougher 762443c15812032991c98b33b5424b17bcd55fe3575plougherint dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk) 763443c15812032991c98b33b5424b17bcd55fe3575plougher{ 764443c15812032991c98b33b5424b17bcd55fe3575plougher struct dir *dir = squashfs_openddir(start_block, offset, sBlk); 765443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int type; 766443c15812032991c98b33b5424b17bcd55fe3575plougher char *name, pathname[1024]; 767443c15812032991c98b33b5424b17bcd55fe3575plougher 768443c15812032991c98b33b5424b17bcd55fe3575plougher if(dir == NULL) { 769fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset); 770443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 771443c15812032991c98b33b5424b17bcd55fe3575plougher } 772443c15812032991c98b33b5424b17bcd55fe3575plougher 773443c15812032991c98b33b5424b17bcd55fe3575plougher if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1) { 774443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno)); 775443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 776443c15812032991c98b33b5424b17bcd55fe3575plougher } 777443c15812032991c98b33b5424b17bcd55fe3575plougher 778443c15812032991c98b33b5424b17bcd55fe3575plougher while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) { 779fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type); 780443c15812032991c98b33b5424b17bcd55fe3575plougher 781443c15812032991c98b33b5424b17bcd55fe3575plougher strcat(strcat(strcpy(pathname, parent_name), "/"), name); 782fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 783443c15812032991c98b33b5424b17bcd55fe3575plougher if(lsonly || info) 784443c15812032991c98b33b5424b17bcd55fe3575plougher printf("%s\n", pathname); 785fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 786443c15812032991c98b33b5424b17bcd55fe3575plougher if(type == SQUASHFS_DIR_TYPE) 787443c15812032991c98b33b5424b17bcd55fe3575plougher dir_scan(pathname, start_block, offset, sBlk); 788443c15812032991c98b33b5424b17bcd55fe3575plougher else 789443c15812032991c98b33b5424b17bcd55fe3575plougher if(!lsonly) 790443c15812032991c98b33b5424b17bcd55fe3575plougher create_inode(pathname, start_block, offset, sBlk); 791443c15812032991c98b33b5424b17bcd55fe3575plougher } 792443c15812032991c98b33b5424b17bcd55fe3575plougher 793443c15812032991c98b33b5424b17bcd55fe3575plougher !lsonly && set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, TRUE); 794443c15812032991c98b33b5424b17bcd55fe3575plougher 795443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_closedir(dir); 796443c15812032991c98b33b5424b17bcd55fe3575plougher dir_count ++; 797443c15812032991c98b33b5424b17bcd55fe3575plougher 798443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 799443c15812032991c98b33b5424b17bcd55fe3575plougher} 800443c15812032991c98b33b5424b17bcd55fe3575plougher 801443c15812032991c98b33b5424b17bcd55fe3575plougher 802443c15812032991c98b33b5424b17bcd55fe3575plougherint read_super(squashfs_super_block *sBlk, char *source) 803443c15812032991c98b33b5424b17bcd55fe3575plougher{ 804443c15812032991c98b33b5424b17bcd55fe3575plougher read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) sBlk); 805443c15812032991c98b33b5424b17bcd55fe3575plougher 806443c15812032991c98b33b5424b17bcd55fe3575plougher /* Check it is a SQUASHFS superblock */ 807443c15812032991c98b33b5424b17bcd55fe3575plougher swap = 0; 808443c15812032991c98b33b5424b17bcd55fe3575plougher if(sBlk->s_magic != SQUASHFS_MAGIC) { 809443c15812032991c98b33b5424b17bcd55fe3575plougher if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) { 810443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_super_block sblk; 811443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source); 812443c15812032991c98b33b5424b17bcd55fe3575plougher SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk); 813443c15812032991c98b33b5424b17bcd55fe3575plougher memcpy(sBlk, &sblk, sizeof(squashfs_super_block)); 814443c15812032991c98b33b5424b17bcd55fe3575plougher swap = 1; 815443c15812032991c98b33b5424b17bcd55fe3575plougher } else { 816443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Can't find a SQUASHFS superblock on %s\n", source); 817443c15812032991c98b33b5424b17bcd55fe3575plougher goto failed_mount; 818443c15812032991c98b33b5424b17bcd55fe3575plougher } 819443c15812032991c98b33b5424b17bcd55fe3575plougher } 820443c15812032991c98b33b5424b17bcd55fe3575plougher 821443c15812032991c98b33b5424b17bcd55fe3575plougher /* Check the MAJOR & MINOR versions */ 822443c15812032991c98b33b5424b17bcd55fe3575plougher if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { 823443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Major/Minor mismatch, filesystem on %s is (%d:%d)\n", 824443c15812032991c98b33b5424b17bcd55fe3575plougher source, sBlk->s_major, sBlk->s_minor); 8259b5bf8c73c0eaf4f1ba0461615f4ed0d405a30ccplougher ERROR("I only support Squashfs 3.0 filesystems! Later releases will support older Squashfs filesystems\n"); 826443c15812032991c98b33b5424b17bcd55fe3575plougher goto failed_mount; 827443c15812032991c98b33b5424b17bcd55fe3575plougher } 828443c15812032991c98b33b5424b17bcd55fe3575plougher 829443c15812032991c98b33b5424b17bcd55fe3575plougher#if __BYTE_ORDER == __BIG_ENDIAN 830443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "little" : "big", source); 831443c15812032991c98b33b5424b17bcd55fe3575plougher#else 832443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "big" : "little", source); 833443c15812032991c98b33b5424b17bcd55fe3575plougher#endif 834443c15812032991c98b33b5424b17bcd55fe3575plougher 835443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); 836443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); 837443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : ""); 838443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tCheck data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not"); 839443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not" : ""); 840443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not"); 841443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not"); 842443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0)); 843443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tBlock size %d\n", sBlk->block_size); 844443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tNumber of fragments %d\n", sBlk->fragments); 845443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tNumber of inodes %d\n", sBlk->inodes); 846443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tNumber of uids %d\n", sBlk->no_uids); 847443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\tNumber of gids %d\n", sBlk->no_guids); 848fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start); 849fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("sBlk->directory_table_start 0x%llx\n", sBlk->directory_table_start); 850fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("sBlk->uid_start 0x%llx\n", sBlk->uid_start); 851fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start); 852443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("\n"); 853443c15812032991c98b33b5424b17bcd55fe3575plougher 854443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 855443c15812032991c98b33b5424b17bcd55fe3575plougher 856443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount: 857443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 858443c15812032991c98b33b5424b17bcd55fe3575plougher} 859443c15812032991c98b33b5424b17bcd55fe3575plougher 860443c15812032991c98b33b5424b17bcd55fe3575plougher 861443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \ 8629b5bf8c73c0eaf4f1ba0461615f4ed0d405a30ccplougher printf("unsquashfs version 1.0 (2006/03/15)\n");\ 8639b5bf8c73c0eaf4f1ba0461615f4ed0d405a30ccplougher printf("copyright (C) 2006 Phillip Lougher <phillip@lougher.org.uk>\n\n"); \ 864443c15812032991c98b33b5424b17bcd55fe3575plougher printf("This program is free software; you can redistribute it and/or\n");\ 865443c15812032991c98b33b5424b17bcd55fe3575plougher printf("modify it under the terms of the GNU General Public License\n");\ 866443c15812032991c98b33b5424b17bcd55fe3575plougher printf("as published by the Free Software Foundation; either version 2,\n");\ 867443c15812032991c98b33b5424b17bcd55fe3575plougher printf("or (at your option) any later version.\n\n");\ 868443c15812032991c98b33b5424b17bcd55fe3575plougher printf("This program is distributed in the hope that it will be useful,\n");\ 869443c15812032991c98b33b5424b17bcd55fe3575plougher printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\ 870443c15812032991c98b33b5424b17bcd55fe3575plougher printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");\ 871443c15812032991c98b33b5424b17bcd55fe3575plougher printf("GNU General Public License for more details.\n"); 872443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[]) 873443c15812032991c98b33b5424b17bcd55fe3575plougher{ 874443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_super_block sBlk; 875443c15812032991c98b33b5424b17bcd55fe3575plougher char *dest = "squashfs-root"; 876443c15812032991c98b33b5424b17bcd55fe3575plougher int i, version = FALSE; 877443c15812032991c98b33b5424b17bcd55fe3575plougher 878443c15812032991c98b33b5424b17bcd55fe3575plougher for(i = 1; i < argc; i++) { 879443c15812032991c98b33b5424b17bcd55fe3575plougher if(*argv[i] != '-') 880443c15812032991c98b33b5424b17bcd55fe3575plougher break; 881443c15812032991c98b33b5424b17bcd55fe3575plougher if(strcmp(argv[i], "-version") == 0) { 882443c15812032991c98b33b5424b17bcd55fe3575plougher VERSION(); 883443c15812032991c98b33b5424b17bcd55fe3575plougher version = TRUE; 884443c15812032991c98b33b5424b17bcd55fe3575plougher } else if(strcmp(argv[i], "-info") == 0) 885443c15812032991c98b33b5424b17bcd55fe3575plougher info = TRUE; 886443c15812032991c98b33b5424b17bcd55fe3575plougher else if(strcmp(argv[i], "-ls") == 0) 887443c15812032991c98b33b5424b17bcd55fe3575plougher lsonly = TRUE; 888443c15812032991c98b33b5424b17bcd55fe3575plougher else if(strcmp(argv[i], "-dest") == 0) { 889443c15812032991c98b33b5424b17bcd55fe3575plougher if(++i == argc) 890443c15812032991c98b33b5424b17bcd55fe3575plougher goto options; 891443c15812032991c98b33b5424b17bcd55fe3575plougher dest = argv[i]; 892443c15812032991c98b33b5424b17bcd55fe3575plougher } 893443c15812032991c98b33b5424b17bcd55fe3575plougher } 894443c15812032991c98b33b5424b17bcd55fe3575plougher 895443c15812032991c98b33b5424b17bcd55fe3575plougher if(i == argc) { 896443c15812032991c98b33b5424b17bcd55fe3575plougher if(!version) { 897443c15812032991c98b33b5424b17bcd55fe3575plougheroptions: 898443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("SYNTAX: %s [-ls | -dest] filesystem\n", argv[0]); 899443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("\t-version\t\tprint version, licence and copyright information\n"); 900443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("\t-info\t\t\tprint files as they are unsquashed\n"); 901443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("\t-ls\t\t\tlist filesystem only\n"); 902443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("\t-dest <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n"); 903443c15812032991c98b33b5424b17bcd55fe3575plougher } 904443c15812032991c98b33b5424b17bcd55fe3575plougher exit(1); 905443c15812032991c98b33b5424b17bcd55fe3575plougher } 906443c15812032991c98b33b5424b17bcd55fe3575plougher 907443c15812032991c98b33b5424b17bcd55fe3575plougher if((fd = open(argv[i], O_RDONLY)) == -1) { 908443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Could not open %s, because %s\n", argv[i], strerror(errno)); 909443c15812032991c98b33b5424b17bcd55fe3575plougher exit(1); 910443c15812032991c98b33b5424b17bcd55fe3575plougher } 911443c15812032991c98b33b5424b17bcd55fe3575plougher 912443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_super(&sBlk, argv[i]) == FALSE) 913443c15812032991c98b33b5424b17bcd55fe3575plougher exit(1); 914443c15812032991c98b33b5424b17bcd55fe3575plougher 915443c15812032991c98b33b5424b17bcd55fe3575plougher block_size = sBlk.block_size; 916443c15812032991c98b33b5424b17bcd55fe3575plougher if((fragment_data = malloc(block_size)) == NULL) 917443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("failed to allocate fragment_data\n"); 918443c15812032991c98b33b5424b17bcd55fe3575plougher 919443c15812032991c98b33b5424b17bcd55fe3575plougher if((file_data = malloc(block_size)) == NULL) 920443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("failed to allocate file_data"); 921443c15812032991c98b33b5424b17bcd55fe3575plougher 922443c15812032991c98b33b5424b17bcd55fe3575plougher if((data = malloc(block_size)) == NULL) 923443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("failed to allocate datan\n"); 924443c15812032991c98b33b5424b17bcd55fe3575plougher 925443c15812032991c98b33b5424b17bcd55fe3575plougher if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL) 926443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("failed to allocate created_inode\n"); 927443c15812032991c98b33b5424b17bcd55fe3575plougher 928443c15812032991c98b33b5424b17bcd55fe3575plougher memset(created_inode, 0, sBlk.inodes * sizeof(char *)); 929443c15812032991c98b33b5424b17bcd55fe3575plougher 930443c15812032991c98b33b5424b17bcd55fe3575plougher read_uids_guids(&sBlk); 931443c15812032991c98b33b5424b17bcd55fe3575plougher read_fragment_table(&sBlk); 932443c15812032991c98b33b5424b17bcd55fe3575plougher uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start, &sBlk); 933443c15812032991c98b33b5424b17bcd55fe3575plougher uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start, &sBlk); 934443c15812032991c98b33b5424b17bcd55fe3575plougher 935443c15812032991c98b33b5424b17bcd55fe3575plougher dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), &sBlk); 936443c15812032991c98b33b5424b17bcd55fe3575plougher 937443c15812032991c98b33b5424b17bcd55fe3575plougher if(!lsonly) { 938443c15812032991c98b33b5424b17bcd55fe3575plougher printf("\n"); 939443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d files\n", file_count); 940443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d directories\n", dir_count); 941443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d symlinks\n", sym_count); 942443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d devices\n", dev_count); 943443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d fifos\n", fifo_count); 944443c15812032991c98b33b5424b17bcd55fe3575plougher } 945443c15812032991c98b33b5424b17bcd55fe3575plougher 946443c15812032991c98b33b5424b17bcd55fe3575plougher} 947