/kernel-2.6/102-mksquashfs.patch
Patch | 2086 lines | 2086 code | 0 blank | 0 comment | 0 complexity | 769d52ee7edea26ee2430209a2ce1890 MD5 | raw file
Possible License(s): GPL-2.0
Large files files are truncated, but you can click here to view the full file
- diff -BurpN linux-2.6.22.orig/scripts/squashfs/Makefile linux-2.6.22/scripts/squashfs/Makefile
- --- linux-2.6.22.orig/scripts/squashfs/Makefile 1970-01-01 00:00:00.000000000 +0000
- +++ linux-2.6.22/scripts/squashfs/Makefile 2009-10-24 17:47:57.000000000 +0000
- @@ -0,0 +1,22 @@
- +INCLUDEDIR = $(SRCBASE)/linux/linux-2.6/include/linux
- +
- +CFLAGS := -I. -idirafter$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -O2
- +
- +all: mksquashfs unsquashfs
- +
- +mksquashfs: mksquashfs.o read_fs.o sort.o
- + $(CC) mksquashfs.o read_fs.o sort.o -lz -lpthread -lm -o $@
- +
- +mksquashfs.o: mksquashfs.c mksquashfs.h global.h sort.h
- +
- +read_fs.o: read_fs.c read_fs.h global.h
- +
- +sort.o: sort.c global.h sort.h
- +
- +unsquashfs: unsquashfs.o
- + $(CC) unsquashfs.o -lz -lpthread -lm -o $@
- +
- +unsquashfs.o: unsquashfs.c read_fs.h global.h
- +
- +clean:
- + -rm -f *.o mksquashfs unsquashfs
- diff -BurpN linux-2.6.22.orig/scripts/squashfs/global.h linux-2.6.22/scripts/squashfs/global.h
- --- linux-2.6.22.orig/scripts/squashfs/global.h 1970-01-01 00:00:00.000000000 +0000
- +++ linux-2.6.22/scripts/squashfs/global.h 2008-08-20 04:45:40.000000000 +0000
- @@ -0,0 +1,74 @@
- +#ifndef GLOBAL_H
- +#define GLOBAL_H
- +
- +/*
- + * Squashfs
- + *
- + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- + * Phillip Lougher <phillip@lougher.demon.co.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * global.h
- + */
- +
- +typedef struct squashfs_super_block squashfs_super_block;
- +typedef struct squashfs_dir_index squashfs_dir_index;
- +typedef struct squashfs_base_inode_header squashfs_base_inode_header;
- +typedef struct squashfs_ipc_inode_header squashfs_ipc_inode_header;
- +typedef struct squashfs_dev_inode_header squashfs_dev_inode_header;
- +typedef struct squashfs_symlink_inode_header squashfs_symlink_inode_header;
- +typedef struct squashfs_reg_inode_header squashfs_reg_inode_header;
- +typedef struct squashfs_lreg_inode_header squashfs_lreg_inode_header;
- +typedef struct squashfs_dir_inode_header squashfs_dir_inode_header;
- +typedef struct squashfs_ldir_inode_header squashfs_ldir_inode_header;
- +typedef struct squashfs_dir_entry squashfs_dir_entry;
- +typedef struct squashfs_dir_header squashfs_dir_header;
- +typedef struct squashfs_fragment_entry squashfs_fragment_entry;
- +typedef union squashfs_inode_header squashfs_inode_header;
- +
- +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
- +typedef struct squashfs_dir_index_1 squashfs_dir_index_1;
- +typedef struct squashfs_base_inode_header_1 squashfs_base_inode_header_1;
- +typedef struct squashfs_ipc_inode_header_1 squashfs_ipc_inode_header_1;
- +typedef struct squashfs_dev_inode_header_1 squashfs_dev_inode_header_1;
- +typedef struct squashfs_symlink_inode_header_1 squashfs_symlink_inode_header_1;
- +typedef struct squashfs_reg_inode_header_1 squashfs_reg_inode_header_1;
- +typedef struct squashfs_dir_inode_header_1 squashfs_dir_inode_header_1;
- +typedef union squashfs_inode_header_1 squashfs_inode_header_1;
- +#endif
- +
- +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
- +typedef struct squashfs_dir_index_2 squashfs_dir_index_2;
- +typedef struct squashfs_base_inode_header_2 squashfs_base_inode_header_2;
- +typedef struct squashfs_ipc_inode_header_2 squashfs_ipc_inode_header_2;
- +typedef struct squashfs_dev_inode_header_2 squashfs_dev_inode_header_2;
- +typedef struct squashfs_symlink_inode_header_2 squashfs_symlink_inode_header_2;
- +typedef struct squashfs_reg_inode_header_2 squashfs_reg_inode_header_2;
- +typedef struct squashfs_lreg_inode_header_2 squashfs_lreg_inode_header_2;
- +typedef struct squashfs_dir_inode_header_2 squashfs_dir_inode_header_2;
- +typedef struct squashfs_ldir_inode_header_2 squashfs_ldir_inode_header_2;
- +typedef struct squashfs_dir_entry_2 squashfs_dir_entry_2;
- +typedef struct squashfs_dir_header_2 squashfs_dir_header_2;
- +typedef struct squashfs_fragment_entry_2 squashfs_fragment_entry_2;
- +typedef union squashfs_inode_header_2 squashfs_inode_header_2;
- +#endif
- +
- +typedef unsigned int squashfs_uid;
- +typedef long long squashfs_fragment_index;
- +typedef squashfs_inode_t squashfs_inode;
- +typedef squashfs_block_t squashfs_block;
- +
- +#endif
- diff -BurpN linux-2.6.22.orig/scripts/squashfs/mksquashfs.c linux-2.6.22/scripts/squashfs/mksquashfs.c
- --- linux-2.6.22.orig/scripts/squashfs/mksquashfs.c 1970-01-01 00:00:00.000000000 +0000
- +++ linux-2.6.22/scripts/squashfs/mksquashfs.c 2008-08-26 07:01:39.000000000 +0000
- @@ -0,0 +1,4223 @@
- +/*
- + * Create a squashfs filesystem. This is a highly compressed read only filesystem.
- + *
- + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
- + * Phillip Lougher <phillip@lougher.demon.co.uk>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2,
- + * or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- + *
- + * mksquashfs.c
- + */
- +
- +#define FALSE 0
- +#define TRUE 1
- +
- +#include <pwd.h>
- +#include <grp.h>
- +#include <time.h>
- +#include <unistd.h>
- +#include <stdio.h>
- +#include <sys/time.h>
- +#include <sys/types.h>
- +#include <sys/stat.h>
- +#include <fcntl.h>
- +#include <errno.h>
- +#include <dirent.h>
- +#include <string.h>
- +#include <zlib.h>
- +#include <stdlib.h>
- +#include <signal.h>
- +#include <setjmp.h>
- +#include <sys/ioctl.h>
- +#include <sys/types.h>
- +#include <sys/mman.h>
- +#include <pthread.h>
- +#include <math.h>
- +#include <regex.h>
- +#include <fnmatch.h>
- +
- +#ifndef linux
- +#define __BYTE_ORDER BYTE_ORDER
- +#define __BIG_ENDIAN BIG_ENDIAN
- +#define __LITTLE_ENDIAN LITTLE_ENDIAN
- +#include <sys/sysctl.h>
- +#else
- +#include <endian.h>
- +#include <sys/sysinfo.h>
- +#endif
- +
- +#include <squashfs_fs.h>
- +#include "mksquashfs.h"
- +#include "global.h"
- +#include "sort.h"
- +
- +#ifdef SQUASHFS_TRACE
- +#define TRACE(s, args...) do { \
- + if(progress_enabled) \
- + printf("\n"); \
- + printf("mksquashfs: "s, ## args); \
- + } while(0)
- +#else
- +#define TRACE(s, args...)
- +#endif
- +
- +#define INFO(s, args...) do {\
- + if(!silent)\
- + printf("mksquashfs: "s, ## args);\
- + } while(0)
- +#define ERROR(s, args...) do {\
- + pthread_mutex_lock(&progress_mutex); \
- + if(progress_enabled) \
- + fprintf(stderr, "\n"); \
- + fprintf(stderr, s, ## args);\
- + pthread_mutex_unlock(&progress_mutex); \
- + } while(0)
- +#define EXIT_MKSQUASHFS() do {\
- + if(restore)\
- + restorefs();\
- + if(delete && destination_file && !block_device)\
- + unlink(destination_file);\
- + exit(1);\
- + } while(0)
- +#define BAD_ERROR(s, args...) do {\
- + pthread_mutex_lock(&progress_mutex); \
- + if(progress_enabled) \
- + fprintf(stderr, "\n"); \
- + fprintf(stderr, "FATAL ERROR:" s, ##args);\
- + pthread_mutex_unlock(&progress_mutex); \
- + EXIT_MKSQUASHFS();\
- + } while(0)
- +
- +int delete = FALSE;
- +int fd;
- +int cur_uncompressed = 0, estimated_uncompressed = 0;
- +int columns;
- +
- +/* filesystem flags for building */
- +int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0;
- +int noI = 0, noD = 0, check_data = 0;
- +int swap, silent = TRUE;
- +long long global_uid = -1, global_gid = -1;
- +int exportable = TRUE;
- +int progress = TRUE;
- +int progress_enabled = FALSE;
- +int sparse_files = TRUE;
- +int old_exclude = TRUE;
- +int use_regex = FALSE;
- +
- +/* superblock attributes */
- +int block_size = SQUASHFS_FILE_SIZE, block_log;
- +unsigned short uid_count = 0, guid_count = 0;
- +squashfs_uid uids[SQUASHFS_UIDS], guids[SQUASHFS_GUIDS];
- +int block_offset;
- +int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0;
- +
- +/* write position within data section */
- +long long bytes = 0, total_bytes = 0;
- +
- +/* in memory directory table - possibly compressed */
- +char *directory_table = NULL;
- +unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
- +
- +/* cached directory table */
- +char *directory_data_cache = NULL;
- +unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
- +
- +/* in memory inode table - possibly compressed */
- +char *inode_table = NULL;
- +unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
- +
- +/* cached inode table */
- +char *data_cache = NULL;
- +unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
- +
- +/* inode lookup table */
- +squashfs_inode *inode_lookup_table = NULL;
- +
- +/* in memory directory data */
- +#define I_COUNT_SIZE 128
- +#define DIR_ENTRIES 32
- +#define INODE_HASH_SIZE 65536
- +#define INODE_HASH_MASK (INODE_HASH_SIZE - 1)
- +#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK)
- +
- +struct cached_dir_index {
- + squashfs_dir_index index;
- + char *name;
- +};
- +
- +struct directory {
- + unsigned int start_block;
- + unsigned int size;
- + unsigned char *buff;
- + unsigned char *p;
- + unsigned int entry_count;
- + unsigned char *entry_count_p;
- + unsigned int i_count;
- + unsigned int i_size;
- + struct cached_dir_index *index;
- + unsigned char *index_count_p;
- + unsigned int inode_number;
- +};
- +
- +struct inode_info *inode_info[INODE_HASH_SIZE];
- +
- +/* hash tables used to do fast duplicate searches in duplicate check */
- +struct file_info *dupl[65536];
- +int dup_files = 0;
- +
- +/* exclude file handling */
- +/* list of exclude dirs/files */
- +struct exclude_info {
- + dev_t st_dev;
- + ino_t st_ino;
- +};
- +
- +#define EXCLUDE_SIZE 8192
- +int exclude = 0;
- +struct exclude_info *exclude_paths = NULL;
- +int old_excluded(char *filename, struct stat *buf);
- +
- +struct path_entry {
- + char *name;
- + regex_t *preg;
- + struct pathname *paths;
- +};
- +
- +struct pathname {
- + int names;
- + struct path_entry *name;
- +};
- +
- +struct pathnames {
- + int count;
- + struct pathname *path[0];
- +};
- +#define PATHS_ALLOC_SIZE 10
- +
- +struct pathnames *paths = NULL;
- +struct pathname *path = NULL;
- +struct pathname *stickypath = NULL;
- +int excluded(struct pathnames *paths, char *name, struct pathnames **new);
- +
- +/* fragment block data structures */
- +int fragments = 0;
- +struct file_buffer *fragment_data = NULL;
- +int fragment_size = 0;
- +
- +struct fragment {
- + unsigned int index;
- + int offset;
- + int size;
- +};
- +
- +#define FRAG_SIZE 32768
- +#define FRAG_INDEX (1LL << 32)
- +
- +squashfs_fragment_entry *fragment_table = NULL;
- +int fragments_outstanding = 0;
- +
- +/* current inode number for directories and non directories */
- +unsigned int dir_inode_no = 1;
- +unsigned int inode_no = 0;
- +unsigned int root_inode_number = 0;
- +
- +/* list of source dirs/files */
- +int source = 0;
- +char **source_path;
- +
- +/* list of root directory entries read from original filesystem */
- +int old_root_entries = 0;
- +struct old_root_entry_info {
- + char name[SQUASHFS_NAME_LEN + 1];
- + squashfs_inode inode;
- + int type;
- + int inode_number;
- +};
- +struct old_root_entry_info *old_root_entry;
- +
- +/* in memory file info */
- +struct file_info {
- + long long file_size;
- + long long bytes;
- + unsigned short checksum;
- + unsigned short fragment_checksum;
- + long long start;
- + unsigned int *block_list;
- + struct file_info *next;
- + struct fragment *fragment;
- + char checksum_flag;
- +};
- +
- +/* count of how many times SIGINT or SIGQUIT has been sent */
- +int interrupted = 0;
- +
- +/* restore orignal filesystem state if appending to existing filesystem is cancelled */
- +jmp_buf env;
- +char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
- +
- +long long sbytes, stotal_bytes;
- +
- +unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
- + sdirectory_cache_bytes, sdirectory_compressed_bytes, suid_count, sguid_count,
- + stotal_inode_bytes, stotal_directory_bytes,
- + sinode_count = 0, sfile_count, ssym_count, sdev_count,
- + sdir_count, sfifo_count, ssock_count, sdup_files;
- +int sfragments;
- +int restore = 0;
- +int threads;
- +
- +/* flag whether destination file is a block device */
- +int block_device = 0;
- +
- +/* flag indicating whether files are sorted using sort list(s) */
- +int sorted = 0;
- +
- +/* save destination file name for deleting on error */
- +char *destination_file = NULL;
- +
- +/* recovery file for abnormal exit on appending */
- +char recovery_file[1024] = "";
- +int recover = TRUE;
- +
- +/* struct describing a cache entry passed between threads */
- +struct file_buffer {
- + struct cache *cache;
- + int keep;
- + long long file_size;
- + long long index;
- + long long block;
- + long long sequence;
- + int size;
- + int c_byte;
- + int used;
- + int fragment;
- + int error;
- + struct file_buffer *hash_next;
- + struct file_buffer *hash_prev;
- + struct file_buffer *free_next;
- + struct file_buffer *free_prev;
- + struct file_buffer *next;
- + char data[0];
- +};
- +
- +
- +/* struct describing queues used to pass data between threads */
- +struct queue {
- + int size;
- + int readp;
- + int writep;
- + pthread_mutex_t mutex;
- + pthread_cond_t empty;
- + pthread_cond_t full;
- + void **data;
- +};
- +
- +/* describes the list of blocks in a file which is a possible
- + duplicate. For each block, it indicates whether the block is
- + in memory or on disk */
- +struct buffer_list {
- + long long start;
- + int size;
- + struct file_buffer *read_buffer;
- +};
- +
- +struct cache *reader_buffer, *writer_buffer, *fragment_buffer;
- +struct queue *to_reader, *from_reader, *to_writer, *from_writer, *from_deflate, *to_frag;
- +pthread_t *thread, *deflator_thread, *frag_deflator_thread, progress_thread;
- +pthread_mutex_t fragment_mutex;
- +pthread_cond_t fragment_waiting;
- +pthread_mutex_t pos_mutex;
- +pthread_mutex_t progress_mutex;
- +pthread_cond_t progress_wait;
- +int rotate = 0;
- +
- +/* user options that control parallelisation */
- +int processors = -1;
- +/* default size of output buffer in Mbytes */
- +#define WRITER_BUFFER_DEFAULT 512
- +/* default size of input buffer in Mbytes */
- +#define READER_BUFFER_DEFAULT 64
- +/* default size of fragment buffer in Mbytes */
- +#define FRAGMENT_BUFFER_DEFAULT 64
- +int writer_buffer_size;
- +int reader_buffer_size;
- +int fragment_buffer_size;
- +
- +void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type);
- +extern int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source);
- +extern long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table,
- + char **data_cache, char **cdirectory_table, char **directory_data_cache,
- + unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
- + unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
- + int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids,
- + unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
- + long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
- + unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode,
- + void (push_directory_entry)(char *, squashfs_inode, int, int),
- + squashfs_fragment_entry **fragment_table, squashfs_inode **inode_lookup_table);
- +extern int read_sort_file(char *filename, int source, char *source_path[]);
- +extern void sort_files_and_write(struct dir_info *dir);
- +struct file_info *duplicate(long long file_size, long long bytes, unsigned int **block_list, long long *start, struct fragment **fragment, struct file_buffer *file_buffer, struct buffer_list *buffer_list, int blocks, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag);
- +struct dir_info *dir_scan1(char *, struct pathnames *, int (_readdir)(char *, char *, struct dir_info *));
- +void dir_scan2(squashfs_inode *inode, struct dir_info *dir_info);
- +struct file_info *add_non_dup(long long file_size, long long bytes, unsigned int *block_list, long long start, struct fragment *fragment, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag);
- +extern void generate_file_priorities(struct dir_info *dir, int priority, struct stat *buf);
- +extern struct priority_entry *priority_list[65536];
- +void progress_bar(long long current, long long max, int columns);
- +
- +
- +struct queue *queue_init(int size)
- +{
- + struct queue *queue = malloc(sizeof(struct queue));
- +
- + if(queue == NULL)
- + return NULL;
- +
- + if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) {
- + free(queue);
- + return NULL;
- + }
- +
- + queue->size = size + 1;
- + queue->readp = queue->writep = 0;
- + pthread_mutex_init(&queue->mutex, NULL);
- + pthread_cond_init(&queue->empty, NULL);
- + pthread_cond_init(&queue->full, NULL);
- +
- + return queue;
- +}
- +
- +
- +void queue_put(struct queue *queue, void *data)
- +{
- + int nextp;
- +
- + pthread_mutex_lock(&queue->mutex);
- +
- + while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
- + pthread_cond_wait(&queue->full, &queue->mutex);
- +
- + queue->data[queue->writep] = data;
- + queue->writep = nextp;
- + pthread_cond_signal(&queue->empty);
- + pthread_mutex_unlock(&queue->mutex);
- +}
- +
- +
- +void *queue_get(struct queue *queue)
- +{
- + void *data;
- + pthread_mutex_lock(&queue->mutex);
- +
- + while(queue->readp == queue->writep)
- + pthread_cond_wait(&queue->empty, &queue->mutex);
- +
- + data = queue->data[queue->readp];
- + queue->readp = (queue->readp + 1) % queue->size;
- + pthread_cond_signal(&queue->full);
- + pthread_mutex_unlock(&queue->mutex);
- +
- + return data;
- +}
- +
- +
- +/* Cache status struct. Caches are used to keep
- + track of memory buffers passed between different threads */
- +struct cache {
- + int max_buffers;
- + int count;
- + int buffer_size;
- + pthread_mutex_t mutex;
- + pthread_cond_t wait_for_free;
- + struct file_buffer *free_list;
- + struct file_buffer *hash_table[65536];
- +};
- +
- +
- +#define INSERT_LIST(NAME, TYPE) \
- +void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
- + if(*list) { \
- + entry->NAME##_next = *list; \
- + entry->NAME##_prev = (*list)->NAME##_prev; \
- + (*list)->NAME##_prev->NAME##_next = entry; \
- + (*list)->NAME##_prev = entry; \
- + } else { \
- + *list = entry; \
- + entry->NAME##_prev = entry->NAME##_next = entry; \
- + } \
- +}
- +
- +
- +#define REMOVE_LIST(NAME, TYPE) \
- +void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
- + if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
- + /* only this entry in the list */ \
- + *list = NULL; \
- + } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
- + /* more than one entry in the list */ \
- + entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
- + entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
- + if(*list == entry) \
- + *list = entry->NAME##_next; \
- + } \
- + entry->NAME##_prev = entry->NAME##_next = NULL; \
- +}
- +
- +
- +#define CALCULATE_HASH(start) (start & 0xffff) \
- +
- +
- +/* Called with the cache mutex held */
- +void insert_hash_table(struct cache *cache, struct file_buffer *entry)
- +{
- + int hash = CALCULATE_HASH(entry->index);
- +
- + entry->hash_next = cache->hash_table[hash];
- + cache->hash_table[hash] = entry;
- + entry->hash_prev = NULL;
- + if(entry->hash_next)
- + entry->hash_next->hash_prev = entry;
- +}
- +
- +
- +/* Called with the cache mutex held */
- +void remove_hash_table(struct cache *cache, struct file_buffer *entry)
- +{
- + if(entry->hash_prev)
- + entry->hash_prev->hash_next = entry->hash_next;
- + else
- + cache->hash_table[CALCULATE_HASH(entry->index)] = entry->hash_next;
- + if(entry->hash_next)
- + entry->hash_next->hash_prev = entry->hash_prev;
- +
- + entry->hash_prev = entry->hash_next = NULL;
- +}
- +
- +
- +/* Called with the cache mutex held */
- +INSERT_LIST(free, struct file_buffer)
- +
- +/* Called with the cache mutex held */
- +REMOVE_LIST(free, struct file_buffer)
- +
- +
- +struct cache *cache_init(int buffer_size, int max_buffers)
- +{
- + struct cache *cache = malloc(sizeof(struct cache));
- +
- + if(cache == NULL)
- + return NULL;
- +
- + cache->max_buffers = max_buffers;
- + cache->buffer_size = buffer_size;
- + cache->count = 0;
- + cache->free_list = NULL;
- + memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
- + pthread_mutex_init(&cache->mutex, NULL);
- + pthread_cond_init(&cache->wait_for_free, NULL);
- +
- + return cache;
- +}
- +
- +
- +struct file_buffer *cache_lookup(struct cache *cache, long long index)
- +{
- + /* Lookup block in the cache, if found return with usage count
- + * incremented, if not found return NULL */
- + int hash = CALCULATE_HASH(index);
- + struct file_buffer *entry;
- +
- + pthread_mutex_lock(&cache->mutex);
- +
- + for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
- + if(entry->index == index)
- + break;
- +
- + if(entry) {
- + /* found the block in the cache, increment used count and
- + * if necessary remove from free list so it won't disappear
- + */
- + entry->used ++;
- + remove_free_list(&cache->free_list, entry);
- + }
- +
- + pthread_mutex_unlock(&cache->mutex);
- +
- + return entry;
- +}
- +
- +
- +#define GET_FREELIST 1
- +
- +struct file_buffer *cache_get(struct cache *cache, long long index, int keep)
- +{
- + /* Get a free block out of the cache indexed on index. */
- + struct file_buffer *entry;
- +
- + pthread_mutex_lock(&cache->mutex);
- +
- + while(1) {
- + /* first try to get a block from the free list */
- +#ifdef GET_FREELIST
- + if(cache->free_list) {
- + /* a block on the free_list is a "keep" block */
- + entry = cache->free_list;
- + remove_free_list(&cache->free_list, entry);
- + remove_hash_table(cache, entry);
- + break;
- + } else
- +#endif
- + if(cache->count < cache->max_buffers) {
- + /* next try to allocate new block */
- + entry = malloc(sizeof(struct file_buffer) + cache->buffer_size);
- + if(entry == NULL)
- + goto failed;
- + entry->cache = cache;
- + entry->free_prev = entry->free_next = NULL;
- + cache->count ++;
- + break;
- + } else
- +#ifndef GET_FREELIST
- + if(cache->free_list) {
- + /* a block on the free_list is a "keep" block */
- + entry = cache->free_list;
- + remove_free_list(&cache->free_list, entry);
- + remove_hash_table(cache, entry);
- + break;
- + }
- +#endif
- + /* wait for a block */
- + pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
- + }
- +
- + /* initialise block and if a keep block insert into the hash table */
- + entry->used = 1;
- + entry->error = FALSE;
- + entry->keep = keep;
- + if(keep) {
- + entry->index = index;
- + insert_hash_table(cache, entry);
- + }
- + pthread_mutex_unlock(&cache->mutex);
- +
- + return entry;
- +
- +failed:
- + pthread_mutex_unlock(&cache->mutex);
- + return NULL;
- +}
- +
- +
- +void cache_rehash(struct file_buffer *entry, long long index)
- +{
- + struct cache *cache = entry->cache;
- +
- + pthread_mutex_lock(&cache->mutex);
- + if(entry->keep)
- + remove_hash_table(cache, entry);
- + entry->keep = TRUE;
- + entry->index = index;
- + insert_hash_table(cache, entry);
- + pthread_mutex_unlock(&cache->mutex);
- +}
- +
- +
- +void cache_block_put(struct file_buffer *entry)
- +{
- + struct cache *cache;
- +
- + /* finished with this cache entry, once the usage count reaches zero it
- + * can be reused and if a keep block put onto the free list. As keep
- + * blocks remain accessible via the hash table they can be found getting a
- + * new lease of life before they are reused. */
- +
- + if(entry == NULL)
- + return;
- +
- + cache = entry->cache;
- +
- + pthread_mutex_lock(&cache->mutex);
- +
- + entry->used --;
- + if(entry->used == 0) {
- + if(entry->keep)
- + insert_free_list(&cache->free_list, entry);
- + else {
- + free(entry);
- + cache->count --;
- + }
- +
- + /* One or more threads may be waiting on this block */
- + pthread_cond_signal(&cache->wait_for_free);
- + }
- +
- + pthread_mutex_unlock(&cache->mutex);
- +}
- +
- +
- +#define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) + (((char *)A) - data_cache)))
- +
- +
- +inline void inc_progress_bar()
- +{
- + cur_uncompressed ++;
- +}
- +
- +
- +inline void update_progress_bar()
- +{
- + pthread_mutex_lock(&progress_mutex);
- + pthread_cond_signal(&progress_wait);
- + pthread_mutex_unlock(&progress_mutex);
- +}
- +
- +
- +inline void waitforthread(int i)
- +{
- + TRACE("Waiting for thread %d\n", i);
- + while(thread[i] != 0)
- + sched_yield();
- +}
- +
- +
- +void restorefs()
- +{
- + int i;
- +
- + if(thread == NULL || thread[0] == 0)
- + return;
- +
- + ERROR("Exiting - restoring original filesystem!\n\n");
- +
- + for(i = 0; i < 2 + processors * 2; i++)
- + if(thread[i])
- + pthread_kill(thread[i], SIGUSR1);
- + for(i = 0; i < 2 + processors * 2; i++)
- + waitforthread(i);
- + TRACE("All threads in signal handler\n");
- + bytes = sbytes;
- + memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
- + memcpy(directory_data_cache, sdirectory_data_cache, directory_cache_bytes = sdirectory_cache_bytes);
- + inode_bytes = sinode_bytes;
- + directory_bytes = sdirectory_bytes;
- + memcpy(directory_table + directory_bytes, sdirectory_compressed, sdirectory_compressed_bytes);
- + directory_bytes += sdirectory_compressed_bytes;
- + uid_count = suid_count;
- + guid_count = sguid_count;
- + total_bytes = stotal_bytes;
- + total_inode_bytes = stotal_inode_bytes;
- + total_directory_bytes = stotal_directory_bytes;
- + inode_count = sinode_count;
- + file_count = sfile_count;
- + sym_count = ssym_count;
- + dev_count = sdev_count;
- + dir_count = sdir_count;
- + fifo_count = sfifo_count;
- + sock_count = ssock_count;
- + dup_files = sdup_files;
- + fragments = sfragments;
- + fragment_size = 0;
- + longjmp(env, 1);
- +}
- +
- +
- +void sighandler()
- +{
- + if(++interrupted > 2)
- + return;
- + if(interrupted == 2)
- + restorefs();
- + else {
- + ERROR("Interrupting will restore original filesystem!\n");
- + ERROR("Interrupt again to quit\n");
- + }
- +}
- +
- +
- +void sighandler2()
- +{
- + EXIT_MKSQUASHFS();
- +}
- +
- +
- +void sigusr1_handler()
- +{
- + int i;
- + sigset_t sigmask;
- + pthread_t thread_id = pthread_self();
- +
- + for(i = 0; i < (2 + processors * 2) && thread[i] != thread_id; i++);
- + thread[i] = (pthread_t) 0;
- +
- + TRACE("Thread %d(%p) in sigusr1_handler\n", i, &thread_id);
- +
- + sigemptyset(&sigmask);
- + sigaddset(&sigmask, SIGINT);
- + sigaddset(&sigmask, SIGQUIT);
- + sigaddset(&sigmask, SIGUSR1);
- + while(1) {
- + sigsuspend(&sigmask);
- + TRACE("After wait in sigusr1_handler :(\n");
- + }
- +}
- +
- +
- +void sigwinch_handler()
- +{
- + struct winsize winsize;
- +
- + if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
- + printf("TIOCGWINSZ ioctl failed, defaulting to 80 columns\n");
- + columns = 80;
- + } else
- + columns = winsize.ws_col;
- +}
- +
- +
- +void sigalrm_handler()
- +{
- + rotate = (rotate + 1) % 4;
- +}
- +
- +
- +unsigned int mangle2(z_stream **strm, char *d, char *s, int size, int block_size, int uncompressed, int data_block)
- +{
- + unsigned long c_byte;
- + unsigned int res;
- + z_stream *stream = *strm;
- +
- + if(uncompressed)
- + goto notcompressed;
- +
- + if(stream == NULL) {
- + if((stream = *strm = malloc(sizeof(z_stream))) == NULL)
- + BAD_ERROR("mangle::compress failed, not enough memory\n");
- +
- + stream->zalloc = Z_NULL;
- + stream->zfree = Z_NULL;
- + stream->opaque = 0;
- +
- + if((res = deflateInit(stream, 9)) != Z_OK) {
- + if(res == Z_MEM_ERROR)
- + BAD_ERROR("zlib::compress failed, not enough memory\n");
- + else if(res == Z_STREAM_ERROR)
- + BAD_ERROR("zlib::compress failed, not a valid compression level\n");
- + else if(res == Z_VERSION_ERROR)
- + BAD_ERROR("zlib::compress failed, incorrect zlib version\n");
- + else
- + BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
- + }
- + } else if((res = deflateReset(stream)) != Z_OK) {
- + if(res == Z_STREAM_ERROR)
- + BAD_ERROR("zlib::compress failed, stream state inconsistent\n");
- + else
- + BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
- + }
- +
- + stream->next_in = (unsigned char *) s;
- + stream->avail_in = size;
- + stream->next_out = (unsigned char *) d;
- + stream->avail_out = block_size;
- +
- + res = deflate(stream, Z_FINISH);
- + if(res != Z_STREAM_END && res != Z_OK) {
- + if(res == Z_STREAM_ERROR)
- + BAD_ERROR("zlib::compress failed, stream state inconsistent\n");
- + else if(res == Z_BUF_ERROR)
- + BAD_ERROR("zlib::compress failed, no progress possible\n");
- + else
- + BAD_ERROR("zlib::compress failed, unknown error %d\n", res);
- + }
- +
- + c_byte = stream->total_out;
- +
- + if(res != Z_STREAM_END || c_byte >= size) {
- +notcompressed:
- + memcpy(d, s, size);
- + return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT);
- + }
- +
- + return (unsigned int) c_byte;
- +}
- +
- +
- +unsigned int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block)
- +{
- + static z_stream *stream = NULL;
- +
- + return mangle2(&stream, d, s, size, block_size, uncompressed, data_block);
- +}
- +
- +
- +squashfs_base_inode_header *get_inode(int req_size)
- +{
- + int data_space;
- + unsigned short c_byte;
- +
- + while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
- + if((inode_size - inode_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) {
- + if((inode_table = (char *) realloc(inode_table, inode_size + (SQUASHFS_METADATA_SIZE << 1) + 2))
- + == NULL) {
- + goto failed;
- + }
- + inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
- + }
- +
- + c_byte = mangle(inode_table + inode_bytes + block_offset, data_cache,
- + SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
- + TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
- + if(!swap)
- + memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
- + else
- + SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
- + if(check_data)
- + *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
- + inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
- + total_inode_bytes += SQUASHFS_METADATA_SIZE + block_offset;
- + memcpy(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE);
- + cache_bytes -= SQUASHFS_METADATA_SIZE;
- + }
- +
- + data_space = (cache_size - cache_bytes);
- + if(data_space < req_size) {
- + int realloc_size = cache_size == 0 ? ((req_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - data_space;
- +
- + if((data_cache = (char *) realloc(data_cache, cache_size + realloc_size)) == NULL) {
- + goto failed;
- + }
- + cache_size += realloc_size;
- + }
- +
- + cache_bytes += req_size;
- +
- + return (squashfs_base_inode_header *)(data_cache + (cache_bytes - req_size));
- +
- +failed:
- + BAD_ERROR("Out of memory in inode table reallocation!\n");
- +}
- +
- +
- +void read_bytes(int fd, long long byte, int bytes, char *buff)
- +{
- + off_t off = byte;
- +
- + pthread_mutex_lock(&pos_mutex);
- + if(lseek(fd, off, SEEK_SET) == -1)
- + BAD_ERROR("Lseek on destination failed because %s\n", strerror(errno));
- +
- + if(read(fd, buff, bytes) == -1)
- + BAD_ERROR("Read on destination failed because %s\n", strerror(errno));
- + pthread_mutex_unlock(&pos_mutex);
- +}
- +
- +
- +void write_bytes(int fd, long long byte, int bytes, char *buff)
- +{
- + off_t off = byte;
- +
- + if(interrupted < 2)
- + pthread_mutex_lock(&pos_mutex);
- +
- + if(lseek(fd, off, SEEK_SET) == -1)
- + BAD_ERROR("Lseek on destination failed because %s\n", strerror(errno));
- +
- + if(write(fd, buff, bytes) == -1)
- + BAD_ERROR("Write on destination failed because %s\n", strerror(errno));
- +
- + if(interrupted < 2)
- + pthread_mutex_unlock(&pos_mutex);
- +}
- +
- +
- +long long write_inodes()
- +{
- + unsigned short c_byte;
- + int avail_bytes;
- + char *datap = data_cache;
- + long long start_bytes = bytes;
- +
- + while(cache_bytes) {
- + if(inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
- + if((inode_table = (char *) realloc(inode_table, inode_size + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
- + BAD_ERROR("Out of memory in inode table reallocation!\n");
- + }
- + inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
- + }
- + avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes;
- + c_byte = mangle(inode_table + inode_bytes + block_offset, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
- + TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
- + if(!swap)
- + memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short));
- + else
- + SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1);
- + if(check_data)
- + *((unsigned char *)(inode_table + inode_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
- + inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
- + total_inode_bytes += avail_bytes + block_offset;
- + datap += avail_bytes;
- + cache_bytes -= avail_bytes;
- + }
- +
- + write_bytes(fd, bytes, inode_bytes, (char *) inode_table);
- + bytes += inode_bytes;
- +
- + return start_bytes;
- +}
- +
- +
- +long long write_directories()
- +{
- + unsigned short c_byte;
- + int avail_bytes;
- + char *directoryp = directory_data_cache;
- + long long start_bytes = bytes;
- +
- + while(directory_cache_bytes) {
- + if(directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
- + if((directory_table = (char *) realloc(directory_table, directory_size +
- + ((SQUASHFS_METADATA_SIZE << 1) + 2))) == NULL) {
- + BAD_ERROR("Out of memory in directory table reallocation!\n");
- + }
- + directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
- + }
- + avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : directory_cache_bytes;
- + c_byte = mangle(directory_table + directory_bytes + block_offset, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
- + TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte);
- + if(!swap)
- + memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
- + else
- + SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
- + if(check_data)
- + *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
- + directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
- + total_directory_bytes += avail_bytes + block_offset;
- + directoryp += avail_bytes;
- + directory_cache_bytes -= avail_bytes;
- + }
- + write_bytes(fd, bytes, directory_bytes, (char *) directory_table);
- + bytes += directory_bytes;
- +
- + return start_bytes;
- +}
- +
- +
- +unsigned int get_uid(squashfs_uid uid)
- +{
- + int i;
- +
- + for(i = 0; (i < uid_count) && uids[i] != uid; i++);
- + if(i == uid_count) {
- + if(uid_count == SQUASHFS_UIDS) {
- + ERROR("Out of uids! - using uid 0 - probably not what's wanted!\n");
- + i = 0;
- + } else
- + uids[uid_count++] = uid;
- + }
- +
- + return i;
- +}
- +
- +
- +unsigned int get_guid(squashfs_uid uid, squashfs_uid guid)
- +{
- + int i;
- +
- + if(uid == guid)
- + return SQUASHFS_GUIDS;
- +
- + for(i = 0; (i < guid_count) && guids[i] != guid; i++);
- + if(i == guid_count) {
- + if(guid_count == SQUASHFS_GUIDS) {
- + ERROR("Out of gids! - using gid 0 - probably not what's wanted!\n");
- + return SQUASHFS_GUIDS;
- + } else
- + guids[guid_count++] = guid;
- + }
- +
- + return i;
- +}
- +
- +
- +int create_inode(squashfs_inode *i_no, struct dir_ent *dir_ent, int type, long long byte_size, long long start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment, struct directory *dir_in)
- +{
- + struct stat *buf = &dir_ent->inode->buf;
- + squashfs_inode_header inode_header;
- + squashfs_base_inode_header *inode, *base = &inode_header.base;
- + char *filename = dir_ent->pathname;
- + int nlink = dir_ent->inode->nlink;
- + int inode_number = (type == SQUASHFS_LDIR_TYPE || type == SQUASHFS_DIR_TYPE) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
- +
- + base->mode = SQUASHFS_MODE(buf->st_mode);
- + base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid);
- + base->inode_type = type;
- + base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf->st_gid : global_gid);
- + base->mtime = buf->st_mtime;
- + base->inode_number = inode_number;
- +
- + if(type == SQUASHFS_FILE_TYPE) {
- + int i;
- + squashfs_reg_inode_header *reg = &inode_header.reg, *inodep;
- +
- + inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
- + inodep = (squashfs_reg_inode_header *) inode;
- + reg->file_size = byte_size;
- + reg->start_block = start_block;
- + reg->fragment = fragment->index;
- + reg->offset = fragment->offset;
- + if(!swap) {
- + memcpy(inodep, reg, sizeof(*reg));
- + memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
- + } else {
- + SQUASHFS_SWAP_REG_INODE_HEADER(reg, inodep);
- + SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
- + }
- + TRACE("File inode, file_size %lld, start_block 0x%llx, blocks %d, fragment %d, offset %d, size %d\n", byte_size,
- + start_block, offset, fragment->index, fragment->offset, fragment->size);
- + for(i = 0; i < offset; i++)
- + TRACE("Block %d, size %d\n", i, block_list[i]);
- + }
- + else if(type == SQUASHFS_LREG_TYPE) {
- + int i;
- + squashfs_lreg_inode_header *reg = &inode_header.lreg, *inodep;
- +
- + inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
- + inodep = (squashfs_lreg_inode_header *) inode;
- + reg->nlink = nlink;
- + reg->file_size = byte_size;
- + reg->start_block = start_block;
- + reg->fragment = fragment->index;
- + reg->offset = fragment->offset;
- + if(!swap) {
- + memcpy(inodep, reg, sizeof(*reg));
- + memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int));
- + } else {
- + SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inodep);
- + SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset);
- + }
- + TRACE("Long file inode, file_size %lld, start_block 0x%llx, blocks %d, fragment %d, offset %d, size %d, nlink %d\n", byte_size,
- + start_block, offset, fragment->index, fragment->offset, fragment->size, nlink);
- + for(i = 0; i < offset; i++)
- + TRACE("Block %d, size %d\n", i, block_list[i]);
- + }
- + else if(type == SQUASHFS_LDIR_TYPE) {
- + int i;
- + unsigned char *p;
- + squashfs_ldir_inode_header *dir = &inode_header.ldir, *inodep;
- + struct cached_dir_index *index = dir_in->index;
- + unsigned int i_count = dir_in->i_count;
- + unsigned int i_size = dir_in->i_size;
- +
- + if(byte_size >= 1 << 27)
- + BAD_ERROR("directory greater than 2^27-1 bytes!\n");
- +
- + inode = get_inode(sizeof(*dir) + i_size);
- + inodep = (squashfs_ldir_inode_header *) inode;
- + dir->inode_type = SQUASHFS_LDIR_TYPE;
- + dir->nlink = dir_ent->dir->directory_count + 2;
- + dir->file_size = byte_size;
- + dir->offset = offset;
- + dir->start_block = start_block;
- + dir->i_count = i_count;
- + dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
- +
- + if(!swap)
- + memcpy(inode, dir, sizeof(*dir));
- + else
- + SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
- + p = (unsigned char *) inodep->index;
- + for(i = 0; i < i_count; i++) {
- + if(!swap)
- + memcpy(p, &index[i].index, sizeof(squashfs_dir_index));
- + else
- + SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
- + memcpy(((squashfs_dir_index *)p)->name, index[i].name, index[i].index.size + 1);
- + p += sizeof(squashfs_dir_index) + index[i].index.size + 1;
- + }
- + TRACE("Long directory inode, file_size %lld, start_block 0x%llx, offset 0x%x, nlink %d\n", byte_size,
- + start_block, offset, dir_ent->dir->directory_count + 2);
- + }
- + else if(type == SQUASHFS_DIR_TYPE) {
- + squashfs_dir_inode_header *dir = &inode_header.dir;
- +
- + inode = get_inode(sizeof(*dir));
- + dir->nlink = dir_ent->dir->directory_count + 2;
- + dir->file_size = byte_size;
- + dir->offset = offset;
- + dir->start_block = start_block;
- + dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no;
- + if(!swap)
- + memcpy(inode, dir, sizeof(*dir));
- + else
- + SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
- + TRACE("Directory inode, file_size %lld, start_block 0x%llx, offset 0x%x, nlink %d\n", byte_size,
- + start_block, offset, dir_ent->dir->directory_count + 2);
- + }
- + else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
- + squashfs_dev_inode_header *dev = &inode_header.dev;
- +
- + inode = get_inode(sizeof(*dev));
- + dev->nlink = nlink;
- + dev->rdev = (unsigned short) ((major(buf->st_rdev) << 8) |
- + (minor(buf->st_rdev) & 0xff));
- + if(!swap)
- + memcpy(inode, dev, sizeof(*dev));
- + else
- + SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
- + TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
- + }
- + else if(type == SQUASHFS_SYMLINK_TYPE) {
- + squashfs_symlink_inode_header *symlink = &inode_header.symlink, *inodep;
- + int byte;
- + char buff[65536];
- +
- + if((byte = readlink(filename, buff, 65536)) == -1) {
- + ERROR("Failed to read symlink %s, creating empty symlink\n", filename);
- + byte = 0;
- + }
- +
- + if(byte == 65536) {
- + ERROR("Symlink %s is greater than 65536 bytes! Creating empty symlink\n", filename);
- + byte = 0;
- + }
- +
- + inode = get_inode(sizeof(*symlink) + byte);
- + symlink->nlink = nlink;
- + inodep = (squashfs_symlink_inode_header *) inode;
- + symlink->symlink_size = byte;
- + if(!swap)
- + memcpy(inode, symlink, sizeof(*symlink));
- + else
- + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
- + strncpy(inodep->symlink, buff, byte);
- + TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink);
- + }
- + else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
- + squashfs_ipc_inode_header *ipc = &inode_header.ipc;
- +
- + inode = get_inode(sizeof(*ipc));
- + ipc->nlink = nlink;
- + if(!swap)
- + memcpy(inode, ipc, sizeof(*ipc));
- + else
- + SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
- + TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
- + } else
- + BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
- +
- + *i_no = MKINODE(inode);
- + inode_count ++;
- +
- + TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, base->uid, base->guid);
- +
- + return TRUE;
- +}
- +
- +
- +void scan2_init_dir(struct directory *dir)
- +{
- + if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) {
- + BAD_ERROR("Out of memory allocating directory buffer\n");
- + }
- +
- + dir->size = SQUASHFS_METADATA_SIZE;
- + dir->p = dir->index_count_p = dir->buff;
- + dir->entry_count = 256;
- + dir->entry_count_p = NULL;
- + dir->index = NULL;
- + dir->i_count = dir->i_size = 0;
- +}
- +
- +
- +void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, int type, struct directory *dir)
- +{
- + unsigned char *buff;
- + squashfs_dir_entry idir, *idirp;
- + unsigned int start_block = inode >> 16;
- + unsigned int offset = inode & 0xffff;
- + unsigned int size;
- +
- + if((size = strlen(name)) > SQUASHFS_NAME_LEN) {
- + size = SQUASHFS_NAME_LEN;
- + ERROR("Filename is greater than %d characters, truncating! ...\n", SQUASHFS_NAME_LEN);
- + }
- +
- + if(dir->p + sizeof(squashfs_dir_entry) + size + sizeof(squashfs_dir_header) >= dir->buff + dir->size) {
- + if((buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL) {
- + BAD_ERROR("Out of memory reallocating directory buffer\n");
- + }
- +
- + dir->p = (dir->p - dir->buff) + buff;
- + if(dir->entry_count_p)
- + dir->entry_count_p = (dir->entry_count_p - dir->buff + buff);
- + dir->index_count_p = dir->index_count_p - dir->buff + buff;
- + dir->buff = buff;
- + }
- +
- + if(dir->entry_count == 256 || start_block != dir->start_block || ((dir->entry_count_p != NULL) && ((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE)) || ((long long) inode_number - dir->inode_number) > 32767 || ((long long) inode_number - dir->inode_number) < - 32768) {
- + if(dir->entry_count_p) {
- + squashfs_dir_header dir_header;
- +
- + if((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE) {
- + if(dir->i_count % I_COUNT_SIZE == 0)
- + if((dir->index = realloc(dir->index, (dir->i_count + I_COUNT_SIZE) * sizeof(struct cached_dir_index))) == NULL)
- + BAD_ERROR("Out of memory in directory index table reallocation!\n");
- + dir->index[dir->i_count].index.index = dir->p - dir->buff;
- + dir->index[dir->i_count].index.size = size - 1;
- + dir->index[dir->i_count++].name = name;
- + dir->i_size += sizeof(squashfs_dir_index) + size;
- + dir->index_count_p = dir->p;
- + }
- +
- + dir_header.count = dir->entry_count - 1;
- + dir_header.start_block = dir->start_block;
- + dir_header.inode_number = dir->inode_number;
- + if(!swap)
- + memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
- + else
- + SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
- +
- + }
- +
- +
- + dir->entry_count_p = dir->p;
- + dir->start_block = start_block;
- + dir->entry_count = 0;
- + dir->inode_number = inode_number;
- + dir->p += sizeof(squashfs_dir_header);
- + }
- +
- + idirp = (squashfs_dir_entry *) dir->p;
- + idir.offset = offset;
- + idir.type = type;
- + idir.size = size - 1;
- + idir.inode_number = ((long long) inode_number - dir->inode_number);
- + if(!swap)
- + memcpy(idirp, &idir, sizeof(idir));
- + else
- + SQUASHFS_SWAP_DIR_ENTRY((&idir), idirp);
- + strncpy(idirp->name, name, size);
- + dir->p += sizeof(squashfs_dir_entry) + size;
- + dir->entry_count ++;
- +}
- +
- +
- +void write_dir(squashfs_inode *inode, struct dir_info *dir_info, struct directory *dir)
- +{
- + unsigned int dir_size = dir->p - dir->buff;
- + int data_space = (directory_cache_size - directory_cache_bytes);
- + unsigned int directory_block, directory_offset, i_count, index;
- + unsigned short c_byte;
- +
- + if(data_space < dir_size) {
- + int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
- +
- + if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) {
- + goto failed;
- + }
- + directory_cache_size += realloc_size;
- + }
- +
- + if(dir_size) {
- + squashfs_dir_header dir_header;
- +
- + dir_header.count = dir->entry_count - 1;
- + dir_header.start_block = dir->start_block;
- + dir_header.inode_number = dir->inode_number;
- + if(!swap)
- + memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header));
- + else
- + SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p);
- + memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size);
- + }
- + directory_offset = directory_cache_bytes;
- + directory_block = directory_bytes;
- + directory_cache_bytes += dir_size;
- + i_count = 0;
- + index = SQUASHFS_METADATA_SIZE - directory_offset;
- +
- + while(1) {
- + while(i_count < dir->i_count && dir->index[i_count].index.index < index)
- + dir->index[i_count++].index.start_block = directory_bytes;
- + index += SQUASHFS_METADATA_SIZE;
- +
- + if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
- + break;
- +
- + if((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) {
- + if((directory_table = (char *) realloc(directory_table,
- + directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2)) == NULL) {
- + goto failed;
- + }
- + directory_size += SQUASHFS_METADATA_SIZE << 1;
- + }
- +
- + c_byte = mangle(directory_table + directory_bytes + block_offset, directory_data_cache,
- + SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0);
- + TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte);
- + if(!swap)
- + memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short));
- + else
- + SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1);
- + if(check_data)
- + *((unsigned char *)(directory_table + directory_bytes + block_offset - 1)) = SQUASHFS_MARKER_BYTE;
- + directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + block_offset;
- + total_directory_bytes += SQUASHFS_METADATA_SIZE + block_offset;
- + memcpy(directory_data_cache, directory_data_cache + SQUASHFS_METADATA_SIZE, directory_cache_bytes - SQUASHFS_METADATA_SIZE);
- + directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
- + }
- +
- + if(dir_info->dir_is_ldir)
- + create_inode(inode, dir_info->dir_ent, SQUASHFS_LDIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, dir);
- + else
- + create_inode(inode, dir_info->dir_ent, SQUASHFS_DIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, NULL);
- +
- +#ifdef SQUASHFS_TRACE
- + if(!swap) {
- + unsigned char *dirp;
- + int count;
- +
- + TRACE("Directory contents of inode 0x%llx\n", *inode);
- + dirp = dir->buff;
- + while(dirp < dir->p) {
- + char buffer[SQUASHFS_NAME_LEN + 1];
- + squashfs_dir_entry idir, *idirp;
- + squashfs_dir_header *dirh = (squashfs_dir_header *) dirp;
- + count = dirh->count + 1;
- + dirp += sizeof(squashfs_dir_header);
- +
- + TRACE("\tStart block 0x%x, count %d\n", dirh->start_block, count);
- +
- + while(count--) {
- + idirp = (squashfs_dir_entry *) dirp;
- + memcpy((char *) &idir, (char *) idirp, sizeof(idir));
- + strncpy(buffer, idirp->name, idir.size + 1);
- + buffer[idir.size + 1] = '\0';
- + TRACE("\t\tname %s, inode offset 0x%x, type %d\n", buffer,
- + idir.offset, idir.type);
- + dirp += sizeof(squashfs_dir_entry) + idir.size + 1;
- + }
- + }
- + }
- +#endif
- + dir_count ++;
- +
- + return;
- +
- +failed:
- + BAD_ERROR("Out of memory in directory table reallocation!\n");
- +}
- +
- +
- +struct file_buffer *get_fragment(struct fragment *fragment)
- +{
- + squashfs_fragment_entry *disk_fragment;
- + int size;
- + long long start_block;
- + struct file_buffer *buffer, *compressed_buffer;
- +
- + if(fragment->index == SQUASHFS_INVALID_FRAG)
- + return NULL;
- +
- + buffer = cache_lookup(fragment_buffer, fragment->index);
- + if(buffer)
- + return buffer;
- +
- + compressed_buffer = cache_lookup(writer_buffer, fragment->index + FRAG_INDEX);
- +
- + buffer = cache_get(fragment_buffer, fragment->index, 1);
- +
- + pthread_mutex_lock(&fragment_mutex);
- + disk_fragment = &fragment_table[fragment->index];
- + size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
- + start_block = disk_fragment->start_block;
- + pthread_mutex_unlock(&fragment_mutex);
- +
- + if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
- + int res;
- + unsigned long bytes = block_size;
- + char *data;
- + char cbuffer[block_size];
- +
- + if(compressed_buffer)
- + data = compressed_buffer->data;
- + else {
- + data = cbuffer;
- + read_bytes(fd, start_block, size, data);
- + }
- +
- + if((res = uncompress((unsigned char…
Large files files are truncated, but you can click here to view the full file