tools/squashfs4: update to version 4.2 (adds support for xz compression)
tools/squashfs4: update to version 4.2 (adds support for xz compression)

Based on a patch by Jonas Gorski

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@26422 3c298f89-4303-0410-b956-a3cf2f4a3e73

--- a/include/image.mk
+++ b/include/image.mk
@@ -40,6 +40,14 @@
 endif
 ifneq ($(CONFIG_JFFS2_LZMA),y)
   JFFS2OPTS += -x lzma
+endif
+
+LZMA_XZ_OPTIONS := -Xpreset 9 -Xe -Xlc 0 -Xlp 2 -Xpb 2
+ifeq ($(CONFIG_SQUASHFS_LZMA),y)
+  SQUASHFSCOMP := lzma $(LZMA_XZ_OPTIONS)
+endif
+ifeq ($(CONFIG_SQUASHFS_XZ),y)
+  SQUASHFSCOMP := xz $(LZMA_XZ_OPTIONS)
 endif
 
 JFFS2_BLOCKSIZE ?= 64k 128k
@@ -86,7 +94,7 @@
   ifneq ($(CONFIG_TARGET_ROOTFS_SQUASHFS),)
     define Image/mkfs/squashfs
 		@mkdir -p $(TARGET_DIR)/overlay
-		$(STAGING_DIR_HOST)/bin/mksquashfs4 $(TARGET_DIR) $(KDIR)/root.squashfs -nopad -noappend -root-owned -comp lzma -processors 1
+		$(STAGING_DIR_HOST)/bin/mksquashfs4 $(TARGET_DIR) $(KDIR)/root.squashfs -nopad -noappend -root-owned -comp $(SQUASHFSCOMP) -processors 1
 		$(call Image/Build,squashfs)
     endef
   endif

--- a/tools/Makefile
+++ b/tools/Makefile
@@ -38,7 +38,7 @@
 $(curdir)/pkg-config/compile := $(curdir)/sed/install
 $(curdir)/libtool/compile := $(curdir)/sed/install
 $(curdir)/squashfs/compile := $(curdir)/lzma-old/install
-$(curdir)/squashfs4/compile := $(curdir)/lzma/install
+$(curdir)/squashfs4/compile := $(curdir)/xz/install
 $(curdir)/quilt/compile := $(curdir)/sed/install $(curdir)/autoconf/install
 $(curdir)/dtc/compile := $(curdir)/bison/install
 $(curdir)/autoconf/compile := $(curdir)/m4/install $(curdir)/libtool/install

--- a/tools/lzma/Makefile
+++ b/tools/lzma/Makefile
@@ -26,10 +26,8 @@
 endef
 
 define Host/Install
-	$(INSTALL_DIR) $(STAGING_DIR_HOST)/lib $(STAGING_DIR_HOST)/include $(STAGING_DIR_HOST)/bin
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
 	$(INSTALL_BIN) $(HOST_BUILD_DIR)/CPP/7zip/Compress/LZMA_Alone/lzma_alone $(STAGING_DIR_HOST)/bin/lzma
