unsquashfs.c revision 68ba26e4a9ee62315d5d2bf5c23bfbc02347b646
168ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher, size/* 2443c15812032991c98b33b5424b17bcd55fe3575plougher * Unsquash a squashfs filesystem. This is a highly compressed read only filesystem. 3443c15812032991c98b33b5424b17bcd55fe3575plougher * 4d9b631e9e82c9e0d0e14b7f3d0f2965c523b113dplougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 579df93becb68081effabebba3006c794be308598plougher * Phillip Lougher <phillip@lougher.demon.co.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 * 21ed5124f016834932db2c63d60d259d846171c216plougher * unsquashfs.c 22443c15812032991c98b33b5424b17bcd55fe3575plougher */ 23443c15812032991c98b33b5424b17bcd55fe3575plougher 24ed5124f016834932db2c63d60d259d846171c216plougher#include "unsquashfs.h" 256490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_swap.h" 266490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_compat.h" 276490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "read_fs.h" 288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *fragment_cache, *data_cache; 308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *to_reader, *to_deflate, *to_writer, *from_writer; 318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_t *thread, *deflator_thread; 328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_mutex_t fragment_mutex; 338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* user options that control parallelisation */ 358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherint processors = -1; 368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 376490378e5b5e8dc058daf28423a7465699a6ba7bplougherstruct super_block sBlk; 3802bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_operations s_ops; 3902bc3bcabf2b219f63961f07293b83629948f026plougher 409dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, 419dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher dev_count = 0, fifo_count = 0; 42443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL; 43443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536]; 44443c15812032991c98b33b5424b17bcd55fe3575plougherint fd; 45443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table; 46443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG; 47443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data; 48443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data; 49443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data; 50443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size; 51ae271cc93e3684d5314bcdc45b631e497ae43166plougherunsigned int block_log; 524dba330d7b952f2f044d38e342e2ae3ea78910d6plougherint lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE, use_regex = FALSE; 53443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode; 549dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint root_process; 55eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint columns; 56eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint rotate = 0; 571b42101056befe25b5f19d5b099e806a2ecee9cdplougherpthread_mutex_t screen_mutex; 58eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherpthread_cond_t progress_wait; 591b42101056befe25b5f19d5b099e806a2ecee9cdplougherint progress = TRUE, progress_enabled = FALSE; 60eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int total_blocks = 0, total_files = 0, total_inodes = 0; 61eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int cur_blocks = 0; 62ed5124f016834932db2c63d60d259d846171c216plougherint inode_number = 1; 63443c15812032991c98b33b5424b17bcd55fe3575plougher 64476dcb48b24efff22caa970f000e151f1b28918dplougherint lookup_type[] = { 65476dcb48b24efff22caa970f000e151f1b28918dplougher 0, 66476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFDIR, 67476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFREG, 68476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFLNK, 69476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFBLK, 70476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFCHR, 71476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFIFO, 72476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFSOCK, 73476dcb48b24efff22caa970f000e151f1b28918dplougher S_IFDIR, 74eabe4dbeaec52acc95278663d7a13da7384ef9baplougher S_IFREG, 75eabe4dbeaec52acc95278663d7a13da7384ef9baplougher S_IFLNK, 76eabe4dbeaec52acc95278663d7a13da7384ef9baplougher S_IFBLK, 77eabe4dbeaec52acc95278663d7a13da7384ef9baplougher S_IFCHR, 78eabe4dbeaec52acc95278663d7a13da7384ef9baplougher S_IFIFO, 79eabe4dbeaec52acc95278663d7a13da7384ef9baplougher S_IFSOCK 80476dcb48b24efff22caa970f000e151f1b28918dplougher}; 81476dcb48b24efff22caa970f000e151f1b28918dplougher 82476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test table[] = { 83476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IFMT, S_IFSOCK, 0, 's' }, 84476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IFMT, S_IFLNK, 0, 'l' }, 85476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IFMT, S_IFBLK, 0, 'b' }, 86476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IFMT, S_IFDIR, 0, 'd' }, 87476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IFMT, S_IFCHR, 0, 'c' }, 88476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IFMT, S_IFIFO, 0, 'p' }, 89476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IRUSR, S_IRUSR, 1, 'r' }, 90476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IWUSR, S_IWUSR, 2, 'w' }, 91476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IRGRP, S_IRGRP, 4, 'r' }, 92476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IWGRP, S_IWGRP, 5, 'w' }, 93476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IROTH, S_IROTH, 7, 'r' }, 94476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IWOTH, S_IWOTH, 8, 'w' }, 95476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' }, 96476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXUSR | S_ISUID, S_ISUID, 3, 'S' }, 97476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' }, 98476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' }, 99476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXGRP | S_ISGID, S_ISGID, 6, 'S' }, 100476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' }, 101476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' }, 102476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' }, 103476dcb48b24efff22caa970f000e151f1b28918dplougher { S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' }, 1048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher { 0, 0, 0, 0} 1058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}; 1068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 107eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns); 108eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar(); 109eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 110eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid sigwinch_handler() 111eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{ 112eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct winsize winsize; 113eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 114eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(ioctl(1, TIOCGWINSZ, &winsize) == -1) { 1151b42101056befe25b5f19d5b099e806a2ecee9cdplougher ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 columns\n"); 116eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher columns = 80; 117eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } else 118eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher columns = winsize.ws_col; 119eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher} 120eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1221b5f6c5145f284683a2628b73ab5f8a0e37dd7b4ploughervoid sigalrm_handler() 1231b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher{ 1241b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher rotate = (rotate + 1) % 4; 1251b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher} 1261b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher 1271b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher 1288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *queue_init(int size) 1298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 1308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct queue *queue = malloc(sizeof(struct queue)); 1318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(queue == NULL) 1338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return NULL; 1348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) { 1368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher free(queue); 1378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return NULL; 1388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 1398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue->size = size + 1; 1418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue->readp = queue->writep = 0; 1428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_init(&queue->mutex, NULL); 1438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_init(&queue->empty, NULL); 1448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_init(&queue->full, NULL); 1458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return queue; 1478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 1488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1508888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid queue_put(struct queue *queue, void *data) 1518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 1528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int nextp; 1538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_lock(&queue->mutex); 1558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher while((nextp = (queue->writep + 1) % queue->size) == queue->readp) 1578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_wait(&queue->full, &queue->mutex); 1588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue->data[queue->writep] = data; 1608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue->writep = nextp; 1618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_signal(&queue->empty); 1628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&queue->mutex); 1638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 1648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1668888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *queue_get(struct queue *queue) 1678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 1688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher void *data; 1698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_lock(&queue->mutex); 1708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher while(queue->readp == queue->writep) 1728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_wait(&queue->empty, &queue->mutex); 1738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher data = queue->data[queue->readp]; 1758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue->readp = (queue->readp + 1) % queue->size; 1768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_signal(&queue->full); 1778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&queue->mutex); 1788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return data; 1808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 1818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */ 1848888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_hash_table(struct cache *cache, struct cache_entry *entry) 1858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 1868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int hash = CALCULATE_HASH(entry->block); 1878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->hash_next = cache->hash_table[hash]; 1898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->hash_table[hash] = entry; 1908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->hash_prev = NULL; 1918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->hash_next) 1928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->hash_next->hash_prev = entry; 1938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 1948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */ 1978888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_hash_table(struct cache *cache, struct cache_entry *entry) 1988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 1998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->hash_prev) 2008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->hash_prev->hash_next = entry->hash_next; 2018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher else 2028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->hash_table[CALCULATE_HASH(entry->block)] = entry->hash_next; 2038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->hash_next) 2048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->hash_next->hash_prev = entry->hash_prev; 2058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->hash_prev = entry->hash_next = NULL; 2078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 2088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */ 2118888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_free_list(struct cache *cache, struct cache_entry *entry) 2128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 2138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(cache->free_list) { 2148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->free_next = cache->free_list; 2158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->free_prev = cache->free_list->free_prev; 2168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->free_list->free_prev->free_next = entry; 2178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->free_list->free_prev = entry; 2188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } else { 2198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->free_list = entry; 2208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->free_prev = entry->free_next = entry; 2218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 2228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 2238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */ 2268888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_free_list(struct cache *cache, struct cache_entry *entry) 2278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 2288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->free_prev == NULL && entry->free_next == NULL) 2298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* not in free list */ 2308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return; 231222e49e257bccb10c0e608f071778f26fce28f01plougher else if(entry->free_prev == entry && entry->free_next == entry) { 2328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* only this entry in the free list */ 2338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->free_list = NULL; 2348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } else { 2358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* more than one entry in the free list */ 2368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->free_next->free_prev = entry->free_prev; 2378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->free_prev->free_next = entry->free_next; 2388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(cache->free_list == entry) 2398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->free_list = entry->free_next; 2408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 2418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->free_prev = entry->free_next = NULL; 2438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 2448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *cache_init(int buffer_size, int max_buffers) 2478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 2488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct cache *cache = malloc(sizeof(struct cache)); 2498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(cache == NULL) 2518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return NULL; 2528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->max_buffers = max_buffers; 2548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->buffer_size = buffer_size; 2558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->count = 0; 2568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->free_list = NULL; 2578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536); 2588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->wait_free = FALSE; 2598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->wait_pending = FALSE; 2608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_init(&cache->mutex, NULL); 2618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_init(&cache->wait_for_free, NULL); 2628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_init(&cache->wait_for_pending, NULL); 2638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return cache; 2658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 2668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry *cache_get(struct cache *cache, long long block, int size) 2698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 2708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* Get a block out of the cache. If the block isn't in the cache 2718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * it is added and queued to the reader() and deflate() threads for reading 2728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * off disk and decompression. The cache grows until max_blocks is reached, 2738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * once this occurs existing discarded blocks on the free list are reused */ 2748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int hash = CALCULATE_HASH(block); 2758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct cache_entry *entry; 2768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_lock(&cache->mutex); 2788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next) 2808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->block == block) 2818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher break; 2828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry) { 2848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* found the block in the cache, increment used count and 2858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * if necessary remove from free list so it won't disappear 2868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher */ 2878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->used ++; 2888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher remove_free_list(cache, entry); 2898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&cache->mutex); 2908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } else { 2918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* not in the cache */ 2928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 2938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* first try to allocate new block */ 2948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(cache->count < cache->max_buffers) { 2958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry = malloc(sizeof(struct cache_entry)); 2968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry == NULL) 2978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher goto failed; 2988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->data = malloc(cache->buffer_size); 2998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->data == NULL) { 3008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher free(entry); 3018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher goto failed; 3028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->cache = cache; 3048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->free_prev = entry->free_next = NULL; 3058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->count ++; 3068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } else { 3078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* try to get from free list */ 3088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher while(cache->free_list == NULL) { 3098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache->wait_free = TRUE; 3108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_wait(&cache->wait_for_free, &cache->mutex); 3118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry = cache->free_list; 3138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher remove_free_list(cache, entry); 3148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher remove_hash_table(cache, entry); 3158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* initialise block and insert into the hash table */ 3188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->block = block; 3198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->size = size; 3208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->used = 1; 3218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->error = FALSE; 3228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->pending = TRUE; 3238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher insert_hash_table(cache, entry); 3248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* queue to read thread to read and ultimately (via the decompress 3268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * threads) decompress the buffer 3278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher */ 3288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&cache->mutex); 3298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_put(to_reader, entry); 3308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return entry; 3338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherfailed: 3358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&cache->mutex); 3368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher return NULL; 3378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 3388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3408888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_ready(struct cache_entry *entry, int error) 3418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 3428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* mark cache entry as being complete, reading and (if necessary) 3438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * decompression has taken place, and the buffer is valid for use. 3448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * If an error occurs reading or decompressing, the buffer also 3458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * becomes ready but with an error... */ 3468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_lock(&entry->cache->mutex); 3478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->pending = FALSE; 3488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->error = error; 3498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* if the wait_pending flag is set, one or more threads may be waiting on 3518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * this buffer */ 3528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->cache->wait_pending) { 3538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->cache->wait_pending = FALSE; 3548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_broadcast(&entry->cache->wait_for_pending); 3558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&entry->cache->mutex); 3588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 3598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3618888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_wait(struct cache_entry *entry) 3628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 3638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* wait for this cache entry to become ready, when reading and (if necessary) 3648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * decompression has taken place */ 3658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_lock(&entry->cache->mutex); 3668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher while(entry->pending) { 3688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->cache->wait_pending = TRUE; 3698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_wait(&entry->cache->wait_for_pending, &entry->cache->mutex); 3708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&entry->cache->mutex); 3738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 3748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3768888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_put(struct cache_entry *entry) 3778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 3788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* finished with this cache entry, once the usage count reaches zero it 3798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * can be reused and is put onto the free list. As it remains accessible 3808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * via the hash table it can be found getting a new lease of life before it 3818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * is reused. */ 3828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_lock(&entry->cache->mutex); 3838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->used --; 3858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->used == 0) { 3868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher insert_free_list(entry->cache, entry); 3878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* if the wait_free flag is set, one or more threads may be waiting on 3898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * this buffer */ 3908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(entry->cache->wait_free) { 3918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->cache->wait_free = FALSE; 3928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_cond_broadcast(&entry->cache->wait_for_free); 3938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 3958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 3968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_unlock(&entry->cache->mutex); 3978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 398476dcb48b24efff22caa970f000e151f1b28918dplougher 399476dcb48b24efff22caa970f000e151f1b28918dplougher 400476dcb48b24efff22caa970f000e151f1b28918dplougherchar *modestr(char *str, int mode) 401476dcb48b24efff22caa970f000e151f1b28918dplougher{ 402476dcb48b24efff22caa970f000e151f1b28918dplougher int i; 403476dcb48b24efff22caa970f000e151f1b28918dplougher 404476dcb48b24efff22caa970f000e151f1b28918dplougher strcpy(str, "----------"); 405476dcb48b24efff22caa970f000e151f1b28918dplougher 406476dcb48b24efff22caa970f000e151f1b28918dplougher for(i = 0; table[i].mask != 0; i++) { 407476dcb48b24efff22caa970f000e151f1b28918dplougher if((mode & table[i].mask) == table[i].value) 408476dcb48b24efff22caa970f000e151f1b28918dplougher str[table[i].position] = table[i].mode; 409476dcb48b24efff22caa970f000e151f1b28918dplougher } 410476dcb48b24efff22caa970f000e151f1b28918dplougher 411476dcb48b24efff22caa970f000e151f1b28918dplougher return str; 412476dcb48b24efff22caa970f000e151f1b28918dplougher} 413476dcb48b24efff22caa970f000e151f1b28918dplougher 414476dcb48b24efff22caa970f000e151f1b28918dplougher 4153edfa57b6a463f7d441d995559143f4861d62e98plougher#define TOTALCHARS 25 4166f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint print_filename(char *pathname, struct inode *inode) 417476dcb48b24efff22caa970f000e151f1b28918dplougher{ 4186f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher char str[11], dummy[100], dummy2[100], *userstr, *groupstr; 4196f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher int padchars; 420476dcb48b24efff22caa970f000e151f1b28918dplougher struct passwd *user; 421476dcb48b24efff22caa970f000e151f1b28918dplougher struct group *group; 42288facddfd83e48a907b82210ddccbb4f84d80aecplougher struct tm *t; 423476dcb48b24efff22caa970f000e151f1b28918dplougher 424476dcb48b24efff22caa970f000e151f1b28918dplougher if(short_ls) { 425476dcb48b24efff22caa970f000e151f1b28918dplougher printf("%s\n", pathname); 426476dcb48b24efff22caa970f000e151f1b28918dplougher return 1; 427476dcb48b24efff22caa970f000e151f1b28918dplougher } 428476dcb48b24efff22caa970f000e151f1b28918dplougher 4296f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if((user = getpwuid(inode->uid)) == NULL) { 4306f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher sprintf(dummy, "%d", inode->uid); 4313edfa57b6a463f7d441d995559143f4861d62e98plougher userstr = dummy; 4323edfa57b6a463f7d441d995559143f4861d62e98plougher } else 4333edfa57b6a463f7d441d995559143f4861d62e98plougher userstr = user->pw_name; 4343edfa57b6a463f7d441d995559143f4861d62e98plougher 4356f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if((group = getgrgid(inode->gid)) == NULL) { 4366f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher sprintf(dummy2, "%d", inode->gid); 4373edfa57b6a463f7d441d995559143f4861d62e98plougher groupstr = dummy2; 4383edfa57b6a463f7d441d995559143f4861d62e98plougher } else 4393edfa57b6a463f7d441d995559143f4861d62e98plougher groupstr = group->gr_name; 4403edfa57b6a463f7d441d995559143f4861d62e98plougher 4416f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr); 4423edfa57b6a463f7d441d995559143f4861d62e98plougher 4436f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher switch(inode->mode & S_IFMT) { 4443edfa57b6a463f7d441d995559143f4861d62e98plougher case S_IFREG: 4453edfa57b6a463f7d441d995559143f4861d62e98plougher case S_IFDIR: 4463edfa57b6a463f7d441d995559143f4861d62e98plougher case S_IFSOCK: 4473edfa57b6a463f7d441d995559143f4861d62e98plougher case S_IFIFO: 4483edfa57b6a463f7d441d995559143f4861d62e98plougher case S_IFLNK: 4493edfa57b6a463f7d441d995559143f4861d62e98plougher padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr); 4503edfa57b6a463f7d441d995559143f4861d62e98plougher 451caf2f0f593c7f14a4e7e151eeeed773c72578f69plougher printf("%*lld ", padchars > 0 ? padchars : 0, inode->data); 4523edfa57b6a463f7d441d995559143f4861d62e98plougher break; 4533edfa57b6a463f7d441d995559143f4861d62e98plougher case S_IFCHR: 4543edfa57b6a463f7d441d995559143f4861d62e98plougher case S_IFBLK: 4553edfa57b6a463f7d441d995559143f4861d62e98plougher padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr) - 7; 4563edfa57b6a463f7d441d995559143f4861d62e98plougher 45747fc2f0b451e12cddb0cc482019e6abe5bd59d46plougher printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ", (int) inode->data >> 8, (int) inode->data & 0xff); 4583edfa57b6a463f7d441d995559143f4861d62e98plougher break; 4593edfa57b6a463f7d441d995559143f4861d62e98plougher } 460476dcb48b24efff22caa970f000e151f1b28918dplougher 4616f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher t = localtime(&inode->time); 46288facddfd83e48a907b82210ddccbb4f84d80aecplougher 46388facddfd83e48a907b82210ddccbb4f84d80aecplougher printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, pathname); 4646f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if((inode->mode & S_IFMT) == S_IFLNK) 4656f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher printf(" -> %s", inode->symlink); 4663edfa57b6a463f7d441d995559143f4861d62e98plougher printf("\n"); 4673edfa57b6a463f7d441d995559143f4861d62e98plougher 468476dcb48b24efff22caa970f000e151f1b28918dplougher return 1; 469476dcb48b24efff22caa970f000e151f1b28918dplougher} 470476dcb48b24efff22caa970f000e151f1b28918dplougher 471443c15812032991c98b33b5424b17bcd55fe3575plougher 472f404f4914fdb272a70e18664e8963d793cc90f44plougherint add_entry(struct hash_table_entry *hash_table[], long long start, int bytes) 473443c15812032991c98b33b5424b17bcd55fe3575plougher{ 474443c15812032991c98b33b5424b17bcd55fe3575plougher int hash = CALCULATE_HASH(start); 475443c15812032991c98b33b5424b17bcd55fe3575plougher struct hash_table_entry *hash_table_entry; 476443c15812032991c98b33b5424b17bcd55fe3575plougher 477443c15812032991c98b33b5424b17bcd55fe3575plougher if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) { 478443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("add_hash: out of memory in malloc\n"); 479443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 480443c15812032991c98b33b5424b17bcd55fe3575plougher } 481443c15812032991c98b33b5424b17bcd55fe3575plougher 482443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table_entry->start = start; 483443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table_entry->bytes = bytes; 484443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table_entry->next = hash_table[hash]; 485443c15812032991c98b33b5424b17bcd55fe3575plougher hash_table[hash] = hash_table_entry; 486443c15812032991c98b33b5424b17bcd55fe3575plougher 487443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 488443c15812032991c98b33b5424b17bcd55fe3575plougher} 489443c15812032991c98b33b5424b17bcd55fe3575plougher 490443c15812032991c98b33b5424b17bcd55fe3575plougher 491f404f4914fdb272a70e18664e8963d793cc90f44plougherint lookup_entry(struct hash_table_entry *hash_table[], long long start) 492443c15812032991c98b33b5424b17bcd55fe3575plougher{ 493443c15812032991c98b33b5424b17bcd55fe3575plougher int hash = CALCULATE_HASH(start); 494443c15812032991c98b33b5424b17bcd55fe3575plougher struct hash_table_entry *hash_table_entry; 495443c15812032991c98b33b5424b17bcd55fe3575plougher 4969dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher for(hash_table_entry = hash_table[hash]; hash_table_entry; 4979dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher hash_table_entry = hash_table_entry->next) 4987a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher 499443c15812032991c98b33b5424b17bcd55fe3575plougher if(hash_table_entry->start == start) 500443c15812032991c98b33b5424b17bcd55fe3575plougher return hash_table_entry->bytes; 501443c15812032991c98b33b5424b17bcd55fe3575plougher 502443c15812032991c98b33b5424b17bcd55fe3575plougher return -1; 503443c15812032991c98b33b5424b17bcd55fe3575plougher} 504443c15812032991c98b33b5424b17bcd55fe3575plougher 505443c15812032991c98b33b5424b17bcd55fe3575plougher 506443c15812032991c98b33b5424b17bcd55fe3575plougherint read_bytes(long long byte, int bytes, char *buff) 507443c15812032991c98b33b5424b17bcd55fe3575plougher{ 508443c15812032991c98b33b5424b17bcd55fe3575plougher off_t off = byte; 509443c15812032991c98b33b5424b17bcd55fe3575plougher 510fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); 511fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 512443c15812032991c98b33b5424b17bcd55fe3575plougher if(lseek(fd, off, SEEK_SET) == -1) { 5135d415c6659faaa7a69c9baa7175610d889747142plougher ERROR("Lseek failed because %s\n", strerror(errno)); 514443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 515443c15812032991c98b33b5424b17bcd55fe3575plougher } 516443c15812032991c98b33b5424b17bcd55fe3575plougher 517443c15812032991c98b33b5424b17bcd55fe3575plougher if(read(fd, buff, bytes) == -1) { 518443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Read on destination failed because %s\n", strerror(errno)); 519443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 520443c15812032991c98b33b5424b17bcd55fe3575plougher } 521443c15812032991c98b33b5424b17bcd55fe3575plougher 522443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 523443c15812032991c98b33b5424b17bcd55fe3575plougher} 524443c15812032991c98b33b5424b17bcd55fe3575plougher 525443c15812032991c98b33b5424b17bcd55fe3575plougher 52602bc3bcabf2b219f63961f07293b83629948f026plougherint read_block(long long start, long long *next, char *block) 527443c15812032991c98b33b5424b17bcd55fe3575plougher{ 528443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned short c_byte; 529443c15812032991c98b33b5424b17bcd55fe3575plougher int offset = 2; 530443c15812032991c98b33b5424b17bcd55fe3575plougher 531443c15812032991c98b33b5424b17bcd55fe3575plougher if(swap) { 532443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, 2, block) == FALSE) 533fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 534443c15812032991c98b33b5424b17bcd55fe3575plougher ((unsigned char *) &c_byte)[1] = block[0]; 535443c15812032991c98b33b5424b17bcd55fe3575plougher ((unsigned char *) &c_byte)[0] = block[1]; 536443c15812032991c98b33b5424b17bcd55fe3575plougher } else 537443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, 2, (char *)&c_byte) == FALSE) 538fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 539fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 540fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed"); 541443c15812032991c98b33b5424b17bcd55fe3575plougher 54202bc3bcabf2b219f63961f07293b83629948f026plougher if(SQUASHFS_CHECK_DATA(sBlk.flags)) 543443c15812032991c98b33b5424b17bcd55fe3575plougher offset = 3; 544443c15812032991c98b33b5424b17bcd55fe3575plougher if(SQUASHFS_COMPRESSED(c_byte)) { 545443c15812032991c98b33b5424b17bcd55fe3575plougher char buffer[SQUASHFS_METADATA_SIZE]; 546443c15812032991c98b33b5424b17bcd55fe3575plougher int res; 547443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned long bytes = SQUASHFS_METADATA_SIZE; 548443c15812032991c98b33b5424b17bcd55fe3575plougher 549443c15812032991c98b33b5424b17bcd55fe3575plougher c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); 550443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start + offset, c_byte, buffer) == FALSE) 551fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 552443c15812032991c98b33b5424b17bcd55fe3575plougher 553545404219cdd79c1e06ac7d0698d02a15240c4c3plougher res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte); 554545404219cdd79c1e06ac7d0698d02a15240c4c3plougher 555545404219cdd79c1e06ac7d0698d02a15240c4c3plougher if(res != Z_OK) { 556443c15812032991c98b33b5424b17bcd55fe3575plougher if(res == Z_MEM_ERROR) 557443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough memory\n"); 558443c15812032991c98b33b5424b17bcd55fe3575plougher else if(res == Z_BUF_ERROR) 559443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough room in output buffer\n"); 560443c15812032991c98b33b5424b17bcd55fe3575plougher else 561443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, unknown error %d\n", res); 562fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 563443c15812032991c98b33b5424b17bcd55fe3575plougher } 564443c15812032991c98b33b5424b17bcd55fe3575plougher if(next) 565443c15812032991c98b33b5424b17bcd55fe3575plougher *next = start + offset + c_byte; 566443c15812032991c98b33b5424b17bcd55fe3575plougher return bytes; 567443c15812032991c98b33b5424b17bcd55fe3575plougher } else { 568443c15812032991c98b33b5424b17bcd55fe3575plougher c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); 569443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start + offset, c_byte, block) == FALSE) 570fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher goto failed; 571443c15812032991c98b33b5424b17bcd55fe3575plougher if(next) 572443c15812032991c98b33b5424b17bcd55fe3575plougher *next = start + offset + c_byte; 573443c15812032991c98b33b5424b17bcd55fe3575plougher return c_byte; 574443c15812032991c98b33b5424b17bcd55fe3575plougher } 575fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 576fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed: 57768ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher ERROR("read_block: failed to read block @0x%llx\n", start); 578fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher return FALSE; 579443c15812032991c98b33b5424b17bcd55fe3575plougher} 580443c15812032991c98b33b5424b17bcd55fe3575plougher 581443c15812032991c98b33b5424b17bcd55fe3575plougher 582443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block) 583443c15812032991c98b33b5424b17bcd55fe3575plougher{ 584443c15812032991c98b33b5424b17bcd55fe3575plougher int res; 585443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned long bytes = block_size; 586443c15812032991c98b33b5424b17bcd55fe3575plougher int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size); 587443c15812032991c98b33b5424b17bcd55fe3575plougher 588fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 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"); 589fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 590443c15812032991c98b33b5424b17bcd55fe3575plougher if(SQUASHFS_COMPRESSED_BLOCK(size)) { 591443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, c_byte, data) == FALSE) 59268ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher goto failed; 593443c15812032991c98b33b5424b17bcd55fe3575plougher 594545404219cdd79c1e06ac7d0698d02a15240c4c3plougher res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte); 595545404219cdd79c1e06ac7d0698d02a15240c4c3plougher 596545404219cdd79c1e06ac7d0698d02a15240c4c3plougher if(res != Z_OK) { 597443c15812032991c98b33b5424b17bcd55fe3575plougher if(res == Z_MEM_ERROR) 598443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough memory\n"); 599443c15812032991c98b33b5424b17bcd55fe3575plougher else if(res == Z_BUF_ERROR) 600443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, not enough room in output buffer\n"); 601443c15812032991c98b33b5424b17bcd55fe3575plougher else 602443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("zlib::uncompress failed, unknown error %d\n", res); 60368ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher goto failed; 604443c15812032991c98b33b5424b17bcd55fe3575plougher } 605443c15812032991c98b33b5424b17bcd55fe3575plougher 606443c15812032991c98b33b5424b17bcd55fe3575plougher return bytes; 607443c15812032991c98b33b5424b17bcd55fe3575plougher } else { 608443c15812032991c98b33b5424b17bcd55fe3575plougher if(read_bytes(start, c_byte, block) == FALSE) 60968ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher goto failed; 610443c15812032991c98b33b5424b17bcd55fe3575plougher 611443c15812032991c98b33b5424b17bcd55fe3575plougher return c_byte; 612443c15812032991c98b33b5424b17bcd55fe3575plougher } 61368ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher 61468ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougherfailed: 61568ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start, size); 61668ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher return FALSE; 617443c15812032991c98b33b5424b17bcd55fe3575plougher} 618443c15812032991c98b33b5424b17bcd55fe3575plougher 619443c15812032991c98b33b5424b17bcd55fe3575plougher 62002bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_inode_table(long long start, long long end) 621443c15812032991c98b33b5424b17bcd55fe3575plougher{ 622443c15812032991c98b33b5424b17bcd55fe3575plougher int size = 0, bytes = 0, res; 623443c15812032991c98b33b5424b17bcd55fe3575plougher 624443c15812032991c98b33b5424b17bcd55fe3575plougher while(start < end) { 625443c15812032991c98b33b5424b17bcd55fe3575plougher if((size - bytes < SQUASHFS_METADATA_SIZE) && 6269dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher ((inode_table = realloc(inode_table, size += 6279dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher SQUASHFS_METADATA_SIZE)) == NULL)) 628443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n"); 629443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("uncompress_inode_table: reading block 0x%llx\n", start); 630443c15812032991c98b33b5424b17bcd55fe3575plougher add_entry(inode_table_hash, start, bytes); 63102bc3bcabf2b219f63961f07293b83629948f026plougher if((res = read_block(start, &start, inode_table + bytes)) == 0) { 632443c15812032991c98b33b5424b17bcd55fe3575plougher free(inode_table); 633443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n"); 634443c15812032991c98b33b5424b17bcd55fe3575plougher } 635443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += res; 636443c15812032991c98b33b5424b17bcd55fe3575plougher } 637443c15812032991c98b33b5424b17bcd55fe3575plougher} 638443c15812032991c98b33b5424b17bcd55fe3575plougher 639443c15812032991c98b33b5424b17bcd55fe3575plougher 6406f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time, unsigned int set_mode) 641443c15812032991c98b33b5424b17bcd55fe3575plougher{ 6426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher struct utimbuf times = { time, time }; 643443c15812032991c98b33b5424b17bcd55fe3575plougher 644443c15812032991c98b33b5424b17bcd55fe3575plougher if(utime(pathname, ×) == -1) { 645443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno)); 646443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 647443c15812032991c98b33b5424b17bcd55fe3575plougher } 648443c15812032991c98b33b5424b17bcd55fe3575plougher 6499dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher if(root_process) { 6506f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if(chown(pathname, uid, guid) == -1) { 651443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); 652443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 653443c15812032991c98b33b5424b17bcd55fe3575plougher } 6549dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher } else 6559dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher mode &= ~07000; 6569dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher 6579dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) { 6589dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno)); 6599dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher return FALSE; 660443c15812032991c98b33b5424b17bcd55fe3575plougher } 661443c15812032991c98b33b5424b17bcd55fe3575plougher 662443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 663443c15812032991c98b33b5424b17bcd55fe3575plougher} 664443c15812032991c98b33b5424b17bcd55fe3575plougher 665443c15812032991c98b33b5424b17bcd55fe3575plougher 666b9cee889506e674726856035dba52d5e1cceeb99plougherint lseek_broken = FALSE; 667c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherchar *zero_data = NULL; 668b9cee889506e674726856035dba52d5e1cceeb99plougher 669c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherint write_block(int file_fd, char *buffer, int size, int hole, int sparse) 670b9cee889506e674726856035dba52d5e1cceeb99plougher{ 671b9cee889506e674726856035dba52d5e1cceeb99plougher off_t off = hole; 672b9cee889506e674726856035dba52d5e1cceeb99plougher 673b9cee889506e674726856035dba52d5e1cceeb99plougher if(hole) { 674c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if(sparse && lseek_broken == FALSE) { 675c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher int error = lseek(file_fd, off, SEEK_CUR); 676c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if(error == -1) 677c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher /* failed to seek beyond end of file */ 678c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher lseek_broken = TRUE; 679c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher } 680c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher 681c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if((sparse == FALSE || lseek_broken) && zero_data == NULL) { 682b9cee889506e674726856035dba52d5e1cceeb99plougher if((zero_data = malloc(block_size)) == NULL) 683b9cee889506e674726856035dba52d5e1cceeb99plougher EXIT_UNSQUASH("write_block: failed to alloc zero data block\n"); 684b9cee889506e674726856035dba52d5e1cceeb99plougher memset(zero_data, 0, block_size); 685b9cee889506e674726856035dba52d5e1cceeb99plougher } 686c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher 687c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if(sparse == FALSE || lseek_broken) { 688b9cee889506e674726856035dba52d5e1cceeb99plougher int blocks = (hole + block_size -1) / block_size; 689b9cee889506e674726856035dba52d5e1cceeb99plougher int avail_bytes, i; 690b9cee889506e674726856035dba52d5e1cceeb99plougher for(i = 0; i < blocks; i++, hole -= avail_bytes) { 691b9cee889506e674726856035dba52d5e1cceeb99plougher avail_bytes = hole > block_size ? block_size : hole; 692b9cee889506e674726856035dba52d5e1cceeb99plougher if(write(file_fd, zero_data, avail_bytes) < avail_bytes) 693b9cee889506e674726856035dba52d5e1cceeb99plougher goto failure; 694b9cee889506e674726856035dba52d5e1cceeb99plougher } 695b9cee889506e674726856035dba52d5e1cceeb99plougher } 696b9cee889506e674726856035dba52d5e1cceeb99plougher } 697b9cee889506e674726856035dba52d5e1cceeb99plougher 698b9cee889506e674726856035dba52d5e1cceeb99plougher if(write(file_fd, buffer, size) < size) 699b9cee889506e674726856035dba52d5e1cceeb99plougher goto failure; 700b9cee889506e674726856035dba52d5e1cceeb99plougher 701b9cee889506e674726856035dba52d5e1cceeb99plougher return TRUE; 702b9cee889506e674726856035dba52d5e1cceeb99plougher 703b9cee889506e674726856035dba52d5e1cceeb99plougherfailure: 704b9cee889506e674726856035dba52d5e1cceeb99plougher return FALSE; 705b9cee889506e674726856035dba52d5e1cceeb99plougher} 706b9cee889506e674726856035dba52d5e1cceeb99plougher 7078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 70879df93becb68081effabebba3006c794be308598plougherint write_file(struct inode *inode, char *pathname) 709443c15812032991c98b33b5424b17bcd55fe3575plougher{ 7108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher unsigned int file_fd, i; 711f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher unsigned int *block_list; 71279df93becb68081effabebba3006c794be308598plougher int file_end = inode->data / block_size; 71379df93becb68081effabebba3006c794be308598plougher long long start = inode->start; 7148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct squashfs_file *file; 715443c15812032991c98b33b5424b17bcd55fe3575plougher 71679df93becb68081effabebba3006c794be308598plougher TRACE("write_file: regular file, blocks %d\n", inode->blocks); 717443c15812032991c98b33b5424b17bcd55fe3575plougher 71879df93becb68081effabebba3006c794be308598plougher if((file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0), (mode_t) inode->mode & 0777)) == -1) { 719443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("write_file: failed to create file %s, because %s\n", pathname, 720443c15812032991c98b33b5424b17bcd55fe3575plougher strerror(errno)); 721443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 722443c15812032991c98b33b5424b17bcd55fe3575plougher } 723443c15812032991c98b33b5424b17bcd55fe3575plougher 72479df93becb68081effabebba3006c794be308598plougher if((block_list = malloc(inode->blocks * sizeof(unsigned int))) == NULL) 7258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("write_file: unable to malloc block list\n"); 726443c15812032991c98b33b5424b17bcd55fe3575plougher 72779df93becb68081effabebba3006c794be308598plougher s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks); 728443c15812032991c98b33b5424b17bcd55fe3575plougher 7298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if((file = malloc(sizeof(struct squashfs_file))) == NULL) 7308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("write_file: unable to malloc file\n"); 731443c15812032991c98b33b5424b17bcd55fe3575plougher 7328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* the writer thread is queued a squashfs_file structure describing the 7338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * file. If the file has one or more blocks or a fragments they are queued 7348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * separately (references to blocks in the cache). */ 7358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher file->fd = file_fd; 73679df93becb68081effabebba3006c794be308598plougher file->file_size = inode->data; 73779df93becb68081effabebba3006c794be308598plougher file->mode = inode->mode; 73879df93becb68081effabebba3006c794be308598plougher file->gid = inode->gid; 73979df93becb68081effabebba3006c794be308598plougher file->uid = inode->uid; 74079df93becb68081effabebba3006c794be308598plougher file->time = inode->time; 74179df93becb68081effabebba3006c794be308598plougher file->pathname = strdup(pathname); 74279df93becb68081effabebba3006c794be308598plougher file->blocks = inode->blocks + (inode->frag_bytes > 0); 7437f6692575a1b1c8d7d55afac647b72b84b79e378plougher file->sparse = inode->sparse; 7448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_put(to_writer, file); 745443c15812032991c98b33b5424b17bcd55fe3575plougher 74679df93becb68081effabebba3006c794be308598plougher for(i = 0; i < inode->blocks; i++) { 7478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); 7488372232d2460411adaa2299c32a0a88665e44902plougher struct file_entry *block = malloc(sizeof(struct file_entry)); 7498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 7508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(block == NULL) 7518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("write_file: unable to malloc file\n"); 7528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher block->offset = 0; 75379df93becb68081effabebba3006c794be308598plougher block->size = i == file_end ? inode->data & (block_size - 1) : block_size; 7548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(block_list[i] == 0) /* sparse file */ 7558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher block->buffer = NULL; 7568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher else { 7578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher block->buffer = cache_get(data_cache, start, block_list[i]); 7588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(block->buffer == NULL) 7598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("write_file: cache_get failed\n"); 7608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher start += c_byte; 761443c15812032991c98b33b5424b17bcd55fe3575plougher } 7628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_put(to_writer, block); 763443c15812032991c98b33b5424b17bcd55fe3575plougher } 764443c15812032991c98b33b5424b17bcd55fe3575plougher 76579df93becb68081effabebba3006c794be308598plougher if(inode->frag_bytes) { 7668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int size; 7678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher long long start; 7688372232d2460411adaa2299c32a0a88665e44902plougher struct file_entry *block = malloc(sizeof(struct file_entry)); 7698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 7708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(block == NULL) 7718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("write_file: unable to malloc file\n"); 77279df93becb68081effabebba3006c794be308598plougher s_ops.read_fragment(inode->fragment, &start, &size); 7738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher block->buffer = cache_get(fragment_cache, start, size); 7748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(block->buffer == NULL) 7758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("write_file: cache_get failed\n"); 77679df93becb68081effabebba3006c794be308598plougher block->offset = inode->offset; 77779df93becb68081effabebba3006c794be308598plougher block->size = inode->frag_bytes; 7788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_put(to_writer, block); 779b9cee889506e674726856035dba52d5e1cceeb99plougher } 780b9cee889506e674726856035dba52d5e1cceeb99plougher 781b9cee889506e674726856035dba52d5e1cceeb99plougher free(block_list); 782443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 783443c15812032991c98b33b5424b17bcd55fe3575plougher} 784476dcb48b24efff22caa970f000e151f1b28918dplougher 785476dcb48b24efff22caa970f000e151f1b28918dplougher 7866f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint create_inode(char *pathname, struct inode *i) 787443c15812032991c98b33b5424b17bcd55fe3575plougher{ 7886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher TRACE("create_inode: pathname %s\n", pathname); 789443c15812032991c98b33b5424b17bcd55fe3575plougher 7906f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if(created_inode[i->inode_number - 1]) { 791443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: hard link\n"); 7926013a30bd39550decc2546a47e5168e57bfcfde8plougher if(force) 7936013a30bd39550decc2546a47e5168e57bfcfde8plougher unlink(pathname); 7946013a30bd39550decc2546a47e5168e57bfcfde8plougher 7956f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if(link(created_inode[i->inode_number - 1], pathname) == -1) { 796443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno)); 797443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 798443c15812032991c98b33b5424b17bcd55fe3575plougher } 799443c15812032991c98b33b5424b17bcd55fe3575plougher 800443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 801443c15812032991c98b33b5424b17bcd55fe3575plougher } 802443c15812032991c98b33b5424b17bcd55fe3575plougher 8036f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher switch(i->type) { 8046f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher case SQUASHFS_FILE_TYPE: 8056f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher case SQUASHFS_LREG_TYPE: 8066f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher TRACE("create_inode: regular file, file_size %lld, blocks %d\n", i->data, i->blocks); 807443c15812032991c98b33b5424b17bcd55fe3575plougher 80879df93becb68081effabebba3006c794be308598plougher if(write_file(i, pathname)) 809443c15812032991c98b33b5424b17bcd55fe3575plougher file_count ++; 810443c15812032991c98b33b5424b17bcd55fe3575plougher break; 8116f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher case SQUASHFS_SYMLINK_TYPE: 812545404219cdd79c1e06ac7d0698d02a15240c4c3plougher TRACE("create_inode: symlink, symlink_size %lld\n", i->data); 813443c15812032991c98b33b5424b17bcd55fe3575plougher 814a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher if(force) 815a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher unlink(pathname); 816a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher 8176f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if(symlink(i->symlink, pathname) == -1) { 818443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create symlink %s, because %s\n", pathname, 819443c15812032991c98b33b5424b17bcd55fe3575plougher strerror(errno)); 820443c15812032991c98b33b5424b17bcd55fe3575plougher break; 821443c15812032991c98b33b5424b17bcd55fe3575plougher } 822443c15812032991c98b33b5424b17bcd55fe3575plougher 8239dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher if(root_process) { 8246f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if(lchown(pathname, i->uid, i->gid) == -1) 825443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); 826443c15812032991c98b33b5424b17bcd55fe3575plougher } 827443c15812032991c98b33b5424b17bcd55fe3575plougher 828443c15812032991c98b33b5424b17bcd55fe3575plougher sym_count ++; 829443c15812032991c98b33b5424b17bcd55fe3575plougher break; 830443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_BLKDEV_TYPE: 831443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_CHRDEV_TYPE: { 8326f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher int chrdev = i->type == SQUASHFS_CHRDEV_TYPE; 833545404219cdd79c1e06ac7d0698d02a15240c4c3plougher TRACE("create_inode: dev, rdev 0x%llx\n", i->data); 834443c15812032991c98b33b5424b17bcd55fe3575plougher 8359dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher if(root_process) { 836a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher if(force) 837a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher unlink(pathname); 838a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher 8396f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK, 8406f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher makedev((i->data >> 8) & 0xff, i->data & 0xff)) == -1) { 841443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create %s device %s, because %s\n", 8426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher chrdev ? "character" : "block", pathname, strerror(errno)); 843443c15812032991c98b33b5424b17bcd55fe3575plougher break; 844443c15812032991c98b33b5424b17bcd55fe3575plougher } 8456f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher set_attributes(pathname, i->mode, i->uid, i->gid, i->time, TRUE); 846443c15812032991c98b33b5424b17bcd55fe3575plougher dev_count ++; 847443c15812032991c98b33b5424b17bcd55fe3575plougher } else 848443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: could not create %s device %s, because you're not superuser!\n", 849545404219cdd79c1e06ac7d0698d02a15240c4c3plougher chrdev ? "character" : "block", pathname); 850443c15812032991c98b33b5424b17bcd55fe3575plougher break; 8516f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher } 852443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_FIFO_TYPE: 853443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: fifo\n"); 854443c15812032991c98b33b5424b17bcd55fe3575plougher 855a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher if(force) 856a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher unlink(pathname); 857a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher 858443c15812032991c98b33b5424b17bcd55fe3575plougher if(mknod(pathname, S_IFIFO, 0) == -1) { 859443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: failed to create fifo %s, because %s\n", 860443c15812032991c98b33b5424b17bcd55fe3575plougher pathname, strerror(errno)); 861443c15812032991c98b33b5424b17bcd55fe3575plougher break; 862443c15812032991c98b33b5424b17bcd55fe3575plougher } 8636f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher set_attributes(pathname, i->mode, i->uid, i->gid, i->time, TRUE); 864443c15812032991c98b33b5424b17bcd55fe3575plougher fifo_count ++; 865443c15812032991c98b33b5424b17bcd55fe3575plougher break; 866443c15812032991c98b33b5424b17bcd55fe3575plougher case SQUASHFS_SOCKET_TYPE: 867443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("create_inode: socket\n"); 868443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("create_inode: socket %s ignored\n", pathname); 869443c15812032991c98b33b5424b17bcd55fe3575plougher break; 870443c15812032991c98b33b5424b17bcd55fe3575plougher default: 8716f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher ERROR("Unknown inode type %d in create_inode_table!\n", i->type); 872443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 873443c15812032991c98b33b5424b17bcd55fe3575plougher } 874fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 8756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher created_inode[i->inode_number - 1] = strdup(pathname); 876443c15812032991c98b33b5424b17bcd55fe3575plougher 877443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 878443c15812032991c98b33b5424b17bcd55fe3575plougher} 879443c15812032991c98b33b5424b17bcd55fe3575plougher 880443c15812032991c98b33b5424b17bcd55fe3575plougher 88102bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_directory_table(long long start, long long end) 882443c15812032991c98b33b5424b17bcd55fe3575plougher{ 883443c15812032991c98b33b5424b17bcd55fe3575plougher int bytes = 0, size = 0, res; 884443c15812032991c98b33b5424b17bcd55fe3575plougher 885443c15812032991c98b33b5424b17bcd55fe3575plougher while(start < end) { 8869dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table = 8879dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher realloc(directory_table, size += 8889dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher SQUASHFS_METADATA_SIZE)) == NULL) 889443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n"); 890443c15812032991c98b33b5424b17bcd55fe3575plougher TRACE("uncompress_directory_table: reading block 0x%llx\n", start); 891443c15812032991c98b33b5424b17bcd55fe3575plougher add_entry(directory_table_hash, start, bytes); 89202bc3bcabf2b219f63961f07293b83629948f026plougher if((res = read_block(start, &start, directory_table + bytes)) == 0) 893443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n"); 894443c15812032991c98b33b5424b17bcd55fe3575plougher bytes += res; 895443c15812032991c98b33b5424b17bcd55fe3575plougher } 896443c15812032991c98b33b5424b17bcd55fe3575plougher} 897443c15812032991c98b33b5424b17bcd55fe3575plougher 898443c15812032991c98b33b5424b17bcd55fe3575plougher 8999dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, 9009dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherunsigned int *offset, unsigned int *type) 901443c15812032991c98b33b5424b17bcd55fe3575plougher{ 902443c15812032991c98b33b5424b17bcd55fe3575plougher if(dir->cur_entry == dir->dir_count) 903443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 904443c15812032991c98b33b5424b17bcd55fe3575plougher 905443c15812032991c98b33b5424b17bcd55fe3575plougher *name = dir->dirs[dir->cur_entry].name; 906443c15812032991c98b33b5424b17bcd55fe3575plougher *start_block = dir->dirs[dir->cur_entry].start_block; 907443c15812032991c98b33b5424b17bcd55fe3575plougher *offset = dir->dirs[dir->cur_entry].offset; 908443c15812032991c98b33b5424b17bcd55fe3575plougher *type = dir->dirs[dir->cur_entry].type; 909443c15812032991c98b33b5424b17bcd55fe3575plougher dir->cur_entry ++; 910443c15812032991c98b33b5424b17bcd55fe3575plougher 911443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 912443c15812032991c98b33b5424b17bcd55fe3575plougher} 913443c15812032991c98b33b5424b17bcd55fe3575plougher 914443c15812032991c98b33b5424b17bcd55fe3575plougher 915443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir) 916443c15812032991c98b33b5424b17bcd55fe3575plougher{ 917443c15812032991c98b33b5424b17bcd55fe3575plougher free(dir->dirs); 918443c15812032991c98b33b5424b17bcd55fe3575plougher free(dir); 919443c15812032991c98b33b5424b17bcd55fe3575plougher} 920443c15812032991c98b33b5424b17bcd55fe3575plougher 921443c15812032991c98b33b5424b17bcd55fe3575plougher 922b54566f5c433764830c29c83151691d0034de094plougherchar *get_component(char *target, char *targname) 923b54566f5c433764830c29c83151691d0034de094plougher{ 924b54566f5c433764830c29c83151691d0034de094plougher while(*target == '/') 9253cef656655723444fb1e2de1a001e6c2a54cf81erlougher target ++; 926b54566f5c433764830c29c83151691d0034de094plougher 927b54566f5c433764830c29c83151691d0034de094plougher while(*target != '/' && *target!= '\0') 928b54566f5c433764830c29c83151691d0034de094plougher *targname ++ = *target ++; 929b54566f5c433764830c29c83151691d0034de094plougher 930b54566f5c433764830c29c83151691d0034de094plougher *targname = '\0'; 931b54566f5c433764830c29c83151691d0034de094plougher 932b54566f5c433764830c29c83151691d0034de094plougher return target; 933b54566f5c433764830c29c83151691d0034de094plougher} 934b54566f5c433764830c29c83151691d0034de094plougher 935b54566f5c433764830c29c83151691d0034de094plougher 9366ee88c6b5da9f7b3ea88ab7481db126efa01c8f4ploughervoid free_path(struct pathname *paths) 9376ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher{ 9386ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher int i; 9396ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher 9406ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher for(i = 0; i < paths->names; i++) { 9416ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher if(paths->name[i].paths) 9426ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher free_path(paths->name[i].paths); 9436ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher free(paths->name[i].name); 9446ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher if(paths->name[i].preg) { 9456ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher regfree(paths->name[i].preg); 9466ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher free(paths->name[i].preg); 9476ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher } 9486ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher } 9496ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher 9506ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher free(paths); 9516ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher} 9526ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher 9536ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher 9544dba330d7b952f2f044d38e342e2ae3ea78910d6plougherstruct pathname *add_path(struct pathname *paths, char *target, char *alltarget) 955b54566f5c433764830c29c83151691d0034de094plougher{ 95671add234b27054974d5e29f95b3fab3072792a62plougher char targname[1024]; 9574dba330d7b952f2f044d38e342e2ae3ea78910d6plougher int i, error; 95871add234b27054974d5e29f95b3fab3072792a62plougher 95971add234b27054974d5e29f95b3fab3072792a62plougher target = get_component(target, targname); 96071add234b27054974d5e29f95b3fab3072792a62plougher 96171add234b27054974d5e29f95b3fab3072792a62plougher if(paths == NULL) { 9624dba330d7b952f2f044d38e342e2ae3ea78910d6plougher if((paths = malloc(sizeof(struct pathname))) == NULL) 9634dba330d7b952f2f044d38e342e2ae3ea78910d6plougher EXIT_UNSQUASH("failed to allocate paths\n"); 9644dba330d7b952f2f044d38e342e2ae3ea78910d6plougher 96571add234b27054974d5e29f95b3fab3072792a62plougher paths->names = 0; 96671add234b27054974d5e29f95b3fab3072792a62plougher paths->name = NULL; 96771add234b27054974d5e29f95b3fab3072792a62plougher } 96871add234b27054974d5e29f95b3fab3072792a62plougher 96971add234b27054974d5e29f95b3fab3072792a62plougher for(i = 0; i < paths->names; i++) 97071add234b27054974d5e29f95b3fab3072792a62plougher if(strcmp(paths->name[i].name, targname) == 0) 97171add234b27054974d5e29f95b3fab3072792a62plougher break; 97271add234b27054974d5e29f95b3fab3072792a62plougher 9736ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher if(i == paths->names) { 9746ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher /* allocate new name entry */ 97571add234b27054974d5e29f95b3fab3072792a62plougher paths->names ++; 97671add234b27054974d5e29f95b3fab3072792a62plougher paths->name = realloc(paths->name, (i + 1) * sizeof(struct path_entry)); 97771add234b27054974d5e29f95b3fab3072792a62plougher paths->name[i].name = strdup(targname); 9786ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher paths->name[i].paths = NULL; 9794dba330d7b952f2f044d38e342e2ae3ea78910d6plougher if(use_regex) { 9804dba330d7b952f2f044d38e342e2ae3ea78910d6plougher paths->name[i].preg = malloc(sizeof(regex_t)); 981545404219cdd79c1e06ac7d0698d02a15240c4c3plougher error = regcomp(paths->name[i].preg, targname, REG_EXTENDED|REG_NOSUB); 982545404219cdd79c1e06ac7d0698d02a15240c4c3plougher if(error) { 9834dba330d7b952f2f044d38e342e2ae3ea78910d6plougher char str[1024]; 9844dba330d7b952f2f044d38e342e2ae3ea78910d6plougher 9854dba330d7b952f2f044d38e342e2ae3ea78910d6plougher regerror(error, paths->name[i].preg, str, 1024); 9864dba330d7b952f2f044d38e342e2ae3ea78910d6plougher EXIT_UNSQUASH("invalid regex %s in export %s, because %s\n", targname, alltarget, str); 9874dba330d7b952f2f044d38e342e2ae3ea78910d6plougher } 9884dba330d7b952f2f044d38e342e2ae3ea78910d6plougher } else 9894dba330d7b952f2f044d38e342e2ae3ea78910d6plougher paths->name[i].preg = NULL; 9906ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher 9916ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher if(target[0] == '\0') 9926ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher /* at leaf pathname component */ 99371add234b27054974d5e29f95b3fab3072792a62plougher paths->name[i].paths = NULL; 99471add234b27054974d5e29f95b3fab3072792a62plougher else 9956ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher /* recurse adding child components */ 9964dba330d7b952f2f044d38e342e2ae3ea78910d6plougher paths->name[i].paths = add_path(NULL, target, alltarget); 9976ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher } else { 9986ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher /* existing matching entry */ 9996ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher if(paths->name[i].paths == NULL) { 10006ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher /* No sub-directory which means this is the leaf component of a 10016ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher pre-existing extract which subsumes the extract currently 10026ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher being added, in which case stop adding components */ 10036ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher } else if(target[0] == '\0') { 10046ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher /* at leaf pathname component and child components exist from more 10056ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher specific extracts, delete as they're subsumed by this extract 10066ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher */ 10076ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher free_path(paths->name[i].paths); 10086ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher paths->name[i].paths = NULL; 10096ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher } else 10106ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher /* recurse adding child components */ 10116ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher add_path(paths->name[i].paths, target, alltarget); 101271add234b27054974d5e29f95b3fab3072792a62plougher } 101371add234b27054974d5e29f95b3fab3072792a62plougher 101471add234b27054974d5e29f95b3fab3072792a62plougher return paths; 101571add234b27054974d5e29f95b3fab3072792a62plougher} 10166ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher 10176ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher 1018a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *init_subdir() 101971add234b27054974d5e29f95b3fab3072792a62plougher{ 10208372232d2460411adaa2299c32a0a88665e44902plougher struct pathnames *new = malloc(sizeof(struct pathnames)); 1021a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher new->count = 0; 1022a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher return new; 1023a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher} 1024a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1025a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1026a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *add_subdir(struct pathnames *paths, struct pathname *path) 1027a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{ 1028a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher if(paths->count % PATHS_ALLOC_SIZE == 0) 1029a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher paths = realloc(paths, sizeof(struct pathnames *) + (paths->count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *)); 1030a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1031a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher paths->path[paths->count++] = path; 1032a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher return paths; 1033a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher} 1034a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1035a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1036a706f1b6bb48f288ecaf74e218ce20504bda52c6ploughervoid free_subdir(struct pathnames *paths) 1037a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{ 1038a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher free(paths); 1039a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher} 1040a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1041a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1042a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint matches(struct pathnames *paths, char *name, struct pathnames **new) 1043a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{ 1044a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher int i, n; 104571add234b27054974d5e29f95b3fab3072792a62plougher 104671add234b27054974d5e29f95b3fab3072792a62plougher if(paths == NULL) { 104771add234b27054974d5e29f95b3fab3072792a62plougher *new = NULL; 1048b54566f5c433764830c29c83151691d0034de094plougher return TRUE; 104971add234b27054974d5e29f95b3fab3072792a62plougher } 105071add234b27054974d5e29f95b3fab3072792a62plougher 1051a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher *new = init_subdir(); 1052a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1053a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher for(n = 0; n < paths->count; n++) { 1054a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher struct pathname *path = paths->path[n]; 1055a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher for(i = 0; i < path->names; i++) { 1056a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher int match = use_regex ? 1057a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher regexec(path->name[i].preg, name, (size_t) 0, NULL, 0) == 0 : 1058a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher fnmatch(path->name[i].name, name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0; 1059a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher if(match && path->name[i].paths == NULL) 1060a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher /* match on a leaf component, any subdirectories will 1061a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher * implicitly match, therefore return an empty new search set */ 1062a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher goto empty_set; 1063a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1064a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher if(match) 1065a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher /* match on a non-leaf component, add any subdirectories to 1066a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher * the new set of subdirectories to scan for this name */ 1067a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher *new = add_subdir(*new, path->name[i].paths); 1068a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher } 1069a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher } 1070b54566f5c433764830c29c83151691d0034de094plougher 1071a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher if((*new)->count == 0) { 1072a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher /* no matching names found, delete empty search set, and return 1073a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher * FALSE */ 1074a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher free_subdir(*new); 1075a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher *new = NULL; 1076a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher return FALSE; 1077a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher } 1078a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1079a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher /* one or more matches with sub-directories found (no leaf matches), 1080a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher * return new search set and return TRUE */ 1081a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher return TRUE; 1082a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1083a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherempty_set: 1084a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher /* found matching leaf exclude, return empty search set and return TRUE */ 1085a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher free_subdir(*new); 1086a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher *new = NULL; 1087a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher return TRUE; 1088b54566f5c433764830c29c83151691d0034de094plougher} 1089b54566f5c433764830c29c83151691d0034de094plougher 1090b54566f5c433764830c29c83151691d0034de094plougher 1091eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint pre_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths) 1092eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{ 1093eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher unsigned int type; 1094eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher char *name, pathname[1024]; 1095eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct pathnames *new; 1096eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct inode *i; 1097eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i); 1098eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1099eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(dir == NULL) { 1100eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher ERROR("pre_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset); 1101eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher return FALSE; 1102eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1103eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1104eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) { 1105eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct inode *i; 1106eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1107eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type); 1108eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1109eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(!matches(paths, name, &new)) 1110eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher continue; 1111eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1112eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher strcat(strcat(strcpy(pathname, parent_name), "/"), name); 1113eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1114eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(type == SQUASHFS_DIR_TYPE) 1115eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher pre_scan(parent_name, start_block, offset, new); 1116eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher else if(new == NULL) { 1117eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(type == SQUASHFS_FILE_TYPE || type == SQUASHFS_LREG_TYPE) { 1118eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if((i = s_ops.read_inode(start_block, offset)) == NULL) { 1119eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher ERROR("failed to read header\n"); 1120eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher continue; 1121eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1122eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(created_inode[i->inode_number - 1] == NULL) { 1123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher created_inode[i->inode_number - 1] = (char *) i; 1124eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher total_blocks += (i->data + (block_size - 1)) >> block_log; 1125eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1126eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher total_files ++; 1127eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1128eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher total_inodes ++; 1129eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1130eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1131eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher free_subdir(new); 1132eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1133eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1134eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher squashfs_closedir(dir); 1135eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1136eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher return TRUE; 1137eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher} 1138eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1139eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1140a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths) 1141443c15812032991c98b33b5424b17bcd55fe3575plougher{ 1142443c15812032991c98b33b5424b17bcd55fe3575plougher unsigned int type; 1143443c15812032991c98b33b5424b17bcd55fe3575plougher char *name, pathname[1024]; 1144a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher struct pathnames *new; 1145eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct inode *i; 1146eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i); 1147443c15812032991c98b33b5424b17bcd55fe3575plougher 1148443c15812032991c98b33b5424b17bcd55fe3575plougher if(dir == NULL) { 1149fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset); 1150443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 1151443c15812032991c98b33b5424b17bcd55fe3575plougher } 1152443c15812032991c98b33b5424b17bcd55fe3575plougher 1153eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(lsonly || info) 1154eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher print_filename(parent_name, i); 1155eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1156a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1 && (!force || errno != EEXIST)) { 1157443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno)); 1158443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 1159443c15812032991c98b33b5424b17bcd55fe3575plougher } 1160443c15812032991c98b33b5424b17bcd55fe3575plougher 1161443c15812032991c98b33b5424b17bcd55fe3575plougher while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) { 11626f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type); 1163b54566f5c433764830c29c83151691d0034de094plougher 116471add234b27054974d5e29f95b3fab3072792a62plougher 116571add234b27054974d5e29f95b3fab3072792a62plougher if(!matches(paths, name, &new)) 1166b54566f5c433764830c29c83151691d0034de094plougher continue; 1167b54566f5c433764830c29c83151691d0034de094plougher 1168443c15812032991c98b33b5424b17bcd55fe3575plougher strcat(strcat(strcpy(pathname, parent_name), "/"), name); 1169fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher 1170443c15812032991c98b33b5424b17bcd55fe3575plougher if(type == SQUASHFS_DIR_TYPE) 117171add234b27054974d5e29f95b3fab3072792a62plougher dir_scan(pathname, start_block, offset, new); 1172a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher else if(new == NULL) { 11736f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if((i = s_ops.read_inode(start_block, offset)) == NULL) { 11746f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher ERROR("failed to read header\n"); 11756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher continue; 11766f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher } 11776f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher 11786f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher if(lsonly || info) 11796f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher print_filename(pathname, i); 11806f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher 1181eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(!lsonly) { 11826f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher create_inode(pathname, i); 1183eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher update_progress_bar(); 1184eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1185427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher 1186427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher if(i->type == SQUASHFS_SYMLINK_TYPE || i->type == SQUASHFS_LSYMLINK_TYPE) 1187427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher free(i->symlink); 11886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher } 1189a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1190a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher free_subdir(new); 1191443c15812032991c98b33b5424b17bcd55fe3575plougher } 1192443c15812032991c98b33b5424b17bcd55fe3575plougher 1193074d3f1129eae914655f6637773488052bf22327rlougher if(!lsonly) 1194074d3f1129eae914655f6637773488052bf22327rlougher set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, force); 1195443c15812032991c98b33b5424b17bcd55fe3575plougher 1196443c15812032991c98b33b5424b17bcd55fe3575plougher squashfs_closedir(dir); 1197443c15812032991c98b33b5424b17bcd55fe3575plougher dir_count ++; 1198443c15812032991c98b33b5424b17bcd55fe3575plougher 1199443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 1200443c15812032991c98b33b5424b17bcd55fe3575plougher} 1201443c15812032991c98b33b5424b17bcd55fe3575plougher 1202443c15812032991c98b33b5424b17bcd55fe3575plougher 1203b624936abba03d38b7e9245c647339d8f6f34274ploughervoid squashfs_stat(char *source) 1204b624936abba03d38b7e9245c647339d8f6f34274plougher{ 1205b624936abba03d38b7e9245c647339d8f6f34274plougher time_t mkfs_time = (time_t) sBlk.mkfs_time; 1206b624936abba03d38b7e9245c647339d8f6f34274plougher char *mkfs_str = ctime(&mkfs_time); 1207b624936abba03d38b7e9245c647339d8f6f34274plougher 1208b624936abba03d38b7e9245c647339d8f6f34274plougher#if __BYTE_ORDER == __BIG_ENDIAN 12090f74340e3b68533339adc60f418ddf59fa188f61plougher printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", sBlk.s_major == 4 ? "" : swap ? "little endian " : "big endian ", sBlk.s_major, sBlk.s_minor, source); 1210b624936abba03d38b7e9245c647339d8f6f34274plougher#else 12110f74340e3b68533339adc60f418ddf59fa188f61plougher printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", sBlk.s_major == 4 ? "" : swap ? "big endian " : "little endian ", sBlk.s_major, sBlk.s_minor, source); 1212b624936abba03d38b7e9245c647339d8f6f34274plougher#endif 1213b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Creation or last append time %s", mkfs_str ? mkfs_str : "failed to get time\n"); 1214b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Filesystem is %sexportable via NFS\n", SQUASHFS_EXPORTABLE(sBlk.flags) ? "" : "not "); 1215b624936abba03d38b7e9245c647339d8f6f34274plougher 1216b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags) ? "un" : ""); 1217b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags) ? "un" : ""); 1218b624936abba03d38b7e9245c647339d8f6f34274plougher if(sBlk.s_major > 1 && !SQUASHFS_NO_FRAGMENTS(sBlk.flags)) 1219b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Fragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags) ? "un" : ""); 1220b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Check data is %spresent in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk.flags) ? "" : "not "); 1221b624936abba03d38b7e9245c647339d8f6f34274plougher if(sBlk.s_major > 1) { 1222b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Fragments are %spresent in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk.flags) ? "not " : ""); 1223b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Always_use_fragments option is %sspecified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags) ? "" : "not "); 1224b624936abba03d38b7e9245c647339d8f6f34274plougher } else 1225b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Fragments are not supported by the filesystem\n"); 1226b624936abba03d38b7e9245c647339d8f6f34274plougher 12270337de3977eec74e6a3d28e0d0863299246de8b7plougher if(sBlk.s_major > 1) 12280337de3977eec74e6a3d28e0d0863299246de8b7plougher printf("Duplicates are %sremoved\n", SQUASHFS_DUPLICATES(sBlk.flags) ? "" : "not "); 12290337de3977eec74e6a3d28e0d0863299246de8b7plougher else 12300337de3977eec74e6a3d28e0d0863299246de8b7plougher printf("Duplicates are removed\n"); 1231b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk.bytes_used / 1024.0, sBlk.bytes_used / (1024.0 * 1024.0)); 1232b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Block size %d\n", sBlk.block_size); 1233b624936abba03d38b7e9245c647339d8f6f34274plougher if(sBlk.s_major > 1) 1234b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Number of fragments %d\n", sBlk.fragments); 1235b624936abba03d38b7e9245c647339d8f6f34274plougher printf("Number of inodes %d\n", sBlk.inodes); 12360f74340e3b68533339adc60f418ddf59fa188f61plougher if(sBlk.s_major == 4) 12370f74340e3b68533339adc60f418ddf59fa188f61plougher printf("Number of ids %d\n", sBlk.no_ids); 12380f74340e3b68533339adc60f418ddf59fa188f61plougher else { 12390f74340e3b68533339adc60f418ddf59fa188f61plougher printf("Number of uids %d\n", sBlk.no_uids); 12400f74340e3b68533339adc60f418ddf59fa188f61plougher printf("Number of gids %d\n", sBlk.no_guids); 12410f74340e3b68533339adc60f418ddf59fa188f61plougher } 1242b624936abba03d38b7e9245c647339d8f6f34274plougher 1243b624936abba03d38b7e9245c647339d8f6f34274plougher TRACE("sBlk.inode_table_start 0x%llx\n", sBlk.inode_table_start); 1244b624936abba03d38b7e9245c647339d8f6f34274plougher TRACE("sBlk.directory_table_start 0x%llx\n", sBlk.directory_table_start); 12450f74340e3b68533339adc60f418ddf59fa188f61plougher if(sBlk.s_major == 4) 12460f74340e3b68533339adc60f418ddf59fa188f61plougher TRACE("sBlk.id_table_start 0x%llx\n", sBlk.id_table_start); 12470f74340e3b68533339adc60f418ddf59fa188f61plougher else { 12480f74340e3b68533339adc60f418ddf59fa188f61plougher TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start); 12490f74340e3b68533339adc60f418ddf59fa188f61plougher TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start); 12500f74340e3b68533339adc60f418ddf59fa188f61plougher } 1251b624936abba03d38b7e9245c647339d8f6f34274plougher if(sBlk.s_major > 1) 1252b624936abba03d38b7e9245c647339d8f6f34274plougher TRACE("sBlk.fragment_table_start 0x%llx\n\n", sBlk.fragment_table_start); 1253b624936abba03d38b7e9245c647339d8f6f34274plougher} 1254b624936abba03d38b7e9245c647339d8f6f34274plougher 1255b624936abba03d38b7e9245c647339d8f6f34274plougher 125602bc3bcabf2b219f63961f07293b83629948f026plougherint read_super(char *source) 1257443c15812032991c98b33b5424b17bcd55fe3575plougher{ 12586490378e5b5e8dc058daf28423a7465699a6ba7bplougher squashfs_super_block_3 sBlk_3; 12596490378e5b5e8dc058daf28423a7465699a6ba7bplougher squashfs_super_block sBlk_4; 12606490378e5b5e8dc058daf28423a7465699a6ba7bplougher 12616490378e5b5e8dc058daf28423a7465699a6ba7bplougher /* 12626490378e5b5e8dc058daf28423a7465699a6ba7bplougher * Try to read a Squashfs 4 superblock 12636490378e5b5e8dc058daf28423a7465699a6ba7bplougher */ 12646490378e5b5e8dc058daf28423a7465699a6ba7bplougher read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk_4); 126554660e177ba40ab08ee2f3304b9f030eb5675677plougher swap = sBlk_4.s_magic != SQUASHFS_MAGIC; 12666490378e5b5e8dc058daf28423a7465699a6ba7bplougher SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4); 12676490378e5b5e8dc058daf28423a7465699a6ba7bplougher 126833277b81b13643bb3b89a710d6612c182f36d1a6plougher if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 && sBlk_4.s_minor == 0) { 12696490378e5b5e8dc058daf28423a7465699a6ba7bplougher s_ops.squashfs_opendir = squashfs_opendir_4; 12706490378e5b5e8dc058daf28423a7465699a6ba7bplougher s_ops.read_fragment = read_fragment_4; 12716490378e5b5e8dc058daf28423a7465699a6ba7bplougher s_ops.read_fragment_table = read_fragment_table_4; 12726490378e5b5e8dc058daf28423a7465699a6ba7bplougher s_ops.read_block_list = read_block_list_2; 12736490378e5b5e8dc058daf28423a7465699a6ba7bplougher s_ops.read_inode = read_inode_4; 12746490378e5b5e8dc058daf28423a7465699a6ba7bplougher s_ops.read_uids_guids = read_uids_guids_4; 12756490378e5b5e8dc058daf28423a7465699a6ba7bplougher memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4)); 12766490378e5b5e8dc058daf28423a7465699a6ba7bplougher return TRUE; 12776490378e5b5e8dc058daf28423a7465699a6ba7bplougher } 12786490378e5b5e8dc058daf28423a7465699a6ba7bplougher 12796490378e5b5e8dc058daf28423a7465699a6ba7bplougher /* 12806490378e5b5e8dc058daf28423a7465699a6ba7bplougher * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock 12816490378e5b5e8dc058daf28423a7465699a6ba7bplougher * (compatible with 1 and 2 filesystems) 12826490378e5b5e8dc058daf28423a7465699a6ba7bplougher */ 12836490378e5b5e8dc058daf28423a7465699a6ba7bplougher read_bytes(SQUASHFS_START, sizeof(squashfs_super_block_3), (char *) &sBlk_3); 1284443c15812032991c98b33b5424b17bcd55fe3575plougher 1285443c15812032991c98b33b5424b17bcd55fe3575plougher /* Check it is a SQUASHFS superblock */ 1286443c15812032991c98b33b5424b17bcd55fe3575plougher swap = 0; 128721ee4773956342a8a7d0f14e430ae77ffbd10601plougher if(sBlk_3.s_magic != SQUASHFS_MAGIC) { 128821ee4773956342a8a7d0f14e430ae77ffbd10601plougher if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) { 12897a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher squashfs_super_block_3 sblk; 1290443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source); 12916490378e5b5e8dc058daf28423a7465699a6ba7bplougher SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3); 12926490378e5b5e8dc058daf28423a7465699a6ba7bplougher memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3)); 1293443c15812032991c98b33b5424b17bcd55fe3575plougher swap = 1; 1294443c15812032991c98b33b5424b17bcd55fe3575plougher } else { 1295443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Can't find a SQUASHFS superblock on %s\n", source); 1296443c15812032991c98b33b5424b17bcd55fe3575plougher goto failed_mount; 1297443c15812032991c98b33b5424b17bcd55fe3575plougher } 1298443c15812032991c98b33b5424b17bcd55fe3575plougher } 1299443c15812032991c98b33b5424b17bcd55fe3575plougher 13006490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.s_magic = sBlk_3.s_magic; 13016490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.inodes = sBlk_3.inodes; 13026490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.mkfs_time = sBlk_3.mkfs_time; 13036490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.block_size = sBlk_3.block_size; 13046490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.fragments = sBlk_3.fragments; 13056490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.block_log = sBlk_3.block_log; 13066490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.flags = sBlk_3.flags; 13076490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.s_major = sBlk_3.s_major; 13086490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.s_minor = sBlk_3.s_minor; 13096490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.root_inode = sBlk_3.root_inode; 13106490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.bytes_used = sBlk_3.bytes_used; 13116490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.inode_table_start = sBlk_3.inode_table_start; 13126490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.directory_table_start = sBlk_3.directory_table_start; 13136490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.fragment_table_start = sBlk_3.fragment_table_start; 13146490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.lookup_table_start = sBlk_3.lookup_table_start; 13156490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.no_uids = sBlk_3.no_uids; 13166490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.no_guids = sBlk_3.no_guids; 13176490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.uid_start = sBlk_3.uid_start; 13186490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.guid_start = sBlk_3.guid_start; 13196490378e5b5e8dc058daf28423a7465699a6ba7bplougher 1320443c15812032991c98b33b5424b17bcd55fe3575plougher /* Check the MAJOR & MINOR versions */ 1321ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher if(sBlk.s_major == 1 || sBlk.s_major == 2) { 13226490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.bytes_used = sBlk_3.bytes_used_2; 13236490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.uid_start = sBlk_3.uid_start_2; 13246490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.guid_start = sBlk_3.guid_start_2; 13256490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.inode_table_start = sBlk_3.inode_table_start_2; 13266490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.directory_table_start = sBlk_3.directory_table_start_2; 132702bc3bcabf2b219f63961f07293b83629948f026plougher 1328ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher if(sBlk.s_major == 1) { 13296490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.block_size = sBlk_3.block_size_1; 13305ff400bfbae6bb397cf3110190e83a29725fcd07plougher sBlk.fragment_table_start = sBlk.uid_start; 1331ed5124f016834932db2c63d60d259d846171c216plougher s_ops.squashfs_opendir = squashfs_opendir_1; 1332ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher s_ops.read_fragment_table = read_fragment_table_1; 1333ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher s_ops.read_block_list = read_block_list_1; 13346f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher s_ops.read_inode = read_inode_1; 133579e700efc62527661ce140bd1013a2b60577917eplougher s_ops.read_uids_guids = read_uids_guids_1; 1336ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher } else { 13376490378e5b5e8dc058daf28423a7465699a6ba7bplougher sBlk.fragment_table_start = sBlk_3.fragment_table_start_2; 1338ed5124f016834932db2c63d60d259d846171c216plougher s_ops.squashfs_opendir = squashfs_opendir_1; 1339ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher s_ops.read_fragment = read_fragment_2; 1340ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher s_ops.read_fragment_table = read_fragment_table_2; 1341ed5124f016834932db2c63d60d259d846171c216plougher s_ops.read_block_list = read_block_list_2; 13426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher s_ops.read_inode = read_inode_2; 134379e700efc62527661ce140bd1013a2b60577917eplougher s_ops.read_uids_guids = read_uids_guids_1; 1344ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher } 13454ce87501a1b07102cef9750060d9a53cd5b00a61plougher } else if(sBlk.s_major == 3) { 1346ed5124f016834932db2c63d60d259d846171c216plougher s_ops.squashfs_opendir = squashfs_opendir_3; 1347ed5124f016834932db2c63d60d259d846171c216plougher s_ops.read_fragment = read_fragment_3; 1348ed5124f016834932db2c63d60d259d846171c216plougher s_ops.read_fragment_table = read_fragment_table_3; 1349ed5124f016834932db2c63d60d259d846171c216plougher s_ops.read_block_list = read_block_list_2; 1350ed5124f016834932db2c63d60d259d846171c216plougher s_ops.read_inode = read_inode_3; 135179e700efc62527661ce140bd1013a2b60577917eplougher s_ops.read_uids_guids = read_uids_guids_1; 135202bc3bcabf2b219f63961f07293b83629948f026plougher } else { 13534c99cb7f458d8e1c598f1c80793daf3696c9b528plougher ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s_major, sBlk.s_minor); 13544c99cb7f458d8e1c598f1c80793daf3696c9b528plougher ERROR("which is a later filesystem version than I support!\n"); 1355443c15812032991c98b33b5424b17bcd55fe3575plougher goto failed_mount; 1356443c15812032991c98b33b5424b17bcd55fe3575plougher } 1357443c15812032991c98b33b5424b17bcd55fe3575plougher 1358443c15812032991c98b33b5424b17bcd55fe3575plougher return TRUE; 1359443c15812032991c98b33b5424b17bcd55fe3575plougher 1360443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount: 1361443c15812032991c98b33b5424b17bcd55fe3575plougher return FALSE; 1362443c15812032991c98b33b5424b17bcd55fe3575plougher} 1363443c15812032991c98b33b5424b17bcd55fe3575plougher 1364443c15812032991c98b33b5424b17bcd55fe3575plougher 1365a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathname *process_extract_files(struct pathname *path, char *filename) 136671add234b27054974d5e29f95b3fab3072792a62plougher{ 136771add234b27054974d5e29f95b3fab3072792a62plougher FILE *fd; 136871add234b27054974d5e29f95b3fab3072792a62plougher char name[16384]; 136971add234b27054974d5e29f95b3fab3072792a62plougher 13704dba330d7b952f2f044d38e342e2ae3ea78910d6plougher if((fd = fopen(filename, "r")) == NULL) 13714dba330d7b952f2f044d38e342e2ae3ea78910d6plougher EXIT_UNSQUASH("Could not open %s, because %s\n", filename, strerror(errno)); 137271add234b27054974d5e29f95b3fab3072792a62plougher 137371add234b27054974d5e29f95b3fab3072792a62plougher while(fscanf(fd, "%16384[^\n]\n", name) != EOF) 1374a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher path = add_path(path, name, name); 137571add234b27054974d5e29f95b3fab3072792a62plougher 137671add234b27054974d5e29f95b3fab3072792a62plougher fclose(fd); 1377a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher return path; 137871add234b27054974d5e29f95b3fab3072792a62plougher} 137971add234b27054974d5e29f95b3fab3072792a62plougher 138071add234b27054974d5e29f95b3fab3072792a62plougher 13818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* reader thread. This thread processes read requests queued by the 13828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * cache_get() routine. */ 13838888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *reader(void *arg) 13848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 13858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher while(1) { 13868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct cache_entry *entry = queue_get(to_reader); 13878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int res = read_bytes(entry->block, 13888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), 13898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher entry->data); 13908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 13918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size)) 13928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* queue successfully read block to the deflate thread(s) 13938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * for further processing */ 13948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_put(to_deflate, entry); 13958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher else 13968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* block has either been successfully read and is uncompressed, 13978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * or an error has occurred, clear pending flag, set 13988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * error appropriately, and wake up any threads waiting on 13998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * this buffer */ 14008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache_block_ready(entry, !res); 14018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 14038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* writer thread. This processes file write requests queued by the 14068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * write_file() routine. */ 14078888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *writer(void *arg) 14088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 14098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int i; 14108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher while(1) { 14128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct squashfs_file *file = queue_get(to_writer); 14138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int file_fd; 14148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int hole = 0; 141527636cb2cec37a68313f9eb825c0548245eecad0plougher int failed = FALSE; 1416c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher int error; 14178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(file == NULL) { 14198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_put(from_writer, NULL); 14208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher continue; 14218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher TRACE("writer: regular file, blocks %d\n", file->blocks); 14248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher file_fd = file->fd; 14268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1427eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher for(i = 0; i < file->blocks; i++, cur_blocks ++) { 14288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct file_entry *block = queue_get(to_writer); 14298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(block->buffer == 0) { /* sparse file */ 14318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher hole += block->size; 14328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher free(block); 14338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher continue; 14348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache_block_wait(block->buffer); 143727636cb2cec37a68313f9eb825c0548245eecad0plougher 143827636cb2cec37a68313f9eb825c0548245eecad0plougher if(block->buffer->error) 143927636cb2cec37a68313f9eb825c0548245eecad0plougher failed = TRUE; 144027636cb2cec37a68313f9eb825c0548245eecad0plougher 1441c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if(failed) 1442c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher continue; 1443c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher 1444c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher error = write_block(file_fd, block->buffer->data + 1445c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher block->offset, block->size, hole, file->sparse); 1446c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher 1447c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if(error == FALSE) { 14488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher ERROR("writer: failed to write data block %d\n", i); 144927636cb2cec37a68313f9eb825c0548245eecad0plougher failed = TRUE; 14508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 1451c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher 14528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher hole = 0; 14538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache_block_put(block->buffer); 14548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher free(block); 14558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 145727636cb2cec37a68313f9eb825c0548245eecad0plougher if(hole && failed == FALSE) { 14588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* corner case for hole extending to end of file */ 1459c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if(file->sparse == FALSE || lseek(file_fd, hole, SEEK_CUR) == -1) { 1460c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher /* for files which we don't want to write 1461c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher * sparsely, or for broken lseeks which cannot 1462c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher * seek beyond end of file, write_block will do 1463c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher * the right thing 1464c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher */ 14658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher hole --; 1466c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher if(write_block(file_fd, "\0", 1, hole, file->sparse) == FALSE) { 14678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher ERROR("writer: failed to write sparse data block\n"); 146827636cb2cec37a68313f9eb825c0548245eecad0plougher failed = TRUE; 14698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } else if(ftruncate(file_fd, file->file_size) == -1) { 14718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher ERROR("writer: failed to write sparse data block\n"); 147227636cb2cec37a68313f9eb825c0548245eecad0plougher failed = TRUE; 14738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher close(file_fd); 147727636cb2cec37a68313f9eb825c0548245eecad0plougher if(failed == FALSE) 147827636cb2cec37a68313f9eb825c0548245eecad0plougher set_attributes(file->pathname, file->mode, file->uid, file->gid, file->time, force); 147927636cb2cec37a68313f9eb825c0548245eecad0plougher else { 148027636cb2cec37a68313f9eb825c0548245eecad0plougher ERROR("Failed to write %s, skipping\n", file->pathname); 148127636cb2cec37a68313f9eb825c0548245eecad0plougher unlink(file->pathname); 148227636cb2cec37a68313f9eb825c0548245eecad0plougher } 148379df93becb68081effabebba3006c794be308598plougher free(file->pathname); 14848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher free(file); 148527636cb2cec37a68313f9eb825c0548245eecad0plougher 14868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 14878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 14888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* decompress thread. This decompresses buffers queued by the read thread */ 14918888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *deflator(void *arg) 14928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 14938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher char tmp[block_size]; 14948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 14958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher while(1) { 14968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher struct cache_entry *entry = queue_get(to_deflate); 14978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int res; 14988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher unsigned long bytes = block_size; 14998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher res = uncompress((unsigned char *) tmp, &bytes, (const unsigned char *) entry->data, SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size)); 15018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(res != Z_OK) { 15038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(res == Z_MEM_ERROR) 15048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher ERROR("zlib::uncompress failed, not enough memory\n"); 15058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher else if(res == Z_BUF_ERROR) 15068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher ERROR("zlib::uncompress failed, not enough room in output buffer\n"); 15078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher else 15088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher ERROR("zlib::uncompress failed, unknown error %d\n", res); 15098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } else 15108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher memcpy(entry->data, tmp, bytes); 15118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher /* block has been either successfully decompressed, or an error 15138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * occurred, clear pending flag, set error appropriately and 15148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * wake up any threads waiting on this block */ 15158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher cache_block_ready(entry, res != Z_OK); 15168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 15178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 15188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1520eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid *progress_thread(void *arg) 1521eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{ 1522eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct timeval timeval; 1523eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct timespec timespec; 15241b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher struct itimerval itimerval; 15251b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher struct winsize winsize; 15261b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher 15271b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher if(ioctl(1, TIOCGWINSZ, &winsize) == -1) { 15281b42101056befe25b5f19d5b099e806a2ecee9cdplougher ERROR("TIOCGWINZ ioctl failed, defaulting to 80 columns\n"); 15291b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher columns = 80; 15301b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher } else 15311b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher columns = winsize.ws_col; 15321b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher signal(SIGWINCH, sigwinch_handler); 15331b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher signal(SIGALRM, sigalrm_handler); 15341b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher 15351b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher itimerval.it_value.tv_sec = 0; 15361b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher itimerval.it_value.tv_usec = 250000; 15371b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher itimerval.it_interval.tv_sec = 0; 15381b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher itimerval.it_interval.tv_usec = 250000; 15391b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher setitimer(ITIMER_REAL, &itimerval, NULL); 1540eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1541eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher pthread_cond_init(&progress_wait, NULL); 1542eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 15431b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_lock(&screen_mutex); 1544eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher while(1) { 1545eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher gettimeofday(&timeval, NULL); 1546eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher timespec.tv_sec = timeval.tv_sec; 1547eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(timeval.tv_usec + 250000 > 999999) 1548eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher timespec.tv_sec++; 1549eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) * 1000; 15501b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_cond_timedwait(&progress_wait, &screen_mutex, ×pec); 15511b42101056befe25b5f19d5b099e806a2ecee9cdplougher if(progress_enabled) 15521b42101056befe25b5f19d5b099e806a2ecee9cdplougher progress_bar(sym_count + dev_count + 15531b42101056befe25b5f19d5b099e806a2ecee9cdplougher fifo_count + cur_blocks, total_inodes - total_files + 15541b42101056befe25b5f19d5b099e806a2ecee9cdplougher total_blocks, columns); 1555eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1556eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher} 1557eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1558eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 15598888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid initialise_threads(int fragment_buffer_size, int data_buffer_size) 15608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{ 15618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int i; 15628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher sigset_t sigmask, old_mask; 15638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int all_buffers_size = fragment_buffer_size + data_buffer_size; 15648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher sigemptyset(&sigmask); 15668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher sigaddset(&sigmask, SIGINT); 15678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher sigaddset(&sigmask, SIGQUIT); 15688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1) 15698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n"); 15708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(processors == -1) { 15728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifndef linux 15738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher int mib[2]; 15748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher size_t len = sizeof(processors); 15758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher mib[0] = CTL_HW; 15778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifdef HW_AVAILCPU 15788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher mib[1] = HW_AVAILCPU; 15798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else 15808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher mib[1] = HW_NCPU; 15818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif 15828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) { 15848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher ERROR("Failed to get number of available processors. Defaulting to 1\n"); 15858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher processors = 1; 15868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 15878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else 15888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher processors = get_nprocs(); 15898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif 15908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 15918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1592eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if((thread = malloc((3 + processors) * sizeof(pthread_t))) == NULL) 15938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("Out of memory allocating thread descriptors\n"); 1594eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher deflator_thread = &thread[3]; 15958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 15968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher to_reader = queue_init(all_buffers_size); 15978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher to_deflate = queue_init(all_buffers_size); 1598eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher to_writer = queue_init(1000); 15998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher from_writer = queue_init(1); 16008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher fragment_cache = cache_init(block_size, fragment_buffer_size); 16018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher data_cache = cache_init(block_size, data_buffer_size); 16028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_create(&thread[0], NULL, reader, NULL); 16038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_create(&thread[1], NULL, writer, NULL); 1604eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher pthread_create(&thread[2], NULL, progress_thread, NULL); 16058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher pthread_mutex_init(&fragment_mutex, NULL); 16068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 16078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher for(i = 0; i < processors; i++) { 16088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) != 0 ) 16098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("Failed to create thread\n"); 16108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher } 16118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 16128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher printf("Parallel unsquashfs: Using %d processor%s\n", processors, 16138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher processors == 1 ? "" : "s"); 16148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 16158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) 16168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n"); 16178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher} 16188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 16198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 16201b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid enable_progress_bar() 16211b42101056befe25b5f19d5b099e806a2ecee9cdplougher{ 16221b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_lock(&screen_mutex); 16231b42101056befe25b5f19d5b099e806a2ecee9cdplougher progress_enabled = TRUE; 16241b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_unlock(&screen_mutex); 16251b42101056befe25b5f19d5b099e806a2ecee9cdplougher} 16261b42101056befe25b5f19d5b099e806a2ecee9cdplougher 16271b42101056befe25b5f19d5b099e806a2ecee9cdplougher 16281b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid disable_progress_bar() 16291b42101056befe25b5f19d5b099e806a2ecee9cdplougher{ 16301b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_lock(&screen_mutex); 16311b42101056befe25b5f19d5b099e806a2ecee9cdplougher progress_enabled = FALSE; 16321b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_unlock(&screen_mutex); 16331b42101056befe25b5f19d5b099e806a2ecee9cdplougher} 16341b42101056befe25b5f19d5b099e806a2ecee9cdplougher 16351b42101056befe25b5f19d5b099e806a2ecee9cdplougher 1636eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar() 1637eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{ 16381b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_lock(&screen_mutex); 1639eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher pthread_cond_signal(&progress_wait); 16401b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_unlock(&screen_mutex); 1641eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher} 1642eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1643eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1644eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns) 1645eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{ 1646eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher char rotate_list[] = { '|', '/', '-', '\\' }; 164784ece5dece9234d3ec58f988690c02aa41b41eb0plougher int max_digits = floor(log10(max)) + 1; 1648eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher int used = max_digits * 2 + 11; 1649eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher int hashes = (current * (columns - used)) / max; 1650eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher int spaces = columns - used - hashes; 1651eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1652eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher if(current > max) { 1653eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher printf("%lld %lld\n", current, max); 1654eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher return; 1655eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher } 1656eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 16575c7885bc293ab675812fd77a05f59c2917e3e8b4plougher if(columns - used < 0) 1658eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher return; 1659eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1660eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher printf("\r["); 1661eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1662eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher while (hashes --) 1663eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher putchar('='); 1664eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1665eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher putchar(rotate_list[rotate]); 1666eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1667eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher while(spaces --) 1668eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher putchar(' '); 1669eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1670eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher printf("] %*lld/%*lld", max_digits, current, max_digits, max); 1671eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher printf(" %3lld%%", current * 100 / max); 1672eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher fflush(stdout); 1673eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher} 1674eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1675eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1676443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \ 1677c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher printf("unsquashfs version 4.0-CVS (2009/03/24)\n");\ 1678f6bc3209482f955de1d37bc8f877c6ec399736ecplougher printf("copyright (C) 2009 Phillip Lougher <phillip@lougher.demon.co.uk>\n\n"); \ 1679443c15812032991c98b33b5424b17bcd55fe3575plougher printf("This program is free software; you can redistribute it and/or\n");\ 1680443c15812032991c98b33b5424b17bcd55fe3575plougher printf("modify it under the terms of the GNU General Public License\n");\ 1681443c15812032991c98b33b5424b17bcd55fe3575plougher printf("as published by the Free Software Foundation; either version 2,\n");\ 1682443c15812032991c98b33b5424b17bcd55fe3575plougher printf("or (at your option) any later version.\n\n");\ 1683443c15812032991c98b33b5424b17bcd55fe3575plougher printf("This program is distributed in the hope that it will be useful,\n");\ 1684443c15812032991c98b33b5424b17bcd55fe3575plougher printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\ 1685443c15812032991c98b33b5424b17bcd55fe3575plougher printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");\ 1686443c15812032991c98b33b5424b17bcd55fe3575plougher printf("GNU General Public License for more details.\n"); 1687443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[]) 1688443c15812032991c98b33b5424b17bcd55fe3575plougher{ 1689443c15812032991c98b33b5424b17bcd55fe3575plougher char *dest = "squashfs-root"; 1690b624936abba03d38b7e9245c647339d8f6f34274plougher int i, stat_sys = FALSE, version = FALSE; 1691545404219cdd79c1e06ac7d0698d02a15240c4c3plougher int n; 1692a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher struct pathnames *paths = NULL; 1693a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher struct pathname *path = NULL; 1694ae271cc93e3684d5314bcdc45b631e497ae43166plougher int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT; 1695ae271cc93e3684d5314bcdc45b631e497ae43166plougher int data_buffer_size = DATA_BUFFER_DEFAULT; 16960cf5c297bec42c7c220d2825f12f9499f2293279plougher char *b; 1697eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher struct winsize winsize; 1698443c15812032991c98b33b5424b17bcd55fe3575plougher 16991b42101056befe25b5f19d5b099e806a2ecee9cdplougher pthread_mutex_init(&screen_mutex, NULL); 1700545404219cdd79c1e06ac7d0698d02a15240c4c3plougher root_process = geteuid() == 0; 1701545404219cdd79c1e06ac7d0698d02a15240c4c3plougher if(root_process) 17029dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher umask(0); 17039dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher 1704443c15812032991c98b33b5424b17bcd55fe3575plougher for(i = 1; i < argc; i++) { 1705443c15812032991c98b33b5424b17bcd55fe3575plougher if(*argv[i] != '-') 1706443c15812032991c98b33b5424b17bcd55fe3575plougher break; 1707a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher if(strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { 1708443c15812032991c98b33b5424b17bcd55fe3575plougher VERSION(); 1709443c15812032991c98b33b5424b17bcd55fe3575plougher version = TRUE; 1710a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher } else if(strcmp(argv[i], "-info") == 0 || strcmp(argv[i], "-i") == 0) 1711443c15812032991c98b33b5424b17bcd55fe3575plougher info = TRUE; 1712a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher else if(strcmp(argv[i], "-ls") == 0 || strcmp(argv[i], "-l") == 0) 1713443c15812032991c98b33b5424b17bcd55fe3575plougher lsonly = TRUE; 1714296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher else if(strcmp(argv[i], "-no-progress") == 0 || strcmp(argv[i], "-n") == 0) 1715296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher progress = FALSE; 1716a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher else if(strcmp(argv[i], "-dest") == 0 || strcmp(argv[i], "-d") == 0) { 171771add234b27054974d5e29f95b3fab3072792a62plougher if(++i == argc) { 171871add234b27054974d5e29f95b3fab3072792a62plougher fprintf(stderr, "%s: -dest missing filename\n", argv[0]); 171971add234b27054974d5e29f95b3fab3072792a62plougher exit(1); 172071add234b27054974d5e29f95b3fab3072792a62plougher } 1721443c15812032991c98b33b5424b17bcd55fe3575plougher dest = argv[i]; 17220cf5c297bec42c7c220d2825f12f9499f2293279plougher } else if(strcmp(argv[i], "-processors") == 0 || strcmp(argv[i], "-p") == 0) { 17230cf5c297bec42c7c220d2825f12f9499f2293279plougher if((++i == argc) || (processors = strtol(argv[i], &b, 10), *b != '\0')) { 17240cf5c297bec42c7c220d2825f12f9499f2293279plougher ERROR("%s: -processors missing or invalid processor number\n", argv[0]); 17250cf5c297bec42c7c220d2825f12f9499f2293279plougher exit(1); 17260cf5c297bec42c7c220d2825f12f9499f2293279plougher } 17270cf5c297bec42c7c220d2825f12f9499f2293279plougher if(processors < 1) { 17280cf5c297bec42c7c220d2825f12f9499f2293279plougher ERROR("%s: -processors should be 1 or larger\n", argv[0]); 17290cf5c297bec42c7c220d2825f12f9499f2293279plougher exit(1); 17300cf5c297bec42c7c220d2825f12f9499f2293279plougher } 1731ae271cc93e3684d5314bcdc45b631e497ae43166plougher } else if(strcmp(argv[i], "-data-queue") == 0 || strcmp(argv[i], "-da") == 0) { 1732ae271cc93e3684d5314bcdc45b631e497ae43166plougher if((++i == argc) || (data_buffer_size = strtol(argv[i], &b, 10), *b != '\0')) { 1733ae271cc93e3684d5314bcdc45b631e497ae43166plougher ERROR("%s: -data-queue missing or invalid queue size\n", argv[0]); 1734ae271cc93e3684d5314bcdc45b631e497ae43166plougher exit(1); 1735ae271cc93e3684d5314bcdc45b631e497ae43166plougher } 1736ae271cc93e3684d5314bcdc45b631e497ae43166plougher if(data_buffer_size < 1) { 1737ae271cc93e3684d5314bcdc45b631e497ae43166plougher ERROR("%s: -data-queue should be 1 Mbyte or larger\n", argv[0]); 1738ae271cc93e3684d5314bcdc45b631e497ae43166plougher exit(1); 1739ae271cc93e3684d5314bcdc45b631e497ae43166plougher } 1740ae271cc93e3684d5314bcdc45b631e497ae43166plougher } else if(strcmp(argv[i], "-frag-queue") == 0 || strcmp(argv[i], "-fr") == 0) { 1741ae271cc93e3684d5314bcdc45b631e497ae43166plougher if((++i == argc) || (fragment_buffer_size = strtol(argv[i], &b, 10), *b != '\0')) { 1742ae271cc93e3684d5314bcdc45b631e497ae43166plougher ERROR("%s: -frag-queue missing or invalid queue size\n", argv[0]); 1743ae271cc93e3684d5314bcdc45b631e497ae43166plougher exit(1); 1744ae271cc93e3684d5314bcdc45b631e497ae43166plougher } 1745ae271cc93e3684d5314bcdc45b631e497ae43166plougher if(fragment_buffer_size < 1) { 1746ae271cc93e3684d5314bcdc45b631e497ae43166plougher ERROR("%s: -frag-queue should be 1 Mbyte or larger\n", argv[0]); 1747ae271cc93e3684d5314bcdc45b631e497ae43166plougher exit(1); 1748ae271cc93e3684d5314bcdc45b631e497ae43166plougher } 1749a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher } else if(strcmp(argv[i], "-force") == 0 || strcmp(argv[i], "-f") == 0) 1750a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher force = TRUE; 1751b624936abba03d38b7e9245c647339d8f6f34274plougher else if(strcmp(argv[i], "-stat") == 0 || strcmp(argv[i], "-s") == 0) 1752b624936abba03d38b7e9245c647339d8f6f34274plougher stat_sys = TRUE; 17539baf35a00f38816d2054deb70184943d0686d03eplougher else if(strcmp(argv[i], "-lls") == 0 || strcmp(argv[i], "-ll") == 0) { 17549baf35a00f38816d2054deb70184943d0686d03eplougher lsonly = TRUE; 17559baf35a00f38816d2054deb70184943d0686d03eplougher short_ls = FALSE; 17563edfa57b6a463f7d441d995559143f4861d62e98plougher } else if(strcmp(argv[i], "-linfo") == 0 || strcmp(argv[i], "-li") == 0) { 17579baf35a00f38816d2054deb70184943d0686d03eplougher info = TRUE; 17589baf35a00f38816d2054deb70184943d0686d03eplougher short_ls = FALSE; 175971add234b27054974d5e29f95b3fab3072792a62plougher } else if(strcmp(argv[i], "-ef") == 0 || strcmp(argv[i], "-e") == 0) { 176071add234b27054974d5e29f95b3fab3072792a62plougher if(++i == argc) { 176171add234b27054974d5e29f95b3fab3072792a62plougher fprintf(stderr, "%s: -ef missing filename\n", argv[0]); 176271add234b27054974d5e29f95b3fab3072792a62plougher exit(1); 176371add234b27054974d5e29f95b3fab3072792a62plougher } 1764a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher path = process_extract_files(path, argv[i]); 17654dba330d7b952f2f044d38e342e2ae3ea78910d6plougher } else if(strcmp(argv[i], "-regex") == 0 || strcmp(argv[i], "-r") == 0) 17664dba330d7b952f2f044d38e342e2ae3ea78910d6plougher use_regex = TRUE; 17674dba330d7b952f2f044d38e342e2ae3ea78910d6plougher else 1768b624936abba03d38b7e9245c647339d8f6f34274plougher goto options; 1769443c15812032991c98b33b5424b17bcd55fe3575plougher } 1770443c15812032991c98b33b5424b17bcd55fe3575plougher 1771feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher if(lsonly || info) 1772feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher progress = FALSE; 1773feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher 1774443c15812032991c98b33b5424b17bcd55fe3575plougher if(i == argc) { 1775443c15812032991c98b33b5424b17bcd55fe3575plougher if(!version) { 1776443c15812032991c98b33b5424b17bcd55fe3575plougheroptions: 177771add234b27054974d5e29f95b3fab3072792a62plougher ERROR("SYNTAX: %s [options] filesystem [directories or files to extract]\n", argv[0]); 1778a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher ERROR("\t-v[ersion]\t\tprint version, licence and copyright information\n"); 17790cf5c297bec42c7c220d2825f12f9499f2293279plougher ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n"); 1780296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher ERROR("\t-n[o-progress]\t\tdon't display the progress bar\n"); 17810cf5c297bec42c7c220d2825f12f9499f2293279plougher ERROR("\t-p[rocessors] <number>\tuse <number> processors. By default will use\n\t\t\t\tnumber of processors available\n"); 1782a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher ERROR("\t-i[nfo]\t\t\tprint files as they are unsquashed\n"); 17839baf35a00f38816d2054deb70184943d0686d03eplougher ERROR("\t-li[nfo]\t\tprint files as they are unsquashed with file\n\t\t\t\tattributes (like ls -l output)\n"); 17849baf35a00f38816d2054deb70184943d0686d03eplougher ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash\n"); 17859baf35a00f38816d2054deb70184943d0686d03eplougher ERROR("\t-ll[s]\t\t\tlist filesystem with file attributes (like\n\t\t\t\tls -l output), but don't unsquash\n"); 1786a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher ERROR("\t-f[orce]\t\tif file already exists then overwrite\n"); 17870337de3977eec74e6a3d28e0d0863299246de8b7plougher ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock information\n"); 178871add234b27054974d5e29f95b3fab3072792a62plougher ERROR("\t-e[f] <extract file>\tlist of directories or files to extract.\n\t\t\t\tOne per line\n"); 1789ae271cc93e3684d5314bcdc45b631e497ae43166plougher ERROR("\t-da[ta-queue] <size>\tSet data queue to <size> Mbytes. Default %d\n\t\t\t\tMbytes\n", DATA_BUFFER_DEFAULT); 1790ae271cc93e3684d5314bcdc45b631e497ae43166plougher ERROR("\t-fr[ag-queue] <size>\tSet fagment queue to <size> Mbytes. Default %d\n\t\t\t\tMbytes\n", FRAGMENT_BUFFER_DEFAULT); 17914dba330d7b952f2f044d38e342e2ae3ea78910d6plougher ERROR("\t-r[egex]\t\ttreat extract names as POSIX regular expressions\n\t\t\t\trather than use the default shell wildcard\n\t\t\t\texpansion (globbing)\n"); 1792443c15812032991c98b33b5424b17bcd55fe3575plougher } 1793443c15812032991c98b33b5424b17bcd55fe3575plougher exit(1); 1794443c15812032991c98b33b5424b17bcd55fe3575plougher } 1795443c15812032991c98b33b5424b17bcd55fe3575plougher 179671add234b27054974d5e29f95b3fab3072792a62plougher for(n = i + 1; n < argc; n++) 1797a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher path = add_path(path, argv[n], argv[n]); 1798b54566f5c433764830c29c83151691d0034de094plougher 1799443c15812032991c98b33b5424b17bcd55fe3575plougher if((fd = open(argv[i], O_RDONLY)) == -1) { 1800443c15812032991c98b33b5424b17bcd55fe3575plougher ERROR("Could not open %s, because %s\n", argv[i], strerror(errno)); 1801443c15812032991c98b33b5424b17bcd55fe3575plougher exit(1); 1802443c15812032991c98b33b5424b17bcd55fe3575plougher } 1803443c15812032991c98b33b5424b17bcd55fe3575plougher 180402bc3bcabf2b219f63961f07293b83629948f026plougher if(read_super(argv[i]) == FALSE) 1805443c15812032991c98b33b5424b17bcd55fe3575plougher exit(1); 1806443c15812032991c98b33b5424b17bcd55fe3575plougher 1807b624936abba03d38b7e9245c647339d8f6f34274plougher if(stat_sys) { 1808b624936abba03d38b7e9245c647339d8f6f34274plougher squashfs_stat(argv[i]); 1809b624936abba03d38b7e9245c647339d8f6f34274plougher exit(0); 1810b624936abba03d38b7e9245c647339d8f6f34274plougher } 1811b624936abba03d38b7e9245c647339d8f6f34274plougher 1812443c15812032991c98b33b5424b17bcd55fe3575plougher block_size = sBlk.block_size; 1813ae271cc93e3684d5314bcdc45b631e497ae43166plougher block_log = sBlk.block_log; 1814ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher 1815ae271cc93e3684d5314bcdc45b631e497ae43166plougher fragment_buffer_size <<= 20 - block_log; 1816ae271cc93e3684d5314bcdc45b631e497ae43166plougher data_buffer_size <<= 20 - block_log; 18178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher initialise_threads(fragment_buffer_size, data_buffer_size); 18188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 1819443c15812032991c98b33b5424b17bcd55fe3575plougher if((fragment_data = malloc(block_size)) == NULL) 1820443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("failed to allocate fragment_data\n"); 1821443c15812032991c98b33b5424b17bcd55fe3575plougher 1822443c15812032991c98b33b5424b17bcd55fe3575plougher if((file_data = malloc(block_size)) == NULL) 1823443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("failed to allocate file_data"); 1824443c15812032991c98b33b5424b17bcd55fe3575plougher 1825443c15812032991c98b33b5424b17bcd55fe3575plougher if((data = malloc(block_size)) == NULL) 1826eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher EXIT_UNSQUASH("failed to allocate data\n"); 1827443c15812032991c98b33b5424b17bcd55fe3575plougher 1828443c15812032991c98b33b5424b17bcd55fe3575plougher if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL) 1829443c15812032991c98b33b5424b17bcd55fe3575plougher EXIT_UNSQUASH("failed to allocate created_inode\n"); 1830443c15812032991c98b33b5424b17bcd55fe3575plougher 1831443c15812032991c98b33b5424b17bcd55fe3575plougher memset(created_inode, 0, sBlk.inodes * sizeof(char *)); 1832443c15812032991c98b33b5424b17bcd55fe3575plougher 183379e700efc62527661ce140bd1013a2b60577917eplougher s_ops.read_uids_guids(); 1834ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher 183502bc3bcabf2b219f63961f07293b83629948f026plougher s_ops.read_fragment_table(); 1836ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher 183702bc3bcabf2b219f63961f07293b83629948f026plougher uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start); 1838ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher 183902bc3bcabf2b219f63961f07293b83629948f026plougher uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start); 1840443c15812032991c98b33b5424b17bcd55fe3575plougher 1841a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher if(path) { 1842a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher paths = init_subdir(); 1843a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher paths = add_subdir(paths, path); 1844a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher } 1845a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher 1846eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths); 1847eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1848eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher memset(created_inode, 0, sBlk.inodes * sizeof(char *)); 18499b58176e667b67770569c9076a410b27aaa3bcf5plougher inode_number = 1; 1850eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1851b336488f2497ba8da6dcf9086e4b0b104f8fe072plougher printf("%d inodes (%d blocks) to write\n\n", total_inodes, total_inodes - total_files + total_blocks); 1852eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 18531b42101056befe25b5f19d5b099e806a2ecee9cdplougher if(progress) 18541b42101056befe25b5f19d5b099e806a2ecee9cdplougher enable_progress_bar(); 18551b42101056befe25b5f19d5b099e806a2ecee9cdplougher 185671add234b27054974d5e29f95b3fab3072792a62plougher dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths); 1857443c15812032991c98b33b5424b17bcd55fe3575plougher 18588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_put(to_writer, NULL); 18598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher queue_get(from_writer); 18608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 18615c7885bc293ab675812fd77a05f59c2917e3e8b4plougher if(progress) { 18621b42101056befe25b5f19d5b099e806a2ecee9cdplougher disable_progress_bar(); 18635c7885bc293ab675812fd77a05f59c2917e3e8b4plougher progress_bar(sym_count + dev_count + fifo_count + cur_blocks, 18641b42101056befe25b5f19d5b099e806a2ecee9cdplougher total_inodes - total_files + total_blocks, columns); 18655c7885bc293ab675812fd77a05f59c2917e3e8b4plougher } 1866eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 1867443c15812032991c98b33b5424b17bcd55fe3575plougher if(!lsonly) { 1868443c15812032991c98b33b5424b17bcd55fe3575plougher printf("\n"); 1869443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d files\n", file_count); 1870443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d directories\n", dir_count); 1871443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d symlinks\n", sym_count); 1872443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d devices\n", dev_count); 1873443c15812032991c98b33b5424b17bcd55fe3575plougher printf("created %d fifos\n", fifo_count); 1874443c15812032991c98b33b5424b17bcd55fe3575plougher } 1875eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher 18769dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher return 0; 1877443c15812032991c98b33b5424b17bcd55fe3575plougher} 1878