-	$(CP) $(HOST_BUILD_DIR)/C/*.h $(STAGING_DIR_HOST)/include/
-	$(CP) $(UTIL_DIR)/liblzma.a $(STAGING_DIR_HOST)/lib/
 endef
 
 define Host/Clean

--- a/tools/squashfs4/Makefile
+++ b/tools/squashfs4/Makefile
@@ -7,11 +7,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=squashfs4
-PKG_VERSION:=4.0
+PKG_VERSION:=4.2
 
 PKG_SOURCE:=squashfs$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=@SF/squashfs
-PKG_MD5SUM:=a3c23391da4ebab0ac4a75021ddabf96
+PKG_MD5SUM:=1b7a781fb4cf8938842279bd3e8ee852
 PKG_CAT:=zcat
 
 HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/squashfs$(PKG_VERSION)
@@ -20,9 +20,11 @@
 
 define Host/Compile
 	$(MAKE) -C $(HOST_BUILD_DIR)/squashfs-tools \
-		USE_LZMA=1 \
-		LZMA_CFLAGS="-I$(STAGING_DIR_HOST)/include -DUSE_LZMA" \
+		XZ_SUPPORT=1 \
+		LZMA_XZ_SUPPORT=1 \
+		XATTR_SUPPORT= \
 		LZMA_LIB="$(STAGING_DIR_HOST)/lib/liblzma.a" \
+		EXTRA_CFLAGS="-I$(STAGING_DIR_HOST)/include" \
 		mksquashfs unsquashfs
 endef
 

--- a/tools/squashfs4/patches/100-portability.patch
+++ b/tools/squashfs4/patches/100-portability.patch
@@ -1,17 +1,19 @@
---- a/squashfs-tools/global.h
-+++ b/squashfs-tools/global.h
-@@ -44,4 +44,8 @@ typedef long long squashfs_fragment_inde
- typedef squashfs_inode_t squashfs_inode;
- typedef squashfs_block_t squashfs_block;
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -60,6 +60,10 @@
+ #include <sys/sysinfo.h>
+ #endif
  
 +#ifndef FNM_EXTMATCH
 +#define FNM_EXTMATCH 0
 +#endif
 +
- #endif
+ #ifdef SQUASHFS_TRACE
+ #define TRACE(s, args...) \
+ 		do { \
 --- a/squashfs-tools/unsquashfs.h
 +++ b/squashfs-tools/unsquashfs.h
-@@ -49,8 +49,10 @@
+@@ -49,8 +49,14 @@
  #define __BYTE_ORDER BYTE_ORDER
  #define __BIG_ENDIAN BIG_ENDIAN
  #define __LITTLE_ENDIAN LITTLE_ENDIAN
@@ -19,7 +21,21 @@
  #else
  #include <endian.h>
 +#include <sys/sysinfo.h>
++#endif
++
++#ifndef FNM_EXTMATCH
++#define FNM_EXTMATCH 0
  #endif
  
  #include "squashfs_fs.h"
+--- a/squashfs-tools/unsquashfs.c
++++ b/squashfs-tools/unsquashfs.c
+@@ -29,7 +29,6 @@
+ #include "compressor.h"
+ #include "xattr.h"
+ 
+-#include <sys/sysinfo.h>
+ #include <sys/types.h>
+ 
+ struct cache *fragment_cache, *data_cache;
 

--- /dev/null
+++ b/tools/squashfs4/patches/110-allow_static_liblzma.patch
@@ -1,1 +1,31 @@
+--- a/squashfs-tools/Makefile
++++ b/squashfs-tools/Makefile
+@@ -129,7 +129,6 @@ ifeq ($(LZMA_XZ_SUPPORT),1)
+ CFLAGS += -DLZMA_SUPPORT
+ MKSQUASHFS_OBJS += lzma_xz_wrapper.o
+ UNSQUASHFS_OBJS += lzma_xz_wrapper.o
+-LIBS += -llzma
+ COMPRESSORS += lzma
+ endif
+ 
+@@ -137,10 +136,18 @@ ifeq ($(XZ_SUPPORT),1)
+ CFLAGS += -DXZ_SUPPORT
+ MKSQUASHFS_OBJS += xz_wrapper.o
+ UNSQUASHFS_OBJS += xz_wrapper.o
+-LIBS += -llzma
+ COMPRESSORS += xz
+ endif
+ 
++ifneq ($(LZMA_XZ_SUPPORT)$(XZ_SUPPORT),)
++ifneq ($(LZMA_LIB),)
++MKSQUASHFS_OBJS += $(LZMA_LIB)
++UNSQUASHFS_OBJS += $(LZMA_LIB)
++else
++LIBS += -llzma
++endif
++endif
++
+ ifeq ($(LZO_SUPPORT),1)
+ CFLAGS += -DLZO_SUPPORT
+ ifdef LZO_DIR
 

--- a/tools/squashfs4/patches/110-lzma.patch
+++ /dev/null
@@ -1,2227 +1,1 @@
-diff -Nur squashfs4.0/squashfs-tools/compressor.c squashfs4.0-lzma-snapshot/squashfs-tools/compressor.c
---- squashfs4.0/squashfs-tools/compressor.c	1970-01-01 01:00:00.000000000 +0100
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/compressor.c	2009-10-20 06:03:37.000000000 +0200
-@@ -0,0 +1,78 @@
-+/*
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-+ * 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.
-+ *
-+ * compressor.c
-+ */
-+
-+#include <stdio.h>
-+#include <string.h>
-+#include "compressor.h"
-+#include "squashfs_fs.h"
-+
-+extern int gzip_compress(void **, char *, char *, int, int, int *);
-+extern int gzip_uncompress(char *, char *, int, int, int *);
-+extern int lzma_compress(void **, char *, char *, int, int, int *);
-+extern int lzma_uncompress(char *, char *, int, int, int *);
-+
-+struct compressor compressor[] = {
-+	{ gzip_compress, gzip_uncompress, ZLIB_COMPRESSION, "gzip", 1 },
-+#ifdef LZMA_SUPPORT
-+	{ lzma_compress, lzma_uncompress, LZMA_COMPRESSION, "lzma", 1 },
-+#else
-+	{ NULL, NULL, LZMA_COMPRESSION, "lzma", 0 },
-+#endif
-+	{ NULL, NULL , 0, "unknown", 0}
-+};
-+
-+
-+struct compressor *lookup_compressor(char *name)
-+{
-+	int i;
-+
-+	for(i = 0; compressor[i].id; i++)
-+		if(strcmp(compressor[i].name, name) == 0)
-+			break;
-+
-+	return &compressor[i];
-+}
-+
-+
-+struct compressor *lookup_compressor_id(int id)
-+{
-+	int i;
-+
-+	for(i = 0; compressor[i].id; i++)
-+		if(id == compressor[i].id)
-+			break;
-+
-+	return &compressor[i];
-+}
-+
-+
-+void display_compressors(char *indent, char *def_comp)
-+{
-+	int i;
-+
-+	for(i = 0; compressor[i].id; i++)
-+		if(compressor[i].supported)
-+			fprintf(stderr, "%s\t%s%s\n", indent,
-+				compressor[i].name,
-+				strcmp(compressor[i].name, def_comp) == 0 ?
-+				" (default)" : "");
-+}
-diff -Nur squashfs4.0/squashfs-tools/compressor.h squashfs4.0-lzma-snapshot/squashfs-tools/compressor.h
---- squashfs4.0/squashfs-tools/compressor.h	1970-01-01 01:00:00.000000000 +0100
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/compressor.h	2009-10-20 06:03:37.000000000 +0200
-@@ -0,0 +1,33 @@
-+/*
-+ *
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-+ * 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.
-+ *
-+ * compressor.h
-+ */
-+
-+struct compressor {
-+	int (*compress)(void **, char *, char *, int, int, int *);
-+	int (*uncompress)(char *, char *, int, int, int *);
-+	int id;
-+	char *name;
-+	int supported;
-+};
-+
-+extern struct compressor *lookup_compressor(char *);
-+extern struct compressor *lookup_compressor_id(int);
-+extern void display_compressors(char *, char *);
-diff -Nur squashfs4.0/squashfs-tools/gzip_wrapper.c squashfs4.0-lzma-snapshot/squashfs-tools/gzip_wrapper.c
---- squashfs4.0/squashfs-tools/gzip_wrapper.c	1970-01-01 01:00:00.000000000 +0100
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/gzip_wrapper.c	2009-10-20 06:03:37.000000000 +0200
-@@ -0,0 +1,80 @@
-+/*
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-+ * 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.
-+ *
-+ * gzip_wrapper.c
-+ */
-+
-+#include <stdlib.h>
-+#include <zlib.h>
-+
-+int gzip_compress(void **strm, char *d, char *s, int size, int block_size,
-+		int *error)
-+{
-+	int res = 0;
-+	z_stream *stream = *strm;
-+
-+	if(stream == NULL) {
-+		if((stream = *strm = malloc(sizeof(z_stream))) == NULL)
-+			goto failed;
-+
-+		stream->zalloc = Z_NULL;
-+		stream->zfree = Z_NULL;
-+		stream->opaque = 0;
-+
-+		if((res = deflateInit(stream, 9)) != Z_OK)
-+			goto failed;
-+	} else if((res = deflateReset(stream)) != Z_OK)
-+		goto failed;
-+
-+	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)
-+		/*
-+		 * Success, return the compressed size.
-+		 */
-+		return (int) stream->total_out;
-+	if(res == Z_OK)
-+		/*
-+		 * Output buffer overflow.  Return out of buffer space
-+		 */
-+		return 0;
-+failed:
-+	/*
-+	 * All other errors return failure, with the compressor
-+	 * specific error code in *error
-+	 */
-+	*error = res;
-+	return -1;
-+}
-+
-+
-+int gzip_uncompress(char *d, char *s, int size, int block_size, int *error)
-+{
-+	int res;
-+	unsigned long bytes = block_size;
-+
-+	res = uncompress((unsigned char *) d, &bytes,
-+		(const unsigned char *) s, size);
-+
-+	*error = res;
-+	return res == Z_OK ? (int) bytes : -1;
-+}
-diff -Nur squashfs4.0/squashfs-tools/lzma_wrapper.c squashfs4.0-lzma-snapshot/squashfs-tools/lzma_wrapper.c
---- squashfs4.0/squashfs-tools/lzma_wrapper.c	1970-01-01 01:00:00.000000000 +0100
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/lzma_wrapper.c	2009-10-14 05:32:57.000000000 +0200
-@@ -0,0 +1,93 @@
-+/*
-+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-+ * 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.
-+ *
-+ * lzma_wrapper.c
-+ */
-+
-+#include <LzmaLib.h>
-+
-+#define LZMA_HEADER_SIZE	(LZMA_PROPS_SIZE + 8)
-+
-+int lzma_compress(void **strm, char *dest, char *src,  int size,int block_size,
-+		int *error)
-+{
-+	unsigned char *d = (unsigned char *) dest, *s = (unsigned char *) src;
-+	size_t props_size = LZMA_PROPS_SIZE,
-+		outlen = block_size - LZMA_HEADER_SIZE;
-+	int res;
-+
-+	res = LzmaCompress(d + LZMA_HEADER_SIZE, &outlen, s, size, d,
-+		&props_size, 5, block_size, 3, 0, 2, 32, 1);
-+	
-+	if(res == SZ_ERROR_OUTPUT_EOF) {
-+		/*
-+		 * Output buffer overflow.  Return out of buffer space error
-+		 */
-+		return 0;
-+	}
-+
-+	if(res != SZ_OK) {
-+		/*
-+		 * All other errors return failure, with the compressor
-+		 * specific error code in *error
-+		 */
-+		*error = res;
-+		return -1;
-+	}
-+
-+	/*
-+	 * Fill in the 8 byte little endian uncompressed size field in the
-+	 * LZMA header.  8 bytes is excessively large for squashfs but
-+	 * this is the standard LZMA header and which is expected by the kernel
-+	 * code
-+	 */
-+	d[LZMA_PROPS_SIZE] = size & 255;
-+	d[LZMA_PROPS_SIZE + 1] = (size >> 8) & 255;
-+	d[LZMA_PROPS_SIZE + 2] = (size >> 16) & 255;
-+	d[LZMA_PROPS_SIZE + 3] = (size >> 24) & 255;
-+	d[LZMA_PROPS_SIZE + 4] = 0;
-+	d[LZMA_PROPS_SIZE + 5] = 0;
-+	d[LZMA_PROPS_SIZE + 6] = 0;
-+	d[LZMA_PROPS_SIZE + 7] = 0;
-+
-+	/*
-+	 * Success, return the compressed size.  Outlen returned by the LZMA
-+	 * compressor does not include the LZMA header space
-+	 */
-+	return outlen + LZMA_HEADER_SIZE;
-+}
-+
-+
-+int lzma_uncompress(char *dest, char *src, int size, int block_size,
-+	int *error)
-+{
-+	unsigned char *d = (unsigned char *) dest, *s = (unsigned char *) src;
-+	size_t outlen, inlen = size - LZMA_HEADER_SIZE;
-+	int res;
-+
-+	outlen = s[LZMA_PROPS_SIZE] |
-+		(s[LZMA_PROPS_SIZE + 1] << 8) |
-+		(s[LZMA_PROPS_SIZE + 2] << 16) |
-+		(s[LZMA_PROPS_SIZE + 3] << 24);
-+
-+	res = LzmaUncompress(d, &outlen, s + LZMA_HEADER_SIZE, &inlen,
-+		s, LZMA_PROPS_SIZE);
-+	
-+	*error = res;
-+	return res == SZ_OK ? outlen : -1;
-+}
-diff -Nur squashfs4.0/squashfs-tools/Makefile squashfs4.0-lzma-snapshot/squashfs-tools/Makefile
---- squashfs4.0/squashfs-tools/Makefile	2009-04-05 04:03:36.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/Makefile	2009-10-22 06:17:12.000000000 +0200
-@@ -1,40 +1,76 @@
-+#
-+# Building LZMA support
-+# Download LZMA sdk (4.65 used in development, other versions may work),
-+# set LZMA_DIR to unpacked source, and uncomment next line
-+LZMA_SUPPORT = 1
-+LZMA_DIR = ../../lzma-4.65
-+
-+#Compression default.
-+COMP_DEFAULT = gzip
-+
-+INCLUDEDIR = -I.
- INSTALL_DIR = /usr/local/bin
- 
--INCLUDEDIR = .
-+MKSQUASHFS_OBJS = mksquashfs.o read_fs.o sort.o swap.o pseudo.o compressor.o \
-+	gzip_wrapper.o
-+
-+UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
-+	unsquash-4.o swap.o compressor.o gzip_wrapper.o
- 
--CFLAGS := -I$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -O2
-+CFLAGS = $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
-+	-D_GNU_SOURCE -DCOMP_DEFAULT=\"$(COMP_DEFAULT)\" -O2 -Wall
- 
-+ifdef LZMA_SUPPORT
-+LZMA_OBJS = $(LZMA_DIR)/C/Alloc.o $(LZMA_DIR)/C/LzFind.o \
-+	$(LZMA_DIR)/C/LzmaDec.o $(LZMA_DIR)/C/LzmaEnc.o $(LZMA_DIR)/C/LzmaLib.o
-+INCLUDEDIR += -I$(LZMA_DIR)/C
-+CFLAGS += -DLZMA_SUPPORT
-+MKSQUASHFS_OBJS += lzma_wrapper.o $(LZMA_OBJS)
-+UNSQUASHFS_OBJS += lzma_wrapper.o $(LZMA_OBJS)
-+endif
-+
-+.PHONY: all
- all: mksquashfs unsquashfs
- 
--mksquashfs: mksquashfs.o read_fs.o sort.o swap.o pseudo.o
--	$(CC) mksquashfs.o read_fs.o sort.o swap.o pseudo.o -lz -lpthread -lm -o $@
-+mksquashfs: $(MKSQUASHFS_OBJS)
-+	$(CC) $(MKSQUASHFS_OBJS) -lz -lpthread -lm -o $@
-+
-+mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h global.h sort.h \
-+	squashfs_swap.h
- 
--mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h global.h sort.h squashfs_swap.h Makefile
-+read_fs.o: read_fs.c squashfs_fs.h read_fs.h global.h squashfs_swap.h
- 
--read_fs.o: read_fs.c squashfs_fs.h read_fs.h global.h squashfs_swap.h Makefile
-+sort.o: sort.c squashfs_fs.h global.h sort.h
- 
--sort.o: sort.c squashfs_fs.h global.h sort.h Makefile
-+swap.o: swap.c
- 
--swap.o: swap.c Makefile
-+pseudo.o: pseudo.c pseudo.h
- 
--pseudo.o: pseudo.c pseudo.h Makefile
-+compressor.o: compressor.c compressor.h
- 
--unsquashfs: unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o unsquash-4.o swap.o
--	$(CC) unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o unsquash-4.o swap.o -lz -lpthread -lm -o $@
-+unsquashfs: $(UNSQUASHFS_OBJS)
-+	$(CC) $(UNSQUASHFS_OBJS) -lz -lpthread -lm -o $@
- 
--unsquashfs.o: unsquashfs.h unsquashfs.c squashfs_fs.h squashfs_swap.h squashfs_compat.h global.h Makefile
-+unsquashfs.o: unsquashfs.h unsquashfs.c squashfs_fs.h squashfs_swap.h \
-+	squashfs_compat.h global.h
- 
--unsquash-1.o: unsquashfs.h unsquash-1.c squashfs_fs.h squashfs_compat.h global.h Makefile
-+unsquash-1.o: unsquashfs.h unsquash-1.c squashfs_fs.h squashfs_compat.h \
-+	global.h
- 
--unsquash-2.o: unsquashfs.h unsquash-2.c unsquashfs.h squashfs_fs.h squashfs_compat.h global.h Makefile
-+unsquash-2.o: unsquashfs.h unsquash-2.c unsquashfs.h squashfs_fs.h \
-+	squashfs_compat.h global.h
- 
--unsquash-3.o: unsquashfs.h unsquash-3.c squashfs_fs.h squashfs_compat.h global.h Makefile
-+unsquash-3.o: unsquashfs.h unsquash-3.c squashfs_fs.h squashfs_compat.h \
-+	global.h
- 
--unsquash-4.o: unsquashfs.h unsquash-4.c squashfs_fs.h squashfs_swap.h global.h Makefile
-+unsquash-4.o: unsquashfs.h unsquash-4.c squashfs_fs.h squashfs_swap.h \
-+	global.h
- 
-+.PHONY: clean
- clean:
- 	-rm -f *.o mksquashfs unsquashfs
- 
-+.PHONY: install
- install: mksquashfs unsquashfs
- 	mkdir -p $(INSTALL_DIR)
- 	cp mksquashfs $(INSTALL_DIR)
-diff -Nur squashfs4.0/squashfs-tools/mksquashfs.c squashfs4.0-lzma-snapshot/squashfs-tools/mksquashfs.c
---- squashfs4.0/squashfs-tools/mksquashfs.c	2009-04-05 23:22:48.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/mksquashfs.c	2009-10-20 06:03:38.000000000 +0200
-@@ -36,7 +36,6 @@
- #include <errno.h>
- #include <dirent.h>
- #include <string.h>
--#include <zlib.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <setjmp.h>
-@@ -47,6 +46,7 @@
- #include <math.h>
- #include <regex.h>
- #include <fnmatch.h>
-+#include <sys/wait.h>
- 
- #ifndef linux
- #define __BYTE_ORDER BYTE_ORDER
-@@ -64,6 +64,7 @@
- #include "global.h"
- #include "sort.h"
- #include "pseudo.h"
-+#include "compressor.h"
- 
- #ifdef SQUASHFS_TRACE
- #define TRACE(s, args...)	do { \
-@@ -245,10 +246,8 @@
- /* 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;
-+	char			*name;
-+	struct inode_info	inode;
- };
- struct old_root_entry_info *old_root_entry;
- 
-@@ -371,10 +370,15 @@
- int reader_buffer_size;
- int fragment_buffer_size;
- 
-+/* compression operations structure */
-+static struct compressor *comp;
-+char *comp_name = COMP_DEFAULT;
-+
- char *read_from_disk(long long start, unsigned int avail_bytes);
- 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, char *source);
-+extern struct compressor  *read_super(int fd, squashfs_super_block *sBlk,
-+	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,
-@@ -831,83 +835,32 @@
- }
- 
- 
--unsigned int mangle2(z_stream **strm, char *d, char *s, int size,
-+int mangle2(void **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);
--	}
-+	int error, c_byte = 0;
- 
--	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);
-+	if(!uncompressed) {
-+		c_byte = comp->compress(strm, d, s, size, block_size, &error);
-+		if(c_byte == -1)
-+			BAD_ERROR("mangle2:: %s compress failed with error "
-+				"code %d\n", comp->name, error);
- 	}
- 
--	c_byte = stream->total_out;
--
--	if(res != Z_STREAM_END || c_byte >= size) {
--notcompressed:
-+	if(c_byte == 0 || c_byte >= size) {
- 		memcpy(d, s, size);
- 		return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
- 			SQUASHFS_COMPRESSED_BIT);
- 	}
- 
--	return (unsigned int) c_byte;
-+	return c_byte;
- }
- 
- 
--unsigned int mangle(char *d, char *s, int size, int block_size,
-+int mangle(char *d, char *s, int size, int block_size,
- 	int uncompressed, int data_block)
- {
--	static z_stream *stream = NULL;
-+	static void *stream = NULL;
- 
- 	return mangle2(&stream, d, s, size, block_size, uncompressed,
- 		data_block);
-@@ -1660,8 +1613,7 @@
- 	pthread_mutex_unlock(&fragment_mutex);
- 
- 	if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
--		int res;
--		unsigned long bytes = block_size;
-+		int error, res;
- 		char *data;
- 
- 		if(compressed_buffer)
-@@ -1669,19 +1621,11 @@
- 		else
- 			data = read_from_disk(start_block, size);
- 
--		res = uncompress((unsigned char *) buffer->data, &bytes,
--			(const unsigned char *) data, size);
--		if(res != Z_OK) {
--			if(res == Z_MEM_ERROR)
--				BAD_ERROR("zlib::uncompress failed, not enough "
--					"memory\n");
--			else if(res == Z_BUF_ERROR)
--				BAD_ERROR("zlib::uncompress failed, not enough "
--					"room in output buffer\n");
--			else
--				BAD_ERROR("zlib::uncompress failed,"
--					"  unknown error %d\n", res);
--		}
-+		res = comp->uncompress(buffer->data, data, size, block_size,
-+			&error);
-+		if(res == -1)
-+			BAD_ERROR("%s uncompress failed with error code %d\n",
-+				comp->name, error);
- 	} else if(compressed_buffer)
- 		memcpy(buffer->data, compressed_buffer->data, size);
- 	else
-@@ -1733,9 +1677,7 @@
- 		entry->buffer->block = bytes;
- 		bytes += compressed_size;
- 		fragments_outstanding --;
--		pthread_mutex_unlock(&fragment_mutex);
- 		queue_put(to_writer, entry->buffer);
--		pthread_mutex_lock(&fragment_mutex);
- 		TRACE("fragment_locked writing fragment %d, compressed size %d"
- 			"\n", entry->fragment, compressed_size);
- 		free(entry);
-@@ -1758,6 +1700,8 @@
- 	pthread_mutex_lock(&fragment_mutex);
- 	insert_fragment_list(&frag_locked_list, entry);
- 	pthread_mutex_unlock(&fragment_mutex);
-+
-+	return TRUE;
- }
- 
- 
-@@ -1824,7 +1768,9 @@
- 	unsigned short c_byte;
- 	char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
- 	
-+#ifdef SQUASHFS_TRACE
- 	long long obytes = bytes;
-+#endif
- 
- 	for(i = 0; i < meta_blocks; i++) {
- 		int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
-@@ -2170,11 +2116,85 @@
- }
- 
- 
-+static int seq = 0;
-+void reader_read_process(struct dir_ent *dir_ent)
-+{
-+	struct file_buffer *prev_buffer = NULL, *file_buffer;
-+	int status, res, byte, count = 0;
-+	int file = get_pseudo_file(dir_ent->inode->pseudo_id)->fd;
-+	int child = get_pseudo_file(dir_ent->inode->pseudo_id)->child;
-+	long long bytes = 0;
-+
-+	while(1) {
-+		file_buffer = cache_get(reader_buffer, 0, 0);
-+		file_buffer->sequence = seq ++;
-+
-+		byte = read_bytes(file, file_buffer->data, block_size);
-+		if(byte == -1)
-+			goto read_err;
-+
-+		file_buffer->size = byte;
-+		file_buffer->file_size = -1;
-+		file_buffer->block = count ++;
-+		file_buffer->error = FALSE;
-+		file_buffer->fragment = FALSE;
-+		bytes += byte;
-+
-+		if(byte == 0)
-+			break;
-+
-+		/*
-+		 * Update estimated_uncompressed block count.  This is done
-+		 * on every block rather than waiting for all blocks to be
-+		 * read incase write_file_process() is running in parallel
-+		 * with this.  Otherwise cur uncompressed block count may
-+		 * get ahead of the total uncompressed block count.
-+		 */ 
-+		estimated_uncompressed ++;
-+
-+		if(prev_buffer)
-+			queue_put(from_reader, prev_buffer);
-+		prev_buffer = file_buffer;
-+	}
-+
-+	/*
-+ 	 * Update inode file size now that the size of the dynamic pseudo file
-+	 * is known.  This is needed for the -info option.
-+	 */
-+	dir_ent->inode->buf.st_size = bytes;
-+
-+	res = waitpid(child, &status, 0);
-+	if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
-+		goto read_err;
-+
-+	if(prev_buffer == NULL)
-+		prev_buffer = file_buffer;
-+	else {
-+		cache_block_put(file_buffer);
-+		seq --;
-+	}
-+	prev_buffer->file_size = bytes;
-+	prev_buffer->fragment = !no_fragments &&
-+		(count == 2 || always_use_fragments) && (byte < block_size);
-+	queue_put(from_reader, prev_buffer);
-+
-+	return;
-+
-+read_err:
-+	if(prev_buffer) {
-+		cache_block_put(file_buffer);
-+		seq --;
-+		file_buffer = prev_buffer;
-+	}
-+	file_buffer->error = TRUE;
-+	queue_put(from_deflate, file_buffer);
-+}
-+
-+
- void reader_read_file(struct dir_ent *dir_ent)
- {
- 	struct stat *buf = &dir_ent->inode->buf, buf2;
- 	struct file_buffer *file_buffer;
--	static int index = 0;
- 	int blocks, byte, count, expected, file, frag_block;
- 	long long bytes, read_size;
- 
-@@ -2202,7 +2222,7 @@
- 		if(file_buffer)
- 			queue_put(from_reader, file_buffer);
- 		file_buffer = cache_get(reader_buffer, 0, 0);
--		file_buffer->sequence = index ++;
-+		file_buffer->sequence = seq ++;
- 
- 		byte = file_buffer->size = read_bytes(file, file_buffer->data,
- 			block_size);
-@@ -2238,7 +2258,7 @@
- 
- read_err:
- 	file_buffer = cache_get(reader_buffer, 0, 0);
--	file_buffer->sequence = index ++;
-+	file_buffer->sequence = seq ++;
- read_err2:
- 	file_buffer->error = TRUE;
- 	queue_put(from_deflate, file_buffer);
-@@ -2262,9 +2282,14 @@
- 	for(i = 0; i < dir->count; i++) {
- 		struct dir_ent *dir_ent = dir->list[i];
- 		struct stat *buf = &dir_ent->inode->buf;
--		if(dir_ent->data)
-+		if(dir_ent->inode->root_entry)
- 			continue;
- 
-+		if(dir_ent->inode->pseudo_file) {
-+			reader_read_process(dir_ent);
-+			continue;
-+		}
-+
- 		switch(buf->st_mode & S_IFMT) {
- 			case S_IFREG:
- 				reader_read_file(dir_ent);
-@@ -2365,7 +2390,7 @@
- 
- void *deflator(void *arg)
- {
--	z_stream *stream = NULL;
-+	void *stream = NULL;
- 	int oldstate;
- 
- 	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-@@ -2402,7 +2427,7 @@
- 
- void *frag_deflator(void *arg)
- {
--	z_stream *stream = NULL;
-+	void *stream = NULL;
- 	int oldstate;
- 
- 	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-@@ -2426,8 +2451,8 @@
- 			write_buffer->block = bytes;
- 			bytes += compressed_size;
- 			fragments_outstanding --;
--			pthread_mutex_unlock(&fragment_mutex);
- 			queue_put(to_writer, write_buffer);
-+			pthread_mutex_unlock(&fragment_mutex);
- 			TRACE("Writing fragment %lld, uncompressed size %d, "
- 				"compressed size %d\n", file_buffer->block,
- 				file_buffer->size, compressed_size);
-@@ -2674,6 +2699,98 @@
- }
- 
- 
-+int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
-+	struct file_buffer *read_buffer, int *duplicate_file)
-+{
-+	long long read_size, file_bytes, start;
-+	struct fragment *fragment;
-+	unsigned int *block_list = NULL;
-+	int block = 0, status;
-+	long long sparse = 0;
-+	struct file_buffer *fragment_buffer = NULL;
-+
-+	*duplicate_file = FALSE;
-+
-+	lock_fragments();
-+
-+	file_bytes = 0;
-+	start = bytes;
-+	while (1) {
-+		read_size = read_buffer->file_size;
-+		if(read_buffer->fragment && read_buffer->c_byte)
-+			fragment_buffer = read_buffer;
-+		else {
-+			block_list = realloc(block_list, (block + 1) *
-+				sizeof(unsigned int));
-+			if(block_list == NULL)
-+				BAD_ERROR("Out of memory allocating block_list"
-+					"\n");
-+			block_list[block ++] = read_buffer->c_byte;
-+			if(read_buffer->c_byte) {
-+				read_buffer->block = bytes;
-+				bytes += read_buffer->size;
-+				cache_rehash(read_buffer, read_buffer->block);
-+				file_bytes += read_buffer->size;
-+				queue_put(to_writer, read_buffer);
-+			} else {
-+				sparse += read_buffer->size;
-+				cache_block_put(read_buffer);
-+			}
-+		}
-+		inc_progress_bar();
-+
-+		if(read_size != -1)
-+			break;
-+
-+		read_buffer = get_file_buffer(from_deflate);
-+		if(read_buffer->error)
-+			goto read_err;
-+	}
-+
-+	unlock_fragments();
-+	fragment = get_and_fill_fragment(fragment_buffer);
-+	cache_block_put(fragment_buffer);
-+
-+	if(duplicate_checking)
-+		add_non_dup(read_size, file_bytes, block_list, start, fragment,
-+			0, 0, FALSE);
-+	file_count ++;
-+	total_bytes += read_size;
-+
-+	if(read_size < (1LL << 32) && start < (1LL << 32) && sparse == 0)
-+		create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, read_size,
-+			start, block, block_list, fragment, NULL, 0);
-+	else
-+		create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, read_size,
-+			start, block, block_list, fragment, NULL, sparse);
-+
-+	if(duplicate_checking == FALSE)
-+		free(block_list);
-+
-+	return 0;
-+
-+read_err:
-+	cur_uncompressed -= block;
-+	status = read_buffer->error;
-+	bytes = start;
-+	if(!block_device) {
-+		int res;
-+
-+		queue_put(to_writer, NULL);
-+		if(queue_get(from_writer) != 0)
-+			EXIT_MKSQUASHFS();
-+		res = ftruncate(fd, bytes);
-+		if(res != 0)
-+			BAD_ERROR("Failed to truncate dest file because %s\n",
-+				strerror(errno));
-+	}
-+	unlock_fragments();
-+	free(block_list);
-+	cache_block_put(read_buffer);
-+	return status;
-+}
-+
-+
- int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
- 	long long read_size, struct file_buffer *read_buffer,
- 	int *duplicate_file)
-@@ -2941,7 +3058,10 @@
- 	
- 	read_size = read_buffer->file_size;
- 
--	if(read_size == 0) {
-+	if(read_size == -1)
-+		status = write_file_process(inode, dir_ent, read_buffer,
-+			duplicate_file);
-+	else if(read_size == 0) {
- 		write_file_empty(inode, dir_ent, duplicate_file);
- 		cache_block_put(read_buffer);
- 	} else if(read_buffer->fragment && read_buffer->c_byte)
-@@ -3036,6 +3156,8 @@
- 
- 	memcpy(&inode->buf, buf, sizeof(struct stat));
- 	inode->read = FALSE;
-+	inode->root_entry = FALSE;
-+	inode->pseudo_file = FALSE;
- 	inode->inode = SQUASHFS_INVALID_BLK;
- 	inode->nlink = 1;
- 
-@@ -3056,7 +3178,7 @@
- 
- 
- inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir,
--	struct inode_info *inode_info, void *data, struct dir_info *dir)
-+	struct inode_info *inode_info, struct dir_info *dir)
- {
- 	if((dir->count % DIR_ENTRIES) == 0) {
- 		dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) *
-@@ -3075,8 +3197,7 @@
- 		NULL;
- 	dir->list[dir->count]->inode = inode_info;
- 	dir->list[dir->count]->dir = sub_dir;
--	dir->list[dir->count]->our_dir = dir;
--	dir->list[dir->count++]->data = data;
-+	dir->list[dir->count++]->our_dir = dir;
- 	dir->byte_count += strlen(name) + sizeof(squashfs_dir_entry);
- }
- 
-@@ -3128,10 +3249,10 @@
- 
- 	if(dir->count < old_root_entries)
- 		for(i = 0; i < old_root_entries; i++) {
--			if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
-+			if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
- 				dir->directory_count ++;
--			add_dir_entry(old_root_entry[i].name, "", NULL, NULL,
--				&old_root_entry[i], dir);
-+			add_dir_entry(old_root_entry[i].name, "", NULL,
-+				&old_root_entry[i].inode, dir);
- 		}
- 
- 	while(index < source) {
-@@ -3167,10 +3288,10 @@
- 
- 	if(dir->count < old_root_entries)
- 		for(i = 0; i < old_root_entries; i++) {
--			if(old_root_entry[i].type == SQUASHFS_DIR_TYPE)
-+			if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
- 				dir->directory_count ++;
--			add_dir_entry(old_root_entry[i].name, "", NULL, NULL,
--				&old_root_entry[i], dir);
-+			add_dir_entry(old_root_entry[i].name, "", NULL,
-+				&old_root_entry[i].inode, dir);
- 		}
- 
- 	if((d_name = readdir(dir->linuxdir)) != NULL) {
-@@ -3215,7 +3336,7 @@
- 	int current_count;
- 
- 	while((current_count = dir_info->current_count++) < dir_info->count)
--		if(dir_info->list[current_count]->data)
-+		if(dir_info->list[current_count]->inode->root_entry)
- 			continue;
- 		else 
- 			return dir_info->list[current_count];
-@@ -3240,11 +3361,11 @@
- 	int current_count;
- 
- 	while((current_count = dir_info->current_count++) < dir_info->count)
--		if(dir_info->list[current_count]->data)
--			add_dir(dir_info->list[current_count]->data->inode,
--				dir_info->list[current_count]->data->inode_number,
-+		if(dir_info->list[current_count]->inode->root_entry)
-+			add_dir(dir_info->list[current_count]->inode->inode,
-+				dir_info->list[current_count]->inode->inode_number,
- 				dir_info->list[current_count]->name,
--				dir_info->list[current_count]->data->type, dir);
-+				dir_info->list[current_count]->inode->type, dir);
- 		else 
- 			return dir_info->list[current_count];
- 	return NULL;	
-@@ -3313,7 +3434,6 @@
- 	dir_ent->name = dir_ent->pathname = strdup(pathname);
- 	dir_ent->dir = dir_info;
- 	dir_ent->our_dir = NULL;
--	dir_ent->data = NULL;
- 	dir_info->dir_ent = dir_ent;
- 
- 	if(sorted)
-@@ -3383,7 +3503,7 @@
- 			sub_dir = NULL;
- 
- 		add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf),
--			NULL, dir);
-+			dir);
- 	}
- 
- 	scan1_freedir(dir);
-@@ -3399,7 +3519,7 @@
- 	struct dir_ent *dir_ent;
- 	struct pseudo_entry *pseudo_ent;
- 	struct stat buf;
--	static pseudo_ino = 1;
-+	static int pseudo_ino = 1;
- 	
- 	if(dir == NULL && (dir = scan1_opendir("")) == NULL)
- 		return NULL;
-@@ -3415,6 +3535,29 @@
- 
- 	while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
- 		dir_ent = scan2_lookup(dir, pseudo_ent->name);
-+		if(pseudo_ent->dev->type == 's') {
-+			struct stat *buf;
-+			if(dir_ent == NULL) {
-+				ERROR("Pseudo set file \"%s\" does not exist "
-+					"in source filesystem.  Ignoring\n",
-+					pseudo_ent->pathname);
-+				continue;
-+			}
-+			if(dir_ent->inode->root_entry) {
-+				ERROR("Pseudo set file \"%s\" is a pre-existing"
-+					" file in the filesystem being appended"
-+					"  to.  It cannot be modified. "
-+					"Ignoring!\n", pseudo_ent->pathname);
-+				continue;
-+			}
-+			buf = &dir_ent->inode->buf;
-+			buf->st_mode = (buf->st_mode & S_IFMT) |
-+				pseudo_ent->dev->mode;
-+			buf->st_uid = pseudo_ent->dev->uid;
-+			buf->st_gid = pseudo_ent->dev->gid;
-+			continue;
-+		}
-+
- 		if(dir_ent) {
- 			ERROR("Pseudo file \"%s\" exists in source filesystem "
- 				"\"%s\"\n", pseudo_ent->pathname,
-@@ -3444,8 +3587,29 @@
- 		buf.st_mtime = time(NULL);
- 		buf.st_ino = pseudo_ino ++;
- 
--		add_dir_entry(pseudo_ent->name, pseudo_ent->pathname, sub_dir,
--			lookup_inode(&buf), NULL, dir);
-+		if(pseudo_ent->dev->type == 'f') {
-+#ifdef USE_TMP_FILE
-+			struct stat buf2;
-+			int res = stat(pseudo_ent->dev->filename, &buf2);
-+			if(res == -1) {
-+				ERROR("Stat on pseudo file \"%s\" failed, "
-+					"skipping...", pseudo_ent->pathname);
-+				continue;
-+			}
-+			buf.st_size = buf2.st_size;
-+			add_dir_entry(pseudo_ent->name,
-+				pseudo_ent->dev->filename, sub_dir,
-+				lookup_inode(&buf), dir);
-+#else
-+			struct inode_info *inode = lookup_inode(&buf);
-+			inode->pseudo_id = pseudo_ent->dev->pseudo_id;
-+			inode->pseudo_file = TRUE;		
-+			add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
-+				sub_dir, inode, dir);
-+#endif
-+		} else
-+			add_dir_entry(pseudo_ent->name, pseudo_ent->pathname,
-+				sub_dir, lookup_inode(&buf), dir);
- 	}
- 
- 	scan2_freedir(dir);
-@@ -3482,8 +3646,9 @@
- 						&duplicate_file);
- 					INFO("file %s, uncompressed size %lld "
- 						"bytes %s\n", filename,
--						buf->st_size, duplicate_file ?
--						"DUPLICATE" : "");
-+						(long long) buf->st_size,
-+						duplicate_file ?  "DUPLICATE" :
-+						 "");
- 					break;
- 
- 				case S_IFDIR:
-@@ -3557,6 +3722,7 @@
- 						INFO("file %s, uncompressed "
- 							"size %lld bytes LINK"
- 							"\n", filename,
-+							(long long)
- 							buf->st_size);
- 					break;
- 				case SQUASHFS_SYMLINK_TYPE:
-@@ -3667,10 +3833,11 @@
- 		BAD_ERROR("Out of memory in old root directory entries "
- 			"reallocation\n");
- 
--	strcpy(old_root_entry[old_root_entries].name, name);
--	old_root_entry[old_root_entries].inode = inode;
--	old_root_entry[old_root_entries].inode_number = inode_number;
--	old_root_entry[old_root_entries++].type = type;
-+	old_root_entry[old_root_entries].name = strdup(name);
-+	old_root_entry[old_root_entries].inode.inode = inode;
-+	old_root_entry[old_root_entries].inode.inode_number = inode_number;
-+	old_root_entry[old_root_entries].inode.type = type;
-+	old_root_entry[old_root_entries++].inode.root_entry = TRUE;
- }
- 
- 
-@@ -4137,7 +4304,7 @@
- 
- 
- #define VERSION() \
--	printf("mksquashfs version 4.0 (2009/04/05)\n");\
-+	printf("mksquashfs version 4.1-CVS (2009/09/20)\n");\
- 	printf("copyright (C) 2009 Phillip Lougher <phillip@lougher.demon.co.uk>\n\n"); \
- 	printf("This program is free software; you can redistribute it and/or\n");\
- 	printf("modify it under the terms of the GNU General Public License\n");\
-@@ -4172,26 +4339,28 @@
- 	source_path = argv + 1;
- 	source = i - 2;
- 	for(; i < argc; i++) {
--		if(strcmp(argv[i], "-pf") == 0) {
-+		if(strcmp(argv[i], "-comp") == 0) {
- 			if(++i == argc) {
--				ERROR("%s: -pf missing filename\n", argv[0]);
-+				ERROR("%s: -comp missing compression type\n",
-+					argv[0]);
- 				exit(1);
- 			}
--			if(read_pseudo_file(&pseudo, argv[i]) == FALSE) {
--				ERROR("Failed to parse pseudo file \"%s\"\n",
--					argv[i]);
-+			comp_name = argv[i];
-+		} else if(strcmp(argv[i], "-pf") == 0) {
-+			if(++i == argc) {
-+				ERROR("%s: -pf missing filename\n", argv[0]);
- 				exit(1);
- 			}
-+			if(read_pseudo_file(&pseudo, argv[i]) == FALSE)
-+				exit(1);
- 		} else if(strcmp(argv[i], "-p") == 0) {
- 			if(++i == argc) {
- 				ERROR("%s: -p missing pseudo file definition\n",
- 					argv[0]);
- 				exit(1);
- 			}
--			if(read_pseudo_def(&pseudo, argv[i]) == FALSE) {
--				ERROR("Failed to parse pseudo definition\n");
-+			if(read_pseudo_def(&pseudo, argv[i]) == FALSE)
- 				exit(1);
--			}
- 		} else if(strcmp(argv[i], "-recover") == 0) {
- 			if(++i == argc) {
- 				ERROR("%s: -recover missing recovery file\n",
-@@ -4394,34 +4563,16 @@
- printOptions:
- 			ERROR("SYNTAX:%s source1 source2 ...  dest [options] "
- 				"[-e list of exclude\ndirs/files]\n", argv[0]);
--			ERROR("\nOptions are\n");
--			ERROR("-version\t\tprint version, licence and "
--				"copyright message\n");
--			ERROR("-recover <name>\t\trecover filesystem data "
--				"using recovery file <name>\n");
--			ERROR("-no-recovery\t\tdon't generate a recovery "
--				"file\n");
--			ERROR("-info\t\t\tprint files written to filesystem\n");
--			ERROR("-no-exports\t\tdon't make the filesystem "
--				"exportable via NFS\n");
--			ERROR("-no-progress\t\tdon't display the progress "
--				"bar\n");
--			ERROR("-no-sparse\t\tdon't detect sparse files\n");
-+			ERROR("\nFilesystem build options:\n");
-+			ERROR("-comp <comp>\t\tselect <comp> compression\n");
-+			ERROR("\t\t\tCompressors available:\n");
-+			display_compressors("\t\t\t", COMP_DEFAULT);
- 			ERROR("-b <block_size>\t\tset data block to "
- 				"<block_size>.  Default %d bytes\n",
- 				SQUASHFS_FILE_SIZE);
--			ERROR("-processors <number>\tUse <number> processors."
--				"  By default will use number of\n");
--			ERROR("\t\t\tprocessors available\n");
--			ERROR("-read-queue <size>\tSet input queue to <size> "
--				"Mbytes.  Default %d Mbytes\n",
--				READER_BUFFER_DEFAULT);
--			ERROR("-write-queue <size>\tSet output queue to <size> "
--				"Mbytes.  Default %d Mbytes\n",
--				WRITER_BUFFER_DEFAULT);
--			ERROR("-fragment-queue <size>\tSet fagment queue to "
--				"<size> Mbytes.  Default %d Mbytes\n",
--				FRAGMENT_BUFFER_DEFAULT);
-+			ERROR("-no-exports\t\tdon't make the filesystem "
-+				"exportable via NFS\n");
-+			ERROR("-no-sparse\t\tdon't detect sparse files\n");
- 			ERROR("-noI\t\t\tdo not compress inode table\n");
- 			ERROR("-noD\t\t\tdo not compress data blocks\n");
- 			ERROR("-noF\t\t\tdo not compress fragment blocks\n");
-@@ -4430,13 +4581,34 @@
- 				"files larger than block size\n");
- 			ERROR("-no-duplicates\t\tdo not perform duplicate "
- 				"checking\n");
--			ERROR("-noappend\t\tdo not append to existing "
--				"filesystem\n");
-+			ERROR("-all-root\t\tmake all files owned by root\n");
-+			ERROR("-force-uid uid\t\tset all file uids to uid\n");
-+			ERROR("-force-gid gid\t\tset all file gids to gid\n");
-+			ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
-+				"of 4K\n");
- 			ERROR("-keep-as-directory\tif one source directory is "
- 				"specified, create a root\n");
- 			ERROR("\t\t\tdirectory containing that directory, "
- 				"rather than the\n");
- 			ERROR("\t\t\tcontents of the directory\n");
-+			ERROR("\nFilesystem filter options:\n");
-+			ERROR("-p <pseudo-definition>\tAdd pseudo file definition\n");
-+			ERROR("-pf <pseudo-file>\tAdd list of pseudo file definitions\n");
-+			ERROR("-sort <sort_file>\tsort files according to "
-+				"priorities in <sort_file>.  One\n");
-+			ERROR("\t\t\tfile or dir with priority per line.  "
-+				"Priority -32768 to\n");
-+			ERROR("\t\t\t32767, default priority 0\n");
-+			ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
-+				"  One per line\n");
-+			ERROR("-wildcards\t\tAllow extended shell wildcards "
-+				"(globbing) to be used in\n\t\t\texclude "
-+				"dirs/files\n");
-+			ERROR("-regex\t\t\tAllow POSIX regular expressions to "
-+				"be used in exclude\n\t\t\tdirs/files\n");
-+			ERROR("\nFilesystem append options:\n");
-+			ERROR("-noappend\t\tdo not append to existing "
-+				"filesystem\n");
- 			ERROR("-root-becomes <name>\twhen appending source "
- 				"files/directories, make the\n");
- 			ERROR("\t\t\toriginal root become a subdirectory in "
-@@ -4444,11 +4616,29 @@
- 			ERROR("\t\t\tcalled <name>, rather than adding the new "
- 				"source items\n");
- 			ERROR("\t\t\tto the original root\n");
--			ERROR("-all-root\t\tmake all files owned by root\n");
--			ERROR("-force-uid uid\t\tset all file uids to uid\n");
--			ERROR("-force-gid gid\t\tset all file gids to gid\n");
--			ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
--				"of 4K\n");
-+			ERROR("\nMksquashfs runtime options:\n");
-+			ERROR("-version\t\tprint version, licence and "
-+				"copyright message\n");
-+			ERROR("-recover <name>\t\trecover filesystem data "
-+				"using recovery file <name>\n");
-+			ERROR("-no-recovery\t\tdon't generate a recovery "
-+				"file\n");
-+			ERROR("-info\t\t\tprint files written to filesystem\n");
-+			ERROR("-no-progress\t\tdon't display the progress "
-+				"bar\n");
-+			ERROR("-processors <number>\tUse <number> processors."
-+				"  By default will use number of\n");
-+			ERROR("\t\t\tprocessors available\n");
-+			ERROR("-read-queue <size>\tSet input queue to <size> "
-+				"Mbytes.  Default %d Mbytes\n",
-+				READER_BUFFER_DEFAULT);
-+			ERROR("-write-queue <size>\tSet output queue to <size> "
-+				"Mbytes.  Default %d Mbytes\n",
-+				WRITER_BUFFER_DEFAULT);
-+			ERROR("-fragment-queue <size>\tSet fagment queue to "
-+				"<size> Mbytes.  Default %d Mbytes\n",
-+				FRAGMENT_BUFFER_DEFAULT);
-+			ERROR("\nMiscellaneous options:\n");
- 			ERROR("-root-owned\t\talternative name for -all-root"
- 				"\n");
- 			ERROR("-noInodeCompression\talternative name for -noI"
-@@ -4457,20 +4647,6 @@
- 				"\n");
- 			ERROR("-noFragmentCompression\talternative name for "
- 				"-noF\n");
--			ERROR("-sort <sort_file>\tsort files according to "
--				"priorities in <sort_file>.  One\n");
--			ERROR("\t\t\tfile or dir with priority per line.  "
--				"Priority -32768 to\n");
--			ERROR("\t\t\t32767, default priority 0\n");
--			ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
--				"  One per line\n");
--			ERROR("-wildcards\t\tAllow extended shell wildcards "
--				"(globbing) to be used in\n\t\t\texclude "
--				"dirs/files\n");
--			ERROR("-regex\t\t\tAllow POSIX regular expressions to "
--				"be used in exclude\n\t\t\tdirs/files\n");
--			ERROR("-p <pseudo-definition>\tAdd pseudo file definition\n");
--			ERROR("-pf <pseudo-file>\tAdd list of pseudo file definitions\n");
- 			exit(1);
- 		}
- 	}
-@@ -4548,11 +4724,10 @@
- 			fclose(fd);
- 		} else if(strcmp(argv[i], "-e") == 0)
- 			break;
--		else if(strcmp(argv[i], "-b") == 0 ||
--				strcmp(argv[i], "-root-becomes") == 0 ||
-+		else if(strcmp(argv[i], "-root-becomes") == 0 ||
- 				strcmp(argv[i], "-sort") == 0 ||
- 				strcmp(argv[i], "-pf") == 0 ||
--				strcmp(argv[i], "-p") == 0)
-+				strcmp(argv[i], "-comp") == 0)
- 			i++;
- 
- 	if(i != argc) {
-@@ -4574,11 +4749,10 @@
- 			sorted ++;
- 		} else if(strcmp(argv[i], "-e") == 0)
- 			break;
--		else if(strcmp(argv[i], "-b") == 0 ||
--				strcmp(argv[i], "-root-becomes") == 0 ||
-+		else if(strcmp(argv[i], "-root-becomes") == 0 ||
- 				strcmp(argv[i], "-ef") == 0 ||
- 				strcmp(argv[i], "-pf") == 0 ||
--				strcmp(argv[i], "-p") == 0)
-+				strcmp(argv[i], "-comp") == 0)
- 			i++;
- 
- #ifdef SQUASHFS_TRACE
-@@ -4586,7 +4760,8 @@
- #endif
- 
- 	if(!delete) {
--	        if(read_super(fd, &sBlk, argv[source + 1]) == 0) {
-+	        comp = read_super(fd, &sBlk, argv[source + 1]);
-+	        if(comp == NULL) {
- 			ERROR("Failed to read existing filesystem - will not "
- 				"overwrite - ABORTING!\n");
- 			ERROR("To force Mksquashfs to write to this block "
-@@ -4603,6 +4778,15 @@
- 		always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
- 		duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
- 		exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
-+	} else {
-+		comp = lookup_compressor(comp_name);
-+		if(!comp->supported) {
-+			ERROR("FATAL_ERROR: Compressor \"%s\" is not "
-+				"supported!\n", comp_name);
-+			ERROR("Compressors available:\n");
-+			display_compressors("", COMP_DEFAULT);
-+			EXIT_MKSQUASHFS();
-+		}
- 	}
- 
- 	initialise_threads();
-@@ -4648,8 +4832,8 @@
- 			"size %d\n", SQUASHFS_MAJOR, s_minor, argv[source + 1],
- 			block_size);
- 		printf("All -b, -noI, -noD, -noF, no-duplicates, no-fragments, "
--			"-always-use-fragments and -exportable options ignored"
--			"\n");
-+			"-always-use-fragments,\n-exportable and -comp options "
-+			"ignored\n");
- 		printf("\nIf appending is not wanted, please re-run with "
- 			"-noappend specified!\n\n");
- 
-@@ -4803,8 +4987,7 @@
- 
- 	sBlk.bytes_used = bytes;
- 
--	/* Only compression supported */
--	sBlk.compression = ZLIB_COMPRESSION;
-+	sBlk.compression = comp->id;
- 
- 	/* Xattrs are not currently supported */
- 	sBlk.xattr_table_start = SQUASHFS_INVALID_BLK;
-@@ -4820,6 +5003,8 @@
- 
- 	close(fd);
- 
-+	delete_pseudo_files();
-+
- 	if(recovery_file[0] != '\0')
- 		unlink(recovery_file);
- 
-@@ -4827,9 +5012,9 @@
- 		* sizeof(unsigned short) + guid_count * sizeof(unsigned short) +
- 		sizeof(squashfs_super_block);
- 
--	printf("\n%sSquashfs %d.%d filesystem, data block size %d\n",
--		exportable ? "Exportable " : "", SQUASHFS_MAJOR, SQUASHFS_MINOR,
--		block_size);
-+	printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
-+		" %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
-+		SQUASHFS_MINOR, comp->name, block_size);
- 	printf("\t%s data, %s metadata, %s fragments\n",
- 		noD ? "uncompressed" : "compressed", noI ?  "uncompressed" :
- 		"compressed", no_fragments ? "no" : noF ? "uncompressed" :
-diff -Nur squashfs4.0/squashfs-tools/pseudo.c squashfs4.0-lzma-snapshot/squashfs-tools/pseudo.c
---- squashfs4.0/squashfs-tools/pseudo.c	2009-04-05 04:01:58.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/pseudo.c	2009-10-20 06:03:38.000000000 +0200
-@@ -30,6 +30,7 @@
- #include <string.h>
- #include <stdlib.h>
- #include <sys/types.h>
-+#include <sys/wait.h>
- 
- #include "pseudo.h"
- 
-@@ -55,6 +56,9 @@
- #define TRUE 1
- #define FALSE 0
- 
-+struct pseudo_dev **pseudo_file = NULL;
-+int pseudo_count = 0;
-+
- static void dump_pseudo(struct pseudo *pseudo, char *string)
- {
- 	int i;
-@@ -99,7 +103,7 @@
- 	char *target, char *alltarget)
- {
- 	char targname[1024];
--	int i, error;
-+	int i;
- 
- 	target = get_component(target, targname);
- 
-@@ -128,12 +132,8 @@
- 		if(target[0] == '\0') {
- 			/* at leaf pathname component */
- 			pseudo->name[i].pseudo = NULL;
--			pseudo->name[i].dev = malloc(sizeof(struct pseudo_dev));
--			if(pseudo->name[i].dev == NULL)
--				BAD_ERROR("failed to allocate pseudo file\n");
- 			pseudo->name[i].pathname = strdup(alltarget);
--			memcpy(pseudo->name[i].dev, pseudo_dev,
--				sizeof(struct pseudo_dev));
-+			pseudo->name[i].dev = pseudo_dev;
- 		} else {
- 			/* recurse adding child components */
- 			pseudo->name[i].dev = NULL;
-@@ -169,15 +169,9 @@
- 			if(target[0] == '\0') {
- 				if(pseudo->name[i].dev == NULL &&
- 						pseudo_dev->type == 'd') {
--					pseudo->name[i].dev =
--						malloc(sizeof(struct pseudo_dev));
--					if(pseudo->name[i].dev == NULL)
--						BAD_ERROR("failed to allocate "
--							"pseudo file\n");
- 					pseudo->name[i].pathname =
- 						strdup(alltarget);
--					memcpy(pseudo->name[i].dev, pseudo_dev,
--						sizeof(struct pseudo_dev));
-+					pseudo->name[i].dev = pseudo_dev;
- 				} else
- 					ERROR("%s already exists as a "
- 						"directory.  Ignoring %s!\n",
-@@ -229,16 +223,113 @@
- }
- 
- 
-+int exec_file(char *command, struct pseudo_dev *dev)
-+{
-+	int child, res;
-+	static pid_t pid = -1;
-+	int pipefd[2];
-+#ifdef USE_TMP_FILE
-+	char filename[1024];
-+	int status;
-+	static int number = 0;
-+#endif
-+
-+	if(pid == -1)
-+		pid = getpid();
-+
-+#ifdef USE_TMP_FILE
-+	sprintf(filename, "/tmp/squashfs_pseudo_%d_%d", pid, number ++);
-+	pipefd[1] = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
-+	if(pipefd[1] == -1) {
-+		printf("open failed\n");
-+		return -1;
-+	}
-+#else
-+	res = pipe(pipefd);
-+	if(res == -1) {
-+		printf("pipe failed\n");
-+		return -1;
-+	}
-+#endif
-+
-+	child = fork();
-+	if(child == -1) {
-+		printf("fork failed\n");
-+		goto failed;
-+	}
-+
-+	if(child == 0) {
-+		close(STDOUT_FILENO);
-+		res = dup(pipefd[1]);
-+		if(res == -1) {
-+			printf("dup failed\n");
-+			exit(EXIT_FAILURE);
-+		}
-+		execl("/bin/sh", "sh", "-c", command, (char *) NULL);
-+		printf("execl failed\n");
-+		exit(EXIT_FAILURE);
-+	}
-+
-+#ifdef USE_TMP_FILE
-+	res = waitpid(child, &status, 0);
-+	close(pipefd[1]);
-+	if(res != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-+		dev->filename = strdup(filename);
-+		return 0;
-+	}
-+failed:
-+	unlink(filename);
-+	return -1;
-+#else
-+	close(pipefd[1]);
-+	dev->fd = pipefd[0];
-+	dev->child = child;
-+	return 0;
-+failed:
-+	return -1;
-+#endif
-+}
-+
-+
-+void add_pseudo_file(struct pseudo_dev *dev)
-+{
-+	pseudo_file = realloc(pseudo_file, (pseudo_count + 1) *
-+		sizeof(struct pseudo_dev *));
-+	if(pseudo_file == NULL)
-+		BAD_ERROR("Failed to realloc pseudo_file\n");
-+
-+	dev->pseudo_id = pseudo_count;
-+	pseudo_file[pseudo_count ++] = dev;
-+}
-+
-+
-+void delete_pseudo_files()
-+{
-+#ifdef USE_TMP_FILE
-+	int i;
-+
-+	for(i = 0; i < pseudo_count; i++)
-+		unlink(pseudo_file[i]->filename);
-+#endif
-+}
-+
-+
-+struct pseudo_dev *get_pseudo_file(int pseudo_id)
-+{
-+	return pseudo_file[pseudo_id];
-+}
-+
-+
- int read_pseudo_def(struct pseudo **pseudo, char *def)
- {
--	int n;
-+	int n, bytes;
- 	unsigned int major = 0, minor = 0, mode;
- 	char filename[2048], type, suid[100], sgid[100], *ptr;
- 	long long uid, gid;
--	struct pseudo_dev dev;
-+	struct pseudo_dev *dev;
- 
--	n = sscanf(def, "%s %c %o %s %s %u %u", filename, &type, &mode, suid, sgid,
--			&major, &minor);
-+	n = sscanf(def, "%s %c %o %s %s %n", filename, &type, &mode, suid,
-+			sgid, &bytes);
- 
- 	if(n < 5) {
- 		ERROR("Not enough or invalid arguments in pseudo file "
-@@ -249,7 +340,9 @@
- 	switch(type) {
- 	case 'b':
- 	case 'c':
--		if(n < 7) {
-+		n = sscanf(def + bytes,  "%u %u", &major, &minor);
-+
-+		if(n < 2) {
- 			ERROR("Not enough or invalid arguments in pseudo file "
- 				"definition\n");
- 			goto error;
-@@ -265,47 +358,15 @@
- 			goto error;
- 		}
- 
--		/* fall through */
--	case 'd':
--		if(mode > 0777) {
--			ERROR("Mode %o out of range\n", mode);
-+	case 'f':
-+		if(def[bytes] == '\0') {
-+			ERROR("Not enough arguments in pseudo file "
-+				"definition\n");
- 			goto error;
--		}
--
--		uid = strtoll(suid, &ptr, 10);
--		if(*ptr == '\0') {
--			if(uid < 0 || uid > ((1LL << 32) - 1)) {
--				ERROR("Uid %s out of range\n", suid);
--				goto error;
--			}
--		} else {
--			struct passwd *pwuid = getpwnam(suid);
--			if(pwuid)
--				uid = pwuid->pw_uid;
--			else {
--				ERROR("Uid %s invalid uid or unknown user\n",
--					suid);
--				goto error;
--			}
--		}
--		
--		gid = strtoll(sgid, &ptr, 10);
--		if(*ptr == '\0') {
--			if(gid < 0 || gid > ((1LL << 32) - 1)) {
--				ERROR("Gid %s out of range\n", sgid);
--				goto error;
--			}
--		} else {
--			struct group *grgid = getgrnam(sgid);
--			if(grgid)
--				gid = grgid->gr_gid;
--			else {
--				ERROR("Gid %s invalid uid or unknown user\n",
--					sgid);
--				goto error;
--			}
--		}
--
-+		}	
-+		break;
-+	case 'd':
-+	case 'm':
- 		break;
- 	default:
- 		ERROR("Unsupported type %c\n", type);
-@@ -313,6 +374,43 @@
- 	}
- 
- 
-+	if(mode > 0777) {
-+		ERROR("Mode %o out of range\n", mode);
-+		goto error;
-+	}
-+
-+	uid = strtoll(suid, &ptr, 10);
-+	if(*ptr == '\0') {
-+		if(uid < 0 || uid > ((1LL << 32) - 1)) {
-+			ERROR("Uid %s out of range\n", suid);
-+			goto error;
-+		}
-+	} else {
-+		struct passwd *pwuid = getpwnam(suid);
-+		if(pwuid)
-+			uid = pwuid->pw_uid;
-+		else {
-+			ERROR("Uid %s invalid uid or unknown user\n", suid);
-+			goto error;
-+		}
-+	}
-+		
-+	gid = strtoll(sgid, &ptr, 10);
-+	if(*ptr == '\0') {
-+		if(gid < 0 || gid > ((1LL << 32) - 1)) {
-+			ERROR("Gid %s out of range\n", sgid);
-+			goto error;
-+		}
-+	} else {
-+		struct group *grgid = getgrnam(sgid);
-+		if(grgid)
-+			gid = grgid->gr_gid;
-+		else {
-+			ERROR("Gid %s invalid uid or unknown user\n", sgid);
-+			goto error;
-+		}
-+	}
-+
- 	switch(type) {
- 	case 'b':
- 		mode |= S_IFBLK;
-@@ -323,16 +421,37 @@
- 	case 'd':
- 		mode |= S_IFDIR;
- 		break;
-+	case 'f':
-+		mode |= S_IFREG;
-+		break;
- 	}
- 
--	dev.type = type;
--	dev.mode = mode;
--	dev.uid = uid;
--	dev.gid = gid;
--	dev.major = major;
--	dev.minor = minor;
-+	dev = malloc(sizeof(struct pseudo_dev));
-+	if(dev == NULL)
-+		BAD_ERROR("Failed to create pseudo_dev\n");
-+
-+	dev->type = type;
-+	dev->mode = mode;
-+	dev->uid = uid;
-+	dev->gid = gid;
-+	dev->major = major;
-+	dev->minor = minor;
-+
-+	if(type == 'f') {
-+		int res;
-+
-+		printf("Executing dynamic pseudo file\n");
-+		printf("\t\"%s\"\n", def);
-+		res = exec_file(def + bytes, dev);
-+		if(res == -1) {
-+			ERROR("Failed to execute dynamic pseudo file definition"
-+				" \"%s\"\n", def);
-+			return FALSE;
-+		}
-+		add_pseudo_file(dev);
-+	}
- 
--	*pseudo = add_pseudo(*pseudo, &dev, filename, filename);
-+	*pseudo = add_pseudo(*pseudo, dev, filename, filename);
- 
- 	return TRUE;
- 
-diff -Nur squashfs4.0/squashfs-tools/pseudo.h squashfs4.0-lzma-snapshot/squashfs-tools/pseudo.h
---- squashfs4.0/squashfs-tools/pseudo.h	2009-04-04 03:44:24.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/pseudo.h	2009-10-20 06:03:38.000000000 +0200
-@@ -27,6 +27,12 @@
- 	unsigned int	gid;
- 	unsigned int	major;
- 	unsigned int	minor;
-+	int		pseudo_id;
-+	int		fd;
-+	int		child;
-+#ifdef USE_TMP_FILE
-+	char		*filename;
-+#endif
- };
- 
- struct pseudo_entry {
-@@ -46,3 +52,5 @@
- extern int read_pseudo_file(struct pseudo **, char *);
- extern struct pseudo *pseudo_subdir(char *, struct pseudo *);
- extern struct pseudo_entry *pseudo_readdir(struct pseudo *);
-+extern struct pseudo_dev *get_pseudo_file(int);
-+extern void delete_pseudo_files();
-diff -Nur squashfs4.0/squashfs-tools/read_fs.c squashfs4.0-lzma-snapshot/squashfs-tools/read_fs.c
---- squashfs4.0/squashfs-tools/read_fs.c	2009-03-31 06:23:14.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/read_fs.c	2009-10-20 06:03:38.000000000 +0200
-@@ -36,7 +36,6 @@
- #include <fcntl.h>
- #include <errno.h>
- #include <string.h>
--#include <zlib.h>
- #include <sys/mman.h>
- 
- #ifndef linux
-@@ -51,6 +50,7 @@
- #include "squashfs_swap.h"
- #include "read_fs.h"
- #include "global.h"
-+#include "compressor.h"
- 
- #include <stdlib.h>
- 
-@@ -66,7 +66,9 @@
- 						fprintf(stderr, s, ## args); \
- 					} while(0)
- 
--int read_block(int fd, long long start, long long *next, unsigned char *block,
-+static struct compressor *comp;
-+
-+int read_block(int fd, long long start, long long *next, void *block,
- 	squashfs_super_block *sBlk)
- {
- 	unsigned short c_byte;
-@@ -77,32 +79,24 @@
- 
- 	if(SQUASHFS_COMPRESSED(c_byte)) {
- 		char buffer[SQUASHFS_METADATA_SIZE];
--		int res;
--		unsigned long bytes = SQUASHFS_METADATA_SIZE;
-+		int error, res;
- 
- 		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
- 		read_destination(fd, start + offset, c_byte, buffer);
- 
--		res = uncompress(block, &bytes, (const unsigned char *) buffer,
--			c_byte);
--		if(res != Z_OK) {
--			if(res == Z_MEM_ERROR)
--				ERROR("zlib::uncompress failed, not enough "
--					"memory\n");
--			else if(res == Z_BUF_ERROR)
--				ERROR("zlib::uncompress failed, not enough "
--					"room in output buffer\n");
--			else
--				ERROR("zlib::uncompress failed, unknown error "
--					"%d\n", res);
-+		res = comp->uncompress(block, buffer, c_byte,
-+			SQUASHFS_METADATA_SIZE, &error);
-+		if(res == -1) {
-+			ERROR("%s uncompress failed with error code %d\n",
-+				comp->name, error);
- 			return 0;
- 		}
- 		if(next)
- 			*next = start + offset + c_byte;
--		return bytes;
-+		return res;
- 	} else {
- 		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
--		read_destination(fd, start + offset, c_byte, (char *) block);
-+		read_destination(fd, start + offset, c_byte, block);
- 		if(next)
- 			*next = start + offset + c_byte;
- 		return c_byte;
-@@ -356,7 +350,7 @@
- }
- 
- 
--int read_super(int fd, squashfs_super_block *sBlk, char *source)
-+struct compressor *read_super(int fd, squashfs_super_block *sBlk, char *source)
- {
- 	read_destination(fd, SQUASHFS_START, sizeof(squashfs_super_block),
- 		(char *) sBlk);
-@@ -388,8 +382,18 @@
- 		goto failed_mount;
- 	}
- 
-+	/* Check the compression type */
-+	comp = lookup_compressor_id(sBlk->compression);
-+	if(!comp->supported) {
-+		ERROR("Filesystem on %s uses %s compression, this is"
-+			"unsupported by this version\n", source, comp->name);
-+		display_compressors("", "");
-+		goto failed_mount;
-+	}
-+
- 	printf("Found a valid %sSQUASHFS superblock on %s.\n",
- 		SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", source);
-+	printf("\tCompression used %s\n", comp->name);
- 	printf("\tInodes are %scompressed\n",
- 		SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
- 	printf("\tData is %scompressed\n",
-@@ -417,10 +421,10 @@
- 	TRACE("sBlk->lookup_table_start %llx\n", sBlk->lookup_table_start);
- 	printf("\n");
- 
--	return TRUE;
-+	return comp;
- 
- failed_mount:
--	return FALSE;
-+	return NULL;
- }
- 
- 
-@@ -514,12 +518,17 @@
- 	SQUASHFS_INSWAP_ID_BLOCKS(index, indexes);
- 
- 	for(i = 0; i < indexes; i++) {
--		int length;
--		length = read_block(fd, index[i], NULL,
-+		int length = read_block(fd, index[i], NULL,
- 			((unsigned char *) id_table) +
- 			(i * SQUASHFS_METADATA_SIZE), sBlk);
- 		TRACE("Read id table block %d, from 0x%llx, length %d\n", i,
- 			index[i], length);
-+		if(length == 0) {
-+			ERROR("Failed to read id table block %d, from 0x%llx, "
-+				"length %d\n", i, index[i], length);
-+			free(id_table);
-+			return NULL;
-+		}
- 	}
- 
- 	SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids);
-@@ -563,6 +572,13 @@
- 			(i * SQUASHFS_METADATA_SIZE), sBlk);
- 		TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
- 			i, fragment_table_index[i], length);
-+		if(length == 0) {
-+			ERROR("Failed to read fragment table block %d, from "
-+				"0x%llx, length %d\n", i,
-+				fragment_table_index[i], length);
-+			free(*fragment_table);
-+			return 0;
-+		}
- 	}
- 
- 	for(i = 0; i < sBlk->fragments; i++)
-@@ -599,6 +615,13 @@
- 			(i * SQUASHFS_METADATA_SIZE), sBlk);
- 		TRACE("Read inode lookup table block %d, from 0x%llx, length "
- 			"%d\n", i, index[i], length);
-+		if(length == 0) {
-+			ERROR("Failed to read inode lookup table block %d, "
-+				"from 0x%llx, length %d\n", i, index[i],
-+				length);
-+			free(*inode_lookup_table);
-+			return 0;
-+		}
- 	}
- 
- 	SQUASHFS_INSWAP_LONG_LONGS(*inode_lookup_table, sBlk->inodes);
-diff -Nur squashfs4.0/squashfs-tools/sort.c squashfs4.0-lzma-snapshot/squashfs-tools/sort.c
---- squashfs4.0/squashfs-tools/sort.c	2009-03-31 06:25:53.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/sort.c	2009-10-20 06:03:38.000000000 +0200
-@@ -198,7 +198,7 @@
- 	while(dir->current_count < dir->count) {
- 		struct dir_ent *dir_ent = dir->list[dir->current_count++];
- 		struct stat *buf = &dir_ent->inode->buf;
--		if(dir_ent->data)
-+		if(dir_ent->inode->root_entry)
- 			continue;
- 
- 		switch(buf->st_mode & S_IFMT) {
-@@ -254,6 +254,7 @@
- 				write_file(&inode, entry->dir, &duplicate_file);
- 				INFO("file %s, uncompressed size %lld bytes %s"
- 					"\n", entry->dir->pathname,
-+					(long long)
- 					entry->dir->inode->buf.st_size,
- 					duplicate_file ? "DUPLICATE" : "");
- 				entry->dir->inode->inode = inode;
-@@ -261,6 +262,7 @@
- 			} else
- 				INFO("file %s, uncompressed size %lld bytes "
- 					"LINK\n", entry->dir->pathname,
-+					(long long)
- 					entry->dir->inode->buf.st_size);
- 		}
- }
-diff -Nur squashfs4.0/squashfs-tools/sort.h squashfs4.0-lzma-snapshot/squashfs-tools/sort.h
---- squashfs4.0/squashfs-tools/sort.h	2009-02-08 13:02:53.000000000 +0100
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/sort.h	2009-10-20 06:03:38.000000000 +0200
-@@ -42,17 +42,19 @@
- 	struct inode_info	*inode;
- 	struct dir_info		*dir;
- 	struct dir_info		*our_dir;
--	struct old_root_entry_info *data;
- };
- 
- struct inode_info {
--	unsigned int		nlink;
- 	struct stat		buf;
-+	struct inode_info	*next;
- 	squashfs_inode		inode;
--	unsigned int		type;
- 	unsigned int		inode_number;
-+	unsigned int		nlink;
-+	int			pseudo_id;
-+	char			type;
- 	char			read;
--	struct inode_info	*next;
-+	char			root_entry;
-+	char			pseudo_file;
- };
- 
- struct priority_entry {
-diff -Nur squashfs4.0/squashfs-tools/squashfs_compat.h squashfs4.0-lzma-snapshot/squashfs-tools/squashfs_compat.h
---- squashfs4.0/squashfs-tools/squashfs_compat.h	2009-03-16 05:27:27.000000000 +0100
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/squashfs_compat.h	2009-10-20 06:03:38.000000000 +0200
-@@ -777,11 +777,10 @@
- #endif
- 
- #define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
--	int bits;\
--	int b_pos = pos % 8;\
--	unsigned long long val = 0;\
--	unsigned char *s = (unsigned char *)p + (pos / 8);\
--	unsigned char *d = ((unsigned char *) &val) + 7;\
-+	b_pos = pos % 8;\
-+	val = 0;\
-+	s = (unsigned char *)p + (pos / 8);\
-+	d = ((unsigned char *) &val) + 7;\
- 	for(bits = 0; bits < (tbits + b_pos); bits += 8) \
- 		*d-- = *s++;\
- 	value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
-diff -Nur squashfs4.0/squashfs-tools/squashfs_fs.h squashfs4.0-lzma-snapshot/squashfs-tools/squashfs_fs.h
---- squashfs4.0/squashfs-tools/squashfs_fs.h	2009-03-18 03:50:20.000000000 +0100
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/squashfs_fs.h	2009-10-20 06:03:38.000000000 +0200
-@@ -229,6 +229,7 @@
- typedef long long		squashfs_inode_t;
- 
- #define ZLIB_COMPRESSION	1
-+#define LZMA_COMPRESSION	2
- 
- struct squashfs_super_block {
- 	unsigned int		s_magic;
-diff -Nur squashfs4.0/squashfs-tools/unsquash-3.c squashfs4.0-lzma-snapshot/squashfs-tools/unsquash-3.c
---- squashfs4.0/squashfs-tools/unsquash-3.c	2009-03-31 06:35:10.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/unsquash-3.c	2009-10-20 06:03:38.000000000 +0200
-@@ -36,7 +36,7 @@
- 		sBlk.fragment_table_start);
- 
- 	if(sBlk.fragments == 0)
--		return;
-+		return TRUE;
- 
- 	if((fragment_table = malloc(sBlk.fragments *
- 			sizeof(squashfs_fragment_entry_3))) == NULL)
-diff -Nur squashfs4.0/squashfs-tools/unsquash-4.c squashfs4.0-lzma-snapshot/squashfs-tools/unsquash-4.c
---- squashfs4.0/squashfs-tools/unsquash-4.c	2009-03-31 06:38:31.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/unsquash-4.c	2009-10-20 06:03:38.000000000 +0200
-@@ -38,7 +38,7 @@
- 		sBlk.fragment_table_start);
- 
- 	if(sBlk.fragments == 0)
--		return;
-+		return TRUE;
- 
- 	if((fragment_table = malloc(sBlk.fragments *
- 			sizeof(squashfs_fragment_entry))) == NULL)
-diff -Nur squashfs4.0/squashfs-tools/unsquashfs.c squashfs4.0-lzma-snapshot/squashfs-tools/unsquashfs.c
---- squashfs4.0/squashfs-tools/unsquashfs.c	2009-04-05 23:23:06.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/unsquashfs.c	2009-10-20 06:03:39.000000000 +0200
-@@ -25,6 +25,7 @@
- #include "squashfs_swap.h"
- #include "squashfs_compat.h"
- #include "read_fs.h"
-+#include "compressor.h"
- 
- struct cache *fragment_cache, *data_cache;
- struct queue *to_reader, *to_deflate, *to_writer, *from_writer;
-@@ -36,6 +39,7 @@
- 
- struct super_block sBlk;
- squashfs_operations s_ops;
-+struct compressor *comp;
- 
- int bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0,
- 	dev_count = 0, fifo_count = 0;
-@@ -590,31 +594,23 @@
- 		offset = 3;
- 	if(SQUASHFS_COMPRESSED(c_byte)) {
- 		char buffer[SQUASHFS_METADATA_SIZE];
--		int res;
--		unsigned long bytes = SQUASHFS_METADATA_SIZE;
-+		int error, res;
- 
- 		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
- 		if(read_bytes(start + offset, c_byte, buffer) == FALSE)
- 			goto failed;
- 
--		res = uncompress((unsigned char *) block, &bytes,
--			(const unsigned char *) buffer, c_byte);
-+		res = comp->uncompress(block, buffer, c_byte,
-+			SQUASHFS_METADATA_SIZE, &error);
- 
--		if(res != Z_OK) {
--			if(res == Z_MEM_ERROR)
--				ERROR("zlib::uncompress failed, not enough "
--					"memory\n");
--			else if(res == Z_BUF_ERROR)
--				ERROR("zlib::uncompress failed, not enough "
--					"room in output buffer\n");
--			else
--				ERROR("zlib::uncompress failed, unknown error "
--					"%d\n", res);
-+		if(res == -1) {
-+			ERROR("%s uncompress failed with error code %d\n",
-+				comp->name, error);
- 			goto failed;
- 		}
- 		if(next)
- 			*next = start + offset + c_byte;
--		return bytes;
-+		return res;
- 	} else {
- 		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
- 		if(read_bytes(start + offset, c_byte, block) == FALSE)
-@@ -632,36 +628,26 @@
- 
- int read_data_block(long long start, unsigned int size, char *block)
- {
--	int res;
--	unsigned long bytes = block_size;
-+	int error, res;
- 	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
- 
- 	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start,
--		SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte),
--		SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" :
-+		c_byte, SQUASHFS_COMPRESSED_BLOCK(size) ? "compressed" :
- 		"uncompressed");
- 
- 	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
- 		if(read_bytes(start, c_byte, data) == FALSE)
- 			goto failed;
- 
--		res = uncompress((unsigned char *) block, &bytes,
--			(const unsigned char *) data, c_byte);
-+		res = comp->uncompress(block, data, c_byte, block_size, &error);
- 
--		if(res != Z_OK) {
--			if(res == Z_MEM_ERROR)
--				ERROR("zlib::uncompress failed, not enough "
--					"memory\n");
--			else if(res == Z_BUF_ERROR)
--				ERROR("zlib::uncompress failed, not enough "
--					"room in output buffer\n");
--			else
--				ERROR("zlib::uncompress failed, unknown error "
--					"%d\n", res);
-+		if(res == -1) {
-+			ERROR("%s uncompress failed with error code %d\n",
-+				comp->name, error);
- 			goto failed;
- 		}
- 
--		return bytes;
-+		return res;
- 	} else {
- 		if(read_bytes(start, c_byte, block) == FALSE)
- 			goto failed;
-@@ -671,7 +657,7 @@
- 
- failed:
- 	ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start,
--		size);
-+		c_byte);
- 	return FALSE;
- }
- 
-@@ -1383,6 +1369,11 @@
- #endif
- 	printf("Creation or last append time %s", mkfs_str ? mkfs_str :
- 		"failed to get time\n");
-+	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n",
-+		sBlk.bytes_used / 1024.0, sBlk.bytes_used / (1024.0 * 1024.0));
-+	if(sBlk.s_major == 4)
-+		printf("Compression %s\n", comp->name);
-+	printf("Block size %d\n", sBlk.block_size);
- 	printf("Filesystem is %sexportable via NFS\n",
- 		SQUASHFS_EXPORTABLE(sBlk.flags) ? "" : "not ");
- 
-@@ -1409,9 +1400,6 @@
- 			SQUASHFS_DUPLICATES(sBlk.flags) ? "" : "not ");
- 	else
- 		printf("Duplicates are removed\n");
--	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n",
--		sBlk.bytes_used / 1024.0, sBlk.bytes_used / (1024.0 * 1024.0));
--	printf("Block size %d\n", sBlk.block_size);
- 	if(sBlk.s_major > 1)
- 		printf("Number of fragments %d\n", sBlk.fragments);
- 	printf("Number of inodes %d\n", sBlk.inodes);
-@@ -1459,6 +1447,18 @@
- 		s_ops.read_inode = read_inode_4;
- 		s_ops.read_uids_guids = read_uids_guids_4;
- 		memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4));
-+
-+		/*
-+		 * Check the compression type
-+		 */
-+		comp = lookup_compressor_id(sBlk.compression);
-+		if(!comp->supported) {
-+			ERROR("Filesystem uses %s compression, this is "
-+				"unsupported by this version\n", comp->name);
-+			ERROR("Decompressors available:\n");
-+			display_compressors("", "");
-+			goto failed_mount;
-+		}
- 		return TRUE;
- 	}
- 
-@@ -1548,6 +1548,11 @@
- 		goto failed_mount;
- 	}
- 
-+	/*
-+	 * 1.x, 2.x and 3.x filesystems use gzip compression.  Gzip is always
-+	 * suppported.
-+	 */
-+	comp = lookup_compressor("gzip");
- 	return TRUE;
- 
- failed_mount:
-@@ -1707,32 +1712,24 @@
- 
- 	while(1) {
- 		struct cache_entry *entry = queue_get(to_deflate);
--		int res;
--		unsigned long bytes = block_size;
-+		int error, res;
- 
--		res = uncompress((unsigned char *) tmp, &bytes,
--			(const unsigned char *) entry->data,
--			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size));
--
--		if(res != Z_OK) {
--			if(res == Z_MEM_ERROR)
--				ERROR("zlib::uncompress failed, not enough"
--					"memory\n");
--			else if(res == Z_BUF_ERROR)
--				ERROR("zlib::uncompress failed, not enough "
--					"room in output buffer\n");
--			else
--				ERROR("zlib::uncompress failed, unknown error "
--					"%d\n", res);
--		} else
--			memcpy(entry->data, tmp, bytes);
-+		res = comp->uncompress(tmp, entry->data,
-+			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), block_size,
-+			&error);
-+
-+		if(res == -1)
-+			ERROR("%s uncompress failed with error code %d\n",
-+				comp->name, error);
-+		else
-+			memcpy(entry->data, tmp, res);
- 
- 		/*
- 		 * block has been either successfully decompressed, or an error
-  		 * occurred, clear pending flag, set error appropriately and
-  		 * wake up any threads waiting on this block
-  		 */ 
--		cache_block_ready(entry, res != Z_OK);
-+		cache_block_ready(entry, res == -1);
- 	}
- }
- 
-@@ -1913,7 +1910,7 @@
- 
- 
- #define VERSION() \
--	printf("unsquashfs version 4.0 (2009/04/05)\n");\
-+	printf("unsquashfs version 4.1-CVS (2009/08/30)\n");\
- 	printf("copyright (C) 2009 Phillip Lougher <phillip@lougher.demon.co.uk>"\
- 		"\n\n");\
-     	printf("This program is free software; you can redistribute it and/or\n");\
-@@ -1938,7 +1935,6 @@
- 	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
- 	int data_buffer_size = DATA_BUFFER_DEFAULT;
- 	char *b;
--	struct winsize winsize;
- 
- 	pthread_mutex_init(&screen_mutex, NULL);
- 	root_process = geteuid() == 0;
-@@ -2087,6 +2083,8 @@
- 				"regular expressions\n");
- 			ERROR("\t\t\t\trather than use the default shell "
- 				"wildcard\n\t\t\t\texpansion (globbing)\n");
-+			ERROR("\nDecompressors available:\n");
-+			display_compressors("", "");
- 		}
- 		exit(1);
- 	}
-diff -Nur squashfs4.0/squashfs-tools/unsquashfs.h squashfs4.0-lzma-snapshot/squashfs-tools/unsquashfs.h
---- squashfs4.0/squashfs-tools/unsquashfs.h	2009-03-29 04:29:02.000000000 +0200
-+++ squashfs4.0-lzma-snapshot/squashfs-tools/unsquashfs.h	2009-10-20 06:03:39.000000000 +0200
-@@ -31,7 +31,6 @@
- #include <fcntl.h>
- #include <errno.h>
- #include <string.h>
--#include <zlib.h>
- #include <sys/mman.h>
- #include <utime.h>
- #include <pwd.h>
 

--- a/tools/squashfs4/patches/120-cygwin_fixes.patch
+++ b/tools/squashfs4/patches/120-cygwin_fixes.patch
@@ -1,20 +1,6 @@
---- a/squashfs-tools/global.h
-+++ b/squashfs-tools/global.h
-@@ -44,6 +44,11 @@ typedef long long squashfs_fragment_inde
- typedef squashfs_inode_t squashfs_inode;
- typedef squashfs_block_t squashfs_block;
- 
-+#ifdef __CYGWIN__
-+#include <sys/termios.h>
-+#define FNM_EXTMATCH  (1 << 5)
-+#endif
-+
- #ifndef FNM_EXTMATCH
- #define FNM_EXTMATCH 0
- #endif
 --- a/squashfs-tools/mksquashfs.c
 +++ b/squashfs-tools/mksquashfs.c
-@@ -49,10 +49,12 @@
+@@ -51,15 +51,22 @@
  #include <sys/wait.h>
  
  #ifndef linux
@@ -27,7 +13,17 @@
  #else
  #include <endian.h>
  #include <sys/sysinfo.h>
-@@ -817,6 +819,7 @@ void sigusr1_handler()
+ #endif
+ 
++#ifdef __CYGWIN__
++#include <sys/termios.h>
++#define FNM_EXTMATCH  (1 << 5)
++#endif
++
+ #ifndef FNM_EXTMATCH
+ #define FNM_EXTMATCH 0
+ #endif
+@@ -844,6 +851,7 @@ void sigusr1_handler()
  
  void sigwinch_handler()
  {
@@ -35,7 +31,7 @@
  	struct winsize winsize;
  
  	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
-@@ -826,6 +829,9 @@ void sigwinch_handler()
+@@ -853,6 +861,9 @@ void sigwinch_handler()
  		columns = 80;
  	} else
  		columns = winsize.ws_col;
@@ -45,28 +41,27 @@
  }
  
  
-@@ -3853,7 +3859,9 @@ void initialise_threads()
- 		BAD_ERROR("Failed to set signal mask in intialise_threads\n");
+@@ -4066,6 +4077,9 @@ void initialise_threads(int readb_mbytes
  
  	signal(SIGUSR1, sigusr1_handler);
--
+ 
 +#ifdef __CYGWIN__
 +	processors = atoi(getenv("NUMBER_OF_PROCESSORS"));
 +#else
  	if(processors == -1) {
  #ifndef linux
  		int mib[2];
-@@ -3875,6 +3883,7 @@ void initialise_threads()
- 		processors = get_nprocs();
+@@ -4087,6 +4101,7 @@ void initialise_threads(int readb_mbytes
+ 		processors = sysconf(_SC_NPROCESSORS_ONLN);
  #endif
  	}
 +#endif /* __CYGWIN__ */
  
- 	if((thread = malloc((2 + processors * 2) * sizeof(pthread_t))) == NULL)
- 		BAD_ERROR("Out of memory allocating thread descriptors\n");
+ 	thread = malloc((2 + processors * 2) * sizeof(pthread_t));
+ 	if(thread == NULL)
 --- a/squashfs-tools/read_fs.c
 +++ b/squashfs-tools/read_fs.c
-@@ -39,9 +39,11 @@ extern unsigned int get_guid(unsigned in
+@@ -33,9 +33,11 @@
  #include <sys/mman.h>
  
  #ifndef linux
@@ -94,7 +89,7 @@
  #endif
 --- a/squashfs-tools/unsquashfs.c
 +++ b/squashfs-tools/unsquashfs.c
-@@ -112,6 +112,7 @@ void update_progress_bar();
+@@ -117,6 +117,7 @@ void update_progress_bar();
  
  void sigwinch_handler()
  {
@@ -102,7 +97,7 @@
  	struct winsize winsize;
  
  	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
-@@ -121,6 +122,9 @@ void sigwinch_handler()
+@@ -126,6 +127,9 @@ void sigwinch_handler()
  		columns = 80;
  	} else
  		columns = winsize.ws_col;
@@ -112,7 +107,7 @@
  }
  
  
-@@ -1787,7 +1791,9 @@ void initialise_threads(int fragment_buf
+@@ -1807,7 +1811,9 @@ void initialise_threads(int fragment_buf
  	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
  		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
  			"\n");
@@ -123,17 +118,17 @@
  	if(processors == -1) {
  #ifndef linux
  		int mib[2];
-@@ -1809,6 +1815,7 @@ void initialise_threads(int fragment_buf
- 		processors = get_nprocs();
+@@ -1829,6 +1835,7 @@ void initialise_threads(int fragment_buf
+ 		processors = sysconf(_SC_NPROCESSORS_ONLN);
  #endif
  	}
 +#endif /* __CYGWIN__ */
  
- 	if((thread = malloc((3 + processors) * sizeof(pthread_t))) == NULL)
- 		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
+ 	thread = malloc((3 + processors) * sizeof(pthread_t));
+ 	if(thread == NULL)
 --- a/squashfs-tools/unsquashfs.h
 +++ b/squashfs-tools/unsquashfs.h
-@@ -45,10 +45,12 @@
+@@ -46,15 +46,22 @@
  #include <sys/time.h>
  
  #ifndef linux
@@ -142,8 +137,18 @@
  #define __BIG_ENDIAN BIG_ENDIAN
  #define __LITTLE_ENDIAN LITTLE_ENDIAN
  #include <sys/sysctl.h>
-+#endif /* __CYGWIN__ */
++#endif
  #else
  #include <endian.h>
  #include <sys/sysinfo.h>
+ #endif
+ 
++#ifdef __CYGWIN__
++#include <sys/termios.h>
++#define FNM_EXTMATCH  (1 << 5)
++#endif
++
+ #ifndef FNM_EXTMATCH
+ #define FNM_EXTMATCH 0
+ #endif
 

--- a/tools/squashfs4/patches/130-dynamic_lzma_params.patch
+++ /dev/null
@@ -1,92 +1,1 @@
---- a/squashfs-tools/lzma_wrapper.c
-+++ b/squashfs-tools/lzma_wrapper.c
-@@ -20,6 +20,8 @@
-  */
- 
- #include <LzmaLib.h>
-+#include <stdio.h>
-+#include "compressor.h"
- 
- #define LZMA_HEADER_SIZE	(LZMA_PROPS_SIZE + 8)
- 
-@@ -30,9 +32,18 @@
- 	size_t props_size = LZMA_PROPS_SIZE,
- 		outlen = block_size - LZMA_HEADER_SIZE;
- 	int res;
-+	int lc;
-+	int lp;
-+	int pb;
-+
-+	if (!comp_args || sscanf(comp_args, "%d:%d:%d", &lc, &lp, &pb) != 3) {
-+		lc = 0;
-+		lp = 2;
-+		pb = 2;
-+	}
- 
- 	res = LzmaCompress(d + LZMA_HEADER_SIZE, &outlen, s, size, d,
--		&props_size, 5, block_size, 3, 0, 2, 32, 1);
-+		&props_size, 5, block_size, lc, lp, pb, 32, 1);
- 	
- 	if(res == SZ_ERROR_OUTPUT_EOF) {
- 		/*
---- a/squashfs-tools/compressor.c
-+++ b/squashfs-tools/compressor.c
-@@ -25,6 +25,7 @@
- #include "compressor.h"
- #include "squashfs_fs.h"
- 
-+char *comp_args = NULL;
- extern int gzip_compress(void **, char *, char *, int, int, int *);
- extern int gzip_uncompress(char *, char *, int, int, int *);
- extern int lzma_compress(void **, char *, char *, int, int, int *);
---- a/squashfs-tools/compressor.h
-+++ b/squashfs-tools/compressor.h
-@@ -31,3 +31,4 @@
- extern struct compressor *lookup_compressor(char *);
- extern struct compressor *lookup_compressor_id(int);
- extern void display_compressors(char *, char *);
-+extern char *comp_args;
---- a/squashfs-tools/mksquashfs.c
-+++ b/squashfs-tools/mksquashfs.c
-@@ -4355,6 +4355,12 @@
- 				exit(1);
- 			}
- 			comp_name = argv[i];
-+		} else if(strcmp(argv[i], "-comp_args") == 0) {
-+			if(++i == argc) {
-+				ERROR("%s: -comp_args missing compression arguments\n", argv[0]);
-+				exit(1);
-+			}
-+			comp_args = argv[i];
- 		} else if(strcmp(argv[i], "-pf") == 0) {
- 			if(++i == argc) {
- 				ERROR("%s: -pf missing filename\n", argv[0]);
-@@ -4574,6 +4580,7 @@
- 				"[-e list of exclude\ndirs/files]\n", argv[0]);
- 			ERROR("\nFilesystem build options:\n");
- 			ERROR("-comp <comp>\t\tselect <comp> compression\n");
-+			ERROR("-comp_args <comp>\t\tselect compression arguments\n");
- 			ERROR("\t\t\tCompressors available:\n");
- 			display_compressors("\t\t\t", COMP_DEFAULT);
- 			ERROR("-b <block_size>\t\tset data block to "
-@@ -4736,7 +4743,8 @@
- 		else if(strcmp(argv[i], "-root-becomes") == 0 ||
- 				strcmp(argv[i], "-sort") == 0 ||
- 				strcmp(argv[i], "-pf") == 0 ||
--				strcmp(argv[i], "-comp") == 0)
-+				strcmp(argv[i], "-comp") == 0 ||
-+				strcmp(argv[i], "-comp_args") == 0)
- 			i++;
- 
- 	if(i != argc) {
-@@ -4761,7 +4769,8 @@
- 		else if(strcmp(argv[i], "-root-becomes") == 0 ||
- 				strcmp(argv[i], "-ef") == 0 ||
- 				strcmp(argv[i], "-pf") == 0 ||
--				strcmp(argv[i], "-comp") == 0)
-+				strcmp(argv[i], "-comp") == 0 ||
-+				strcmp(argv[i], "-comp_args") == 0)
- 			i++;
- 
- #ifdef SQUASHFS_TRACE
 

--- a/tools/squashfs4/patches/140-mode_check.patch
+++ /dev/null
@@ -1,12 +1,1 @@
---- a/squashfs-tools/pseudo.c
-+++ b/squashfs-tools/pseudo.c
-@@ -374,7 +374,7 @@
- 	}
- 
- 
--	if(mode > 0777) {
-+	if(mode > 07777) {
- 		ERROR("Mode %o out of range\n", mode);
- 		goto error;
- 	}
 

--- a/tools/squashfs4/patches/150-freebsd_fixes.patch
+++ b/tools/squashfs4/patches/150-freebsd_fixes.patch
@@ -1,6 +1,6 @@
 --- a/squashfs-tools/pseudo.c
 +++ b/squashfs-tools/pseudo.c
-@@ -31,6 +31,7 @@
+@@ -32,6 +32,7 @@
  #include <stdlib.h>
  #include <sys/types.h>
  #include <sys/wait.h>

--- /dev/null
+++ b/tools/squashfs4/patches/160-expose_lzma_xz_options.patch
@@ -1,1 +1,927 @@
+--- /dev/null
++++ b/squashfs-tools/lzma_xz_options.h
+@@ -0,0 +1,112 @@
++#ifndef LZMA_XZ_OPTIONS_H
++#define LZMA_XZ_OPTIONS_H
++/*
++ * Copyright (c) 2011
++ * Jonas Gorski <jonas.gorski@gmail.com>
++ *
++ * 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.
++ *
++ * lzma_options.h
++ */
++
++#include <stdint.h>
++
++#ifndef linux
++#define __BYTE_ORDER BYTE_ORDER
++#define __BIG_ENDIAN BIG_ENDIAN
++#define __LITTLE_ENDIAN LITTLE_ENDIAN
++#else
++#include <endian.h>
++#endif
++
++
++
++struct lzma_opts {
++	uint32_t flags;
++#define LZMA_OPT_FLT_MASK	0xffff
++#define LZMA_OPT_PRE_OFF	16
++#define LZMA_OPT_PRE_MASK	(0xf << LZMA_OPT_PRE_OFF)
++#define LZMA_OPT_EXTREME	20	
++	uint16_t bit_opts;
++#define LZMA_OPT_LC_OFF		0
++#define LZMA_OPT_LC_MASK	(0x7 << LZMA_OPT_LC_OFF)
++#define LZMA_OPT_LP_OFF		3
++#define LZMA_OPT_LP_MASK	(0x7 << LZMA_OPT_LP_OFF)
++#define LZMA_OPT_PB_OFF		6
++#define LZMA_OPT_PB_MASK	(0x7 << LZMA_OPT_PB_OFF)
++	uint16_t fb;
++	uint32_t dict_size;
++};
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++extern unsigned int inswap_le32(unsigned int);
++
++#define SQUASHFS_INSWAP_LZMA_COMP_OPTS(s) { \
++	(s)->flags = inswap_le32((s)->flags); \
++	(s)->bit_opts = inswap_le16((s)->bit_opts); \
++	(s)->fb = inswap_le16((s)->fb); \
++	(s)->dict_size = inswap_le32((s)->dict_size); \
++}
++#else
++#define SQUASHFS_INSWAP_LZMA_COMP_OPTS(s)
++#endif
++
++#define MEMLIMIT (32 * 1024 * 1024)
++
++#define LZMA_OPT_LC_MIN		0
++#define LZMA_OPT_LC_MAX		4
++#define LZMA_OPT_LC_DEFAULT	3
++
++#define LZMA_OPT_LP_MIN		0
++#define LZMA_OPT_LP_MAX		4
++#define LZMA_OPT_LP_DEFAULT	0
++
++#define LZMA_OPT_PB_MIN		0
++#define LZMA_OPT_PB_MAX		4
++#define LZMA_OPT_PB_DEFAULT	2
++
++#define LZMA_OPT_FB_MIN		5
++#define LZMA_OPT_FB_MAX		273
++#define LZMA_OPT_FB_DEFAULT	64
++
++enum {
++	LZMA_OPT_LZMA = 1,
++	LZMA_OPT_XZ
++};
++
++struct lzma_xz_options {
++	int preset;
++	int extreme;
++	int lc;
++	int lp;
++	int pb;
++	int fb;
++	int dict_size;
++	int flags;
++};
++
++struct lzma_xz_options *lzma_xz_get_options(void);
++
++int lzma_xz_options(char *argv[], int argc, int lzmaver);
++
++int lzma_xz_options_post(int block_size, int lzmaver);
++
++void *lzma_xz_dump_options(int block_size, int *size, int flags);
++
++int lzma_xz_extract_options(int block_size, void *buffer, int size, int lzmaver);
++
++void lzma_xz_usage(int lzmaver);
++
++#endif
+--- /dev/null
++++ b/squashfs-tools/lzma_xz_options.c
+@@ -0,0 +1,365 @@
++/*
++ * Copyright (c) 2011
++ * Jonas Gorski <jonas.gorski@gmail.com>
++ *
++ * 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.
++ *
++ * lzma_options.c
++ * 
++ * Common options for LZMA1 and 2 compressors. Based on xz_wrapper.c
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++
++#include <lzma.h>
++
++#include "lzma_xz_options.h"
++
++static const char const *lzmaver_str[] = { "", "lzma", "xz" };
++
++static struct lzma_xz_options options = {
++	.flags		= 0,
++	.preset		= 6,
++	.extreme	= 0,
++	.lc		= LZMA_OPT_LC_DEFAULT,
++	.lp		= LZMA_OPT_LP_DEFAULT,
++	.pb		= LZMA_OPT_PB_DEFAULT,
++	.fb		= LZMA_OPT_FB_DEFAULT,
++	.dict_size	= 0,
++};
++
++static float lzma_dict_percent = 0;
++
++struct lzma_xz_options *lzma_xz_get_options(void)
++{
++	return &options;
++}
++
++
++int lzma_xz_options(char *argv[], int argc, int lzmaver)
++{
++	const char *comp_name = lzmaver_str[lzmaver];
++	
++	if(strcmp(argv[0], "-Xpreset") == 0) {
++		int preset;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xpreset missing preset\n", comp_name);
++			goto failed;
++		}
++		
++		preset = atoi(argv[1]);
++		
++		if (preset < 0 || preset > 9) {
++			fprintf(stderr, "%s: -Xpreset invalid value\n", comp_name);
++			goto failed;
++		}
++		options.preset = preset;
++		return 1;
++	} else if(strcmp(argv[0], "-Xe") == 0) {
++		options.extreme = 1;
++		return 0;
++	} else if(strcmp(argv[0], "-Xlc") == 0) {
++		int lc;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xlc missing lc\n", comp_name);
++			goto failed;
++		}
++		
++		lc = atoi(argv[1]);
++		
++		if (lc < LZMA_OPT_LC_MIN || lc > LZMA_OPT_LC_MAX) {
++			fprintf(stderr, "%s: -Xlc invalid value\n", comp_name);
++			goto failed;
++		}
++		options.lc = lc;
++		return 1;
++	} else if(strcmp(argv[0], "-Xlp") == 0) {
++		int lp;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xlp missing lp\n", comp_name);
++			goto failed;
++		}
++		
++		lp = atoi(argv[1]);
++		
++		if (lp < LZMA_OPT_LP_MIN || lp > LZMA_OPT_LP_MAX) {
++			fprintf(stderr, "%s: -Xlp invalid value\n", comp_name);
++			goto failed;
++		}
++		options.lp = lp;
++		return 1;
++	} else if(strcmp(argv[0], "-Xpb") == 0) {
++		int pb;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xpb missing pb\n", comp_name);
++			goto failed;
++		}
++		
++		pb = atoi(argv[1]);
++		
++		if (pb < LZMA_OPT_PB_MIN || pb > LZMA_OPT_PB_MAX) {
++			fprintf(stderr, "%s: -Xbp invalid value\n", comp_name);
++			goto failed;
++		}
++		options.pb = pb;
++		return 1;	
++	} else if(strcmp(argv[0], "-Xfb") == 0) {
++		int fb;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xfb missing fb\n", comp_name);
++			goto failed;
++		}
++		
++		fb = atoi(argv[1]);
++		
++		if (fb < LZMA_OPT_FB_MIN || fb > LZMA_OPT_FB_MAX) {
++			fprintf(stderr, "%s: -Xfb invalid value\n", comp_name);
++			goto failed;
++		}
++		options.fb = fb;
++		return 1;
++	} else if(strcmp(argv[0], "-Xdict-size") == 0) {
++		char *b;
++		float size;
++
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xdict-size missing dict-size\n", comp_name);
++			goto failed;
++		}
++
++		size = strtof(argv[1], &b);
++		if(*b == '%') {
++			if(size <= 0 || size > 100) {
++				fprintf(stderr, "%s: -Xdict-size percentage "
++					"should be 0 < dict-size <= 100\n", comp_name);
++				goto failed;
++			}
++
++			lzma_dict_percent = size;
++			options.dict_size = 0;
++		} else {
++			if((float) ((int) size) != size) {
++				fprintf(stderr, "%s: -Xdict-size can't be "
++					"fractional unless a percentage of the"
++					" block size\n", comp_name);
++				goto failed;
++			}
++
++			lzma_dict_percent = 0;
++			options.dict_size = (int) size;
++
++			if(*b == 'k' || *b == 'K')
++				options.dict_size *= 1024;
++			else if(*b == 'm' || *b == 'M')
++				options.dict_size *= 1024 * 1024;
++			else if(*b != '\0') {
++				fprintf(stderr, "%s: -Xdict-size invalid "
++					"dict-size\n", comp_name);
++				goto failed;
++			}
++		}
++
++		return 1;
++	}
++	
++	return -1;
++	
++failed:
++	return -2;
++
++}
++
++int lzma_xz_options_post(int block_size, int lzmaver)
++{
++	const char *comp_name = lzmaver_str[lzmaver];
++	/*
++	 * if -Xdict-size has been specified use this to compute the datablock
++	 * dictionary size
++	 */
++	if(options.dict_size || lzma_dict_percent) {
++		int dict_size_min = (lzmaver == 1 ? 4096 : 8192);
++		int n;
++
++		if(options.dict_size) {
++			if(options.dict_size > block_size) {
++				fprintf(stderr, "%s: -Xdict-size is larger than"
++				" block_size\n", comp_name);
++				goto failed;
++			}
++		} else
++			options.dict_size = block_size * lzma_dict_percent / 100;
++
++		if(options.dict_size < dict_size_min) {
++			fprintf(stderr, "%s: -Xdict-size should be %i bytes "
++				"or larger\n", comp_name, dict_size_min);
++			goto failed;
++		}
++
++		/*
++		 * dictionary_size must be storable in xz header as either
++		 * 2^n or as  2^n+2^(n+1)
++	 	*/
++		n = ffs(options.dict_size) - 1;
++		if(options.dict_size != (1 << n) &&
++				options.dict_size != ((1 << n) + (1 << (n + 1)))) {
++			fprintf(stderr, "%s: -Xdict-size is an unsupported "
++				"value, dict-size must be storable in %s "
++				"header\n", comp_name, comp_name);
++			fprintf(stderr, "as either 2^n or as 2^n+2^(n+1).  "
++				"Example dict-sizes are 75%%, 50%%, 37.5%%, "
++				"25%%,\n");
++			fprintf(stderr, "or 32K, 16K, 8K etc.\n");
++			goto failed;
++		}
++
++	} else
++		/* No -Xdict-size specified, use defaults */
++		options.dict_size = block_size;
++
++	return 0;
++
++failed:
++	return -1;
++}
++
++static struct lzma_opts lzma_comp_opts;
++
++void *lzma_xz_dump_options(int block_size, int *size, int flags)
++{
++	/* No need to store default options */
++	if (options.preset == 6 &&
++			options.extreme == 0 &&
++			options.lc == LZMA_OPT_LC_DEFAULT &&
++			options.lp == LZMA_OPT_LC_DEFAULT &&
++			options.pb == LZMA_OPT_PB_DEFAULT &&
++			options.fb == 0 &&
++			options.dict_size == block_size &&
++			flags == 0)
++		return NULL;
++	
++	*size = sizeof(struct lzma_opts);
++
++	lzma_comp_opts.flags |= flags;
++	
++	if (options.extreme)
++		lzma_comp_opts.flags |= LZMA_OPT_EXTREME;
++	
++	lzma_comp_opts.flags |= ((options.preset << LZMA_OPT_PRE_OFF) & LZMA_OPT_PRE_MASK);
++	
++	lzma_comp_opts.bit_opts = 
++			((options.lc << LZMA_OPT_LC_OFF) & LZMA_OPT_LC_MASK) |
++			((options.lp << LZMA_OPT_LP_OFF) & LZMA_OPT_LP_MASK) |
++			((options.pb << LZMA_OPT_PB_OFF) & LZMA_OPT_PB_MASK);
++	lzma_comp_opts.fb = options.fb;
++	lzma_comp_opts.dict_size = options.dict_size;
++	
++	SQUASHFS_INSWAP_LZMA_COMP_OPTS(&lzma_comp_opts);
++	
++	return &lzma_comp_opts;
++}
++
++int lzma_xz_extract_options(int block_size, void *buffer, int size, int lzmaver)
++{
++	if (size == 0) {
++		/* default options */
++		options.preset = 6;
++		options.extreme = 0;
++		options.lc = LZMA_OPT_LC_DEFAULT;
++		options.lp = LZMA_OPT_LC_DEFAULT;
++		options.pb = LZMA_OPT_PB_DEFAULT;
++		options.fb = LZMA_OPT_FB_DEFAULT;
++		options.dict_size = block_size;
++		options.flags = 0;
++	} else {
++		struct lzma_opts *comp_opts = buffer;
++		int n;
++		
++		if (size != sizeof(struct lzma_opts))
++			goto failed;
++		
++		SQUASHFS_INSWAP_LZMA_COMP_OPTS(&comp_opts);
++		
++		options.flags = comp_opts->flags & LZMA_OPT_FLT_MASK;
++		options.preset  = (comp_opts->flags & LZMA_OPT_PRE_MASK) >> LZMA_OPT_PRE_OFF;
++		options.extreme = !!(comp_opts->flags & LZMA_OPT_EXTREME);
++
++		options.lc = (comp_opts->bit_opts & LZMA_OPT_LC_MASK) >> LZMA_OPT_LC_OFF;
++		options.lp = (comp_opts->bit_opts & LZMA_OPT_LP_MASK) >> LZMA_OPT_LP_OFF;
++		options.pb = (comp_opts->bit_opts & LZMA_OPT_PB_MASK) >> LZMA_OPT_PB_OFF;
++		options.fb = comp_opts->fb;
++		options.dict_size = comp_opts->dict_size;
++		
++		/* check that the LZMA bit options are in range */
++		if (options.lc < LZMA_OPT_LC_MIN || options.lc > LZMA_OPT_LC_MAX ||
++			options.lp < LZMA_OPT_LP_MIN || options.lp > LZMA_OPT_LP_MAX ||
++			options.pb < LZMA_OPT_PB_MIN || options.pb > LZMA_OPT_PB_MAX ||
++			options.fb < LZMA_OPT_FB_MIN || options.fb > LZMA_OPT_FB_MAX)
++			goto failed;
++
++		/*
++		 * check that the dictionary size seems correct - the dictionary
++		 * size should 2^n or 2^n+2^(n+1)
++		 */
++		n = ffs(options.dict_size) - 1;
++		if(options.dict_size != (1 << n) &&
++				options.dict_size != ((1 << n) + (1 << (n + 1))))
++			goto failed;
++		
++	}
++	
++	return 0;
++
++failed:
++	fprintf(stderr, "%s: error reading stored compressor options from "
++		"filesystem!\n", lzmaver_str[lzmaver]);
++	return -1;	
++}
++
++void lzma_xz_usage(int lzmaver)
++{
++	fprintf(stderr, "\t  -Xpreset <preset>\n");
++	fprintf(stderr, "\t\tcompression preset (0-9, default 6)\n");
++	fprintf(stderr, "\t  -Xe\n");
++	fprintf(stderr, "\t\tTry to improve compression ratio by using more ");
++	fprintf(stderr, "CPU time.\n");
++	fprintf(stderr, "\t  -Xlc <lc>\n");
++	fprintf(stderr, "\t\tNumber of literal context bits (0-4, default 3)\n");
++	fprintf(stderr, "\t  -Xlp <lp>\n");
++	fprintf(stderr, "\t\tNumber of literal position bits (0-4, default 0)\n");
++	fprintf(stderr, "\t  -Xpb <pb>\n");
++	fprintf(stderr, "\t\tNumber of position bits (0-4, default 2)\n");
++	fprintf(stderr, "\t  -Xnice <nice>\n");
++	fprintf(stderr, "\t\tNice length of a match (5-273, default 64)\n");
++	fprintf(stderr, "\t  -Xdict-size <dict-size>\n");
++	fprintf(stderr, "\t\tUse <dict-size> as the %s dictionary size.  The",
++			lzmaver == LZMA_OPT_LZMA ? "LZMA" : "XZ");
++	fprintf(stderr, " dictionary size\n\t\tcan be specified as a");
++	fprintf(stderr, " percentage of the block size, or as an\n\t\t");
++	fprintf(stderr, "absolute value.  The dictionary size must be less");
++	fprintf(stderr, " than or equal\n\t\tto the block size and %d bytes", 
++			lzmaver == LZMA_OPT_LZMA ? 4096 : 8192);
++	fprintf(stderr, " or larger.  It must also be\n\t\tstorable in the lzma");
++	fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
++	fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
++	fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n");
++	
++}
+--- a/squashfs-tools/lzma_xz_wrapper.c
++++ b/squashfs-tools/lzma_xz_wrapper.c
+@@ -27,6 +27,7 @@
+ 
+ #include "squashfs_fs.h"
+ #include "compressor.h"
++#include "lzma_xz_options.h"
+ 
+ #define LZMA_PROPS_SIZE 5
+ #define LZMA_UNCOMP_SIZE 8
+@@ -38,13 +39,27 @@
+ static int lzma_compress(void *dummy, void *dest, void *src,  int size,
+ 	int block_size, int *error)
+ {
++	uint32_t preset;
+ 	unsigned char *d = (unsigned char *) dest;
++	struct lzma_xz_options *opts = lzma_xz_get_options();
++
+ 	lzma_options_lzma opt;
+ 	lzma_stream strm = LZMA_STREAM_INIT;
+ 	int res;
+ 
+-	lzma_lzma_preset(&opt, LZMA_OPTIONS);
+-	opt.dict_size = block_size;
++	preset = opts->preset;
++
++	if (opts->extreme)
++		preset |= LZMA_PRESET_EXTREME;
++
++	lzma_lzma_preset(&opt, opts->preset);
++	opt.lc = opts->lc;
++	opt.lp = opts->lp;
++	opt.pb = opts->pb;
++	if (opts->fb)
++		opt.nice_len = opts->fb;
++
++	opt.dict_size = opts->dict_size;
+ 
+ 	res = lzma_alone_encoder(&strm, &opt);
+ 	if(res != LZMA_OK) {
+@@ -143,13 +158,45 @@ failed:
+ 	return -1;
+ }
+ 
++static int lzma_options(char *argv[], int argc)
++{
++	return lzma_xz_options(argv, argc, LZMA_OPT_LZMA);
++}
++
++
++static int lzma_options_post(int block_size)
++{
++	return lzma_xz_options_post(block_size, LZMA_OPT_LZMA);
++}
++
++
++static void *lzma_dump_options(int block_size, int *size)
++{
++	return lzma_xz_dump_options(block_size, size, 0);
++}
++
++
++static int lzma_extract_options(int block_size, void *buffer, int size)
++{
++	return lzma_xz_extract_options(block_size, buffer, size, LZMA_OPT_LZMA);
++}
++
++
++void lzma_usage()
++{
++	lzma_xz_usage(LZMA_OPT_LZMA);
++}
++
+ 
+ struct compressor lzma_comp_ops = {
+ 	.init = NULL,
+ 	.compress = lzma_compress,
+ 	.uncompress = lzma_uncompress,
+-	.options = NULL,
+-	.usage = NULL,
++	.options = lzma_options,
++	.options_post = lzma_options_post,
++	.dump_options = lzma_dump_options,
++	.extract_options = lzma_extract_options,
++	.usage = lzma_usage,
+ 	.id = LZMA_COMPRESSION,
+ 	.name = "lzma",
+ 	.supported = 1
+--- a/squashfs-tools/xz_wrapper.h
++++ b/squashfs-tools/xz_wrapper.h
+@@ -24,25 +24,6 @@
+  *
+  */
+ 
+-#ifndef linux
+-#define __BYTE_ORDER BYTE_ORDER
+-#define __BIG_ENDIAN BIG_ENDIAN
+-#define __LITTLE_ENDIAN LITTLE_ENDIAN
+-#else
+-#include <endian.h>
+-#endif
+-
+-#if __BYTE_ORDER == __BIG_ENDIAN
+-extern unsigned int inswap_le32(unsigned int);
+-
+-#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
+-	(s)->dictionary_size = inswap_le32((s)->dictionary_size); \
+-	(s)->flags = inswap_le32((s)->flags); \
+-}
+-#else
+-#define SQUASHFS_INSWAP_COMP_OPTS(s)
+-#endif
+-
+ #define MEMLIMIT (32 * 1024 * 1024)
+ 
+ struct bcj {
+--- a/squashfs-tools/xz_wrapper.c
++++ b/squashfs-tools/xz_wrapper.c
+@@ -30,6 +30,7 @@
+ #include "squashfs_fs.h"
+ #include "xz_wrapper.h"
+ #include "compressor.h"
++#include "lzma_xz_options.h"
+ 
+ static struct bcj bcj[] = {
+ 	{ "x86", LZMA_FILTER_X86, 0 },
+@@ -41,22 +42,18 @@ static struct bcj bcj[] = {
+ 	{ NULL, LZMA_VLI_UNKNOWN, 0 }
+ };
+ 
+-static struct comp_opts comp_opts;
+-
+ static int filter_count = 1;
+-static int dictionary_size = 0;
+-static float dictionary_percent = 0;
+ 
+ 
+ static int xz_options(char *argv[], int argc)
+ {
+-	int i;
+-	char *name;
+-
+ 	if(strcmp(argv[0], "-Xbcj") == 0) {
++		int i;
++		char *name;
++
+ 		if(argc < 2) {
+ 			fprintf(stderr, "xz: -Xbcj missing filter\n");
+-			goto failed;
++			return -2;
+ 		}
+ 
+ 		name = argv[1];
+@@ -76,190 +73,50 @@ static int xz_options(char *argv[], int 
+ 			}
+ 			if(bcj[i].name == NULL) {
+ 				fprintf(stderr, "xz: -Xbcj unrecognised "
+-					"filter\n");
+-				goto failed;
+-			}
+-		}
+-	
+-		return 1;
+-	} else if(strcmp(argv[0], "-Xdict-size") == 0) {
+-		char *b;
+-		float size;
+-
+-		if(argc < 2) {
+-			fprintf(stderr, "xz: -Xdict-size missing dict-size\n");
+-			goto failed;
+-		}
+-
+-		size = strtof(argv[1], &b);
+-		if(*b == '%') {
+-			if(size <= 0 || size > 100) {
+-				fprintf(stderr, "xz: -Xdict-size percentage "
+-					"should be 0 < dict-size <= 100\n");
+-				goto failed;
+-			}
+-
+-			dictionary_percent = size;
+-			dictionary_size = 0;
+-		} else {
+-			if((float) ((int) size) != size) {
+-				fprintf(stderr, "xz: -Xdict-size can't be "
+-					"fractional unless a percentage of the"
+-					" block size\n");
+-				goto failed;
+-			}
+-
+-			dictionary_percent = 0;
+-			dictionary_size = (int) size;
+-
+-			if(*b == 'k' || *b == 'K')
+-				dictionary_size *= 1024;
+-			else if(*b == 'm' || *b == 'M')
+-				dictionary_size *= 1024 * 1024;
+-			else if(*b != '\0') {
+-				fprintf(stderr, "xz: -Xdict-size invalid "
+-					"dict-size\n");
+-				goto failed;
++						"filter\n");
++				return -2;
+ 			}
+ 		}
+-
+ 		return 1;
++	} else {
++		return lzma_xz_options(argv, argc, LZMA_OPT_XZ);
+ 	}
+-
+-	return -1;
+-	
+-failed:
+-	return -2;
+ }
+ 
+ 
+ static int xz_options_post(int block_size)
+ {
+-	/*
+-	 * if -Xdict-size has been specified use this to compute the datablock
+-	 * dictionary size
+-	 */
+-	if(dictionary_size || dictionary_percent) {
+-		int n;
+-
+-		if(dictionary_size) {
+-			if(dictionary_size > block_size) {
+-				fprintf(stderr, "xz: -Xdict-size is larger than"
+-				" block_size\n");
+-				goto failed;
+-			}
+-		} else
+-			dictionary_size = block_size * dictionary_percent / 100;
+-
+-		if(dictionary_size < 8192) {
+-			fprintf(stderr, "xz: -Xdict-size should be 8192 bytes "
+-				"or larger\n");
+-			goto failed;
+-		}
+-
+-		/*
+-		 * dictionary_size must be storable in xz header as either
+-		 * 2^n or as  2^n+2^(n+1)
+-	 	*/
+-		n = ffs(dictionary_size) - 1;
+-		if(dictionary_size != (1 << n) && 
+-				dictionary_size != ((1 << n) + (1 << (n + 1)))) {
+-			fprintf(stderr, "xz: -Xdict-size is an unsupported "
+-				"value, dict-size must be storable in xz "
+-				"header\n");
+-			fprintf(stderr, "as either 2^n or as 2^n+2^(n+1).  "
+-				"Example dict-sizes are 75%%, 50%%, 37.5%%, "
+-				"25%%,\n");
+-			fprintf(stderr, "or 32K, 16K, 8K etc.\n");
+-			goto failed;
+-		}
+-
+-	} else
+-		/* No -Xdict-size specified, use defaults */
+-		dictionary_size = block_size;
+-
+-	return 0;
+-
+-failed:
+-	return -1;
++	return lzma_xz_options_post(block_size, LZMA_OPT_XZ);
+ }
+ 
+ 
+ static void *xz_dump_options(int block_size, int *size)
+ {
+-	int flags = 0, i;
+-
+-	/*
+-	 * don't store compressor specific options in file system if the
+-	 * default options are being used - no compressor options in the
+-	 * file system means the default options are always assumed
+-	 *
+-	 * Defaults are:
+-	 *  metadata dictionary size: SQUASHFS_METADATA_SIZE
+-	 *  datablock dictionary size: block_size
+-	 *  1 filter
+-	 */
+-	if(dictionary_size == block_size && filter_count == 1)
+-		return NULL;
++	int i, flags = 0;
+ 
+ 	for(i = 0; bcj[i].name; i++)
+ 		flags |= bcj[i].selected << i;
+ 
+-	comp_opts.dictionary_size = dictionary_size;
+-	comp_opts.flags = flags;
+-
+-	SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
+-
+-	*size = sizeof(comp_opts);
+-	return &comp_opts;
++	return lzma_xz_dump_options(block_size, size, flags);
+ }
+ 
+ 
+ static int xz_extract_options(int block_size, void *buffer, int size)
+ {
+-	struct comp_opts *comp_opts = buffer;
+-	int flags, i, n;
+-
+-	if(size == 0) {
+-		/* set defaults */
+-		dictionary_size = block_size;
+-		flags = 0;
+-	} else {
+-		/* check passed comp opts struct is of the correct length */
+-		if(size != sizeof(struct comp_opts))
+-			goto failed;
+-					 
+-		SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
+-
+-		dictionary_size = comp_opts->dictionary_size;
+-		flags = comp_opts->flags;
+-
+-		/*
+-		 * check that the dictionary size seems correct - the dictionary
+-		 * size should 2^n or 2^n+2^(n+1)
+-		 */
+-		n = ffs(dictionary_size) - 1;
+-		if(dictionary_size != (1 << n) && 
+-				dictionary_size != ((1 << n) + (1 << (n + 1))))
+-			goto failed;
+-	}
++	int ret = lzma_xz_extract_options(block_size, buffer, size, LZMA_OPT_XZ);
+ 
+-	filter_count = 1;
+-	for(i = 0; bcj[i].name; i++) {
+-		if((flags >> i) & 1) {
+-			bcj[i].selected = 1;
+-			filter_count ++;
+-		} else
+-			bcj[i].selected = 0;
++	if (!ret) {
++		int i;
++		struct lzma_xz_options *opts = lzma_xz_get_options();
++		for(i = 0; bcj[i].name; i++) {
++			if((opts->flags >> i) & 1) {
++				bcj[i].selected = 1;
++				filter_count ++;
++			} else
++				bcj[i].selected = 0;
++		}
+ 	}
+-
+-	return 0;
+-
+-failed:
+-	fprintf(stderr, "xz: error reading stored compressor options from "
+-		"filesystem!\n");
+-
+-	return -1;
++	return ret;
+ }
+ 
+ 
+@@ -268,6 +125,7 @@ static int xz_init(void **strm, int bloc
+ 	int i, j, filters = datablock ? filter_count : 1;
+ 	struct filter *filter = malloc(filters * sizeof(struct filter));
+ 	struct xz_stream *stream;
++	struct lzma_xz_options *opts = lzma_xz_get_options();
+ 
+ 	if(filter == NULL)
+ 		goto failed;
+@@ -281,7 +139,7 @@ static int xz_init(void **strm, int bloc
+ 
+ 	memset(filter, 0, filters * sizeof(struct filter));
+ 
+-	stream->dictionary_size = datablock ? dictionary_size :
++	stream->dictionary_size = datablock ? opts->dict_size :
+ 		SQUASHFS_METADATA_SIZE;
+ 
+ 	filter[0].filter[0].id = LZMA_FILTER_LZMA2;
+@@ -323,14 +181,25 @@ static int xz_compress(void *strm, void 
+         lzma_ret res = 0;
+ 	struct xz_stream *stream = strm;
+ 	struct filter *selected = NULL;
++	struct lzma_xz_options *opts = lzma_xz_get_options();
+ 
+ 	stream->filter[0].buffer = dest;
+ 
+ 	for(i = 0; i < stream->filters; i++) {
++		uint32_t preset = opts->preset;
+ 		struct filter *filter = &stream->filter[i];
+ 
+-        	if(lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT))
+-                	goto failed;
++		if (opts->extreme)
++			preset |= LZMA_PRESET_EXTREME;
++
++        if(lzma_lzma_preset(&stream->opt, preset))
++               	goto failed;
++
++        stream->opt.lc = opts->lc;
++    	stream->opt.lp = opts->lp;
++    	stream->opt.pb = opts->pb;
++    	if (opts->fb)
++    		stream->opt.nice_len = opts->fb;
+ 
+ 		stream->opt.dict_size = stream->dictionary_size;
+ 
+@@ -384,22 +253,13 @@ static int xz_uncompress(void *dest, voi
+ 
+ void xz_usage()
+ {
++	lzma_xz_usage(LZMA_OPT_XZ);
+ 	fprintf(stderr, "\t  -Xbcj filter1,filter2,...,filterN\n");
+ 	fprintf(stderr, "\t\tCompress using filter1,filter2,...,filterN in");
+ 	fprintf(stderr, " turn\n\t\t(in addition to no filter), and choose");
+ 	fprintf(stderr, " the best compression.\n");
+ 	fprintf(stderr, "\t\tAvailable filters: x86, arm, armthumb,");
+ 	fprintf(stderr, " powerpc, sparc, ia64\n");
+-	fprintf(stderr, "\t  -Xdict-size <dict-size>\n");
+-	fprintf(stderr, "\t\tUse <dict-size> as the XZ dictionary size.  The");
+-	fprintf(stderr, " dictionary size\n\t\tcan be specified as a");
+-	fprintf(stderr, " percentage of the block size, or as an\n\t\t");
+-	fprintf(stderr, "absolute value.  The dictionary size must be less");
+-	fprintf(stderr, " than or equal\n\t\tto the block size and 8192 bytes");
+-	fprintf(stderr, " or larger.  It must also be\n\t\tstorable in the xz");
+-	fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
+-	fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
+-	fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n");
+ }
+ 
+ 
+--- a/squashfs-tools/Makefile
++++ b/squashfs-tools/Makefile
+@@ -140,6 +140,8 @@ COMPRESSORS += xz
+ endif
+ 
+ ifneq ($(LZMA_XZ_SUPPORT)$(XZ_SUPPORT),)
++MKSQUASHFS_OBJS += lzma_xz_options.o
++UNSQUASHFS_OBJS += lzma_xz_options.o
+ ifneq ($(LZMA_LIB),)
+ MKSQUASHFS_OBJS += $(LZMA_LIB)
+ UNSQUASHFS_OBJS += $(LZMA_LIB)
 

comments