diff -Narup Mtd-orig/fs/Kconfig mtd/fs/Kconfig
--- Mtd-orig/fs/Kconfig	2005-11-08 02:02:13.000000000 +0100
+++ mtd/fs/Kconfig	2005-11-28 10:19:04.000000000 +0100
@@ -77,73 +77,26 @@ config JFFS2_SUMMARY
 
 	  If unsure, say 'N'.
 
-config JFFS2_COMPRESSION_OPTIONS
-	bool "Advanced compression options for JFFS2"
+config JFFS2_COMPR_CONTROL
+	string "Compression control string"
 	depends on JFFS2_FS
-	default n
+	default "deflate"
 	help
-	  Enabling this option allows you to explicitly choose which
-	  compression modules, if any, are enabled in JFFS2. Removing
-	  compressors and mean you cannot read existing file systems,
-	  and enabling experimental compressors can mean that you
-	  write a file system which cannot be read by a standard kernel.
-
-	  If unsure, you should _definitely_ say 'N'.
-
-config JFFS2_ZLIB
-	bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS
-	select ZLIB_INFLATE
-	select ZLIB_DEFLATE
-	depends on JFFS2_FS
-	default y
-        help
-          Zlib is designed to be a free, general-purpose, legally unencumbered,
-          lossless data-compression library for use on virtually any computer
-          hardware and operating system. See <http://www.gzip.org/zlib/> for
-          further information.
+	  Describes a comma separated list of compressors used for compression.
+	  c1,c2,c3,.. Compress with c1 then c2 then c3...
+	  [c1,c2,c3,...] Compress with all of them and choose the first working
+	  {c1,c2,c3,...} Compress with all of them and choose the one with
+	  the best compression ratio.
+	  These can be mixed but not nested.
 
-          Say 'Y' if unsure.
-
-config JFFS2_RTIME
-	bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+config JFFS2_COMPR_COMPAT
+	bool "Decompress compatibility with older compression framework"
 	depends on JFFS2_FS
 	default y
-        help
-          Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
-
-config JFFS2_RUBIN
-	bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS
-	depends on JFFS2_FS
-	default n
-        help
-          RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
-
-choice
-        prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
-        default JFFS2_CMODE_PRIORITY
-        depends on JFFS2_FS
-        help
-          You can set here the default compression mode of JFFS2 from
-          the available compression modes. Don't touch if unsure.
-
-config JFFS2_CMODE_NONE
-        bool "no compression"
-        help
-          Uses no compression.
-
-config JFFS2_CMODE_PRIORITY
-        bool "priority"
-        help
-          Tries the compressors in a predefinied order and chooses the first
-          successful one.
-
-config JFFS2_CMODE_SIZE
-        bool "size (EXPERIMENTAL)"
-        help
-          Tries all compressors and chooses the one which has the smallest
-          result.
-
-endchoice
+	help
+	  Add support for decompressing data compressed with the RTIME,
+	  RUBINMIPS and DYNRUBIN compressors and adds decompression
+	  support for ZLIB with full headers.
 
 config JFFS3_FS
 	tristate "Journalling Flash File System v3 (JFFS3) support (EXPERIMENTAL)"
diff -Narup Mtd-orig/fs/jffs2/Makefile.common mtd/fs/jffs2/Makefile.common
--- Mtd-orig/fs/jffs2/Makefile.common	2005-09-15 14:18:12.000000000 +0200
+++ mtd/fs/jffs2/Makefile.common	2005-11-28 10:19:04.000000000 +0100
@@ -12,7 +12,6 @@ jffs2-y	+= symlink.o build.o erase.o bac
 jffs2-y	+= super.o debug.o
 
 jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= wbuf.o
-jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
-jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
-jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
 jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
+
+jffs2-$(CONFIG_JFFS2_COMPR_COMPAT)	+= compr_compat.o
diff -Narup Mtd-orig/fs/jffs2/compr.c mtd/fs/jffs2/compr.c
--- Mtd-orig/fs/jffs2/compr.c	2005-11-08 02:02:14.000000000 +0100
+++ mtd/fs/jffs2/compr.c	2005-11-29 16:24:04.000000000 +0100
@@ -1,457 +1,601 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001-2003 Red Hat, Inc.
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
- * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- * $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $
- *
- */
+#include <linux/crypto.h>
+#include <linux/rwsem.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
 
 #include "compr.h"
 
-static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
+/* TODO: ctx->tree_lock is not used yet. it will be needed if once we implement a tree
+recreation function, for changing it on-the-fly. for this we need to get the new control
+string somehow first, for eg. through a procfs or a sysfs entry. */
+
+/* using caches for better memory organization & debugging aid */
+static kmem_cache_t *ctx_cache = NULL;
+static kmem_cache_t *tree_cache = NULL;
+static kmem_cache_t *crypto_cache = NULL;
+
+/* write locked when a new context is being created or destroyed, read locked in other
+functions */
+static struct rw_semaphore ctx_lock;
+
+int jffs2_init_compr_engine(void)
+{
+	int ret = 0;
+	init_rwsem(&ctx_lock);
+
+	ctx_cache = kmem_cache_create("compress_ctx", sizeof(struct compress_ctx),
+										0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (unlikely(!ctx_cache)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	crypto_cache = kmem_cache_create("cryptolist_entry", sizeof(struct cryptolist_entry),
+										   0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (unlikely(!crypto_cache)) {
+		kmem_cache_destroy(ctx_cache);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	tree_cache = kmem_cache_create("compresstree_node", sizeof(struct compresstree_node),
+										 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (unlikely(!tree_cache)) {
+		kmem_cache_destroy(ctx_cache);
+		kmem_cache_destroy(tree_cache);
+		ret = -ENOMEM;
+	}
+ out:
+	return ret;
+}
+
+void jffs2_exit_compr_engine()
+{
+	if (ctx_cache)
+		kmem_cache_destroy(ctx_cache);
+	if (crypto_cache)
+		kmem_cache_destroy(crypto_cache);
+	if (tree_cache)
+		kmem_cache_destroy(tree_cache);
+}
+
+static int jffs2_create_crypto_alg(struct compress_ctx *ctx, struct cryptolist_entry **walk, char *alg_name)
+{
+	*walk = (struct cryptolist_entry *) kmem_cache_alloc(crypto_cache, GFP_KERNEL);
+	if (!(*walk))
+		return -ENOMEM;
+	memset(*walk, 0, sizeof(struct cryptolist_entry));
+
+	(*walk)->sess = crypto_alloc_tfm(alg_name, 0);
+	if (unlikely(!(*walk)->sess)) {
+		kmem_cache_free(crypto_cache, *walk);
+		return -ENOMEM;
+	}
+
+	up_read(&ctx->crypto_lock);
+	down_write(&ctx->crypto_lock);
+
+	if (unlikely(!ctx->cryptolist_head))
+		ctx->cryptolist_head = *walk;
+	else
+		ctx->cryptolist_tail->next = *walk;
+
+	ctx->cryptolist_tail = *walk;
+	downgrade_write(&ctx->crypto_lock);
+
+	return 0;
+}
+
+/* called with ctx_lock read-locked and ctx->crypto_lock read-locked */
+static struct cryptolist_entry *crypto_compress_wrapper(struct compress_ctx *ctx,
+									char *alg_name, u8 *src, int32_t srclen,
+									u8 *dst, int32_t *dstlen)
+{
+	struct cryptolist_entry *ret = NULL;
+	struct cryptolist_entry *walk;
+	int temp, res;
+
+	temp = strlen(alg_name);
+	if (*dstlen < (temp + 1))
+		goto out;
+	strcpy(dst, alg_name);
+	dst += temp;
+	*dst = '\0';
+	dst++;
+	(*dstlen) -= temp;
+	(*dstlen)--;
+	walk = ctx->cryptolist_head;
+
+	while (walk && strcmp(alg_name, crypto_tfm_alg_name(walk->sess)))
+		walk = walk->next;
+	/* performance hit if a compressor is used first time but after this branch
+		prediction can help much */
+	if (unlikely(!walk)) {
+		res = jffs2_create_crypto_alg(ctx, &walk, alg_name);
+		if (res)
+			goto out;
+	}
+
+	switch (crypto_tfm_alg_type(walk->sess)) {
+		case CRYPTO_ALG_TYPE_CIPHER:
+			printk("%s: CHIPER algorithm type is not supported jet! \n",__FUNCTION__);
+			res = 1;
+			break;
+
+		case CRYPTO_ALG_TYPE_DIGEST:
+			printk("%s: DIGEST algorithm type is not supported jet! \n",__FUNCTION__);
+			res = 1;
+			break;
+
+		case CRYPTO_ALG_TYPE_COMPRESS:
+			res = crypto_comp_compress(walk->sess, src, srclen, dst, dstlen); 
+			break;
+
+		default:
+			printk("%s: unknown algorithm type! \n",__FUNCTION__);
+			res = 1;
+			break;
+	}
+
+	if (res)
+		goto out;
+
+	(*dstlen) += temp;
+	(*dstlen)++;
+	ret = walk;
+out:
+	return ret;
+}
+
+/* called with ctx_lock read-locked and ctx->crypto_lock read-locked */
+static struct cryptolist_entry *crypto_decompress_wrapper(struct compress_ctx *ctx,
+										u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen)
+{
+	struct cryptolist_entry *ret = NULL;
+	struct cryptolist_entry *walk;
+	int temp = 0, res;
+	char *alg_name = (char *) src;
+
+	while (*src) {
+		src++;
+		srclen--;
+		temp++;
+	}
+	src++;
+	srclen--;
+
+	walk = ctx->cryptolist_head;
+	while (walk && strcmp(alg_name, crypto_tfm_alg_name(walk->sess)))
+		walk = walk->next;
+	if (unlikely(!walk)) {
+		res = jffs2_create_crypto_alg(ctx, &walk, alg_name);
+		if (res)
+			goto out;
+	}
+
+	switch (crypto_tfm_alg_type(walk->sess)) {
+		case CRYPTO_ALG_TYPE_CIPHER:
+			printk("%s: CHIPER algorithm type is not supported jet! \n",__FUNCTION__);
+			res = 1;
+			break;
+
+		case CRYPTO_ALG_TYPE_DIGEST:
+			printk("%s: DIGEST algorithm type is not supported jet! \n",__FUNCTION__);
+			res = 1;
+			break;
+
+		case CRYPTO_ALG_TYPE_COMPRESS:
+			res = crypto_comp_decompress(walk->sess, src, srclen, dst, dstlen);
+			break;
+
+		default:
+			printk("%s: unknown algorithm type! \n",__FUNCTION__);
+			res = 1;
+			break;
 
-/* Available compressors are on this list */
-static LIST_HEAD(jffs2_compressor_list);
+		
+	}
 
-/* Actual compression mode */
-static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+	if (!res)
+		ret = walk;
 
-/* Statistics for blocks stored without compression */
-static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
-
-/* jffs2_compress:
- * @data: Pointer to uncompressed data
- * @cdata: Pointer to returned pointer to buffer for compressed data
- * @datalen: On entry, holds the amount of data available for compression.
- *	On exit, expected to hold the amount of data actually compressed.
- * @cdatalen: On entry, holds the amount of space available for compressed
- *	data. On exit, expected to hold the actual size of the compressed
- *	data.
- *
- * Returns: Lower byte to be stored with data indicating compression type used.
- * Zero is used to show that the data could not be compressed - the
- * compressed version was actually larger than the original.
- * Upper byte will be used later. (soon)
- *
- * If the cdata buffer isn't large enough to hold all the uncompressed data,
- * jffs2_compress should compress as much as will fit, and should set
- * *datalen accordingly to show the amount of data which were compressed.
- */
-uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-			     unsigned char *data_in, unsigned char **cpage_out,
-			     uint32_t *datalen, uint32_t *cdatalen)
-{
-	int ret = JFFS2_COMPR_NONE;
-        int compr_ret;
-        struct jffs2_compressor *this, *best=NULL;
-        unsigned char *output_buf = NULL, *tmp_buf;
-        uint32_t orig_slen, orig_dlen;
-        uint32_t best_slen=0, best_dlen=0;
-
-        switch (jffs2_compression_mode) {
-        case JFFS2_COMPR_MODE_NONE:
-                break;
-        case JFFS2_COMPR_MODE_PRIORITY:
-                output_buf = kmalloc(*cdatalen,GFP_KERNEL);
-                if (!output_buf) {
-                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
-                        goto out;
-                }
-                orig_slen = *datalen;
-                orig_dlen = *cdatalen;
-                spin_lock(&jffs2_compressor_list_lock);
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        /* Skip decompress-only backwards-compatibility and disabled modules */
-                        if ((!this->compress)||(this->disabled))
-                                continue;
-
-                        this->usecount++;
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        *datalen  = orig_slen;
-                        *cdatalen = orig_dlen;
-                        compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
-                        spin_lock(&jffs2_compressor_list_lock);
-                        this->usecount--;
-                        if (!compr_ret) {
-                                ret = this->compr;
-                                this->stat_compr_blocks++;
-                                this->stat_compr_orig_size += *datalen;
-                                this->stat_compr_new_size  += *cdatalen;
-                                break;
-                        }
-                }
-                spin_unlock(&jffs2_compressor_list_lock);
-                if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
-                break;
-        case JFFS2_COMPR_MODE_SIZE:
-                orig_slen = *datalen;
-                orig_dlen = *cdatalen;
-                spin_lock(&jffs2_compressor_list_lock);
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        /* Skip decompress-only backwards-compatibility and disabled modules */
-                        if ((!this->compress)||(this->disabled))
-                                continue;
-                        /* Allocating memory for output buffer if necessary */
-                        if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                kfree(this->compr_buf);
-                                spin_lock(&jffs2_compressor_list_lock);
-                                this->compr_buf_size=0;
-                                this->compr_buf=NULL;
-                        }
-                        if (!this->compr_buf) {
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
-                                spin_lock(&jffs2_compressor_list_lock);
-                                if (!tmp_buf) {
-                                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
-                                        continue;
-                                }
-                                else {
-                                        this->compr_buf = tmp_buf;
-                                        this->compr_buf_size = orig_dlen;
-                                }
-                        }
-                        this->usecount++;
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        *datalen  = orig_slen;
-                        *cdatalen = orig_dlen;
-                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
-                        spin_lock(&jffs2_compressor_list_lock);
-                        this->usecount--;
-                        if (!compr_ret) {
-                                if ((!best_dlen)||(best_dlen>*cdatalen)) {
-                                        best_dlen = *cdatalen;
-                                        best_slen = *datalen;
-                                        best = this;
-                                }
-                        }
-                }
-                if (best_dlen) {
-                        *cdatalen = best_dlen;
-                        *datalen  = best_slen;
-                        output_buf = best->compr_buf;
-                        best->compr_buf = NULL;
-                        best->compr_buf_size = 0;
-                        best->stat_compr_blocks++;
-                        best->stat_compr_orig_size += best_slen;
-                        best->stat_compr_new_size  += best_dlen;
-                        ret = best->compr;
-                }
-                spin_unlock(&jffs2_compressor_list_lock);
-                break;
-        default:
-                printk(KERN_ERR "JFFS2: unknow compression mode.\n");
-        }
  out:
-        if (ret == JFFS2_COMPR_NONE) {
-	        *cpage_out = data_in;
-	        *datalen = *cdatalen;
-                none_stat_compr_blocks++;
-                none_stat_compr_size += *datalen;
-        }
-        else {
-                *cpage_out = output_buf;
-        }
 	return ret;
 }
 
-int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-		     uint16_t comprtype, unsigned char *cdata_in,
-		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
-{
-        struct jffs2_compressor *this;
-        int ret;
-
-	/* Older code had a bug where it would write non-zero 'usercompr'
-	   fields. Deal with it. */
-	if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
-		comprtype &= 0xff;
-
-	switch (comprtype & 0xff) {
-	case JFFS2_COMPR_NONE:
-		/* This should be special-cased elsewhere, but we might as well deal with it */
-		memcpy(data_out, cdata_in, datalen);
-                none_stat_decompr_blocks++;
-		break;
-	case JFFS2_COMPR_ZERO:
-		memset(data_out, 0, datalen);
-		break;
-	default:
-                spin_lock(&jffs2_compressor_list_lock);
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        if (comprtype == this->compr) {
-                                this->usecount++;
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
-                                spin_lock(&jffs2_compressor_list_lock);
-                                if (ret) {
-                                        printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
-                                }
-                                else {
-                                        this->stat_decompr_blocks++;
-                                }
-                                this->usecount--;
-                                spin_unlock(&jffs2_compressor_list_lock);
-                                return ret;
-                        }
-                }
-		printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
-                spin_unlock(&jffs2_compressor_list_lock);
-		return -EIO;
+static void destroy_tree(struct compresstree_node *what)
+{
+/* no need for locks as this is called from init_compress, before any locking or from
+the following destroy_compress, after it acquired a global write lock */
+	if (what->sib)
+		destroy_tree(what->sib);
+	if (what->fson)
+		destroy_tree(what->fson);
+	kfree(what->name);
+	kmem_cache_free(tree_cache, what);
+}
+
+int jffs2_destroy_compr_context(struct compress_ctx **ctx)
+{
+	down_write(&ctx_lock);
+	if (*ctx) {
+		struct cryptolist_entry *temp;
+		/* no need for locking as we have global exclusive lock */
+		destroy_tree((*ctx)->compresstree_root);
+		temp = (*ctx)->cryptolist_head;
+		while (temp) {
+			(*ctx)->cryptolist_head = (*ctx)->cryptolist_head->next;
+			crypto_free_tfm(temp->sess);
+			kmem_cache_free(crypto_cache, temp);
+			temp = (*ctx)->cryptolist_head;
+		}
+		kmem_cache_free(ctx_cache, *ctx);
+		*ctx = NULL;
 	}
+	up_write(&ctx_lock);
 	return 0;
 }
 
-int jffs2_register_compressor(struct jffs2_compressor *comp)
+struct compress_ctx *jffs2_create_compr_context(char *cnt)
 {
-        struct jffs2_compressor *this;
+	char *w, *w2, *scan, *c, *ccnt, end;
+	compressmode_t node_type = COMPRESSMODE_NORMAL;
+	int breakout, temp;
+	struct compresstree_node *nodetemp, *nodewalk;
+	struct compresstree_tail *tail, *tailtemp, *tailend;
+	struct compress_ctx *ret = NULL;
+
+	down_write(&ctx_lock);
+
+	ret = (struct compress_ctx *) kmem_cache_alloc(ctx_cache, GFP_KERNEL);
+	if (unlikely(!ret))
+		goto out;
+	memset(ret, 0, sizeof(struct compress_ctx));
+
+	init_rwsem(&ret->crypto_lock);
+	init_rwsem(&ret->tree_lock);
+
+	while (*cnt && ((*cnt == ',') || (*cnt == ' ') || (*cnt == '\t')))
+		cnt++;
+	temp = strlen(cnt);
+
+	ccnt = kmalloc(temp + 1, GFP_KERNEL);
+	if (unlikely(!ccnt))
+		goto was_error;
+	strcpy(ccnt, cnt);
+
+	while (temp && ((ccnt[temp - 1] == ',') || (ccnt[temp - 1] == ' ') ||
+		(ccnt[temp - 1] == '\t'))) {
+			ccnt[temp] = '\0';
+			temp--;
+	}
+	if (unlikely(!temp)) {
+		kfree(ccnt);
+		goto out; /* compression will be turned off */
+	}
 
-        if (!comp->name) {
-                printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
-                return -1;
-        }
-        comp->compr_buf_size=0;
-        comp->compr_buf=NULL;
-        comp->usecount=0;
-        comp->stat_compr_orig_size=0;
-        comp->stat_compr_new_size=0;
-        comp->stat_compr_blocks=0;
-        comp->stat_decompr_blocks=0;
-        D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
-
-        spin_lock(&jffs2_compressor_list_lock);
-
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (this->priority < comp->priority) {
-                        list_add(&comp->list, this->list.prev);
-                        goto out;
-                }
-        }
-        list_add_tail(&comp->list, &jffs2_compressor_list);
-out:
-        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-        })
-
-        spin_unlock(&jffs2_compressor_list_lock);
-
-        return 0;
-}
-
-int jffs2_unregister_compressor(struct jffs2_compressor *comp)
-{
-        D2(struct jffs2_compressor *this;)
-
-        D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
-
-        spin_lock(&jffs2_compressor_list_lock);
-
-        if (comp->usecount) {
-                spin_unlock(&jffs2_compressor_list_lock);
-                printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
-                return -1;
-        }
-        list_del(&comp->list);
-
-        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
-                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
-        })
-        spin_unlock(&jffs2_compressor_list_lock);
-        return 0;
-}
-
-#ifdef CONFIG_JFFS2_PROC
-
-#define JFFS2_STAT_BUF_SIZE 16000
-
-char *jffs2_list_compressors(void)
-{
-        struct jffs2_compressor *this;
-        char *buf, *act_buf;
-
-        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
-                if ((this->disabled)||(!this->compress))
-                        act_buf += sprintf(act_buf,"disabled");
-                else
-                        act_buf += sprintf(act_buf,"enabled");
-                act_buf += sprintf(act_buf,"\n");
-        }
-        return buf;
-}
-
-char *jffs2_stats(void)
-{
-        struct jffs2_compressor *this;
-        char *buf, *act_buf;
-
-        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
-
-        act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
-        act_buf += sprintf(act_buf,"%10s   ","none");
-        act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
-                           none_stat_compr_size, none_stat_decompr_blocks);
-        spin_lock(&jffs2_compressor_list_lock);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                act_buf += sprintf(act_buf,"%10s ",this->name);
-                if ((this->disabled)||(!this->compress))
-                        act_buf += sprintf(act_buf,"- ");
-                else
-                        act_buf += sprintf(act_buf,"+ ");
-                act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
-                                   this->stat_compr_new_size, this->stat_compr_orig_size,
-                                   this->stat_decompr_blocks);
-                act_buf += sprintf(act_buf,"\n");
-        }
-        spin_unlock(&jffs2_compressor_list_lock);
-
-        return buf;
-}
-
-char *jffs2_get_compression_mode_name(void)
-{
-        switch (jffs2_compression_mode) {
-        case JFFS2_COMPR_MODE_NONE:
-                return "none";
-        case JFFS2_COMPR_MODE_PRIORITY:
-                return "priority";
-        case JFFS2_COMPR_MODE_SIZE:
-                return "size";
-        }
-        return "unkown";
-}
-
-int jffs2_set_compression_mode_name(const char *name)
-{
-        if (!strcmp("none",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-                return 0;
-        }
-        if (!strcmp("priority",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-                return 0;
-        }
-        if (!strcmp("size",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-                return 0;
-        }
-        return 1;
-}
-
-static int jffs2_compressor_Xable(const char *name, int disabled)
-{
-        struct jffs2_compressor *this;
-        spin_lock(&jffs2_compressor_list_lock);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (!strcmp(this->name, name)) {
-                        this->disabled = disabled;
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        return 0;
-                }
-        }
-        spin_unlock(&jffs2_compressor_list_lock);
-        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
-        return 1;
-}
-
-int jffs2_enable_compressor_name(const char *name)
-{
-        return jffs2_compressor_Xable(name, 0);
-}
-
-int jffs2_disable_compressor_name(const char *name)
-{
-        return jffs2_compressor_Xable(name, 1);
-}
-
-int jffs2_set_compressor_priority(const char *name, int priority)
-{
-        struct jffs2_compressor *this,*comp;
-        spin_lock(&jffs2_compressor_list_lock);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (!strcmp(this->name, name)) {
-                        this->priority = priority;
-                        comp = this;
-                        goto reinsert;
-                }
-        }
-        spin_unlock(&jffs2_compressor_list_lock);
-        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
-        return 1;
-reinsert:
-        /* list is sorted in the order of priority, so if
-           we change it we have to reinsert it into the
-           good place */
-        list_del(&comp->list);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (this->priority < comp->priority) {
-                        list_add(&comp->list, this->list.prev);
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        return 0;
-                }
-        }
-        list_add_tail(&comp->list, &jffs2_compressor_list);
-        spin_unlock(&jffs2_compressor_list_lock);
-        return 0;
-}
-
-#endif
-
-void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
-{
-        if (orig != comprbuf)
-                kfree(comprbuf);
-}
-
-int jffs2_compressors_init(void)
-{
-/* Registering compressors */
-#ifdef CONFIG_JFFS2_ZLIB
-        jffs2_zlib_init();
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-        jffs2_rtime_init();
-#endif
-#ifdef CONFIG_JFFS2_RUBIN
-        jffs2_rubinmips_init();
-        jffs2_dynrubin_init();
-#endif
-/* Setting default compression mode */
-#ifdef CONFIG_JFFS2_CMODE_NONE
-        jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-        D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
-#else
-#ifdef CONFIG_JFFS2_CMODE_SIZE
-        jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-        D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
-#else
-        D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
-#endif
-#endif
-        return 0;
-}
-
-int jffs2_compressors_exit(void)
-{
-/* Unregistering compressors */
-#ifdef CONFIG_JFFS2_RUBIN
-        jffs2_dynrubin_exit();
-        jffs2_rubinmips_exit();
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-        jffs2_rtime_exit();
-#endif
-#ifdef CONFIG_JFFS2_ZLIB
-        jffs2_zlib_exit();
-#endif
-        return 0;
+	tail = kmalloc(sizeof(struct compresstree_tail), GFP_KERNEL);
+	tailend = tail;
+	if (unlikely(!tail)) {
+		kfree(ccnt);
+		goto was_error;
+	}
+
+	tail->owner = NULL;
+	tail->next = NULL;
+	tail->tail = ccnt;
+
+	while (tail) {
+		w2 = w = tail->tail;
+		scan = NULL;
+		breakout = 0;
+		while (!breakout) {
+			switch (*w) {
+				case '{':
+				case '[':
+					if (unlikely(node_type != COMPRESSMODE_NORMAL))
+						goto was_error_clean;
+					if (unlikely(*w == '{')) {
+						node_type = COMPRESSMODE_BESTCOMPRESS;
+						end = '}';
+					} else
+					if (unlikely(*w == '[')) {
+						node_type = COMPRESSMODE_FIRSTCOMPRESS;
+						end = ']';
+					} else
+						end = '\0';
+					w++;
+					while (*w && ((*w == ',') || (*w == '\t') || (*w == ' ')))
+						w++;
+					w2 = w;
+					scan = w;
+					while (*scan && (*scan != end)) scan++;
+					if (*scan) scan++;
+					while (*scan && ((*scan == ',') || (*scan == '\t') || (*scan == ' ')))
+						scan++;
+					break;
+
+				case '\0':
+				case ' ':
+				case '\t':
+				case ',':
+				case '}':
+				case ']':
+					if (unlikely((*w == '}') && (node_type != COMPRESSMODE_BESTCOMPRESS)))
+						goto was_error_clean;
+					if (unlikely((*w == ']') && (node_type != COMPRESSMODE_FIRSTCOMPRESS)))
+						goto was_error_clean;
+					if (unlikely(w2 != w)) { /* to skip empty {} and [] */
+						c = kmalloc(w - w2 + 1, GFP_KERNEL);
+						if (unlikely(!c))
+							goto was_error_clean;
+						strncpy(c, w2, w - w2);
+						c[w - w2] = '\0';
+
+						nodetemp = kmem_cache_alloc(tree_cache, GFP_KERNEL);
+						if (unlikely(!nodetemp)) {
+							kfree(c);
+							goto was_error_clean;
+						}
+						nodetemp->dad = tail->owner;
+						nodetemp->sib = nodetemp->fson = NULL;
+						nodetemp->name = c;
+						nodetemp->node_type = node_type;
+						if (tail->owner) {
+							if (unlikely(!tail->owner->fson))
+								tail->owner->fson = nodetemp;
+							else {
+								nodewalk = tail->owner->fson;
+								while (nodewalk->sib)
+									nodewalk = nodewalk->sib;
+								nodewalk->sib = nodetemp;
+							}
+						} else
+							if (unlikely(!ret->compresstree_root))
+								ret->compresstree_root = nodetemp;
+							else {
+								nodewalk = ret->compresstree_root;
+								while (nodewalk->sib)
+									nodewalk = nodewalk->sib;
+								nodewalk->sib = nodetemp;
+							}
+						if (scan && *scan) {
+							tailtemp = kmalloc(sizeof(struct compresstree_tail), GFP_KERNEL);
+							if (unlikely(!tailtemp))
+								goto was_error_clean;
+
+							tailtemp->owner = nodetemp;
+							tailtemp->next = NULL;
+
+							tailtemp->tail = kmalloc(strlen(scan) + 1, GFP_KERNEL);
+							if (unlikely(!tailtemp->tail))
+								goto was_error_clean;
+							strcpy(tailtemp->tail, scan);
+							tailend->next = tailtemp;
+							tailend = tailtemp;
+						}
+						if (unlikely((*w == '}') || (*w == ']')))
+							node_type = COMPRESSMODE_NORMAL;
+						if (tail && ((node_type == COMPRESSMODE_NORMAL) || !*w)) {
+							scan = NULL;
+							tailtemp = tail;
+							tail = tail->next;
+							kfree(tailtemp->tail);
+							kfree(tailtemp);
+							breakout = 1;
+							break;
+						}
+					} else
+						node_type = COMPRESSMODE_NORMAL;
+					if (*w)
+						w++;
+					while (*w && ((*w == ',') || (*w == '\t') || (*w == ' ')))
+						w++;
+					w2 = w;
+					break;
+
+				default:
+					w++;
+					if (unlikely(!scan)) {
+						scan = w;
+						while (*scan && (*scan != ',') && (*scan != '\t') && (*scan != ' '))
+							scan++;
+						while (*scan && ((*scan == ',') || (*scan == '\t') || (*scan == ' ')))
+							scan++;
+					}
+			}
+		}
+	}
+	goto out;
+ was_error_clean:
+	destroy_tree(ret->compresstree_root);
+	while (tail) {
+		tailtemp = tail;
+		tail = tail->next;
+		kfree(tailtemp->tail);
+		kfree(tailtemp);
+	}
+ was_error:
+	kmem_cache_free(ctx_cache, ret);
+	ret = NULL;
+ out:
+	up_write(&ctx_lock);
+	return ret;
+}
+
+/* ctx is not modified but can be changed by a running destroy */
+int jffs2_compress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen)
+{
+	int ret = 0;
+	int32_t selectedlen = srclen;
+	u8 *selected;
+	struct compresstree_node *selwalk;
+	struct cryptolist_entry *currc, *selc = NULL;
+
+	down_read(&ctx_lock);
+	if (unlikely(!*ctx))
+		goto out;
+
+	selected = vmalloc(selectedlen);
+	if (unlikely(!selected)) {
+		ret = -1;
+		goto out;
+	}
+	memcpy(selected, src, selectedlen);
+	selwalk = (*ctx)->compresstree_root;
+
+	while (selwalk) {
+		u8 *best = NULL;
+		struct compresstree_node *walk = selwalk;
+		int32_t bestlen = 0;
+
+		down_read(&(*ctx)->crypto_lock);
+
+		while (walk) {
+			u8 *curr;
+			int32_t currlen = *dstlen;
+
+			curr = vmalloc(currlen);
+			if (unlikely(!curr)) {
+				vfree(selected);
+				ret = -1;
+				goto out_unlock;
+			}
+
+			currc = crypto_compress_wrapper(*ctx, walk->name, selected, selectedlen, curr, &currlen);
+			if (currc && (!bestlen || ((walk->node_type == COMPRESSMODE_BESTCOMPRESS) && (currlen < bestlen)))) {
+				if (bestlen)
+					vfree(best);
+				bestlen = currlen;
+				best = curr;
+				selwalk = walk;
+				selc = currc;
+			} else
+				vfree(curr);
+
+			if (walk->node_type == COMPRESSMODE_NORMAL || (walk->node_type == COMPRESSMODE_FIRSTCOMPRESS && currc))
+				break;
+
+			walk = walk->sib;
+		}
+
+		if (!bestlen || /*(selectedlen < bestlen)*/
+						(*dstlen < bestlen))
+			break;
+
+		vfree(selected);
+		selected = best;
+		/* compiler complains here but everything's ok. execution will reach this
+		point only if bestlen is set but that time selc is set, too. */
+		selc->tot_to_compress += selectedlen;
+		selc->tot_compressed += bestlen;
+		selc->compr_blocks++;
+		selectedlen = bestlen;
+		selwalk = selwalk->fson;
+		ret++;
+	}
+	if (likely(ret && (selectedlen <= *dstlen)))
+		memcpy(dst, selected, *dstlen = selectedlen);
+	else
+		ret = -1;
+	vfree(selected);
+
+ out_unlock:
+	up_read(&(*ctx)->crypto_lock);
+
+ out:
+	up_read(&ctx_lock);
+	return ret;
+}
+
+/* ctx is not modified but can be changed by a running destroy */
+int jffs2_decompress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst,
+					int32_t *dstlen, int compressors)
+{
+	int tmplen = srclen;
+	struct cryptolist_entry *currc;
+	int ret = 0;
+	u8 *tmp;
+
+	/* deny destroy while we are running */
+	down_read(&ctx_lock);
+	if (unlikely(!*ctx))
+		goto out;
+
+	tmp = vmalloc(tmplen);
+	if (unlikely(!tmp)) {
+		ret = -1;
+		goto out;
+	}
+	memcpy(tmp, src, tmplen);
+	/* just a read lock for concurrent decompress's and concurrent compress's. will be
+	converted to a write lock by crypto_[de]compress_wrapper, when needed */
+	down_read(&(*ctx)->crypto_lock);
+	while (compressors) {
+		u8 *tmp2 = tmp;
+		int slen = tmplen;
+
+		tmplen = *dstlen;
+		tmp = vmalloc(tmplen);
+		if (unlikely(!tmp)) {
+			ret = -1;
+			goto out;
+		}
+
+		currc = crypto_decompress_wrapper(*ctx, tmp2, slen, tmp, &tmplen);
+		if (!currc) {
+			vfree(tmp);
+			vfree(tmp2);
+			ret = -1;
+			goto out_unlock;
+		} else {
+			/* we have read lock but this is write. it's no matter when data is added to
+			the statistics. two concurrent updates don't make any trouble. the side effect
+			is that the statistics given by compress_stats are the live ones. but more
+			decompress's can run concurrently :-) */
+			currc->tot_to_decompress += slen;
+			currc->tot_decompressed += tmplen;
+			currc->decompr_blocks++;
+		}
+		vfree(tmp2);
+		compressors--;
+	}
+	memcpy(dst, tmp, *dstlen = tmplen);
+	vfree(tmp);
+ out_unlock:
+	up_read(&(*ctx)->crypto_lock);
+ out:
+	up_read(&ctx_lock);
+	return ret;
+}
+
+/* ctx is not modified but can be changed by a running destroy */
+char *jffs2_compr_stats(struct compress_ctx **ctx)
+{
+	struct cryptolist_entry *temp;
+	char *buf = NULL, *act_buf;
+	/* deny destroy while we are running */
+	down_read(&ctx_lock);
+	/* maybe a destroy has just exited */
+	if (likely(*ctx)) {
+		buf = kmalloc(JFFS2_STAT_BUF_SIZE, GFP_KERNEL);
+		act_buf = buf;
+		if (act_buf) {
+			act_buf += sprintf(act_buf, "Compressors:\n");
+			/* deny registering a new compressor */
+			down_read(&(*ctx)->crypto_lock);
+			temp = (*ctx)->cryptolist_head;
+			while (temp) {
+        		act_buf += sprintf(act_buf, "%10s compressed: %llu -> %llu, %llu blocks; decompressed: %llu -> %llu, %llu blocks\n",
+					crypto_tfm_alg_name(temp->sess), temp->tot_to_compress, temp->tot_compressed, temp->compr_blocks,
+					temp->tot_to_decompress, temp->tot_decompressed, temp->decompr_blocks);
+				temp = temp->next;
+			}
+			up_read(&(*ctx)->crypto_lock);
+		}
+	}
+	up_read(&ctx_lock);
+	return buf;
 }
diff -Narup Mtd-orig/fs/jffs2/compr.h mtd/fs/jffs2/compr.h
--- Mtd-orig/fs/jffs2/compr.h	2005-11-08 02:02:14.000000000 +0100
+++ mtd/fs/jffs2/compr.h	2005-11-28 09:02:04.000000000 +0100
@@ -1,107 +1,66 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in the
- * jffs2 directory.
- *
- * $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $
- *
- */
+#ifndef __COMPR_H
+#define __COMPR_H
 
-#ifndef __JFFS2_COMPR_H__
-#define __JFFS2_COMPR_H__
-
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/list.h>
-#include <linux/types.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/jffs2.h>
-#include <linux/jffs2_fs_i.h>
-#include <linux/jffs2_fs_sb.h>
-#include "nodelist.h"
-
-#define JFFS2_RUBINMIPS_PRIORITY 10
-#define JFFS2_DYNRUBIN_PRIORITY  20
-#define JFFS2_LZARI_PRIORITY     30
-#define JFFS2_LZO_PRIORITY       40
-#define JFFS2_RTIME_PRIORITY     50
-#define JFFS2_ZLIB_PRIORITY      60
-
-#define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
-#define JFFS2_DYNRUBIN_DISABLED  /*        for decompression */
-
-#define JFFS2_COMPR_MODE_NONE       0
-#define JFFS2_COMPR_MODE_PRIORITY   1
-#define JFFS2_COMPR_MODE_SIZE       2
-
-struct jffs2_compressor {
-        struct list_head list;
-        int priority;              /* used by prirority comr. mode */
-        char *name;
-        char compr;                /* JFFS2_COMPR_XXX */
-        int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
-                        uint32_t *srclen, uint32_t *destlen, void *model);
-        int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
-                        uint32_t cdatalen, uint32_t datalen, void *model);
-        int usecount;
-        int disabled;              /* if seted the compressor won't compress */
-        unsigned char *compr_buf;  /* used by size compr. mode */
-        uint32_t compr_buf_size;   /* used by size compr. mode */
-        uint32_t stat_compr_orig_size;
-        uint32_t stat_compr_new_size;
-        uint32_t stat_compr_blocks;
-        uint32_t stat_decompr_blocks;
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/rwsem.h>
+
+#ifdef CONFIG_JFFS2_COMPR_COMPAT
+#include "compr_compat.h"
+#else
+#define jffs2_init_compr_compat() 0
+#define jffs2_exit_compr_compat()
+#define jffs2_create_compr_compat_context(a) 0
+#define jffs2_destroy_compr_compat_context(a)
+#endif
+
+typedef enum {COMPRESSMODE_NORMAL = 0, COMPRESSMODE_FIRSTCOMPRESS,
+			  COMPRESSMODE_BESTCOMPRESS} compressmode_t;
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+struct cryptolist_entry {
+	struct crypto_tfm *sess;
+	struct cryptolist_entry *next;
+	uint64_t tot_to_compress;
+	uint64_t tot_compressed;
+	uint64_t compr_blocks;
+	uint64_t tot_to_decompress;
+	uint64_t tot_decompressed;
+	uint64_t decompr_blocks;
 };
 
-int jffs2_register_compressor(struct jffs2_compressor *comp);
-int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+struct compresstree_node {
+	struct compresstree_node *dad;
+	struct compresstree_node *fson;
+	struct compresstree_node *sib;
+	char *name;
+	compressmode_t node_type;
+};
 
-int jffs2_compressors_init(void);
-int jffs2_compressors_exit(void);
+struct compresstree_tail {
+	struct compresstree_node *owner;
+	char *tail;
+	struct compresstree_tail *next;
+};
 
-uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                             unsigned char *data_in, unsigned char **cpage_out,
-                             uint32_t *datalen, uint32_t *cdatalen);
-
-int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                     uint16_t comprtype, unsigned char *cdata_in,
-                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-
-void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
-
-#ifdef CONFIG_JFFS2_PROC
-int jffs2_enable_compressor_name(const char *name);
-int jffs2_disable_compressor_name(const char *name);
-int jffs2_set_compression_mode_name(const char *mode_name);
-char *jffs2_get_compression_mode_name(void);
-int jffs2_set_compressor_priority(const char *mode_name, int priority);
-char *jffs2_list_compressors(void);
-char *jffs2_stats(void);
-#endif
+struct compress_ctx {
+	struct compresstree_node *compresstree_root;
+	struct cryptolist_entry *cryptolist_head;
+	struct cryptolist_entry *cryptolist_tail;
+	struct rw_semaphore crypto_lock;
+	struct rw_semaphore tree_lock;
+};
 
-/* Compressor modules */
-/* These functions will be called by jffs2_compressors_init/exit */
+struct compress_ctx *jffs2_create_compr_context(char *cnt);
+int jffs2_compress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen);
+int jffs2_decompress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen, int compressors);
+char *jffs2_compr_stats(struct compress_ctx **ctx);
+int jffs2_destroy_compr_context(struct compress_ctx **ctx);
+int jffs2_init_compr_engine(void);
+void jffs2_exit_compr_engine(void);
 
-#ifdef CONFIG_JFFS2_RUBIN
-int jffs2_rubinmips_init(void);
-void jffs2_rubinmips_exit(void);
-int jffs2_dynrubin_init(void);
-void jffs2_dynrubin_exit(void);
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-int jffs2_rtime_init(void);
-void jffs2_rtime_exit(void);
 #endif
-#ifdef CONFIG_JFFS2_ZLIB
-int jffs2_zlib_init(void);
-void jffs2_zlib_exit(void);
-#endif
-
-#endif /* __JFFS2_COMPR_H__ */
diff -Narup Mtd-orig/fs/jffs2/compr_compat.c mtd/fs/jffs2/compr_compat.c
--- Mtd-orig/fs/jffs2/compr_compat.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd/fs/jffs2/compr_compat.c	2005-11-28 10:19:04.000000000 +0100
@@ -0,0 +1,363 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h> 
+#include <linux/jffs2.h> 
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/rwsem.h>
+#include <linux/zlib.h>
+#include <linux/zutil.h>
+#include "compr_rubin.h"
+#include "histo_mips.h"
+
+#include "compr_compat.h"
+
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Arjan van de Ven <arjanv@redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: compr_rtime.c,v 1.15 2005/03/17 20:23:06 gleixner Exp $
+ *
+ *
+ * Very simple lz77-ish encoder.
+ *
+ * Theory of operation: Both encoder and decoder have a list of "last
+ * occurrences" for every possible source-value; after sending the
+ * first source-byte, the second byte indicated the "run" length of
+ * matches
+ *
+ * The algorithm is intended to only send "whole bytes", no bit-messing.
+ *
+ */
+
+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+									uint32_t srclen, uint32_t destlen)
+{
+	short positions[256];
+	int outpos = 0;
+	int pos=0;
+
+	memset(positions,0,sizeof(positions)); 
+
+	while (outpos<destlen) {
+		unsigned char value;
+		int backoffs;
+		int repeat;
+
+		value = data_in[pos++];
+		cpage_out[outpos++] = value; /* first the verbatim copied byte */
+		repeat = data_in[pos++];
+		backoffs = positions[value];
+
+		positions[value]=outpos;
+		if (repeat) {
+			if (backoffs + repeat >= outpos) {
+				while(repeat) {
+					cpage_out[outpos++] = cpage_out[backoffs++];
+					repeat--;
+				}
+			} else {
+				memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
+				outpos+=repeat;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
+ *
+ * Created by Arjan van de Ven <arjanv@redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: compr_rubin.c,v 1.21 2005/05/20 15:39:54 gleixner Exp $
+ *
+ */
+
+static void init_rubin(struct rubin_state *rs, int div, int *bits)
+{
+	int c;
+
+	rs->q = 0;
+	rs->p = (long) (2 * UPPER_BIT_RUBIN);
+	rs->bit_number = (long) 0;
+	rs->bit_divider = div;
+	for (c=0; c<8; c++)
+		rs->bits[c] = bits[c];
+}
+
+static void init_decode(struct rubin_state *rs, int div, int *bits)
+{
+	init_rubin(rs, div, bits);
+
+	/* behalve lower */
+	rs->rec_q = 0;
+
+	for (rs->bit_number = 0; rs->bit_number++ < RUBIN_REG_SIZE; rs->rec_q = rs->rec_q * 2 + (long) (pullbit(&rs->pp)))
+		;
+}
+
+static void __do_decode(struct rubin_state *rs, unsigned long p, unsigned long q)
+{
+	register unsigned long lower_bits_rubin = LOWER_BITS_RUBIN;
+	unsigned long rec_q;
+	int c, bits = 0;
+
+	/*
+	 * First, work out how many bits we need from the input stream.
+	 * Note that we have already done the initial check on this
+	 * loop prior to calling this function.
+	 */
+	do {
+		bits++;
+		q &= lower_bits_rubin;
+		q <<= 1;
+		p <<= 1;
+	} while ((q >= UPPER_BIT_RUBIN) || ((p + q) <= UPPER_BIT_RUBIN));
+
+	rs->p = p;
+	rs->q = q;
+
+	rs->bit_number += bits;
+
+	/*
+	 * Now get the bits.  We really want this to be "get n bits".
+	 */
+	rec_q = rs->rec_q;
+	do {
+		c = pullbit(&rs->pp);
+		rec_q &= lower_bits_rubin;
+		rec_q <<= 1;
+		rec_q += c;
+	} while (--bits);
+	rs->rec_q = rec_q;
+}
+
+static int decode(struct rubin_state *rs, long A, long B)
+{
+	unsigned long p = rs->p, q = rs->q;
+	long i0, threshold;
+	int symbol;
+
+	if (q >= UPPER_BIT_RUBIN || ((p + q) <= UPPER_BIT_RUBIN))
+		__do_decode(rs, p, q);
+
+	i0 = A * rs->p / (A + B);
+	if (i0 <= 0) {
+		i0 = 1;
+	}
+	if (i0 >= rs->p) {
+		i0 = rs->p - 1;
+	}
+
+	threshold = rs->q + i0;
+	symbol = rs->rec_q >= threshold;
+	if (rs->rec_q >= threshold) {
+		rs->q += i0;
+		i0 = rs->p - i0;
+	}
+
+	rs->p = i0;
+
+	return symbol;
+}
+
+static int in_byte(struct rubin_state *rs)
+{
+	int i, result = 0, bit_divider = rs->bit_divider;
+
+	for (i = 0; i < 8; i++)
+		result |= decode(rs, bit_divider - rs->bits[i], rs->bits[i]) << i;
+
+	return result;
+}
+
+static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
+						unsigned char *page_out, uint32_t srclen, uint32_t destlen)
+{
+	int outpos = 0;
+	struct rubin_state rs;
+
+	init_pushpull(&rs.pp, cdata_in, srclen, 0, 0);
+	init_decode(&rs, bit_divider, bits);
+
+	while (outpos < destlen) {
+		page_out[outpos++] = in_byte(&rs);
+	}
+} 
+
+
+static int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
+										uint32_t sourcelen, uint32_t dstlen)
+{
+	rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
+	return 0;
+}
+
+static int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
+										uint32_t sourcelen, uint32_t dstlen)
+{
+	int bits[8];
+	int c;
+
+	for (c=0; c<8; c++)
+		bits[c] = data_in[c];
+
+	rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
+	return 0;
+}
+
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $
+ *
+ */
+
+	/* Plan: call deflate() with avail_in == *sourcelen, 
+		avail_out = *dstlen - 12 and flush == Z_FINISH. 
+		If it doesn't manage to finish,	call it again with
+		avail_in == 0 and avail_out set to the remaining 12
+		bytes for it to clean up. 
+	   Q: Is 12 bytes sufficient?
+	*/
+#define STREAM_END_SPACE 12
+
+static int jffs2_zlib_decompress(z_stream *inf_strm, unsigned char *data_in,
+				 unsigned char *cpage_out, uint32_t srclen, uint32_t destlen)
+{
+	int ret;
+	int wbits = MAX_WBITS;
+
+	inf_strm->next_in = data_in;
+	inf_strm->avail_in = srclen;
+	inf_strm->total_in = 0;
+
+	inf_strm->next_out = cpage_out;
+	inf_strm->avail_out = destlen;
+	inf_strm->total_out = 0;
+
+	/* If it's deflate, and it's got no preset dictionary, then
+	   we can tell zlib to skip the adler32 check. */
+	if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
+		((data_in[0] & 0x0f) == Z_DEFLATED) &&
+		!(((data_in[0]<<8) + data_in[1]) % 31)) {
+		wbits = -((data_in[0] >> 4) + 8);
+		inf_strm->next_in += 2;
+		inf_strm->avail_in -= 2;
+	}
+
+	if (Z_OK != zlib_inflateInit2(inf_strm, wbits)) {
+		printk(KERN_WARNING "inflateInit failed\n");
+		return 1;
+	}
+
+	while((ret = zlib_inflate(inf_strm, Z_FINISH)) == Z_OK)
+		;
+	if (ret != Z_STREAM_END) {
+		printk(KERN_NOTICE "inflate returned %d\n", ret);
+	}
+	zlib_inflateEnd(inf_strm);
+	return 0;
+}
+
+static struct rw_semaphore compress_compat_lock;
+static kmem_cache_t *compat_ctx_cache = NULL;
+
+int jffs2_init_compr_compat(void)
+{
+	int ret = 0;
+	init_rwsem(&compress_compat_lock);
+	compat_ctx_cache = kmem_cache_create("compress_compat_ctx",
+								sizeof(struct compress_compat_ctx), 0,
+								SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (unlikely(!compat_ctx_cache))
+		ret = -ENOMEM;
+	return ret;
+}
+
+void jffs2_exit_compr_compat(void)
+{
+	if (compat_ctx_cache)
+		kmem_cache_destroy(compat_ctx_cache);
+}
+
+int jffs2_create_compr_compat_context(struct compress_compat_ctx **ctx)
+{
+	int ret = 0;
+
+	down_write(&compress_compat_lock);
+	*ctx = kmem_cache_alloc(compat_ctx_cache, GFP_KERNEL);
+	if (unlikely(!(*ctx))) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	(*ctx)->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
+	if (unlikely(!(*ctx)->inf_strm.workspace)) {
+		kmem_cache_free(compat_ctx_cache, *ctx);
+		*ctx = NULL;
+		ret = -ENOMEM;
+	}
+	init_MUTEX(&(*ctx)->z_sem);
+out:
+	up_write(&compress_compat_lock);
+	return ret;
+}
+
+void jffs2_destroy_compr_compat_context(struct compress_compat_ctx **ctx)
+{
+	down_write(&compress_compat_lock);
+	if (!*ctx)
+		goto out;
+	vfree((*ctx)->inf_strm.workspace);
+	kmem_cache_free(compat_ctx_cache, *ctx);
+	*ctx = NULL;
+out:
+	up_write(&compress_compat_lock);
+}
+
+int jffs2_decompress_compat(struct compress_compat_ctx **ctx, u8 *src,
+				int32_t srclen, u8 *dst, int32_t dstlen, int compressor)
+{
+	int ret = 0;
+	down_read(&compress_compat_lock);
+	if (!*ctx)
+		goto out;
+	switch (compressor) {
+		case JFFS2_COMPR_RTIME:
+			ret = jffs2_rtime_decompress(src, dst, srclen, dstlen);
+			break;
+		case JFFS2_COMPR_RUBINMIPS:
+			ret = jffs2_rubinmips_decompress(src, dst, srclen, dstlen);
+			break;
+		case JFFS2_COMPR_DYNRUBIN:
+			ret = jffs2_dynrubin_decompress(src, dst, srclen, dstlen);
+			break;
+		case JFFS2_COMPR_ZLIB:
+			down(&(*ctx)->z_sem);
+			ret = jffs2_zlib_decompress(&(*ctx)->inf_strm, src, dst, srclen, dstlen);
+			up(&(*ctx)->z_sem);
+	}
+out:
+	up_read(&compress_compat_lock);
+	return ret;
+}
diff -Narup Mtd-orig/fs/jffs2/compr_compat.h mtd/fs/jffs2/compr_compat.h
--- Mtd-orig/fs/jffs2/compr_compat.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd/fs/jffs2/compr_compat.h	2005-11-28 10:19:04.000000000 +0100
@@ -0,0 +1,21 @@
+#ifndef __COMPR_COMPAT_H
+#define __COMPR_COMPAT_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/zlib.h>
+#include <linux/zutil.h>
+
+struct compress_compat_ctx {
+	z_stream inf_strm;
+	struct semaphore z_sem;
+};
+
+int jffs2_init_compr_compat(void);
+void jffs2_exit_compr_compat(void);
+int jffs2_create_compr_compat_context(struct compress_compat_ctx **ctx);
+void jffs2_destroy_compr_compat_context(struct compress_compat_ctx **ctx);
+int jffs2_decompress_compat(struct compress_compat_ctx **ctx, u8 *src,
+						int32_t srclen, u8 *dst, int32_t dstlen, int compressor);
+
+#endif
diff -Narup Mtd-orig/fs/jffs2/compr_rtime.c mtd/fs/jffs2/compr_rtime.c
--- Mtd-orig/fs/jffs2/compr_rtime.c	2005-11-08 02:02:14.000000000 +0100
+++ mtd/fs/jffs2/compr_rtime.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,132 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001-2003 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- * $Id: compr_rtime.c,v 1.16 2005/11/07 11:14:38 gleixner Exp $
- *
- *
- * Very simple lz77-ish encoder.
- *
- * Theory of operation: Both encoder and decoder have a list of "last
- * occurrences" for every possible source-value; after sending the
- * first source-byte, the second byte indicated the "run" length of
- * matches
- *
- * The algorithm is intended to only send "whole bytes", no bit-messing.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/jffs2.h>
-#include "compr.h"
-
-/* _compress returns the compressed size, -1 if bigger */
-static int jffs2_rtime_compress(unsigned char *data_in,
-				unsigned char *cpage_out,
-				uint32_t *sourcelen, uint32_t *dstlen,
-				void *model)
-{
-	short positions[256];
-	int outpos = 0;
-	int pos=0;
-
-	memset(positions,0,sizeof(positions));
-
-	while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
-		int backpos, runlen=0;
-		unsigned char value;
-
-		value = data_in[pos];
-
-		cpage_out[outpos++] = data_in[pos++];
-
-		backpos = positions[value];
-		positions[value]=pos;
-
-		while ((backpos < pos) && (pos < (*sourcelen)) &&
-		       (data_in[pos]==data_in[backpos++]) && (runlen<255)) {
-			pos++;
-			runlen++;
-		}
-		cpage_out[outpos++] = runlen;
-	}
-
-	if (outpos >= pos) {
-		/* We failed */
-		return -1;
-	}
-
-	/* Tell the caller how much we managed to compress, and how much space it took */
-	*sourcelen = pos;
-	*dstlen = outpos;
-	return 0;
-}
-
-
-static int jffs2_rtime_decompress(unsigned char *data_in,
-				  unsigned char *cpage_out,
-				  uint32_t srclen, uint32_t destlen,
-				  void *model)
-{
-	short positions[256];
-	int outpos = 0;
-	int pos=0;
-
-	memset(positions,0,sizeof(positions));
-
-	while (outpos<destlen) {
-		unsigned char value;
-		int backoffs;
-		int repeat;
-
-		value = data_in[pos++];
-		cpage_out[outpos++] = value; /* first the verbatim copied byte */
-		repeat = data_in[pos++];
-		backoffs = positions[value];
-
-		positions[value]=outpos;
-		if (repeat) {
-			if (backoffs + repeat >= outpos) {
-				while(repeat) {
-					cpage_out[outpos++] = cpage_out[backoffs++];
-					repeat--;
-				}
-			} else {
-				memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
-				outpos+=repeat;
-			}
-		}
-	}
-        return 0;
-}
-
-static struct jffs2_compressor jffs2_rtime_comp = {
-    .priority = JFFS2_RTIME_PRIORITY,
-    .name = "rtime",
-    .compr = JFFS2_COMPR_RTIME,
-    .compress = &jffs2_rtime_compress,
-    .decompress = &jffs2_rtime_decompress,
-#ifdef JFFS2_RTIME_DISABLED
-    .disabled = 1,
-#else
-    .disabled = 0,
-#endif
-};
-
-int jffs2_rtime_init(void)
-{
-    return jffs2_register_compressor(&jffs2_rtime_comp);
-}
-
-void jffs2_rtime_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_rtime_comp);
-}
diff -Narup Mtd-orig/fs/jffs2/compr_rubin.c mtd/fs/jffs2/compr_rubin.c
--- Mtd-orig/fs/jffs2/compr_rubin.c	2005-11-08 02:02:14.000000000 +0100
+++ mtd/fs/jffs2/compr_rubin.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,379 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- * $Id: compr_rubin.c,v 1.22 2005/11/07 11:14:38 gleixner Exp $
- *
- */
-
-
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/jffs2.h>
-#include "compr_rubin.h"
-#include "histo_mips.h"
-#include "compr.h"
-
-static void init_rubin(struct rubin_state *rs, int div, int *bits)
-{
-	int c;
-
-	rs->q = 0;
-	rs->p = (long) (2 * UPPER_BIT_RUBIN);
-	rs->bit_number = (long) 0;
-	rs->bit_divider = div;
-	for (c=0; c<8; c++)
-		rs->bits[c] = bits[c];
-}
-
-
-static int encode(struct rubin_state *rs, long A, long B, int symbol)
-{
-
-	long i0, i1;
-	int ret;
-
-	while ((rs->q >= UPPER_BIT_RUBIN) || ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) {
-		rs->bit_number++;
-
-		ret = pushbit(&rs->pp, (rs->q & UPPER_BIT_RUBIN) ? 1 : 0, 0);
-		if (ret)
-			return ret;
-		rs->q &= LOWER_BITS_RUBIN;
-		rs->q <<= 1;
-		rs->p <<= 1;
-	}
-	i0 = A * rs->p / (A + B);
-	if (i0 <= 0) {
-		i0 = 1;
-	}
-	if (i0 >= rs->p) {
-		i0 = rs->p - 1;
-	}
-	i1 = rs->p - i0;
-
-	if (symbol == 0)
-		rs->p = i0;
-	else {
-		rs->p = i1;
-		rs->q += i0;
-	}
-	return 0;
-}
-
-
-static void end_rubin(struct rubin_state *rs)
-{
-
-	int i;
-
-	for (i = 0; i < RUBIN_REG_SIZE; i++) {
-		pushbit(&rs->pp, (UPPER_BIT_RUBIN & rs->q) ? 1 : 0, 1);
-		rs->q &= LOWER_BITS_RUBIN;
-		rs->q <<= 1;
-	}
-}
-
-
-static void init_decode(struct rubin_state *rs, int div, int *bits)
-{
-	init_rubin(rs, div, bits);
-
-	/* behalve lower */
-	rs->rec_q = 0;
-
-	for (rs->bit_number = 0; rs->bit_number++ < RUBIN_REG_SIZE; rs->rec_q = rs->rec_q * 2 + (long) (pullbit(&rs->pp)))
-		;
-}
-
-static void __do_decode(struct rubin_state *rs, unsigned long p, unsigned long q)
-{
-	register unsigned long lower_bits_rubin = LOWER_BITS_RUBIN;
-	unsigned long rec_q;
-	int c, bits = 0;
-
-	/*
-	 * First, work out how many bits we need from the input stream.
-	 * Note that we have already done the initial check on this
-	 * loop prior to calling this function.
-	 */
-	do {
-		bits++;
-		q &= lower_bits_rubin;
-		q <<= 1;
-		p <<= 1;
-	} while ((q >= UPPER_BIT_RUBIN) || ((p + q) <= UPPER_BIT_RUBIN));
-
-	rs->p = p;
-	rs->q = q;
-
-	rs->bit_number += bits;
-
-	/*
-	 * Now get the bits.  We really want this to be "get n bits".
-	 */
-	rec_q = rs->rec_q;
-	do {
-		c = pullbit(&rs->pp);
-		rec_q &= lower_bits_rubin;
-		rec_q <<= 1;
-		rec_q += c;
-	} while (--bits);
-	rs->rec_q = rec_q;
-}
-
-static int decode(struct rubin_state *rs, long A, long B)
-{
-	unsigned long p = rs->p, q = rs->q;
-	long i0, threshold;
-	int symbol;
-
-	if (q >= UPPER_BIT_RUBIN || ((p + q) <= UPPER_BIT_RUBIN))
-		__do_decode(rs, p, q);
-
-	i0 = A * rs->p / (A + B);
-	if (i0 <= 0) {
-		i0 = 1;
-	}
-	if (i0 >= rs->p) {
-		i0 = rs->p - 1;
-	}
-
-	threshold = rs->q + i0;
-	symbol = rs->rec_q >= threshold;
-	if (rs->rec_q >= threshold) {
-		rs->q += i0;
-		i0 = rs->p - i0;
-	}
-
-	rs->p = i0;
-
-	return symbol;
-}
-
-
-
-static int out_byte(struct rubin_state *rs, unsigned char byte)
-{
-	int i, ret;
-	struct rubin_state rs_copy;
-	rs_copy = *rs;
-
-	for (i=0;i<8;i++) {
-		ret = encode(rs, rs->bit_divider-rs->bits[i],rs->bits[i],byte&1);
-		if (ret) {
-			/* Failed. Restore old state */
-			*rs = rs_copy;
-			return ret;
-		}
-		byte=byte>>1;
-	}
-	return 0;
-}
-
-static int in_byte(struct rubin_state *rs)
-{
-	int i, result = 0, bit_divider = rs->bit_divider;
-
-	for (i = 0; i < 8; i++)
-		result |= decode(rs, bit_divider - rs->bits[i], rs->bits[i]) << i;
-
-	return result;
-}
-
-
-
-static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
-		      unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen)
-	{
-	int outpos = 0;
-	int pos=0;
-	struct rubin_state rs;
-
-	init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32);
-
-	init_rubin(&rs, bit_divider, bits);
-
-	while (pos < (*sourcelen) && !out_byte(&rs, data_in[pos]))
-		pos++;
-
-	end_rubin(&rs);
-
-	if (outpos > pos) {
-		/* We failed */
-		return -1;
-	}
-
-	/* Tell the caller how much we managed to compress,
-	 * and how much space it took */
-
-	outpos = (pushedbits(&rs.pp)+7)/8;
-
-	if (outpos >= pos)
-		return -1; /* We didn't actually compress */
-	*sourcelen = pos;
-	*dstlen = outpos;
-	return 0;
-}
-#if 0
-/* _compress returns the compressed size, -1 if bigger */
-int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
-		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
-{
-	return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
-}
-#endif
-static int jffs2_dynrubin_compress(unsigned char *data_in,
-				   unsigned char *cpage_out,
-				   uint32_t *sourcelen, uint32_t *dstlen,
-				   void *model)
-{
-	int bits[8];
-	unsigned char histo[256];
-	int i;
-	int ret;
-	uint32_t mysrclen, mydstlen;
-
-	mysrclen = *sourcelen;
-	mydstlen = *dstlen - 8;
-
-	if (*dstlen <= 12)
-		return -1;
-
-	memset(histo, 0, 256);
-	for (i=0; i<mysrclen; i++) {
-		histo[data_in[i]]++;
-	}
-	memset(bits, 0, sizeof(int)*8);
-	for (i=0; i<256; i++) {
-		if (i&128)
-			bits[7] += histo[i];
-		if (i&64)
-			bits[6] += histo[i];
-		if (i&32)
-			bits[5] += histo[i];
-		if (i&16)
-			bits[4] += histo[i];
-		if (i&8)
-			bits[3] += histo[i];
-		if (i&4)
-			bits[2] += histo[i];
-		if (i&2)
-			bits[1] += histo[i];
-		if (i&1)
-			bits[0] += histo[i];
-	}
-
-	for (i=0; i<8; i++) {
-		bits[i] = (bits[i] * 256) / mysrclen;
-		if (!bits[i]) bits[i] = 1;
-		if (bits[i] > 255) bits[i] = 255;
-		cpage_out[i] = bits[i];
-	}
-
-	ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, &mydstlen);
-	if (ret)
-		return ret;
-
-	/* Add back the 8 bytes we took for the probabilities */
-	mydstlen += 8;
-
-	if (mysrclen <= mydstlen) {
-		/* We compressed */
-		return -1;
-	}
-
-	*sourcelen = mysrclen;
-	*dstlen = mydstlen;
-	return 0;
-}
-
-static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
-			 unsigned char *page_out, uint32_t srclen, uint32_t destlen)
-{
-	int outpos = 0;
-	struct rubin_state rs;
-
-	init_pushpull(&rs.pp, cdata_in, srclen, 0, 0);
-	init_decode(&rs, bit_divider, bits);
-
-	while (outpos < destlen) {
-		page_out[outpos++] = in_byte(&rs);
-	}
-}
-
-
-static int jffs2_rubinmips_decompress(unsigned char *data_in,
-				      unsigned char *cpage_out,
-				      uint32_t sourcelen, uint32_t dstlen,
-				      void *model)
-{
-	rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
-        return 0;
-}
-
-static int jffs2_dynrubin_decompress(unsigned char *data_in,
-				     unsigned char *cpage_out,
-				     uint32_t sourcelen, uint32_t dstlen,
-				     void *model)
-{
-	int bits[8];
-	int c;
-
-	for (c=0; c<8; c++)
-		bits[c] = data_in[c];
-
-	rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
-        return 0;
-}
-
-static struct jffs2_compressor jffs2_rubinmips_comp = {
-    .priority = JFFS2_RUBINMIPS_PRIORITY,
-    .name = "rubinmips",
-    .compr = JFFS2_COMPR_DYNRUBIN,
-    .compress = NULL, /*&jffs2_rubinmips_compress,*/
-    .decompress = &jffs2_rubinmips_decompress,
-#ifdef JFFS2_RUBINMIPS_DISABLED
-    .disabled = 1,
-#else
-    .disabled = 0,
-#endif
-};
-
-int jffs2_rubinmips_init(void)
-{
-    return jffs2_register_compressor(&jffs2_rubinmips_comp);
-}
-
-void jffs2_rubinmips_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_rubinmips_comp);
-}
-
-static struct jffs2_compressor jffs2_dynrubin_comp = {
-    .priority = JFFS2_DYNRUBIN_PRIORITY,
-    .name = "dynrubin",
-    .compr = JFFS2_COMPR_RUBINMIPS,
-    .compress = jffs2_dynrubin_compress,
-    .decompress = &jffs2_dynrubin_decompress,
-#ifdef JFFS2_DYNRUBIN_DISABLED
-    .disabled = 1,
-#else
-    .disabled = 0,
-#endif
-};
-
-int jffs2_dynrubin_init(void)
-{
-    return jffs2_register_compressor(&jffs2_dynrubin_comp);
-}
-
-void jffs2_dynrubin_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_dynrubin_comp);
-}
diff -Narup Mtd-orig/fs/jffs2/compr_rubin.h mtd/fs/jffs2/compr_rubin.h
--- Mtd-orig/fs/jffs2/compr_rubin.h	2005-11-08 02:02:14.000000000 +0100
+++ mtd/fs/jffs2/compr_rubin.h	2005-11-28 10:19:04.000000000 +0100
@@ -1,7 +1,7 @@
 /* Rubin encoder/decoder header       */
 /* work started at   : aug   3, 1994  */
 /* last modification : aug  15, 1994  */
-/* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */
+/* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */
 
 #include "pushpull.h"
 
diff -Narup Mtd-orig/fs/jffs2/compr_zlib.c mtd/fs/jffs2/compr_zlib.c
--- Mtd-orig/fs/jffs2/compr_zlib.c	2005-11-08 02:02:14.000000000 +0100
+++ mtd/fs/jffs2/compr_zlib.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,222 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001-2003 Red Hat, Inc.
- *
- * Created by David Woodhouse <dwmw2@infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- * $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $
- *
- */
-
-#if !defined(__KERNEL__) && !defined(__ECOS)
-#error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
-#endif
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/zlib.h>
-#include <linux/zutil.h>
-#include "nodelist.h"
-#include "compr.h"
-
-	/* Plan: call deflate() with avail_in == *sourcelen,
-		avail_out = *dstlen - 12 and flush == Z_FINISH.
-		If it doesn't manage to finish,	call it again with
-		avail_in == 0 and avail_out set to the remaining 12
-		bytes for it to clean up.
-	   Q: Is 12 bytes sufficient?
-	*/
-#define STREAM_END_SPACE 12
-
-static DECLARE_MUTEX(deflate_sem);
-static DECLARE_MUTEX(inflate_sem);
-static z_stream inf_strm, def_strm;
-
-#ifdef __KERNEL__ /* Linux-only */
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-
-static int __init alloc_workspaces(void)
-{
-	def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
-	if (!def_strm.workspace) {
-		printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
-		return -ENOMEM;
-	}
-	D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
-	inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
-	if (!inf_strm.workspace) {
-		printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
-		vfree(def_strm.workspace);
-		return -ENOMEM;
-	}
-	D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
-	return 0;
-}
-
-static void free_workspaces(void)
-{
-	vfree(def_strm.workspace);
-	vfree(inf_strm.workspace);
-}
-#else
-#define alloc_workspaces() (0)
-#define free_workspaces() do { } while(0)
-#endif /* __KERNEL__ */
-
-static int jffs2_zlib_compress(unsigned char *data_in,
-			       unsigned char *cpage_out,
-			       uint32_t *sourcelen, uint32_t *dstlen,
-			       void *model)
-{
-	int ret;
-
-	if (*dstlen <= STREAM_END_SPACE)
-		return -1;
-
-	down(&deflate_sem);
-
-	if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
-		printk(KERN_WARNING "deflateInit failed\n");
-		up(&deflate_sem);
-		return -1;
-	}
-
-	def_strm.next_in = data_in;
-	def_strm.total_in = 0;
-
-	def_strm.next_out = cpage_out;
-	def_strm.total_out = 0;
-
-	while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
-		def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
-		def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
-		D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
-			  def_strm.avail_in, def_strm.avail_out));
-		ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
-		D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
-			  def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out));
-		if (ret != Z_OK) {
-			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-			zlib_deflateEnd(&def_strm);
-			up(&deflate_sem);
-			return -1;
-		}
-	}
-	def_strm.avail_out += STREAM_END_SPACE;
-	def_strm.avail_in = 0;
-	ret = zlib_deflate(&def_strm, Z_FINISH);
-	zlib_deflateEnd(&def_strm);
-
-	if (ret != Z_STREAM_END) {
-		D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-		ret = -1;
-		goto out;
-	}
-
-	if (def_strm.total_out >= def_strm.total_in) {
-		D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n",
-			  def_strm.total_in, def_strm.total_out));
-		ret = -1;
-		goto out;
-	}
-
-	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
-		  def_strm.total_in, def_strm.total_out));
-
-	*dstlen = def_strm.total_out;
-	*sourcelen = def_strm.total_in;
-	ret = 0;
- out:
-	up(&deflate_sem);
-	return ret;
-}
-
-static int jffs2_zlib_decompress(unsigned char *data_in,
-				 unsigned char *cpage_out,
-				 uint32_t srclen, uint32_t destlen,
-				 void *model)
-{
-	int ret;
-	int wbits = MAX_WBITS;
-
-	down(&inflate_sem);
-
-	inf_strm.next_in = data_in;
-	inf_strm.avail_in = srclen;
-	inf_strm.total_in = 0;
-
-	inf_strm.next_out = cpage_out;
-	inf_strm.avail_out = destlen;
-	inf_strm.total_out = 0;
-
-	/* If it's deflate, and it's got no preset dictionary, then
-	   we can tell zlib to skip the adler32 check. */
-	if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
-	    ((data_in[0] & 0x0f) == Z_DEFLATED) &&
-	    !(((data_in[0]<<8) + data_in[1]) % 31)) {
-
-		D2(printk(KERN_DEBUG "inflate skipping adler32\n"));
-		wbits = -((data_in[0] >> 4) + 8);
-		inf_strm.next_in += 2;
-		inf_strm.avail_in -= 2;
-	} else {
-		/* Let this remain D1 for now -- it should never happen */
-		D1(printk(KERN_DEBUG "inflate not skipping adler32\n"));
-	}
-
-
-	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
-		printk(KERN_WARNING "inflateInit failed\n");
-		up(&inflate_sem);
-		return 1;
-	}
-
-	while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
-		;
-	if (ret != Z_STREAM_END) {
-		printk(KERN_NOTICE "inflate returned %d\n", ret);
-	}
-	zlib_inflateEnd(&inf_strm);
-	up(&inflate_sem);
-        return 0;
-}
-
-static struct jffs2_compressor jffs2_zlib_comp = {
-    .priority = JFFS2_ZLIB_PRIORITY,
-    .name = "zlib",
-    .compr = JFFS2_COMPR_ZLIB,
-    .compress = &jffs2_zlib_compress,
-    .decompress = &jffs2_zlib_decompress,
-#ifdef JFFS2_ZLIB_DISABLED
-    .disabled = 1,
-#else
-    .disabled = 0,
-#endif
-};
-
-int __init jffs2_zlib_init(void)
-{
-    int ret;
-
-    ret = alloc_workspaces();
-    if (ret)
-        return ret;
-
-    ret = jffs2_register_compressor(&jffs2_zlib_comp);
-    if (ret)
-        free_workspaces();
-
-    return ret;
-}
-
-void jffs2_zlib_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_zlib_comp);
-    free_workspaces();
-}
diff -Narup Mtd-orig/fs/jffs2/comprtest.c mtd/fs/jffs2/comprtest.c
--- Mtd-orig/fs/jffs2/comprtest.c	2005-11-08 02:02:14.000000000 +0100
+++ mtd/fs/jffs2/comprtest.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,307 +0,0 @@
-/* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <asm/types.h>
-#if 0
-#define TESTDATA_LEN 512
-static unsigned char testdata[TESTDATA_LEN] = {
- 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00,
- 0xb0, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x06, 0x00, 0x28, 0x00,
- 0x1e, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x80, 0x04, 0x08,
- 0x34, 0x80, 0x04, 0x08, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x80, 0x04, 0x08,
- 0xf4, 0x80, 0x04, 0x08, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08,
- 0x00, 0x80, 0x04, 0x08, 0x0d, 0x05, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x95, 0x04, 0x08,
- 0x10, 0x95, 0x04, 0x08, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x58, 0x95, 0x04, 0x08,
- 0x58, 0x95, 0x04, 0x08, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x81, 0x04, 0x08,
- 0x08, 0x81, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x75,
- 0x78, 0x2e, 0x73, 0x6f, 0x2e, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
- 0x0c, 0x83, 0x04, 0x08, 0x81, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x1c, 0x83, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
- 0x2c, 0x83, 0x04, 0x08, 0xdd, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
- 0x3c, 0x83, 0x04, 0x08, 0x2e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
- 0x4c, 0x83, 0x04, 0x08, 0x7d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
- 0x00, 0x85, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x67,
- 0x6d, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x5f, 0x00, 0x6c, 0x69, 0x62, 0x63,
- 0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x5f, 0x5f, 0x63};
-#else
-#define TESTDATA_LEN 3481
-static unsigned char testdata[TESTDATA_LEN] = {
- 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x22, 0x64, 0x62, 0x65, 0x6e, 0x63, 0x68,
- 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4d, 0x41, 0x58,
- 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x31, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x73, 0x74, 0x61,
- 0x74, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x62, 0x75, 0x66, 0x5b, 0x37, 0x30, 0x30,
- 0x30, 0x30, 0x5d, 0x3b, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x20,
- 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x61,
- 0x74, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x09, 0x69, 0x6e,
- 0x74, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c,
- 0x65, 0x3b, 0x0a, 0x7d, 0x20, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x4d, 0x41, 0x58, 0x5f,
- 0x46, 0x49, 0x4c, 0x45, 0x53, 0x5d, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f,
- 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e,
- 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72,
- 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x75,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20,
- 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28,
- 0x25, 0x64, 0x29, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61,
- 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09,
- 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75,
- 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72,
- 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a,
- 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66,
- 0x69, 0x6c, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20,
- 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x3b, 0x0a,
- 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a,
- 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x49, 0x4e, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x6f, 0x66,
- 0x28, 0x62, 0x75, 0x66, 0x29, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09,
- 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73,
- 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x3d, 0x20, 0x73, 0x3b, 0x0a,
- 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6f, 0x70,
- 0x65, 0x6e, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20,
- 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20,
- 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c,
- 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d,
- 0x20, 0x4f, 0x5f, 0x52, 0x44, 0x57, 0x52, 0x7c, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x3b,
- 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74,
- 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x63, 0x6f,
- 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28,
- 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69,
- 0x7a, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x7c,
- 0x3d, 0x20, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x64, 0x20,
- 0x3d, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x6c,
- 0x61, 0x67, 0x73, 0x2c, 0x20, 0x30, 0x36, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20,
- 0x28, 0x66, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70,
- 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x6f, 0x70, 0x65, 0x6e,
- 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68,
- 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22,
- 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65,
- 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x68,
- 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28,
- 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
- 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x64, 0x2c,
- 0x20, 0x26, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65,
- 0x20, 0x3e, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b,
- 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
- 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64,
- 0x69, 0x6e, 0x67, 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f,
- 0x6d, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66,
- 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74,
- 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x23, 0x65,
- 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69,
- 0x6c, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x74,
- 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x20, 0x65, 0x6c,
- 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3c, 0x20, 0x73, 0x74,
- 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72,
- 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67,
- 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x25,
- 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e,
- 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09,
- 0x09, 0x66, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73,
- 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69,
- 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69,
- 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20,
- 0x30, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66,
- 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53,
- 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x66, 0x69,
- 0x6c, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x66, 0x6f,
- 0x72, 0x20, 0x25, 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b,
- 0x0a, 0x09, 0x09, 0x65, 0x78, 0x69, 0x74, 0x28, 0x31, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09,
- 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65,
- 0x20, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09,
- 0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x20, 0x25, 0x20, 0x31, 0x30,
- 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e,
- 0x74, 0x66, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76,
- 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x69, 0x6e, 0x74,
- 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a,
- 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x0a, 0x7b,
- 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x62,
- 0x75, 0x66, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x6d, 0x65, 0x6d, 0x73,
- 0x65, 0x74, 0x28, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x6f,
- 0x66, 0x28, 0x62, 0x75, 0x66, 0x29, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28,
- 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b,
- 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d,
- 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a,
- 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58,
- 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x31, 0x0a,
- 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64,
- 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20,
- 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20,
- 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e,
- 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e,
- 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c,
- 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a,
- 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b,
- 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c,
- 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c,
- 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20,
- 0x28, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d,
- 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20,
- 0x21, 0x3d, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
- 0x6e, 0x74, 0x66, 0x28, 0x22, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65,
- 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x5c, 0x6e,
- 0x22, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d,
- 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x28, 0x69,
- 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73,
- 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29,
- 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20,
- 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53,
- 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d,
- 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b,
- 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41,
- 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
- 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61,
- 0x64, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73,
- 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25,
- 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
- 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c,
- 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73,
- 0x65, 0x74, 0x2c, 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09,
- 0x72, 0x65, 0x61, 0x64, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66,
- 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x7d,
- 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28,
- 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69,
- 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b,
- 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29,
- 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b,
- 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e,
- 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09,
- 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c,
- 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22,
- 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x3a, 0x20, 0x68,
- 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74,
- 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20,
- 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
- 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x66, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x29, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20,
- 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6d, 0x6b,
- 0x64, 0x69, 0x72, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29,
- 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61,
- 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6d, 0x6b, 0x64, 0x69, 0x72,
- 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x30, 0x37, 0x30, 0x30, 0x29, 0x20, 0x21, 0x3d,
- 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a,
- 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20,
- 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e,
- 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61,
- 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72,
- 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x7d, 0x0a,
- 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x6d, 0x64, 0x69, 0x72,
- 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a,
- 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29,
- 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x28, 0x66, 0x6e,
- 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70,
- 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x25, 0x73, 0x20,
- 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20,
- 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
- 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29,
- 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f,
- 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6f, 0x6c,
- 0x64, 0x2c, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6e, 0x65, 0x77, 0x29, 0x0a, 0x7b, 0x0a,
- 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6f, 0x6c, 0x64, 0x29, 0x3b, 0x0a,
- 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6e, 0x65, 0x77, 0x29, 0x3b, 0x0a,
- 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6f, 0x6c, 0x64,
- 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09,
- 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20,
- 0x25, 0x73, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73,
- 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72,
- 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d,
- 0x0a, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x28,
- 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74,
- 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
- 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75,
- 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69,
- 0x66, 0x20, 0x28, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x26,
- 0x73, 0x74, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72,
- 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74,
- 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x25,
- 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d,
- 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f,
- 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x53, 0x5f, 0x49,
- 0x53, 0x44, 0x49, 0x52, 0x28, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x29,
- 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28,
- 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x73, 0x69,
- 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22,
- 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73,
- 0x20, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x25, 0x64, 0x20, 0x25,
- 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d,
- 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69,
- 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a,
- 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28,
- 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74,
- 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x6f, 0x70, 0x65,
- 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x35, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x73,
- 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28,
- 0x35, 0x30, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x0a
-};
-#endif
-static unsigned char comprbuf[TESTDATA_LEN];
-static unsigned char decomprbuf[TESTDATA_LEN];
-
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
-		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
-			     uint32_t *datalen, uint32_t *cdatalen);
-
-int init_module(void ) {
-	unsigned char comprtype;
-	uint32_t c, d;
-	int ret;
-
-	printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       testdata[0],testdata[1],testdata[2],testdata[3],
-	       testdata[4],testdata[5],testdata[6],testdata[7],
-	       testdata[8],testdata[9],testdata[10],testdata[11],
-	       testdata[12],testdata[13],testdata[14],testdata[15]);
-	d = TESTDATA_LEN;
-	c = TESTDATA_LEN;
-	comprtype = jffs2_compress(testdata, comprbuf, &d, &c);
-
-	printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n",
-	       comprtype, c, d);
-	printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3],
-	       comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7],
-	       comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11],
-	       comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]);
-
-	ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d);
-	printk("jffs2_decompress returned %d\n", ret);
-	printk("Decompressed data:  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3],
-	       decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7],
-	       decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11],
-	       decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]);
-	if (memcmp(decomprbuf, testdata, d))
-		printk("Compression and decompression corrupted data\n");
-	else
-		printk("Compression good for %d bytes\n", d);
-	return 1;
-}
diff -Narup Mtd-orig/fs/jffs2/gc.c mtd/fs/jffs2/gc.c
--- Mtd-orig/fs/jffs2/gc.c	2005-11-14 02:03:03.000000000 +0100
+++ mtd/fs/jffs2/gc.c	2005-11-28 10:19:04.000000000 +0100
@@ -1060,8 +1060,8 @@ static int jffs2_garbage_collect_dnode(s
 	struct jffs2_full_dnode *new_fn;
 	struct jffs2_raw_inode ri;
 	uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;
-	int ret = 0;
-	unsigned char *comprbuf = NULL, *writebuf;
+	int ret = 0, cr;
+	unsigned char *comprbuf = NULL, *writebuf, *finalbuf;
 	unsigned long pg;
 	unsigned char *pg_ptr;
 
@@ -1214,7 +1214,6 @@ static int jffs2_garbage_collect_dnode(s
 	while(offset < orig_end) {
 		uint32_t datalen;
 		uint32_t cdatalen;
-		uint16_t comprtype = JFFS2_COMPR_NONE;
 
 		ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
 					&alloclen, JFFS2_SUMMARY_INODE_SIZE);
@@ -1224,12 +1223,24 @@ static int jffs2_garbage_collect_dnode(s
 			       sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);
 			break;
 		}
-		cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset);
 		datalen = end - offset;
+		cdatalen = min_t(uint32_t, alloclen - sizeof(ri), datalen);
 
 		writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
 
-		comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen);
+		comprbuf = (unsigned char *) __get_free_page(GFP_KERNEL);
+
+		cr = jffs2_compress(&c->ctx, writebuf, datalen, comprbuf, &cdatalen);
+		if (likely(cr > 0)) {
+			ri.compr = JFFS2_COMPR_ENGINE;
+			ri.usercompr = cr;
+			finalbuf = comprbuf;
+		} else {
+			ri.compr = JFFS2_COMPR_NONE;
+			ri.usercompr = 0;
+			datalen = cdatalen;
+			finalbuf = writebuf;
+		}
 
 		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -1248,14 +1259,12 @@ static int jffs2_garbage_collect_dnode(s
 		ri.offset = cpu_to_je32(offset);
 		ri.csize = cpu_to_je32(cdatalen);
 		ri.dsize = cpu_to_je32(datalen);
-		ri.compr = comprtype & 0xff;
-		ri.usercompr = (comprtype >> 8) & 0xff;
 		ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-		ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
+		ri.data_crc = cpu_to_je32(crc32(0, finalbuf, cdatalen));
 
-		new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC);
+		new_fn = jffs2_write_dnode(c, f, &ri, finalbuf, cdatalen, phys_ofs, ALLOC_GC);
 
-		jffs2_free_comprbuf(comprbuf, writebuf);
+		free_page((unsigned long) comprbuf);
 
 		if (IS_ERR(new_fn)) {
 			printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
diff -Narup Mtd-orig/fs/jffs2/read.c mtd/fs/jffs2/read.c
--- Mtd-orig/fs/jffs2/read.c	2005-11-14 02:03:03.000000000 +0100
+++ mtd/fs/jffs2/read.c	2005-11-28 10:19:04.000000000 +0100
@@ -20,13 +20,17 @@
 #include "nodelist.h"
 #include "compr.h"
 
+#ifdef CONFIG_JFFS2_COMPR_COMPAT
+#include "compr_compat.h"
+#endif
+
 int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 		     struct jffs2_full_dnode *fd, unsigned char *buf,
 		     int ofs, int len)
 {
 	struct jffs2_raw_inode *ri;
 	size_t readlen;
-	uint32_t crc;
+	uint32_t crc, declen;
 	unsigned char *decomprbuf = NULL;
 	unsigned char *readbuf = NULL;
 	int ret = 0;
@@ -125,15 +129,29 @@ int jffs2_read_dnode(struct jffs2_sb_inf
 		goto out_decomprbuf;
 	}
 	D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
-	if (ri->compr != JFFS2_COMPR_NONE) {
+	if (ri->compr == JFFS2_COMPR_ENGINE) {
 		D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
 			  je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
-		ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
+		declen = je32_to_cpu(ri->dsize);
+		ret = jffs2_decompress(&c->ctx, readbuf, je32_to_cpu(ri->csize), decomprbuf, &declen, ri->usercompr);
+		if (ret) {
+			printk(KERN_WARNING "Error: decompress returned %d\n", ret);
+			goto out_decomprbuf;
+		}
+	}
+
+#ifdef CONFIG_JFFS2_COMPR_COMPAT
+	else if (ri->compr != JFFS2_COMPR_NONE) {
+		D2(printk(KERN_DEBUG "Compat decompress %d bytes from %p to %d bytes at %p\n",
+			  je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
+		ret = jffs2_decompress_compat(&c->compat_ctx, readbuf, je32_to_cpu(ri->csize), decomprbuf,
+				declen, ri->compr);
 		if (ret) {
-			printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
+			printk(KERN_WARNING "Error: decompress compat returned %d\n", ret);
 			goto out_decomprbuf;
 		}
 	}
+#endif
 
 	if (len < je32_to_cpu(ri->dsize)) {
 		memcpy(buf, decomprbuf+ofs, len);
diff -Narup Mtd-orig/fs/jffs2/super.c mtd/fs/jffs2/super.c
--- Mtd-orig/fs/jffs2/super.c	2005-11-12 02:02:11.000000000 +0100
+++ mtd/fs/jffs2/super.c	2005-11-28 10:19:04.000000000 +0100
@@ -14,6 +14,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -27,6 +28,8 @@
 #include "compr.h"
 #include "nodelist.h"
 
+static char *compr_control = CONFIG_JFFS2_COMPR_CONTROL;
+
 static void jffs2_put_super(struct super_block *);
 
 static kmem_cache_t *jffs2_inode_cachep;
@@ -125,6 +128,19 @@ static struct super_block *jffs2_get_sb_
 	memset(c, 0, sizeof(*c));
 	c->mtd = mtd;
 
+	c->ctx = jffs2_create_compr_context(compr_control);
+	if (!c->ctx) {
+		kfree(c);
+		return ERR_PTR(-EFAULT);
+	}
+
+	ret = jffs2_create_compr_compat_context(&c->compat_ctx);
+	if (ret) {
+		jffs2_destroy_compr_context(&c->ctx);
+		kfree(c);
+		return ERR_PTR(-EFAULT);
+	}
+
 	sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
 
 	if (IS_ERR(sb))
@@ -165,9 +181,10 @@ static struct super_block *jffs2_get_sb_
 	return sb;
 
  out_put:
+	jffs2_destroy_compr_compat_context(&c->compat_ctx);
+	jffs2_destroy_compr_context(&c->ctx);
 	kfree(c);
 	put_mtd_device(mtd);
-
 	return sb;
 }
 
@@ -302,6 +319,8 @@ static void jffs2_kill_sb(struct super_b
 	if (!(sb->s_flags & MS_RDONLY))
 		jffs2_stop_garbage_collect_thread(c);
 	generic_shutdown_super(sb);
+	jffs2_destroy_compr_compat_context(&c->compat_ctx);
+	jffs2_destroy_compr_context(&c->ctx);
 	put_mtd_device(c->mtd);
 	kfree(c);
 }
@@ -334,15 +353,20 @@ static int __init init_jffs2_fs(void)
 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
 		return -ENOMEM;
 	}
-	ret = jffs2_compressors_init();
+	ret = jffs2_init_compr_engine();
 	if (ret) {
-		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
+		printk(KERN_ERR "JFFS2 error: Failed to initialise compressor engine\n");
 		goto out;
 	}
+	ret = jffs2_init_compr_compat();
+	if (ret) {
+		printk(KERN_ERR "JFFS2 error: Failed to initialise decompressor compatibility engine\n");
+		goto out_compressors;
+	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-		goto out_compressors;
+		goto out_compr_compat;
 	}
 	ret = register_filesystem(&jffs2_fs_type);
 	if (ret) {
@@ -353,8 +377,10 @@ static int __init init_jffs2_fs(void)
 
  out_slab:
 	jffs2_destroy_slab_caches();
+ out_compr_compat:
+	jffs2_exit_compr_compat();
  out_compressors:
-	jffs2_compressors_exit();
+	jffs2_exit_compr_engine();
  out:
 	kmem_cache_destroy(jffs2_inode_cachep);
 	return ret;
@@ -364,13 +390,16 @@ static void __exit exit_jffs2_fs(void)
 {
 	unregister_filesystem(&jffs2_fs_type);
 	jffs2_destroy_slab_caches();
-	jffs2_compressors_exit();
+	jffs2_exit_compr_compat();
+	jffs2_exit_compr_engine();
 	kmem_cache_destroy(jffs2_inode_cachep);
 }
 
 module_init(init_jffs2_fs);
 module_exit(exit_jffs2_fs);
 
+module_param(compr_control, charp, S_IRUGO);
+
 MODULE_DESCRIPTION("The Journalling Flash File System, v2");
 MODULE_AUTHOR("Red Hat, Inc.");
 MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
diff -Narup Mtd-orig/fs/jffs2/test/compr_rubin.h mtd/fs/jffs2/test/compr_rubin.h
--- Mtd-orig/fs/jffs2/test/compr_rubin.h	2001-02-19 11:21:30.000000000 +0100
+++ mtd/fs/jffs2/test/compr_rubin.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,13 +0,0 @@
-/* Rubin encoder/decoder header       */
-/* work started at   : aug   3, 1994  */
-/* last modification : aug  15, 1994  */
-
-#define RUBIN_REG_SIZE   16
-#define UPPER_BIT_RUBIN    (((long) 1)<<RUBIN_REG_SIZE-1)
-#define LOWER_BITS_RUBIN   ((((long) 1)<<RUBIN_REG_SIZE-1)-1)
-
-void init_rubin (void);
-void encode (long, long, int);
-void end_rubin (void);
-void init_decod (void);
-int decode (long, long);
diff -Narup Mtd-orig/fs/jffs2/test/histo.cc mtd/fs/jffs2/test/histo.cc
--- Mtd-orig/fs/jffs2/test/histo.cc	2001-02-26 12:57:30.000000000 +0100
+++ mtd/fs/jffs2/test/histo.cc	1970-01-01 01:00:00.000000000 +0100
@@ -1,80 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-int histo[256];
-int histo2[256];
-int bits[8];
-int total;
-void main() 
-{
-	FILE *file;
-	int i,i2;
-
-	int max=0; 
-	
-/*	file = fopen("/lib/libc-2.2.so","r"); */
-	file = fopen("bigsymb2","r");
-	assert(file!=NULL);
-	while (!feof(file)) {
-		unsigned char cr;
-		fread(&cr,1,1,file);
-		histo[cr]++;		
-		if (histo[cr]>max)
-			max = histo[cr];
-	}	
-	fclose(file);
-
-	i2 = 0;
-
-#if 0
-	printf("static int xlate[257] = { ");
-
-
-	
-	/* Ugh slow */
-	while (max>=0) {	
-		for (i=0;i<256;i++) {	
-			if (histo[i]==max) {
-				printf("\t%i,\n",i);
-				histo2[i2++]=histo[i];
-			}
-		}
-		max--;
-	}	
-
-	printf(" };\n");
-
-	if (i2!=256)
-		printf("/* Uh oh: %i != 256 */ \n");
-#endif
-	
-	for (i=0;i<256;i++) {
-		if (i&128)
-			bits[7]+=histo[i];
-		if (i&64)
-			bits[6]+=histo[i];
-		if (i&32)
-			bits[5]+=histo[i];
-		if (i&16)
-			bits[4]+=histo[i];
-		if (i&8)
-			bits[3]+=histo[i];
-		if (i&4)
-			bits[2]+=histo[i];
-		if (i&2)
-			bits[1]+=histo[i];
-		if (i&1)
-			bits[0]+=histo[i];
-		total+=histo[i];
-	}
-	
-	printf("#define BIT_DIVIDER %i \n",total>>12);
-	printf("static int bits[9] = { ");
-	for (i=0;i<8;i++)
-		if ((bits[i]>>12)>0)
-			printf("%i,",bits[i]>>12);
-		else 
-			printf("1, ");
-	printf("};\n");
-}
\ No newline at end of file
diff -Narup Mtd-orig/fs/jffs2/test/histo.h mtd/fs/jffs2/test/histo.h
--- Mtd-orig/fs/jffs2/test/histo.h	2005-11-08 02:02:16.000000000 +0100
+++ mtd/fs/jffs2/test/histo.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER 1043
-static int bits[9] = { 277,249,290,267,229,341,212,241,};
diff -Narup Mtd-orig/fs/jffs2/test/histo1.h mtd/fs/jffs2/test/histo1.h
--- Mtd-orig/fs/jffs2/test/histo1.h	2005-11-08 02:02:16.000000000 +0100
+++ mtd/fs/jffs2/test/histo1.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER 755
-static int bits[9] = { 108,125,128,93,84,89,119,94,};
diff -Narup Mtd-orig/fs/jffs2/test/histo2.h mtd/fs/jffs2/test/histo2.h
--- Mtd-orig/fs/jffs2/test/histo2.h	2005-11-08 02:02:16.000000000 +0100
+++ mtd/fs/jffs2/test/histo2.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER 504
-static int bits[9] = { 250,210,239,238,233,307,237,144,};
diff -Narup Mtd-orig/fs/jffs2/test/histo_html.h mtd/fs/jffs2/test/histo_html.h
--- Mtd-orig/fs/jffs2/test/histo_html.h	2005-11-08 02:02:16.000000000 +0100
+++ mtd/fs/jffs2/test/histo_html.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER 631
-static int bits[9] = { 268,247,324,252,199,529,436,1, };
diff -Narup Mtd-orig/fs/jffs2/test/histo_text.h mtd/fs/jffs2/test/histo_text.h
--- Mtd-orig/fs/jffs2/test/histo_text.h	2005-11-08 02:02:16.000000000 +0100
+++ mtd/fs/jffs2/test/histo_text.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER 1187
-static int bits[9] = { 518,418,533,414,310,1069,822,1, };
diff -Narup Mtd-orig/fs/jffs2/test/main.c mtd/fs/jffs2/test/main.c
--- Mtd-orig/fs/jffs2/test/main.c	2005-11-08 02:02:16.000000000 +0100
+++ mtd/fs/jffs2/test/main.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,56 +0,0 @@
-#include <stdio.h>
-
-#include "compr_rubin.h"
-
-#define __u32 int
-
-/* _compress returns the compressed size, -1 if bigger */
-int rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-		   __u32 *sourcelen, __u32 *dstlen);
-
-void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      __u32 srclen, __u32 destlen);
-
-void main()
-{
-	unsigned char source[4096];
-	unsigned char compr[40960];
-	unsigned char dest[4096];
-
-	int result;
-	int i;
-	int len,maxlen;
-	FILE *file;
-
-	memset(dest,0xA5,sizeof(dest));
-
-	for (i=0;i<4096;i++)
-		source[i] = i;
-
-	file=fopen("asd","r");
-	while (!feof(file)) {
-		fread(source,1,4096,file);
-
-		len = 4096;
-		maxlen = 40960;
-		result = rubin_compress(source,compr,&len, &maxlen);
-		if (result) {
-			printf("result is %d, exiting\n",result);
-			exit(0);
-		}
-		printf("Compressed to %i bytes \n",maxlen);
-
-		if (maxlen>4096)
-			continue;
-
-		rubin_decompress(compr,dest,4096,4096);
-		for (i=0;i<4096;i++)
-			if (source[i]!=dest[i]) {
-				printf("Mismatch at position %i: %i -> %i \n",i,source[i],dest[i]);
-
-			}
-
-	}
-	fclose(file);
-}
-
diff -Narup Mtd-orig/fs/jffs2/test/pushpull.h mtd/fs/jffs2/test/pushpull.h
--- Mtd-orig/fs/jffs2/test/pushpull.h	2001-02-19 12:20:43.000000000 +0100
+++ mtd/fs/jffs2/test/pushpull.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,11 +0,0 @@
-#define  PPBUFSIZ   2048
-void pushinit(unsigned char *buffer, unsigned int max);
-void pushbit(int bit);
-void pushblk(int blk, int bitsinblk);
-void pushexit(void);
-int pushedbits(void);
-void pullinit(unsigned char *buffer);
-int pullbit(void);
-int pullblk(int bitsinblk);
-void pullexit(void);
-int pulledbits(void);
diff -Narup Mtd-orig/fs/jffs2/test/rtime.h mtd/fs/jffs2/test/rtime.h
--- Mtd-orig/fs/jffs2/test/rtime.h	2005-11-08 02:02:16.000000000 +0100
+++ mtd/fs/jffs2/test/rtime.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,8 +0,0 @@
-#define __u32 int
-
-/* _compress returns the compressed size, -1 if bigger */
-int rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-		   __u32 *sourcelen, __u32 *dstlen);
-
-void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      __u32 srclen, __u32 destlen);
diff -Narup Mtd-orig/fs/jffs2/write.c mtd/fs/jffs2/write.c
--- Mtd-orig/fs/jffs2/write.c	2005-11-12 02:02:11.000000000 +0100
+++ mtd/fs/jffs2/write.c	2005-11-28 10:19:04.000000000 +0100
@@ -349,7 +349,7 @@ int jffs2_write_inode_range(struct jffs2
 			    struct jffs2_raw_inode *ri, unsigned char *buf,
 			    uint32_t offset, uint32_t writelen, uint32_t *retlen)
 {
-	int ret = 0;
+	int ret = 0, cr;
 	uint32_t writtenlen = 0;
 
        	D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n",
@@ -357,8 +357,7 @@ int jffs2_write_inode_range(struct jffs2
 
 	while(writelen) {
 		struct jffs2_full_dnode *fn;
-		unsigned char *comprbuf = NULL;
-		uint16_t comprtype = JFFS2_COMPR_NONE;
+		unsigned char *comprbuf = NULL, *finalbuf;
 		uint32_t phys_ofs, alloclen;
 		uint32_t datalen, cdatalen;
 		int retried = 0;
@@ -376,7 +375,19 @@ int jffs2_write_inode_range(struct jffs2
 		datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
 		cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
 
-		comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
+		comprbuf = (unsigned char *) __get_free_page(GFP_KERNEL);
+
+		cr = jffs2_compress(&c->ctx, buf, datalen, comprbuf, &cdatalen);
+		if (likely(cr > 0)) {
+			ri->compr = JFFS2_COMPR_ENGINE;
+			ri->usercompr = cr;
+			finalbuf = comprbuf;
+		} else {
+			ri->compr = JFFS2_COMPR_NONE;
+			ri->usercompr = 0;
+			datalen = cdatalen;
+			finalbuf = buf;
+		}
 
 		ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 		ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -389,14 +400,12 @@ int jffs2_write_inode_range(struct jffs2
 		ri->offset = cpu_to_je32(offset);
 		ri->csize = cpu_to_je32(cdatalen);
 		ri->dsize = cpu_to_je32(datalen);
-		ri->compr = comprtype & 0xff;
-		ri->usercompr = (comprtype >> 8 ) & 0xff;
 		ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-		ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
+		ri->data_crc = cpu_to_je32(crc32(0, finalbuf, cdatalen));
 
-		fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
+		fn = jffs2_write_dnode(c, f, ri, finalbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
 
-		jffs2_free_comprbuf(comprbuf, buf);
+		free_page((unsigned long) comprbuf);
 
 		if (IS_ERR(fn)) {
 			ret = PTR_ERR(fn);
diff -Narup Mtd-orig/include/linux/jffs2.h mtd/include/linux/jffs2.h
--- Mtd-orig/include/linux/jffs2.h	2005-11-08 02:02:17.000000000 +0100
+++ mtd/include/linux/jffs2.h	2005-11-28 10:19:04.000000000 +0100
@@ -46,11 +46,14 @@
 
 #define JFFS2_COMPR_NONE	0x00
 #define JFFS2_COMPR_ZERO	0x01
+#define JFFS2_COMPR_COPY	0x04
+#define JFFS2_COMPR_ENGINE	0x10
+
 #define JFFS2_COMPR_RTIME	0x02
 #define JFFS2_COMPR_RUBINMIPS	0x03
-#define JFFS2_COMPR_COPY	0x04
 #define JFFS2_COMPR_DYNRUBIN	0x05
 #define JFFS2_COMPR_ZLIB	0x06
+
 /* Compatibility flags. */
 #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
 #define JFFS2_NODE_ACCURATE 0x2000
diff -Narup Mtd-orig/include/linux/jffs2_fs_sb.h mtd/include/linux/jffs2_fs_sb.h
--- Mtd-orig/include/linux/jffs2_fs_sb.h	2005-11-12 02:02:14.000000000 +0100
+++ mtd/include/linux/jffs2_fs_sb.h	2005-11-28 10:19:04.000000000 +0100
@@ -18,6 +18,10 @@
 #define JFFS2_SB_FLAG_BUILDING 4 /* File system building is in progress */
 
 struct jffs2_inodirty;
+struct compress_ctx;
+#ifdef CONFIG_JFFS2_COMPR_COMPAT
+struct compress_compat_ctx;
+#endif
 
 /* A struct for the overall file system control.  Pointers to
    jffs2_sb_info structs are named `c' in the source code.
@@ -117,6 +121,11 @@ struct jffs2_sb_info {
 
 	uint32_t ebh_size;	/* This is the space size occupied by eraseblock_header on flash */
 
+	struct compress_ctx *ctx;
+#ifdef CONFIG_JFFS2_COMPR_COMPAT
+	struct compress_compat_ctx *compat_ctx;
+#endif
+
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };
diff -Narup Mtd-orig/patches/patchin.sh mtd/patches/patchin.sh
--- Mtd-orig/patches/patchin.sh	2005-09-15 14:18:41.000000000 +0200
+++ mtd/patches/patchin.sh	2005-11-28 10:19:04.000000000 +0100
@@ -411,7 +411,7 @@ MTD_FILES_EX26="mtd_blkdevs-24.c blkmtd-
 # JFFS2 files and directories
 JFFS2_DIRS="fs/jffs2"
 JFFS2_FILES="*.[ch] Makefile Rules.make"
-JFFS2_FILES_EX26="compr_lzari.c compr_lzo.c crc32.[hc] rbtree.c super-v24.c symlink-v24.c"
+JFFS2_FILES_EX26="crc32.[hc] rbtree.c super-v24.c symlink-v24.c"
 # kernel version < 2.4.20 needs zlib headers
 JFFS2_INC_BEL2420="jffs*.h workqueue.h z*.h rb*.h suspend.h"
 # kernel version < 2.5.x
diff -Narup Mtd-orig/scripts/patchin.xml mtd/scripts/patchin.xml
--- Mtd-orig/scripts/patchin.xml	2005-07-15 18:07:26.000000000 +0200
+++ mtd/scripts/patchin.xml	2005-11-28 10:19:04.000000000 +0100
@@ -176,7 +176,6 @@ the rule valid (logical OR)
 		<UPDATE pattern="Makefile.common" target="Makefile" />
 		<EXCLUDE pattern=".*v24.c$" />
 		<EXCLUDE pattern="crc.*" />
-		<EXCLUDE pattern="compr_lz.*" />
 		<EXCLUDE pattern="rbtree.*" />
 	</SUBDIR>
 	<SUBDIR name="fs/jffs3" actions="mkdir,rm,cp,ln" depends="jffs3">
diff -Narup Mtd-orig/util/Makefile mtd/util/Makefile
--- Mtd-orig/util/Makefile	2005-11-08 02:02:19.000000000 +0100
+++ mtd/util/Makefile	2005-11-28 10:19:04.000000000 +0100
@@ -11,7 +11,7 @@ CC := $(CROSS)gcc
 CFLAGS := -I../include -O2 -Wall
 
 TARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \
-	mkfs.jffs ftl_check mkfs.jffs2 flash_lock flash_unlock flash_info \
+	mkfs.jffs ftl_check mkfs-old.jffs2 flash_lock flash_unlock flash_info \
 	flash_otp_info flash_otp_dump mtd_debug flashcp nandwrite \
 	jffs2dump \
 	nftldump nftl_format docfdisk \
@@ -34,12 +34,15 @@ IGNORE=${wildcard .*.c.dep}
 -include ${IGNORE}
 
 clean:
-	rm -f *.o $(TARGETS) .*.c.dep $(SYMLINKS)
+	rm -f *.o $(TARGETS) mkfs.jffs2 .*.c.dep $(SYMLINKS)
 
 $(SYMLINKS):
 	ln -sf ../fs/jffs2/$@ $@
 
-mkfs.jffs2: crc32.o compr_rtime.o mkfs.jffs2.o compr_zlib.o compr.o
+mkfs.jffs2: crc32.o mkfs.jffs2.o compr.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
+mkfs-old.jffs2: crc32.o compr_rtime-old.o mkfs-old.jffs2.o compr_zlib-old.o compr-old.o
 	$(CC) $(LDFLAGS) -o $@ $^ -lz
 
 flash_eraseall: crc32.o flash_eraseall.o
diff -Narup Mtd-orig/util/compr-old.c mtd/util/compr-old.c
--- Mtd-orig/util/compr-old.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/compr-old.c	2005-11-28 10:19:04.000000000 +0100
@@ -0,0 +1,586 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory
+ * in the jffs2 directory.
+ *
+ * $Id: compr.c,v 1.8 2005/07/26 13:07:02 havasi Exp $
+ *
+ */
+
+#include "compr-old.h"
+#include <string.h>
+#include <stdlib.h>
+#include <linux/jffs2.h>
+
+extern int page_size;
+
+/* LIST IMPLEMENTATION (from linux/list.h) */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void __list_add(struct list_head *new,
+							  struct list_head *prev,
+							  struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = (void *) 0;
+	entry->prev = (void *) 0;
+}
+
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each_entry(pos, head, member)					\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+		&pos->member != (head);									\
+		pos = list_entry(pos->member.next, typeof(*pos), member))
+
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_list);
+/* Compression sequence depends on the comression mode) */
+static LIST_HEAD(jffs2_compression_list);
+
+/* Actual compression mode */
+static int jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+
+void jffs2_set_compression_mode(int mode) 
+{
+	jffs2_compression_mode = mode;
+}
+
+int jffs2_get_compression_mode(void)
+{
+	return jffs2_compression_mode;
+}
+
+/* Statistics for blocks stored without compression */
+static uint32_t none_stat_compr_blocks = 0,
+				none_stat_decompr_blocks = 0,
+				none_stat_compr_size = 0;
+
+/* Compression test stuffs */
+
+static int jffs2_compression_check = 0;
+static unsigned char *jffs2_compression_check_buf = NULL;
+
+void jffs2_compression_check_set(int yesno)
+{
+	jffs2_compression_check = yesno;
+}
+
+int jffs2_compression_check_get(void)
+{
+	return jffs2_compression_check;
+}
+
+static int jffs2_error_cnt = 0;
+
+int jffs2_compression_check_errorcnt_get(void)
+{
+	return jffs2_error_cnt;
+}
+
+#define JFFS2_BUFFER_FILL 0x55
+
+/* Called before compression (if compression_check is setted) to prepare 
+   the buffer for buffer overflow test */
+static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
+{
+	memset(buf,JFFS2_BUFFER_FILL,size+1);
+}
+
+/* Called after compression (if compression_check is setted) to test the result */
+static void jffs2_decompression_test(struct jffs2_compressor *compr,
+					unsigned char *data_in, unsigned char *output_buf,
+					uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
+{
+	uint32_t i;
+
+	/* buffer overflow test */
+	for (i=buf_size;i>cdatalen;i--) {
+		if (output_buf[i]!=JFFS2_BUFFER_FILL) {
+			fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
+					"(bs=%d csize=%d b[%d]=%d)\n", compr->name, 
+					buf_size, cdatalen, i, (int)(output_buf[i]));
+			jffs2_error_cnt++;
+			return;
+		}
+	}
+	/* allocing temporary buffer for decompression */
+	if (!jffs2_compression_check_buf) {
+		jffs2_compression_check_buf = malloc(page_size);
+		if (!jffs2_compression_check_buf) {
+			fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
+			jffs2_compression_check = 0;
+			return;
+		}
+	}
+	/* decompressing */
+	if (!compr->decompress) {
+		fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
+		jffs2_error_cnt++;
+		return;
+	}
+	if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,NULL)) {
+		fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
+		jffs2_error_cnt++;
+	}
+	/* validate decompression */
+	else {
+		for (i=0;i<datalen;i++) {
+			if (data_in[i]!=jffs2_compression_check_buf[i]) {
+				fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
+				jffs2_error_cnt++;
+				break;
+			}
+		}
+	}
+}
+
+/* jffs2_compress:
+ * @data: Pointer to uncompressed data
+ * @cdata: Pointer to returned pointer to buffer for compressed data
+ * @datalen: On entry, holds the amount of data available for compression.
+ *	On exit, expected to hold the amount of data actually compressed.
+ * @cdatalen: On entry, holds the amount of space available for compressed
+ *	data. On exit, expected to hold the actual size of the compressed
+ *	data.
+ *
+ * Returns: Lower byte to be stored with data indicating compression type used.
+ * Zero is used to show that the data could not be compressed - the 
+ * compressed version was actually larger than the original.
+ * Upper byte will be used later. (soon)
+ *
+ * If the cdata buffer isn't large enough to hold all the uncompressed data,
+ * jffs2_compress should compress as much as will fit, and should set 
+ * *datalen accordingly to show the amount of data which were compressed.
+ */
+uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
+			 uint32_t *datalen, uint32_t *cdatalen)
+{
+	int ret = JFFS2_COMPR_NONE;
+	int compr_ret;
+	struct jffs2_compressor *this, *best=NULL;
+	unsigned char *output_buf = NULL, *tmp_buf;
+	uint32_t orig_slen, orig_dlen;
+	uint32_t best_slen=0, best_dlen=0;
+
+	switch (jffs2_compression_mode) {
+	case JFFS2_COMPR_MODE_NONE:
+		break;
+	case JFFS2_COMPR_MODE_FIRST:
+		orig_slen = *datalen;
+		orig_dlen = *cdatalen;
+		output_buf = malloc(orig_dlen+jffs2_compression_check);
+		if (!output_buf) {
+			fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
+			goto out;
+		}
+		list_for_each_entry(this, &jffs2_compression_list, cn_list) {
+			/* Skip decompress-only backwards-compatibility and disabled modules */
+			if (!this->compress)
+				continue;
+
+			this->usecount++;
+
+			if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+				jffs2_decompression_test_prepare(output_buf, orig_dlen);
+
+			*datalen  = orig_slen;
+			*cdatalen = orig_dlen;
+			compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
+			this->usecount--;
+			if (!compr_ret) {
+				ret = this->compr;
+				this->stat_compr_blocks++;
+				this->stat_compr_orig_size += *datalen;
+				this->stat_compr_new_size  += *cdatalen;
+				if (jffs2_compression_check)
+					jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
+				break;
+			}
+		}
+		if (ret == JFFS2_COMPR_NONE)
+			free(output_buf);
+		break;
+	case JFFS2_COMPR_MODE_BEST:
+		orig_slen = *datalen;
+		orig_dlen = *cdatalen;
+		list_for_each_entry(this, &jffs2_compression_list, cn_list) {
+			/* Skip decompress-only backwards-compatibility and disabled modules */
+			if (!this->compress)
+				continue;
+			/* Allocating memory for output buffer if necessary */
+			if ((this->compr_buf_size<orig_dlen+jffs2_compression_check)&&(this->compr_buf)) {
+				free(this->compr_buf);
+				this->compr_buf_size=0;
+				this->compr_buf=NULL;
+			}
+			if (!this->compr_buf) {
+				tmp_buf = malloc(orig_dlen+jffs2_compression_check);
+				if (!tmp_buf) {
+					fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
+					continue;
+				}
+				else {
+					this->compr_buf = tmp_buf;
+					this->compr_buf_size = orig_dlen;
+				}
+			}
+			this->usecount++;
+			if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+				jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size);
+			*datalen  = orig_slen;
+			*cdatalen = orig_dlen;
+			compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
+			this->usecount--;
+			if (!compr_ret) {
+				if (jffs2_compression_check)
+					jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size);
+				if ((!best_dlen)||(best_dlen>*cdatalen)) {
+					best_dlen = *cdatalen;
+					best_slen = *datalen;
+					best = this;
+				}
+			}
+		}
+		if (best_dlen) {
+			*cdatalen = best_dlen;
+			*datalen  = best_slen;
+			output_buf = best->compr_buf;
+			best->compr_buf = NULL;
+			best->compr_buf_size = 0;
+			best->stat_compr_blocks++;
+			best->stat_compr_orig_size += best_slen;
+			best->stat_compr_new_size  += best_dlen;
+			ret = best->compr;
+		}
+		break;
+	default:
+		fprintf(stderr,"mkfs.jffs2: unknow compression mode.\n");
+	}
+ out:
+	if (ret == JFFS2_COMPR_NONE) {
+		*cpage_out = data_in;
+		*datalen = *cdatalen;
+		none_stat_compr_blocks++;
+		none_stat_compr_size += *datalen;
+	}
+	else {
+		*cpage_out = output_buf;
+	}
+	return ret;
+}
+
+
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+	struct jffs2_compressor *this;
+	char *buf, *act_buf;
+
+	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		act_buf += sprintf(act_buf, "%10s ", this->name);
+		if (!this->compress)
+			act_buf += sprintf(act_buf,"disabled");
+		else
+			act_buf += sprintf(act_buf,"enabled");
+		act_buf += sprintf(act_buf,"\n");
+	}
+	return buf;
+}
+
+char *jffs2_stats(void)
+{
+	struct jffs2_compressor *this;
+	char *buf, *act_buf;
+
+	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+
+	act_buf += sprintf(act_buf,"Compression mode: ");
+	switch (jffs2_compression_mode) {
+	case JFFS2_COMPR_MODE_NONE:
+		act_buf += sprintf(act_buf,"none");
+		break;
+	case JFFS2_COMPR_MODE_FIRST:
+		act_buf += sprintf(act_buf,"first");
+		break;
+	case JFFS2_COMPR_MODE_BEST:
+		act_buf += sprintf(act_buf,"best");
+		break;
+	default:
+		act_buf += sprintf(act_buf,"unkown");
+		break;
+	}
+	act_buf += sprintf(act_buf,"\nCompressors:\n");
+	act_buf += sprintf(act_buf,"%10s	     ","none");
+	act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
+						none_stat_compr_size, none_stat_decompr_blocks);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		act_buf += sprintf(act_buf,"%10s ",this->name);
+		if (!this->compress)
+			act_buf += sprintf(act_buf,"- ");
+		else
+			act_buf += sprintf(act_buf,"+ ");
+		act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
+							this->stat_compr_new_size, this->stat_compr_orig_size,
+							this->stat_decompr_blocks);
+		act_buf += sprintf(act_buf,"\n");
+	}
+	return buf;
+}
+
+static char *jffs2_strcpy_skp_ws(char *in)
+{
+	int i, len;
+	char *new, *tmp_ptr;
+
+	if (!in)
+		return NULL;
+
+	len = strlen(in);
+	new = malloc(len + 1);
+	if (!new)
+		return NULL;
+	tmp_ptr = new;
+
+	for(i=0; i<len; i++) {
+		if (in[i] != ' ' && in[i] != '\t' && in[i] != '\n') {
+			*tmp_ptr = in[i];
+			tmp_ptr++;
+		}
+	}
+	tmp_ptr = '\0';
+
+	len = strlen(new);
+	if (!len) {
+		free(new);
+		return NULL;
+	}
+
+	return new;
+}
+
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+	if (!comp->name) {
+		fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
+		return -1;
+	}
+	comp->compr_buf_size=0;
+	comp->compr_buf=NULL;
+	comp->usecount=0;
+	comp->stat_compr_orig_size=0;
+	comp->stat_compr_new_size=0;
+	comp->stat_compr_blocks=0;
+	comp->stat_decompr_blocks=0;
+	list_add_tail(&comp->list, &jffs2_compressor_list);
+
+	return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+
+	if (comp->usecount) {
+		fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
+		return -1;
+	}
+	list_del(&comp->list);
+
+	return 0;
+}
+
+
+
+/* returns 1 if the selected compressor (compr) is on the comression list, 0 otherwise */
+static int jffs2_is_compr_on_compression_list(struct jffs2_compressor *compr)
+{
+	struct jffs2_compressor *this;
+
+	list_for_each_entry(this, &jffs2_compression_list, cn_list) {
+		if (this == compr) {
+			fprintf(stderr,"Compressor (%s) is already on compression list!\n(It can be on the list only once!)\n",compr->name);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int jffs2_add_compr_to_compression_list(char *name)
+{
+	struct jffs2_compressor *this;
+	int ret;
+
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (!strcmp(this->name, name)) {
+
+			ret = jffs2_is_compr_on_compression_list(this);
+			if (ret)
+				return ret;
+
+			list_add_tail(&this->cn_list,&jffs2_compression_list);
+			return 0;
+		}
+	}
+	fprintf(stderr,"Compressor (%s) not found.\n",name);
+	return 1;
+}
+
+int jffs2_setup_compression(char *compr_cont)
+{
+	char *data, *from, *to, *iter;
+	char* cmpr_name = NULL;
+	int mode, run, ret;
+	int len, flag = 0;
+
+	data = jffs2_strcpy_skp_ws(compr_cont);
+	if (!data)
+		return -1;
+
+	printf("Compression control string: %s\n",data);
+
+	iter = data;
+	from = to = data;
+	mode = JFFS2_COMPR_MODE_NONE;
+	run = 1;
+	while (run) {
+		switch(*iter) {
+			case '{' :
+			case '[' :
+				if (mode || flag) {
+					fprintf(stdout,"Compression control string parse error!\n");
+					goto error;
+				}
+
+				if (*iter == '{')
+					mode = JFFS2_COMPR_MODE_BEST;
+				else {
+					mode = JFFS2_COMPR_MODE_FIRST;
+				}
+
+				from = iter + 1;
+				break;
+
+			case '}' :
+			case ']' :
+			case ',' :
+			case '\0' :
+				if (from == to) {
+					fprintf(stderr,"Compressor name with length 0 is not allowed!\n");
+					goto error;
+				}
+
+				if (*iter == ',' && flag == 1) {
+					fprintf(stderr,"Comma is allowed only between {} or []\n");
+					goto error;
+				}
+
+				if (*iter == '\0' && mode != 0 && !(*(iter-1) == '}' || *(iter-1) == ']')) {
+					fprintf(stderr,"Compression control string contains not determinated expression ({} or [])!\n");
+					goto error;
+				}
+
+				if (*iter == '\0' || *iter == ']' || *iter == '}')
+					run = 0;
+
+				len = to - from;
+
+				cmpr_name = malloc(len + 1);
+				if (!cmpr_name) {
+					fprintf(stderr,"Memory allocation error!\n");
+					goto error;
+				}
+
+				strncpy(cmpr_name, from, len);
+				cmpr_name[len] = '\0';
+
+				ret = jffs2_add_compr_to_compression_list(cmpr_name);
+				if (ret) 
+					goto error;
+
+				free(cmpr_name);
+				from = to = iter + 1;
+				break;
+
+			default :
+				to = iter + 1;
+				if (mode == JFFS2_COMPR_MODE_NONE) {
+					flag = 1;
+				}
+				break;
+		}
+		iter++;
+	}
+
+	if (flag)
+		mode = JFFS2_COMPR_MODE_FIRST;
+
+	jffs2_set_compression_mode(mode);
+	//printf("Compression mode is : %d\n", mode);
+
+	free(data);
+	return 0;
+
+ error:
+	free(data);
+	return -1;
+}
+
+int jffs2_compressors_init(void)
+{
+#ifdef CONFIG_JFFS2_ZLIB
+	jffs2_zlib_init();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+	jffs2_rtime_init();
+#endif
+	return 0;
+}
+
+int jffs2_compressors_exit(void)
+{
+#ifdef CONFIG_JFFS2_RTIME
+	jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+	jffs2_zlib_exit();
+#endif
+	return 0;
+}
diff -Narup Mtd-orig/util/compr-old.h mtd/util/compr-old.h
--- Mtd-orig/util/compr-old.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/compr-old.h	2005-11-28 10:19:04.000000000 +0100
@@ -0,0 +1,106 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in the 
+ * jffs2 directory.
+ *
+ * $Id: compr.h,v 1.6 2005/07/26 13:07:02 havasi Exp $
+ *
+ */
+
+#ifndef __JFFS2_COMPR_H__
+#define __JFFS2_COMPR_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define CONFIG_JFFS2_COMPR_COMPAT
+#include "linux/jffs2.h"
+
+#define CONFIG_JFFS2_ZLIB
+#define CONFIG_JFFS2_RTIME
+
+#define JFFS2_COMPR_MODE_NONE		0
+#define JFFS2_COMPR_MODE_FIRST		1
+#define JFFS2_COMPR_MODE_BEST		2
+
+#define kmalloc(a,b)                malloc(a)
+#define kfree(a)                    free(a)
+#ifndef GFP_KERNEL
+#define GFP_KERNEL                  0
+#endif
+
+#define vmalloc(a)                  malloc(a)
+#define vfree(a)                    free(a)
+
+#define printk(...)                 fprintf(stderr,__VA_ARGS__)
+
+#define KERN_EMERG
+#define KERN_ALERT
+#define KERN_CRIT
+#define KERN_ERR
+#define KERN_WARNING
+#define KERN_NOTICE
+#define KERN_INFO
+#define KERN_DEBUG
+
+struct list_head {
+        struct list_head *next, *prev;
+};
+
+void jffs2_set_compression_mode(int mode);
+int jffs2_get_compression_mode(void);
+int jffs2_set_compression_mode_name(const char *mode_name);
+
+struct jffs2_compressor {
+	struct list_head list;		/* for compressors list */
+	struct list_head cn_list;	/* for compression lint */
+	char *name;
+	char compr;					/* JFFS2_COMPR_XXX */
+	int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+					uint32_t *srclen, uint32_t *destlen, void *model);
+	int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+						uint32_t cdatalen, uint32_t datalen, void *model);
+	int usecount;
+	unsigned char *compr_buf;	/* used by size compr. mode */
+	uint32_t compr_buf_size;	/* used by size compr. mode */
+	uint32_t stat_compr_orig_size;
+	uint32_t stat_compr_new_size;
+	uint32_t stat_compr_blocks;
+	uint32_t stat_decompr_blocks;
+};
+
+int jffs2_register_compressor(struct jffs2_compressor *comp);
+int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+
+int jffs2_compressors_init(void);
+int jffs2_compressors_exit(void);
+int jffs2_setup_compression(char *comp_str);
+
+uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
+							uint32_t *datalen, uint32_t *cdatalen);
+
+/* If it is setted, a decompress will be called after every compress */
+void jffs2_compression_check_set(int yesno);
+int jffs2_compression_check_get(void);
+int jffs2_compression_check_errorcnt_get(void);
+
+char *jffs2_list_compressors(void);
+char *jffs2_stats(void);
+
+/* Compressor modules */
+/* These functions will be called by jffs2_compressors_init/exit */
+#ifdef CONFIG_JFFS2_ZLIB
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+int jffs2_rtime_init(void);
+void jffs2_rtime_exit(void);
+#endif
+
+#endif /* __JFFS2_COMPR_H__ */
diff -Narup Mtd-orig/util/compr.c mtd/util/compr.c
--- Mtd-orig/util/compr.c	2005-11-08 02:02:20.000000000 +0100
+++ mtd/util/compr.c	2005-11-29 16:36:08.000000000 +0100
@@ -1,489 +1,545 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in this directory
- * in the jffs2 directory.
- *
- * $Id: compr.c,v 1.9 2005/11/07 11:15:09 gleixner Exp $
- *
- */
-
-#include "compr.h"
+#include <stdio.h>
 #include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <stdint.h>
+#include <stddef.h>
 #include <stdlib.h>
-#include <linux/jffs2.h>
-
-extern int page_size;
-
-/* LIST IMPLEMENTATION (from linux/list.h) */
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
-        struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void __list_add(struct list_head *new,
-                              struct list_head *prev,
-                              struct list_head *next)
-{
-        next->prev = new;
-        new->next = next;
-        new->prev = prev;
-        prev->next = new;
-}
-
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
-        __list_add(new, head, head->next);
-}
-
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
-        __list_add(new, head->prev, head);
-}
-
-static inline void __list_del(struct list_head *prev, struct list_head *next)
-{
-        next->prev = prev;
-        prev->next = next;
-}
-
-static inline void list_del(struct list_head *entry)
-{
-        __list_del(entry->prev, entry->next);
-        entry->next = (void *) 0;
-        entry->prev = (void *) 0;
-}
-
-#define list_entry(ptr, type, member) \
-        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-#define list_for_each_entry(pos, head, member)                          \
-        for (pos = list_entry((head)->next, typeof(*pos), member);      \
-             &pos->member != (head);                                    \
-             pos = list_entry(pos->member.next, typeof(*pos), member))
-
-
-/* Available compressors are on this list */
-static LIST_HEAD(jffs2_compressor_list);
-
-/* Actual compression mode */
-static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-
-void jffs2_set_compression_mode(int mode)
-{
-        jffs2_compression_mode = mode;
-}
-
-int jffs2_get_compression_mode(void)
-{
-        return jffs2_compression_mode;
-}
-
-/* Statistics for blocks stored without compression */
-static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
-
-/* Compression test stuffs */
-
-static int jffs2_compression_check = 0;
-
-static unsigned char *jffs2_compression_check_buf = NULL;
-
-void jffs2_compression_check_set(int yesno)
-{
-        jffs2_compression_check = yesno;
-}
-
-int jffs2_compression_check_get(void)
-{
-        return jffs2_compression_check;
-}
-
-static int jffs2_error_cnt = 0;
-
-int jffs2_compression_check_errorcnt_get(void)
-{
-        return jffs2_error_cnt;
-}
-
-#define JFFS2_BUFFER_FILL 0x55
 
-/* Called before compression (if compression_check is setted) to prepare
-   the buffer for buffer overflow test */
-static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
-{
-        memset(buf,JFFS2_BUFFER_FILL,size+1);
-}
-
-/* Called after compression (if compression_check is setted) to test the result */
-static void jffs2_decompression_test(struct jffs2_compressor *compr,
-                                     unsigned char *data_in, unsigned char *output_buf,
-                                     uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
-{
-        uint32_t i;
+#include "compr.h"
 
-        /* buffer overflow test */
-        for (i=buf_size;i>cdatalen;i--) {
-                if (output_buf[i]!=JFFS2_BUFFER_FILL) {
-                        fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
-                                    "(bs=%d csize=%d b[%d]=%d)\n", compr->name,
-                                    buf_size, cdatalen, i, (int)(output_buf[i]));
-                        jffs2_error_cnt++;
-                        return;
-                }
-        }
-        /* allocing temporary buffer for decompression */
-        if (!jffs2_compression_check_buf) {
-                jffs2_compression_check_buf = malloc(page_size);
-                if (!jffs2_compression_check_buf) {
-                        fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
-                        jffs2_compression_check = 0;
-                        return;
-                }
-        }
-        /* decompressing */
-        if (!compr->decompress) {
-                fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
-                jffs2_error_cnt++;
-                return;
-        }
-        if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,NULL)) {
-                fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
-                jffs2_error_cnt++;
-        }
-        /* validate decompression */
-        else {
-                for (i=0;i<datalen;i++) {
-                        if (data_in[i]!=jffs2_compression_check_buf[i]) {
-                                fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
-                                jffs2_error_cnt++;
-                                break;
-                        }
-                }
-        }
-}
+static struct cryptolist_entry *crypto_compress_wrapper(struct compress_ctx *ctx,
+									char *alg_name, u8 *src, int32_t srclen,
+									u8 *dst, int32_t *dstlen)
+{
+	struct cryptolist_entry *ret = NULL;
+	int temp;
+	uint32_t alg_type;
+	struct cryptolist_entry *walk;
+	struct crypt_op cryp;
+	temp = strlen(alg_name);
+	if (*dstlen < (temp + 1))
+		goto out;
+	strcpy(dst, alg_name);
+	dst += temp;
+	*dst = '\0';
+	dst++;
+	(*dstlen) -= temp;
+	(*dstlen)--;
+	walk = ctx->cryptolist_head;
+	while (walk && strcmp(alg_name, walk->sess->alg_name))
+		walk = walk->next;
+	if (!walk) {
+		walk = malloc(sizeof(struct cryptolist_entry));
+		if (!walk)
+			goto out;
+
+		memset(walk, 0, sizeof(struct cryptolist_entry));
+		if (ioctl(ctx->global_fd, CRIOGET, &walk->c_fd)) {
+			free(walk);
+			goto out;
+		}
+		if (fcntl(walk->c_fd, F_SETFD, 1) == -1) {
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+
+		walk->sess = malloc(sizeof(struct session_op));
+		if (!walk->sess) {
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+		memset(walk->sess, 0, sizeof(struct session_op));
+		walk->sess->compress = CRYPTO_COMPRESS_NAME;
+
+		walk->sess->alg_name = malloc(temp + 1);
+		if (!walk->sess->alg_name) {
+			free(walk->sess);
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+		strcpy(walk->sess->alg_name, alg_name);
+		walk->sess->alg_namelen = temp;
+		if (ioctl(walk->c_fd, CIOCGSESSION, walk->sess)) {
+			free(walk->sess->alg_name);
+			free(walk->sess);
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+		if (!ctx->cryptolist_head)
+			ctx->cryptolist_head = walk;
+		else
+			ctx->cryptolist_tail->next = walk;
+		ctx->cryptolist_tail = walk;
+	}
+
+	alg_type = walk->sess->ses;
+	if (ioctl(walk->c_fd, CIOCGALGTYPE, &alg_type)) {
+		// error during ioctl
+		goto out;
+	}
+
+	switch (alg_type) {
+		case CRYPTO_ALG_TYPE_COMPRESS:
+			cryp.ses = walk->sess->ses;
+			cryp.len = srclen;
+			cryp.outlen = dstlen;
+			cryp.src = src;
+			cryp.dst = dst;
+			cryp.op = COP_COMPRESS;
+			if (ioctl(walk->c_fd, CIOCCOMPRESS, &cryp))
+				goto out;
+			(*dstlen) += temp;
+			(*dstlen)++;
+			ret = walk;
+			break;
+
+		default:
+			break;
+	}
 
-/* jffs2_compress:
- * @data: Pointer to uncompressed data
- * @cdata: Pointer to returned pointer to buffer for compressed data
- * @datalen: On entry, holds the amount of data available for compression.
- *	On exit, expected to hold the amount of data actually compressed.
- * @cdatalen: On entry, holds the amount of space available for compressed
- *	data. On exit, expected to hold the actual size of the compressed
- *	data.
- *
- * Returns: Lower byte to be stored with data indicating compression type used.
- * Zero is used to show that the data could not be compressed - the
- * compressed version was actually larger than the original.
- * Upper byte will be used later. (soon)
- *
- * If the cdata buffer isn't large enough to hold all the uncompressed data,
- * jffs2_compress should compress as much as will fit, and should set
- * *datalen accordingly to show the amount of data which were compressed.
- */
-uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
-			 uint32_t *datalen, uint32_t *cdatalen)
-{
-	int ret = JFFS2_COMPR_NONE;
-        int compr_ret;
-        struct jffs2_compressor *this, *best=NULL;
-        unsigned char *output_buf = NULL, *tmp_buf;
-        uint32_t orig_slen, orig_dlen;
-        uint32_t best_slen=0, best_dlen=0;
-
-        switch (jffs2_compression_mode) {
-        case JFFS2_COMPR_MODE_NONE:
-                break;
-        case JFFS2_COMPR_MODE_PRIORITY:
-                orig_slen = *datalen;
-                orig_dlen = *cdatalen;
-                output_buf = malloc(orig_dlen+jffs2_compression_check);
-                if (!output_buf) {
-                        fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
-                        goto out;
-                }
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        /* Skip decompress-only backwards-compatibility and disabled modules */
-                        if ((!this->compress)||(this->disabled))
-                                continue;
-
-                        this->usecount++;
-
-                        if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
-                                jffs2_decompression_test_prepare(output_buf, orig_dlen);
-
-                        *datalen  = orig_slen;
-                        *cdatalen = orig_dlen;
-                        compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
-                        this->usecount--;
-                        if (!compr_ret) {
-                                ret = this->compr;
-                                this->stat_compr_blocks++;
-                                this->stat_compr_orig_size += *datalen;
-                                this->stat_compr_new_size  += *cdatalen;
-                                if (jffs2_compression_check)
-                                        jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
-                                break;
-                        }
-                }
-                if (ret == JFFS2_COMPR_NONE) free(output_buf);
-                break;
-        case JFFS2_COMPR_MODE_SIZE:
-                orig_slen = *datalen;
-                orig_dlen = *cdatalen;
-                list_for_each_entry(this, &jffs2_compressor_list, list) {
-                        /* Skip decompress-only backwards-compatibility and disabled modules */
-                        if ((!this->compress)||(this->disabled))
-                                continue;
-                        /* Allocating memory for output buffer if necessary */
-                        if ((this->compr_buf_size<orig_dlen+jffs2_compression_check)&&(this->compr_buf)) {
-                                free(this->compr_buf);
-                                this->compr_buf_size=0;
-                                this->compr_buf=NULL;
-                        }
-                        if (!this->compr_buf) {
-                                tmp_buf = malloc(orig_dlen+jffs2_compression_check);
-                                if (!tmp_buf) {
-                                        fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
-                                        continue;
-                                }
-                                else {
-                                        this->compr_buf = tmp_buf;
-                                        this->compr_buf_size = orig_dlen;
-                                }
-                        }
-                        this->usecount++;
-                        if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
-                                jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size);
-                        *datalen  = orig_slen;
-                        *cdatalen = orig_dlen;
-                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
-                        this->usecount--;
-                        if (!compr_ret) {
-                                if (jffs2_compression_check)
-                                    jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size);
-                                if ((!best_dlen)||(best_dlen>*cdatalen)) {
-                                        best_dlen = *cdatalen;
-                                        best_slen = *datalen;
-                                        best = this;
-                                }
-                        }
-                }
-                if (best_dlen) {
-                        *cdatalen = best_dlen;
-                        *datalen  = best_slen;
-                        output_buf = best->compr_buf;
-                        best->compr_buf = NULL;
-                        best->compr_buf_size = 0;
-                        best->stat_compr_blocks++;
-                        best->stat_compr_orig_size += best_slen;
-                        best->stat_compr_new_size  += best_dlen;
-                        ret = best->compr;
-                }
-                break;
-        default:
-                fprintf(stderr,"mkfs.jffs2: unknow compression mode.\n");
-        }
- out:
-        if (ret == JFFS2_COMPR_NONE) {
-	        *cpage_out = data_in;
-	        *datalen = *cdatalen;
-                none_stat_compr_blocks++;
-                none_stat_compr_size += *datalen;
-        }
-        else {
-                *cpage_out = output_buf;
-        }
+out:
 	return ret;
 }
 
-
-int jffs2_register_compressor(struct jffs2_compressor *comp)
-{
-        struct jffs2_compressor *this;
-
-        if (!comp->name) {
-                fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
-                return -1;
-        }
-        comp->compr_buf_size=0;
-        comp->compr_buf=NULL;
-        comp->usecount=0;
-        comp->stat_compr_orig_size=0;
-        comp->stat_compr_new_size=0;
-        comp->stat_compr_blocks=0;
-        comp->stat_decompr_blocks=0;
-
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (this->priority < comp->priority) {
-                        list_add(&comp->list, this->list.prev);
-                        goto out;
-                }
-        }
-        list_add_tail(&comp->list, &jffs2_compressor_list);
+static struct cryptolist_entry *crypto_decompress_wrapper(struct compress_ctx *ctx,
+									u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen) {
+	struct cryptolist_entry *ret = NULL;
+	int temp = 0;
+	uint32_t alg_type;
+	struct cryptolist_entry *walk;
+	struct crypt_op cryp;
+	char *alg_name = (char *) src;
+	while (*src) {
+		src++;
+		srclen--;
+		temp++;
+	}
+	src++;
+	srclen--;
+	walk = ctx->cryptolist_head;
+	while (walk && strcmp(alg_name, walk->sess->alg_name))
+		walk = walk->next;
+	if (!walk) {
+		walk = malloc(sizeof(struct cryptolist_entry));
+		if (!walk)
+			goto out;
+		memset(walk, 0, sizeof(struct cryptolist_entry));
+		if (ioctl(ctx->global_fd, CRIOGET, &walk->c_fd)) {
+			free(walk);
+			goto out;
+		}
+		if (fcntl(walk->c_fd, F_SETFD, 1) == -1) {
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+
+		walk->sess = malloc(sizeof(struct session_op));
+		if (!walk->sess) {
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+
+		memset(walk->sess, 0, sizeof(struct session_op));
+		walk->sess->compress = CRYPTO_COMPRESS_NAME;
+
+		walk->sess->alg_name = malloc(temp + 1);
+		if (!walk->sess->alg_name) {
+			free(walk->sess);
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+
+		strcpy(walk->sess->alg_name, alg_name);
+		walk->sess->alg_namelen = temp;
+		if (ioctl(walk->c_fd, CIOCGSESSION, walk->sess)) {
+			free(walk->sess->alg_name);
+			free(walk->sess);
+			close(walk->c_fd);
+			free(walk);
+			goto out;
+		}
+		if (!ctx->cryptolist_head)
+			ctx->cryptolist_head = walk;
+		else
+			ctx->cryptolist_tail->next = walk;
+		ctx->cryptolist_tail = walk;
+	}
+	
+	alg_type = walk->sess->ses;
+	if (ioctl(walk->c_fd, CIOCGALGTYPE, &alg_type)) {
+		// error during ioctl
+		goto out;
+	}
+
+	switch (alg_type) {
+		case CRYPTO_ALG_TYPE_COMPRESS:
+			cryp.ses = walk->sess->ses;
+			cryp.len = srclen;
+			cryp.outlen = dstlen;
+			cryp.src = src;
+			cryp.dst = dst;
+			cryp.op = COP_DECOMPRESS;
+			if (!ioctl(walk->c_fd, CIOCCOMPRESS, &cryp))
+				ret = walk;
+			break;
+
+		default:
+			break;
+	}
 out:
-        return 0;
-}
-
-int jffs2_unregister_compressor(struct jffs2_compressor *comp)
-{
-
-        if (comp->usecount) {
-                fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
-                return -1;
-        }
-        list_del(&comp->list);
-
-        return 0;
-}
-
-#define JFFS2_STAT_BUF_SIZE 16000
-
-char *jffs2_list_compressors(void)
-{
-        struct jffs2_compressor *this;
-        char *buf, *act_buf;
-
-        act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
-                if ((this->disabled)||(!this->compress))
-                        act_buf += sprintf(act_buf,"disabled");
-                else
-                        act_buf += sprintf(act_buf,"enabled");
-                act_buf += sprintf(act_buf,"\n");
-        }
-        return buf;
-}
-
-char *jffs2_stats(void)
-{
-        struct jffs2_compressor *this;
-        char *buf, *act_buf;
-
-        act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
-
-        act_buf += sprintf(act_buf,"Compression mode: ");
-        switch (jffs2_compression_mode) {
-        case JFFS2_COMPR_MODE_NONE:
-                act_buf += sprintf(act_buf,"none");
-                break;
-        case JFFS2_COMPR_MODE_PRIORITY:
-                act_buf += sprintf(act_buf,"priority");
-                break;
-        case JFFS2_COMPR_MODE_SIZE:
-                act_buf += sprintf(act_buf,"size");
-                break;
-        default:
-                act_buf += sprintf(act_buf,"unkown");
-                break;
-        }
-        act_buf += sprintf(act_buf,"\nCompressors:\n");
-        act_buf += sprintf(act_buf,"%10s             ","none");
-        act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
-                           none_stat_compr_size, none_stat_decompr_blocks);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority);
-                if ((this->disabled)||(!this->compress))
-                        act_buf += sprintf(act_buf,"- ");
-                else
-                        act_buf += sprintf(act_buf,"+ ");
-                act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
-                                   this->stat_compr_new_size, this->stat_compr_orig_size,
-                                   this->stat_decompr_blocks);
-                act_buf += sprintf(act_buf,"\n");
-        }
-        return buf;
-}
-
-int jffs2_set_compression_mode_name(const char *name)
-{
-        if (!strcmp("none",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-                return 0;
-        }
-        if (!strcmp("priority",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-                return 0;
-        }
-        if (!strcmp("size",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-                return 0;
-        }
-        return 1;
-}
-
-static int jffs2_compressor_Xable(const char *name, int disabled)
-{
-        struct jffs2_compressor *this;
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (!strcmp(this->name, name)) {
-                        this->disabled = disabled;
-                        return 0;
-                }
-        }
-        return 1;
+	return ret;
 }
 
-int jffs2_enable_compressor_name(const char *name)
-{
-        return jffs2_compressor_Xable(name, 0);
+static void destroy_tree(struct compresstree_node *what) {
+	if (what->sib)
+		destroy_tree(what->sib);
+	if (what->fson)
+		destroy_tree(what->fson);
+	free(what->name);
+	free(what);
+}
+
+int destroy_compress_context(struct compress_ctx **ctx) {
+	int ret = 0;
+	if (*ctx) {
+		struct cryptolist_entry *temp;
+		destroy_tree((*ctx)->compresstree_root);
+		while ((temp = (*ctx)->cryptolist_head)) {
+			(*ctx)->cryptolist_head = (*ctx)->cryptolist_head->next;
+			if (ioctl(temp->c_fd, CIOCFSESSION, temp->sess->ses)) {
+				ret = -1;
+				goto out;
+			}
+			free(temp->sess->alg_name);
+			free(temp->sess);
+			close(temp->c_fd);
+			free(temp);
+		}
+		close((*ctx)->global_fd);
+		free(*ctx);
+		*ctx = NULL;
+	}
+out:
+	return ret;
 }
 
-int jffs2_disable_compressor_name(const char *name)
-{
-        return jffs2_compressor_Xable(name, 1);
+struct compress_ctx *create_compress_context(char *cnt) {
+	char *w, *w2, *scan, *c, *ccnt, end;
+	compressmode_t node_type = COMPRESSMODE_NORMAL;
+	int breakout, temp;	
+	struct compresstree_node *nodetemp, *nodewalk;
+	struct compresstree_tail *tail, *tailtemp, *tailend;
+	struct compress_ctx *ret;
+
+	ret = malloc(sizeof(struct compress_ctx));
+	if (!ret)
+		goto out;
+	ret->cryptolist_head = ret->cryptolist_tail = NULL;
+	ret->compresstree_root = NULL;
+	if ((ret->global_fd = open("/dev/crypto", O_RDWR, 0)) < 0)
+		goto was_error;
+	while (*cnt && ((*cnt == ',') || (*cnt == ' ') || (*cnt == '\t')))
+		cnt++;
+	temp = strlen(cnt);
+	if (!(ccnt = (char *) malloc(temp + 1)))
+		goto was_error;
+	strcpy(ccnt, cnt);
+	while (temp && ((ccnt[temp - 1] == ',') || (ccnt[temp - 1] == ' ') || (ccnt[temp - 1] == '\t'))) {
+		ccnt[temp] = '\0';
+		temp--;
+	}
+	if (!temp) {
+		free(ccnt);
+		goto out; /* compression will be turned off */
+	}
+
+	tail = malloc(sizeof(struct compresstree_tail));
+	tailend = tail;
+	if (!tailend) {
+		free(ccnt);
+		goto was_error;
+	}
+
+	tail->owner = NULL;
+	tail->next = NULL;
+	tail->tail = ccnt;
+	while (tail) {
+		w2 = w = tail->tail;
+		scan = NULL;
+		breakout = 0;
+		while (!breakout) {
+			switch (*w) {
+				case '{':
+				case '[':
+					if (node_type != COMPRESSMODE_NORMAL)
+						goto was_error_clean;
+					if (*w == '{') {
+						node_type = COMPRESSMODE_BESTCOMPRESS;
+						end = '}';
+					} else
+					if (*w == '[') {
+						node_type = COMPRESSMODE_FIRSTCOMPRESS;
+						end = ']';
+					} else
+						end = '\0';
+					w++;
+					while (*w && ((*w == ',') || (*w == '\t') || (*w == ' ')))
+						w++;
+					w2 = w;
+					scan = w;
+					while (*scan && (*scan != end)) scan++;
+					if (*scan) scan++;
+					while (*scan && ((*scan == ',') || (*scan == '\t') || (*scan == ' ')))
+						scan++;
+					break;
+				case '\0':
+				case ' ':
+				case '\t':
+				case ',':
+				case '}':
+				case ']':
+					if ((*w == '}') && (node_type != COMPRESSMODE_BESTCOMPRESS))
+						goto was_error_clean;
+					if ((*w == ']') && (node_type != COMPRESSMODE_FIRSTCOMPRESS))
+						goto was_error_clean;
+					if (w2 != w) { /* to skip empty {} and [] */
+						if (!(c = (char *) malloc(w - w2 + 1)))
+							goto was_error_clean;
+						strncpy(c, w2, w - w2);
+						c[w - w2] = '\0';
+
+						nodetemp = malloc(sizeof(struct compresstree_node));
+						if (!nodetemp) {
+							free(c);
+							goto was_error_clean;
+						}
+
+						nodetemp->dad = tail->owner;
+						nodetemp->sib = nodetemp->fson = NULL;
+						nodetemp->name = c;
+						nodetemp->node_type = node_type;
+						if (tail->owner) {
+							if (!tail->owner->fson)
+								tail->owner->fson = nodetemp;
+							else {
+								nodewalk = tail->owner->fson;
+								while (nodewalk->sib)
+									nodewalk = nodewalk->sib;
+								nodewalk->sib = nodetemp;
+							}
+						} else
+							if (!ret->compresstree_root)
+								ret->compresstree_root = nodetemp;
+							else {
+								nodewalk = ret->compresstree_root;
+								while (nodewalk->sib)
+									nodewalk = nodewalk->sib;
+								nodewalk->sib = nodetemp;
+							}
+						if (scan && *scan) {
+							tailtemp = malloc(sizeof(struct compresstree_tail));
+							if (!tailtemp)
+								goto was_error_clean;
+							tailtemp->owner = nodetemp;
+							tailtemp->next = NULL;
+
+							tailtemp->tail = malloc(strlen(scan) + 1);
+							if (!tailtemp->tail)
+								goto was_error_clean;
+							strcpy(tailtemp->tail, scan);
+							tailend->next = tailtemp;
+							tailend = tailtemp;
+						}
+						if ((*w == '}') || (*w == ']'))
+							node_type = COMPRESSMODE_NORMAL;
+						if (tail && ((node_type == COMPRESSMODE_NORMAL) || !*w)) {
+							scan = NULL;
+							tailtemp = tail;
+							tail = tail->next;
+							free(tailtemp->tail);
+							free(tailtemp);
+							breakout = 1;
+							break;
+						}
+					} else
+						node_type = COMPRESSMODE_NORMAL;
+					if (*w)
+						w++;
+					while (*w && ((*w == ',') || (*w == '\t') || (*w == ' ')))
+						w++;
+					w2 = w;
+					break;
+				default:
+					w++;
+					if (!scan) {
+						scan = w;
+						while (*scan && (*scan != ',') && (*scan != '\t') && (*scan != ' '))
+							scan++;
+						while (*scan && ((*scan == ',') || (*scan == '\t') || (*scan == ' ')))
+							scan++;
+					}
+			}
+		}
+	}
+	goto out;
+was_error_clean:
+	destroy_tree(ret->compresstree_root);
+	while (tail) {
+		tailtemp = tail;
+		tail = tail->next;
+		free(tailtemp->tail);
+		free(tailtemp);
+	}
+was_error:
+	close(ret->global_fd);
+	free(ret);
+	ret = NULL;
+out:
+	return ret;
 }
 
-int jffs2_set_compressor_priority(const char *name, int priority)
-{
-        struct jffs2_compressor *this,*comp;
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (!strcmp(this->name, name)) {
-                        this->priority = priority;
-                        comp = this;
-                        goto reinsert;
-                }
-        }
-        fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
-        return 1;
-reinsert:
-        /* list is sorted in the order of priority, so if
-           we change it we have to reinsert it into the
-           good place */
-        list_del(&comp->list);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (this->priority < comp->priority) {
-                        list_add(&comp->list, this->list.prev);
-                        return 0;
-                }
-        }
-        list_add_tail(&comp->list, &jffs2_compressor_list);
-        return 0;
+int compress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen) {
+	int ret = 0;
+	int32_t selectedlen = srclen;
+	u8 *selected;
+	struct compresstree_node *selwalk;
+	struct cryptolist_entry *currc, *selc = NULL;
+	if (!*ctx)
+		goto out;
+
+	selected = malloc(selectedlen);
+	if (!selected) {
+		ret = -1;
+		goto out;
+	}
+
+	memcpy(selected, src, selectedlen);
+	selwalk = (*ctx)->compresstree_root;
+	while (selwalk) {
+		u8 *best = NULL;
+		struct compresstree_node *walk = selwalk;
+		int32_t bestlen = 0;
+		while (walk) {
+			u8 *curr;
+			int32_t currlen = *dstlen;
+
+			curr = malloc(currlen);
+			if (!curr) {
+				free(selected);
+				ret = -1;
+				goto out;
+			}
+			if ((currc = crypto_compress_wrapper(*ctx, walk->name, selected, selectedlen, curr, &currlen)) &&
+				(!bestlen || ((walk->node_type == COMPRESSMODE_BESTCOMPRESS) && (currlen < bestlen)))) {
+					if (bestlen)
+						free(best);
+					bestlen = currlen;
+					best = curr;
+					selwalk = walk;
+					selc = currc;
+			} else
+				free(curr);
+//			if (walk->node_type != COMPRESSMODE_BESTCOMPRESS)
+			if (walk->node_type == COMPRESSMODE_NORMAL || (walk->node_type == COMPRESSMODE_FIRSTCOMPRESS && currc))
+				break;
+			walk = walk->sib;
+		}
+		if (!bestlen || /*(selectedlen < bestlen)*/
+						(*dstlen < bestlen))
+			break;
+		free(selected);
+		selected = best;
+		selc->tot_to_compress += selectedlen;
+		selc->tot_compressed += bestlen;
+		selc->compr_blocks++;
+		selectedlen = bestlen;
+		selwalk = selwalk->fson;
+		/* contains the number of compressors compressed with so far */
+		ret++;
+	}
+	/* just return error if could not compress. app should take care of this */
+	if (ret && (selectedlen <= *dstlen))
+		memcpy(dst, selected, *dstlen = selectedlen);
+	else
+		ret = -1;
+	free(selected);
+out:
+	return ret;
 }
 
-
-int jffs2_compressors_init(void)
-{
-#ifdef CONFIG_JFFS2_ZLIB
-        jffs2_zlib_init();
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-        jffs2_rtime_init();
-#endif
-        return 0;
+int decompress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen, int compressors) {
+	int tmplen = srclen;
+	int ret = 0;
+	struct cryptolist_entry *currc;
+	u8 *tmp;
+	if (!*ctx)
+		goto out;
+
+	tmp = malloc(tmplen);
+	if (!tmp) {
+		ret = -1;
+		goto out;
+	}
+
+	memcpy(tmp, src, tmplen);
+	while (compressors) {
+		u8 *tmp2 = tmp;
+		int slen = tmplen;
+
+		tmplen = *dstlen;
+		tmp = malloc(tmplen);
+		if (!tmp) {
+			ret = -1;
+			goto out;
+		}
+
+		currc = crypto_decompress_wrapper(*ctx, tmp2, slen, tmp, &tmplen);
+		if (!currc) {
+			free(tmp);
+			free(tmp2);
+			ret = -1;
+			goto out;
+		} else {
+			currc->tot_to_decompress += slen;
+			currc->tot_decompressed += tmplen;
+			currc->decompr_blocks++;
+		}
+		free(tmp2);
+		compressors--;
+	}
+	memcpy(dst, tmp, *dstlen = tmplen);
+	free(tmp);
+out:
+	return ret;
 }
 
-int jffs2_compressors_exit(void)
-{
-#ifdef CONFIG_JFFS2_RTIME
-        jffs2_rtime_exit();
-#endif
-#ifdef CONFIG_JFFS2_ZLIB
-        jffs2_zlib_exit();
-#endif
-        return 0;
+char *compress_stats(struct compress_ctx **ctx) {
+	struct cryptolist_entry *temp;
+	char *buf = NULL, *act_buf;
+	if (*ctx) {
+		buf = malloc(JFFS2_STAT_BUF_SIZE);
+		act_buf = buf;
+		if (act_buf) {
+			act_buf += sprintf(act_buf, "Compressors:\n");
+			temp = (*ctx)->cryptolist_head;
+			while (temp) {
+				act_buf += sprintf(act_buf, "%10s compressed: %llu -> %llu, %llu blocks; decompressed: %llu -> %llu, %llu blocks\n",
+				temp->sess->alg_name, temp->tot_to_compress, temp->tot_compressed, temp->compr_blocks,
+				temp->tot_to_decompress, temp->tot_decompressed, temp->decompr_blocks);
+				temp = temp->next;
+			}
+		}
+	}
+	return buf;
 }
diff -Narup Mtd-orig/util/compr.h mtd/util/compr.h
--- Mtd-orig/util/compr.h	2005-11-08 02:02:20.000000000 +0100
+++ mtd/util/compr.h	2005-11-28 10:19:04.000000000 +0100
@@ -1,115 +1,62 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                    University of Szeged, Hungary
- *
- * For licensing information, see the file 'LICENCE' in the
- * jffs2 directory.
- *
- * $Id: compr.h,v 1.7 2005/11/07 11:15:09 gleixner Exp $
- *
- */
-
-#ifndef __JFFS2_COMPR_H__
-#define __JFFS2_COMPR_H__
+#ifndef __COMPRTREE_H
+#define __COMPRTREE_H
 
 #include <stdio.h>
-#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <asm/types.h>
 #include <stdint.h>
-#include "linux/jffs2.h"
-
-#define CONFIG_JFFS2_ZLIB
-#define CONFIG_JFFS2_RTIME
-
-#define JFFS2_RUBINMIPS_PRIORITY 10
-#define JFFS2_DYNRUBIN_PRIORITY  20
-#define JFFS2_RTIME_PRIORITY     50
-#define JFFS2_ZLIB_PRIORITY      60
-
-#define JFFS2_COMPR_MODE_NONE       0
-#define JFFS2_COMPR_MODE_PRIORITY   1
-#define JFFS2_COMPR_MODE_SIZE       2
-
-#define kmalloc(a,b)                malloc(a)
-#define kfree(a)                    free(a)
-#ifndef GFP_KERNEL
-#define GFP_KERNEL                  0
-#endif
+#include <stddef.h>
+#include <stdlib.h>
+#include "cryptodev.h"
 
-#define vmalloc(a)                  malloc(a)
-#define vfree(a)                    free(a)
+#define u8 __u8
 
-#define printk(...)                 fprintf(stderr,__VA_ARGS__)
+typedef enum {COMPRESSMODE_NORMAL = 0, COMPRESSMODE_FIRSTCOMPRESS,
+			  COMPRESSMODE_BESTCOMPRESS} compressmode_t;
 
-#define KERN_EMERG
-#define KERN_ALERT
-#define KERN_CRIT
-#define KERN_ERR
-#define KERN_WARNING
-#define KERN_NOTICE
-#define KERN_INFO
-#define KERN_DEBUG
+#define JFFS2_STAT_BUF_SIZE 16000
 
-struct list_head {
-        struct list_head *next, *prev;
+struct cryptolist_entry {
+	int c_fd;
+	struct session_op *sess;
+	struct cryptolist_entry *next;
+	uint64_t tot_to_compress;
+	uint64_t tot_compressed;
+	uint64_t compr_blocks;
+	uint64_t tot_to_decompress;
+	uint64_t tot_decompressed;
+	uint64_t decompr_blocks;
 };
 
-void jffs2_set_compression_mode(int mode);
-int jffs2_get_compression_mode(void);
-int jffs2_set_compression_mode_name(const char *mode_name);
-
-int jffs2_enable_compressor_name(const char *name);
-int jffs2_disable_compressor_name(const char *name);
-
-int jffs2_set_compressor_priority(const char *name, int priority);
-
-struct jffs2_compressor {
-        struct list_head list;
-        int priority;             /* used by prirority comr. mode */
-        char *name;
-        char compr;               /* JFFS2_COMPR_XXX */
-        int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
-                        uint32_t *srclen, uint32_t *destlen, void *model);
-        int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
-                        uint32_t cdatalen, uint32_t datalen, void *model);
-        int usecount;
-        int disabled;             /* if seted the compressor won't compress */
-        unsigned char *compr_buf; /* used by size compr. mode */
-        uint32_t compr_buf_size;  /* used by size compr. mode */
-        uint32_t stat_compr_orig_size;
-        uint32_t stat_compr_new_size;
-        uint32_t stat_compr_blocks;
-        uint32_t stat_decompr_blocks;
+struct compresstree_node {
+	struct compresstree_node *dad;
+	struct compresstree_node *fson;
+	struct compresstree_node *sib;
+	char *name;
+	compressmode_t node_type;
 };
 
-int jffs2_register_compressor(struct jffs2_compressor *comp);
-int jffs2_unregister_compressor(struct jffs2_compressor *comp);
-
-int jffs2_compressors_init(void);
-int jffs2_compressors_exit(void);
-
-uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
-                             uint32_t *datalen, uint32_t *cdatalen);
-
-/* If it is setted, a decompress will be called after every compress */
-void jffs2_compression_check_set(int yesno);
-int jffs2_compression_check_get(void);
-int jffs2_compression_check_errorcnt_get(void);
+struct compresstree_tail {
+	struct compresstree_node *owner;
+	char *tail;
+	struct compresstree_tail *next;
+};
 
-char *jffs2_list_compressors(void);
-char *jffs2_stats(void);
+struct compress_ctx {
+	struct compresstree_node *compresstree_root;
+	struct cryptolist_entry *cryptolist_head;
+	struct cryptolist_entry *cryptolist_tail;
+	int global_fd;
+};
 
-/* Compressor modules */
+struct compress_ctx *create_compress_context(char *cnt);
+int compress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen);	
+int decompress(struct compress_ctx **ctx, u8 *src, int32_t srclen, u8 *dst, int32_t *dstlen, int compressors);
+char *compress_stats(struct compress_ctx **ctx);
+int destroy_compress_context(struct compress_ctx **ctx);
 
-/* These functions will be called by jffs2_compressors_init/exit */
-#ifdef CONFIG_JFFS2_ZLIB
-int jffs2_zlib_init(void);
-void jffs2_zlib_exit(void);
-#endif
-#ifdef CONFIG_JFFS2_RTIME
-int jffs2_rtime_init(void);
-void jffs2_rtime_exit(void);
 #endif
-
-#endif /* __JFFS2_COMPR_H__ */
diff -Narup Mtd-orig/util/compr_rtime-old.c mtd/util/compr_rtime-old.c
--- Mtd-orig/util/compr_rtime-old.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/compr_rtime-old.c	2005-11-28 10:19:04.000000000 +0100
@@ -0,0 +1,122 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Arjan van de Ven <arjanv@redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: compr_rtime.c,v 1.3 2004/06/23 15:00:14 havasi Exp $
+ *
+ *
+ * Very simple lz77-ish encoder.
+ *
+ * Theory of operation: Both encoder and decoder have a list of "last
+ * occurrences" for every possible source-value; after sending the
+ * first source-byte, the second byte indicated the "run" length of
+ * matches
+ *
+ * The algorithm is intended to only send "whole bytes", no bit-messing.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "compr-old.h"
+
+/* _compress returns the compressed size, -1 if bigger */
+static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, 
+		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+	short positions[256];
+	int outpos = 0;
+	int pos = 0;
+
+	memset(positions, 0, sizeof(positions)); 
+
+	while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
+		int backpos, runlen = 0;
+		unsigned char value;
+
+		value = data_in[pos];
+
+		cpage_out[outpos++] = data_in[pos++];
+
+		backpos = positions[value];
+		positions[value]=pos;
+
+		while ((backpos < pos) && (pos < (*sourcelen)) &&
+			   (data_in[pos]==data_in[backpos++]) && (runlen<255)) {
+			pos++;
+			runlen++;
+		}
+		cpage_out[outpos++] = runlen;
+	}
+
+	if (outpos >= pos) {
+		/* We failed */
+		return -1;
+	}
+
+	/* Tell the caller how much we managed to compress, and how much space it took */
+	*sourcelen = pos;
+	*dstlen = outpos;
+
+	return 0;
+}
+
+
+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+								uint32_t srclen, uint32_t destlen, void *model)
+{
+	short positions[256];
+	int outpos = 0;
+	int pos=0;
+
+	memset(positions, 0, sizeof(positions)); 
+
+	while (outpos<destlen) {
+		unsigned char value;
+		int backoffs;
+		int repeat;
+
+		value = data_in[pos++];
+		cpage_out[outpos++] = value; /* first the verbatim copied byte */
+		repeat = data_in[pos++];
+		backoffs = positions[value];
+
+		positions[value]=outpos;
+		if (repeat) {
+			if (backoffs + repeat >= outpos) {
+				while(repeat) {
+					cpage_out[outpos++] = cpage_out[backoffs++];
+					repeat--;
+				}
+			} else {
+				memcpy(&cpage_out[outpos], &cpage_out[backoffs], repeat);
+				outpos+=repeat;	
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static struct jffs2_compressor jffs2_rtime_comp = {
+	.name = "rtime",
+	.compr = JFFS2_COMPR_RTIME,
+	.compress = &jffs2_rtime_compress,
+	.decompress = &jffs2_rtime_decompress,
+};
+
+int jffs2_rtime_init(void)
+{
+	return jffs2_register_compressor(&jffs2_rtime_comp);
+}
+
+void jffs2_rtime_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_rtime_comp);
+}
diff -Narup Mtd-orig/util/compr_rtime.c mtd/util/compr_rtime.c
--- Mtd-orig/util/compr_rtime.c	2005-11-08 02:02:20.000000000 +0100
+++ mtd/util/compr_rtime.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,122 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001-2003 Red Hat, Inc.
- *
- * Created by Arjan van de Ven <arjanv@redhat.com>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- * $Id: compr_rtime.c,v 1.4 2005/11/07 11:15:09 gleixner Exp $
- *
- *
- * Very simple lz77-ish encoder.
- *
- * Theory of operation: Both encoder and decoder have a list of "last
- * occurrences" for every possible source-value; after sending the
- * first source-byte, the second byte indicated the "run" length of
- * matches
- *
- * The algorithm is intended to only send "whole bytes", no bit-messing.
- *
- */
-
-#include <stdint.h>
-#include <string.h>
-#include "compr.h"
-
-/* _compress returns the compressed size, -1 if bigger */
-static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
-		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
-{
-	short positions[256];
-	int outpos = 0;
-	int pos=0;
-
-	memset(positions,0,sizeof(positions));
-
- 	while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
-		int backpos, runlen=0;
-		unsigned char value;
-
-		value = data_in[pos];
-
-		cpage_out[outpos++] = data_in[pos++];
-
-		backpos = positions[value];
-		positions[value]=pos;
-
-		while ((backpos < pos) && (pos < (*sourcelen)) &&
-		       (data_in[pos]==data_in[backpos++]) && (runlen<255)) {
-			pos++;
-			runlen++;
-		}
-		cpage_out[outpos++] = runlen;
-	}
-
-	if (outpos >= pos) {
-		/* We failed */
-		return -1;
-	}
-
-	/* Tell the caller how much we managed to compress, and how much space it took */
-	*sourcelen = pos;
-	*dstlen = outpos;
-	return 0;
-}
-
-
-static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      uint32_t srclen, uint32_t destlen, void *model)
-{
-	short positions[256];
-	int outpos = 0;
-	int pos=0;
-
-	memset(positions,0,sizeof(positions));
-
-	while (outpos<destlen) {
-		unsigned char value;
-		int backoffs;
-		int repeat;
-
-		value = data_in[pos++];
-		cpage_out[outpos++] = value; /* first the verbatim copied byte */
-		repeat = data_in[pos++];
-		backoffs = positions[value];
-
-		positions[value]=outpos;
-		if (repeat) {
-			if (backoffs + repeat >= outpos) {
-				while(repeat) {
-					cpage_out[outpos++] = cpage_out[backoffs++];
-					repeat--;
-				}
-			} else {
-				memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
-				outpos+=repeat;
-			}
-		}
-	}
-        return 0;
-}
-
-
-static struct jffs2_compressor jffs2_rtime_comp = {
-    .priority = JFFS2_RTIME_PRIORITY,
-    .name = "rtime",
-    .disabled = 0,
-    .compr = JFFS2_COMPR_RTIME,
-    .compress = &jffs2_rtime_compress,
-    .decompress = &jffs2_rtime_decompress,
-};
-
-int jffs2_rtime_init(void)
-{
-    return jffs2_register_compressor(&jffs2_rtime_comp);
-}
-
-void jffs2_rtime_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_rtime_comp);
-}
diff -Narup Mtd-orig/util/compr_zlib-old.c mtd/util/compr_zlib-old.c
--- Mtd-orig/util/compr_zlib-old.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/compr_zlib-old.c	2005-11-28 10:19:04.000000000 +0100
@@ -0,0 +1,146 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ *
+ * The original JFFS, from which the design for JFFS2 was derived,
+ * was designed and implemented by Axis Communications AB.
+ *
+ * The contents of this file are subject to the Red Hat eCos Public
+ * License Version 1.1 (the "Licence"); you may not use this file
+ * except in compliance with the Licence.  You may obtain a copy of
+ * the Licence at http://www.redhat.com/
+ *
+ * Software distributed under the Licence is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing rights and
+ * limitations under the Licence.
+ *
+ * The Original Code is JFFS2 - Journalling Flash File System, version 2
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the RHEPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the RHEPL or the GPL.
+ *
+ * $Id: compr_zlib.c,v 1.3 2004/06/23 15:00:14 havasi Exp $
+ *
+ */
+
+#include <stdint.h>
+#include <zlib.h>
+#include <stdio.h>
+#include <asm/types.h>
+#include "compr-old.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+	/* Plan: call deflate() with avail_in == *sourcelen, 
+		avail_out = *dstlen - 12 and flush == Z_FINISH. 
+		If it doesn't manage to finish,	call it again with
+		avail_in == 0 and avail_out set to the remaining 12
+		bytes for it to clean up. 
+	   Q: Is 12 bytes sufficient?
+	*/
+#define STREAM_END_SPACE 12
+
+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
+		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+	z_stream strm;
+	int ret;
+
+	if (*dstlen <= STREAM_END_SPACE)
+		return -1;
+
+	strm.zalloc = (void *)0;
+	strm.zfree = (void *)0;
+
+	if (Z_OK != deflateInit(&strm, 3)) {
+		return -1;
+	}
+	strm.next_in = data_in;
+	strm.total_in = 0;
+	
+	strm.next_out = cpage_out;
+	strm.total_out = 0;
+
+	while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
+		strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
+		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
+		ret = deflate(&strm, Z_PARTIAL_FLUSH);
+		if (ret != Z_OK) {
+			deflateEnd(&strm);
+			return -1;
+		}
+	}
+	strm.avail_out += STREAM_END_SPACE;
+	strm.avail_in = 0;
+	ret = deflate(&strm, Z_FINISH);
+	if (ret != Z_STREAM_END) {
+		deflateEnd(&strm);
+		return -1;
+	}
+	deflateEnd(&strm);
+
+	if (strm.total_out >= strm.total_in)
+		return -1;
+
+	*dstlen = strm.total_out;
+	*sourcelen = strm.total_in;
+
+	return 0;
+}
+
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+		      uint32_t srclen, uint32_t destlen, void *model)
+{
+	z_stream strm;
+	int ret;
+
+	strm.zalloc = (void *)0;
+	strm.zfree = (void *)0;
+
+	if (Z_OK != inflateInit(&strm)) {
+		return 1;
+	}
+	strm.next_in = data_in;
+	strm.avail_in = srclen;
+	strm.total_in = 0;
+	
+	strm.next_out = cpage_out;
+	strm.avail_out = destlen;
+	strm.total_out = 0;
+
+	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
+		;
+
+	inflateEnd(&strm);
+
+	return 0;
+}
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+	.name = "zlib",
+	.compr = JFFS2_COMPR_ZLIB,
+	.compress = &jffs2_zlib_compress,
+	.decompress = &jffs2_zlib_decompress,
+};
+
+int jffs2_zlib_init(void)
+{
+	return jffs2_register_compressor(&jffs2_zlib_comp);
+}
+
+void jffs2_zlib_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_zlib_comp);
+}
diff -Narup Mtd-orig/util/compr_zlib.c mtd/util/compr_zlib.c
--- Mtd-orig/util/compr_zlib.c	2005-11-08 02:02:20.000000000 +0100
+++ mtd/util/compr_zlib.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,148 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001 Red Hat, Inc.
- *
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
- *
- * The original JFFS, from which the design for JFFS2 was derived,
- * was designed and implemented by Axis Communications AB.
- *
- * The contents of this file are subject to the Red Hat eCos Public
- * License Version 1.1 (the "Licence"); you may not use this file
- * except in compliance with the Licence.  You may obtain a copy of
- * the Licence at http://www.redhat.com/
- *
- * Software distributed under the Licence is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing rights and
- * limitations under the Licence.
- *
- * The Original Code is JFFS2 - Journalling Flash File System, version 2
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the RHEPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the RHEPL or the GPL.
- *
- * $Id: compr_zlib.c,v 1.4 2005/11/07 11:15:09 gleixner Exp $
- *
- */
-
-#include <stdint.h>
-#include <zlib.h>
-#include <stdio.h>
-#include <asm/types.h>
-#include <linux/jffs2.h>
-#include "compr.h"
-
-#define min(x,y) ((x)<(y)?(x):(y))
-
-	/* Plan: call deflate() with avail_in == *sourcelen,
-		avail_out = *dstlen - 12 and flush == Z_FINISH.
-		If it doesn't manage to finish,	call it again with
-		avail_in == 0 and avail_out set to the remaining 12
-		bytes for it to clean up.
-	   Q: Is 12 bytes sufficient?
-	*/
-#define STREAM_END_SPACE 12
-
-int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
-		   uint32_t *sourcelen, uint32_t *dstlen, void *model)
-{
-	z_stream strm;
-	int ret;
-
-	if (*dstlen <= STREAM_END_SPACE)
-		return -1;
-
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-
-	if (Z_OK != deflateInit(&strm, 3)) {
-		return -1;
-	}
-	strm.next_in = data_in;
-	strm.total_in = 0;
-
-	strm.next_out = cpage_out;
-	strm.total_out = 0;
-
-	while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
-		strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
-		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
-		ret = deflate(&strm, Z_PARTIAL_FLUSH);
-		if (ret != Z_OK) {
-			deflateEnd(&strm);
-			return -1;
-		}
-	}
-	strm.avail_out += STREAM_END_SPACE;
-	strm.avail_in = 0;
-	ret = deflate(&strm, Z_FINISH);
-	if (ret != Z_STREAM_END) {
-		deflateEnd(&strm);
-		return -1;
-	}
-	deflateEnd(&strm);
-
-	if (strm.total_out >= strm.total_in)
-		return -1;
-
-
-	*dstlen = strm.total_out;
-	*sourcelen = strm.total_in;
-	return 0;
-}
-
-int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      uint32_t srclen, uint32_t destlen, void *model)
-{
-	z_stream strm;
-	int ret;
-
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-
-	if (Z_OK != inflateInit(&strm)) {
-		return 1;
-	}
-	strm.next_in = data_in;
-	strm.avail_in = srclen;
-	strm.total_in = 0;
-
-	strm.next_out = cpage_out;
-	strm.avail_out = destlen;
-	strm.total_out = 0;
-
-	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
-		;
-
-	inflateEnd(&strm);
-        return 0;
-}
-
-static struct jffs2_compressor jffs2_zlib_comp = {
-    .priority = JFFS2_ZLIB_PRIORITY,
-    .name = "zlib",
-    .disabled = 0,
-    .compr = JFFS2_COMPR_ZLIB,
-    .compress = &jffs2_zlib_compress,
-    .decompress = &jffs2_zlib_decompress,
-};
-
-int jffs2_zlib_init(void)
-{
-    return jffs2_register_compressor(&jffs2_zlib_comp);
-}
-
-void jffs2_zlib_exit(void)
-{
-    jffs2_unregister_compressor(&jffs2_zlib_comp);
-}
diff -Narup Mtd-orig/util/cryptodev.h mtd/util/cryptodev.h
--- Mtd-orig/util/cryptodev.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/cryptodev.h	2005-11-29 14:53:07.000000000 +0100
@@ -0,0 +1,101 @@
+/*
+ * Driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2004 Michal Ludvig <mludvig@suse.cz>, SuSE Labs
+ *
+ * Structures and ioctl command names were taken from
+ * OpenBSD to preserve compatibility with their API.
+ *
+ */
+
+/* compression support added by Patrik Kluba */
+
+#ifndef _CRYPTODEV_H
+#define _CRYPTODEV_H
+
+#ifndef __KERNEL__
+#include <inttypes.h>
+#endif
+
+/*
+ * Algorithm masks and types.
+ */
+#define CRYPTO_ALG_TYPE_MASK		0x000000ff
+#define CRYPTO_ALG_TYPE_CIPHER		0x00000001
+#define CRYPTO_ALG_TYPE_DIGEST		0x00000002
+#define CRYPTO_ALG_TYPE_COMPRESS	0x00000004
+
+#define	CRYPTODEV_MINOR	MISC_DYNAMIC_MINOR
+
+#define CRYPTO_FLAG_ECB		0x0000
+#define CRYPTO_FLAG_CBC		0x0001
+#define CRYPTO_FLAG_CFB		0x0002
+#define CRYPTO_FLAG_OFB		0x0003
+#define CRYPTO_FLAG_CTR		0x0004
+#define CRYPTO_FLAG_HMAC	0x0010
+#define CRYPTO_FLAG_MASK	0x00FF
+
+#define	CRYPTO_CIPHER_NAME	0x0100
+#define	CRYPTO_CIPHER_NAME_CBC	(CRYPTO_CIPHER_NAME | CRYPTO_FLAG_CBC)
+#define	CRYPTO_HASH_NAME	0x0200
+#define	CRYPTO_HASH_NAME_HMAC	(CRYPTO_HASH_NAME | CRYPTO_FLAG_HMAC)
+
+#define CRYPTO_COMPRESS_NAME	0x0300
+
+/* ioctl parameter to create a session */
+struct session_op {
+	unsigned int	cipher;		/* e.g. CRYPTO_DES_CBC */
+	unsigned int	mac;		/* e.g. CRYPTO_MD5_HMAC */
+	unsigned int	compress;
+	char		*alg_name;	/* set cipher=CRYPTO_CIPHER_NAME
+					   or  mac=CRYPTO_HASH_NAME */
+	#define	MAX_ALG_NAME_LEN 128
+	size_t		alg_namelen;
+
+	size_t		keylen;		/* cipher key */
+	char		*key;
+	int		mackeylen;	/* mac key */
+	char		*mackey;
+
+	/* Return values */
+	unsigned int	blocksize;	/* selected algorithm's block size */
+	uint32_t	ses;		/* session ID */
+};
+
+/* ioctl parameter to request a crypt/decrypt operation against a session  */
+struct crypt_op {
+	uint32_t	ses;		/* from session_op->ses */
+	#define COP_DECRYPT	0
+	#define COP_ENCRYPT	1
+	#define COP_DECOMPRESS	2
+	#define COP_COMPRESS	3
+	uint32_t	op;		/* ie. COP_ENCRYPT */
+	uint32_t	flags;		/* unused */
+
+	size_t		len;
+	size_t		*outlen; /* compressed/decompressed size */
+	char		*src, *dst;
+	char		*mac;
+	char		*iv;
+};
+
+/* clone original filedescriptor */
+#define CRIOGET         _IOWR('c', 100, uint32_t)
+
+/* create crypto session */
+#define CIOCGSESSION    _IOWR('c', 101, struct session_op)
+
+/* finish crypto session */
+#define CIOCFSESSION    _IOW('c', 102, uint32_t)
+
+/* request encryption/decryptions of a given buffer */
+#define CIOCCRYPT       _IOWR('c', 103, struct crypt_op)
+
+/* ioctl()s for asym-crypto. Not yet supported. */
+#define CIOCKEY         _IOWR('c', 104, void *)
+#define CIOCASYMFEAT    _IOR('c', 105, uint32_t)
+
+#define CIOCCOMPRESS	_IOWR('c', 106, struct crypt_op)
+#define CIOCGALGTYPE	_IOWR('c', 107, uint32_t)
+
+#endif /* _CRYPTODEV_H */
diff -Narup Mtd-orig/util/mkfs-old.jffs2.c mtd/util/mkfs-old.jffs2.c
--- Mtd-orig/util/mkfs-old.jffs2.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/mkfs-old.jffs2.c	2005-11-28 10:19:04.000000000 +0100
@@ -0,0 +1,1566 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Build a JFFS2 image in a file, from a given directory tree.
+ *
+ * Copyright 2001, 2002 Red Hat, Inc.
+ *           2001 David A. Schleef <ds@lineo.com>
+ *           2002 Axis Communications AB
+ *           2001, 2002 Erik Andersen <andersen@codepoet.org>
+ *           2004 University of Szeged, Hungary
+ *
+ * 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Cross-endian support added by David Schleef <ds@schleef.org>.
+ *
+ * Major architectural rewrite by Erik Andersen <andersen@codepoet.org>
+ * to allow support for making hard links (though hard links support is
+ * not yet implemented), and for munging file permissions and ownership
+ * on the fly using --faketime, --squash, --devtable.   And I plugged a
+ * few memory leaks, adjusted the error handling and fixed some little
+ * nits here and there.
+ *
+ * I also added a sample device table file.  See device_table.txt
+ *  -Erik, September 2001
+ *
+ * Cleanmarkers support added by Axis Communications AB
+ *
+ * Rewritten again.  Cleanly separated host and target filsystem
+ * activities (mainly so I can reuse all the host handling stuff as I
+ * rewrite other mkfs utils).  Added a verbose option to list types
+ * and attributes as files are added to the file system.  Major cleanup
+ * and scrubbing of the code so it can be read, understood, and
+ * modified by mere mortals.
+ *
+ *  -Erik, November 2002
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <time.h>
+#include <getopt.h>
+#include <byteswap.h>
+#define crc32 __complete_crap
+#include <zlib.h>
+#undef crc32
+#include "crc32.h"
+
+#define DEFAULT_COMPR_CONTROL "[zlib,rtime]"
+
+/* Do not use the wierd XPG version of basename */
+#undef basename
+
+//#define DMALLOC
+//#define mkfs_debug_msg    error_msg
+#define mkfs_debug_msg(a...)	{ }
+#define min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; })
+
+#define PAD(x) (((x)+3)&~3)
+
+struct filesystem_entry {
+	char *name;					/* Name of this directory (think basename) */
+	char *path;					/* Path of this directory (think dirname) */
+	char *fullname;				/* Full name of this directory (i.e. path+name) */
+	char *hostname;				/* Full path to this file on the host filesystem */
+	struct stat sb;				/* Stores directory permissions and whatnot */
+	char *link;					/* Target a symlink points to. */
+	struct filesystem_entry *parent;	/* Parent directory */
+	struct filesystem_entry *prev;	/* Only relevant to non-directories */
+	struct filesystem_entry *next;	/* Only relevant to non-directories */
+	struct filesystem_entry *files;	/* Only relevant to directories */
+};
+
+
+static int out_fd = -1;
+static int in_fd = -1;
+static char default_rootdir[] = ".";
+static char *rootdir = default_rootdir;
+static int verbose = 0;
+static int squash_uids = 0;
+static int squash_perms = 0;
+static int fake_times = 0;
+int target_endian = __BYTE_ORDER;
+static const char *const app_name = "mkfs.jffs2";
+static const char *const memory_exhausted = "memory exhausted";
+
+static void verror_msg(const char *s, va_list p)
+{
+	fflush(stdout);
+	fprintf(stderr, "%s: ", app_name);
+	vfprintf(stderr, s, p);
+}
+static void error_msg(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	verror_msg(s, p);
+	va_end(p);
+	putc('\n', stderr);
+}
+
+static void error_msg_and_die(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	verror_msg(s, p);
+	va_end(p);
+	putc('\n', stderr);
+	exit(EXIT_FAILURE);
+}
+
+static void vperror_msg(const char *s, va_list p)
+{
+	int err = errno;
+
+	if (s == 0)
+		s = "";
+	verror_msg(s, p);
+	if (*s)
+		s = ": ";
+	fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+static void perror_msg(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	vperror_msg(s, p);
+	va_end(p);
+}
+
+static void perror_msg_and_die(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	vperror_msg(s, p);
+	va_end(p);
+	exit(EXIT_FAILURE);
+}
+
+#ifndef DMALLOC
+extern void *xmalloc(size_t size)
+{
+	void *ptr = malloc(size);
+
+	if (ptr == NULL && size != 0)
+		error_msg_and_die(memory_exhausted);
+	return ptr;
+}
+
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+	void *ptr = calloc(nmemb, size);
+
+	if (ptr == NULL && nmemb != 0 && size != 0)
+		error_msg_and_die(memory_exhausted);
+	return ptr;
+}
+
+extern void *xrealloc(void *ptr, size_t size)
+{
+	ptr = realloc(ptr, size);
+	if (ptr == NULL && size != 0)
+		error_msg_and_die(memory_exhausted);
+	return ptr;
+}
+
+extern char *xstrdup(const char *s)
+{
+	char *t;
+
+	if (s == NULL)
+		return NULL;
+	t = strdup(s);
+	if (t == NULL)
+		error_msg_and_die(memory_exhausted);
+	return t;
+}
+#endif
+
+extern char *xreadlink(const char *path)
+{
+	static const int GROWBY = 80; /* how large we will grow strings by */
+
+	char *buf = NULL;
+	int bufsize = 0, readsize = 0;
+
+	do {
+		buf = xrealloc(buf, bufsize += GROWBY);
+		readsize = readlink(path, buf, bufsize); /* 1st try */
+		if (readsize == -1) {
+		    perror_msg("%s:%s", app_name, path);
+		    return NULL;
+		}
+	}
+	while (bufsize < readsize + 1);
+
+	buf[readsize] = '\0';
+
+	return buf;
+}
+static FILE *xfopen(const char *path, const char *mode)
+{
+	FILE *fp;
+	if ((fp = fopen(path, mode)) == NULL)
+		perror_msg_and_die("%s", path);
+	return fp;
+}
+
+static struct filesystem_entry *find_filesystem_entry(
+		struct filesystem_entry *dir, char *fullname, uint32_t type)
+{
+	struct filesystem_entry *e = dir;
+
+	if (S_ISDIR(dir->sb.st_mode)) {
+		e = dir->files;
+	}
+	while (e) {
+		/* Only bother to do the expensive strcmp on matching file types */
+		if (type == (e->sb.st_mode & S_IFMT)) {
+			if (S_ISDIR(e->sb.st_mode)) {
+				int len = strlen(e->fullname);
+
+				/* Check if we are a parent of the correct path */
+				if (strncmp(e->fullname, fullname, len) == 0) {
+					/* Is this an _exact_ match? */
+					if (strcmp(fullname, e->fullname) == 0) {
+						return (e);
+					}
+					/* Looks like we found a parent of the correct path */
+					if (fullname[len] == '/') {
+						if (e->files) {
+							return (find_filesystem_entry (e, fullname, type));
+						} else {
+							return NULL;
+						}
+					}
+				}
+			} else {
+				if (strcmp(fullname, e->fullname) == 0) {
+					return (e);
+				}
+			}
+		}
+		e = e->next;
+	}
+	return (NULL);
+}
+
+static struct filesystem_entry *add_host_filesystem_entry(
+		char *name, char *path, unsigned long uid, unsigned long gid,
+		unsigned long mode, dev_t rdev, struct filesystem_entry *parent)
+{
+	int status;
+	char *tmp;
+	struct stat sb;
+	time_t timestamp = time(NULL);
+	struct filesystem_entry *entry;
+
+	memset(&sb, 0, sizeof(struct stat));
+	status = lstat(path, &sb);
+
+	if (status >= 0) {
+		/* It is ok for some types of files to not exit on disk (such as
+		 * device nodes), but if they _do_ exist the specified mode had
+		 * better match the actual file or strange things will happen.... */
+		if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) {
+			error_msg_and_die ("%s: file type does not match specified type!", path);
+		}
+		timestamp = sb.st_mtime;
+	} else {
+		/* If this is a regular file, it _must_ exist on disk */
+		if ((mode & S_IFMT) == S_IFREG) {
+			error_msg_and_die("%s: does not exist!", path);
+		}
+	}
+
+	/* Squash all permissions so files are owned by root, all
+	 * timestamps are _right now_, and file permissions
+	 * have group and other write removed */
+	if (squash_uids) {
+		uid = gid = 0;
+	}
+	if (squash_perms) {
+		if (!S_ISLNK(mode)) {
+			mode &= ~(S_IWGRP | S_IWOTH);
+			mode &= ~(S_ISUID | S_ISGID);
+		}
+	}
+	if (fake_times) {
+		timestamp = 0;
+	}
+
+	entry = xcalloc(1, sizeof(struct filesystem_entry));
+
+	entry->hostname = xstrdup(path);
+	entry->fullname = xstrdup(name);
+	tmp = xstrdup(name);
+	entry->name = xstrdup(basename(tmp));
+	free(tmp);
+	tmp = xstrdup(name);
+	entry->path = xstrdup(dirname(tmp));
+	free(tmp);
+
+	entry->sb.st_uid = uid;
+	entry->sb.st_gid = gid;
+	entry->sb.st_mode = mode;
+	entry->sb.st_rdev = rdev;
+	entry->sb.st_atime = entry->sb.st_ctime =
+		entry->sb.st_mtime = timestamp;
+	if (S_ISREG(mode)) {
+		entry->sb.st_size = sb.st_size;
+	}
+	if (S_ISLNK(mode)) {
+		entry->link = xreadlink(path);
+		entry->sb.st_size = strlen(entry->link);
+	}
+
+	/* This happens only for root */
+	if (!parent)
+		return (entry);
+
+	/* Hook the file into the parent directory */
+	entry->parent = parent;
+	if (!parent->files) {
+		parent->files = entry;
+	} else {
+		struct filesystem_entry *prev;
+		for (prev = parent->files; prev->next; prev = prev->next);
+		prev->next = entry;
+		entry->prev = prev;
+	}
+
+	return (entry);
+}
+
+static struct filesystem_entry *recursive_add_host_directory(
+		struct filesystem_entry *parent, char *targetpath, char *hostpath)
+{
+	int i, n;
+	struct stat sb;
+	char *hpath, *tpath;
+	struct dirent *dp, **namelist;
+	struct filesystem_entry *entry;
+
+
+	if (lstat(hostpath, &sb)) {
+		perror_msg_and_die("%s", hostpath);
+	}
+
+	entry = add_host_filesystem_entry(targetpath, hostpath,
+			sb.st_uid, sb.st_gid, sb.st_mode, 0, parent);
+
+	n = scandir(hostpath, &namelist, 0, alphasort);
+	if (n < 0) {
+		perror_msg_and_die("opening directory %s", hostpath);
+	}
+
+	for (i=0; i<n; i++)
+	{
+		dp = namelist[i];
+		if (dp->d_name[0] == '.' && (dp->d_name[1] == 0 ||
+		   (dp->d_name[1] == '.' &&  dp->d_name[2] == 0)))
+		{
+			free(dp);
+			continue;
+		}
+
+		asprintf(&hpath, "%s/%s", hostpath, dp->d_name);
+		if (lstat(hpath, &sb)) {
+			perror_msg_and_die("%s", hpath);
+		}
+		if (strcmp(targetpath, "/") == 0) {
+			asprintf(&tpath, "%s%s", targetpath, dp->d_name);
+		} else {
+			asprintf(&tpath, "%s/%s", targetpath, dp->d_name);
+		}
+
+		switch (sb.st_mode & S_IFMT) {
+			case S_IFDIR:
+				recursive_add_host_directory(entry, tpath, hpath);
+				break;
+
+			case S_IFREG:
+			case S_IFSOCK:
+			case S_IFIFO:
+			case S_IFLNK:
+			case S_IFCHR:
+			case S_IFBLK:
+				add_host_filesystem_entry(tpath, hpath, sb.st_uid,
+						sb.st_gid, sb.st_mode, sb.st_rdev, entry);
+				break;
+
+			default:
+				error_msg("Unknown file type %o for %s", sb.st_mode, hpath);
+				break;
+		}
+		free(dp);
+		free(hpath);
+		free(tpath);
+	}
+	free(namelist);
+	return (entry);
+}
+
+/* the GNU C library has a wonderful scanf("%as", string) which will
+ allocate the string with the right size, good to avoid buffer overruns.
+ the following macros use it if available or use a hacky workaround...
+ */
+
+#ifdef __GNUC__
+#define SCANF_PREFIX "a"
+#define SCANF_STRING(s) (&s)
+#define GETCWD_SIZE 0
+#else
+#define SCANF_PREFIX "511"
+#define SCANF_STRING(s) (s = malloc(512))
+#define GETCWD_SIZE -1
+inline int snprintf(char *str, size_t n, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vsprintf(str, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+#endif
+
+/*  device table entries take the form of:
+    <path>	<type> <mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
+    /dev/mem     c    640       0       0         1       1       0     0         -
+
+    type can be one of:
+	f	A regular file
+	d	Directory
+	c	Character special device file
+	b	Block special device file
+	p	Fifo (named pipe)
+
+    I don't bother with symlinks (permissions are irrelevant), hard
+    links (special cases of regular files), or sockets (why bother).
+
+    Regular files must exist in the target root directory.  If a char,
+    block, fifo, or directory does not exist, it will be created.
+*/
+static int interpret_table_entry(struct filesystem_entry *root, char *line)
+{
+	char *hostpath;
+	char type, *name = NULL, *tmp, *dir;
+	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
+	unsigned long start = 0, increment = 1, count = 0;
+	struct filesystem_entry *parent, *entry;
+
+	if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
+		 SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
+		 &start, &increment, &count) < 0)
+	{
+		return 1;
+	}
+
+	if (!strcmp(name, "/")) {
+		error_msg_and_die("Device table entries require absolute paths");
+	}
+
+	asprintf(&hostpath, "%s%s", rootdir, name);
+
+	/* Check if this file already exists... */
+	switch (type) {
+		case 'd':
+			mode |= S_IFDIR;
+			break;
+		case 'f':
+			mode |= S_IFREG;
+			break;
+		case 'p':
+			mode |= S_IFIFO;
+			break;
+		case 'c':
+			mode |= S_IFCHR;
+			break;
+		case 'b':
+			mode |= S_IFBLK;
+			break;
+		default:
+			error_msg_and_die("Unsupported file type");
+	}
+	entry = find_filesystem_entry(root, name, mode);
+	if (entry) {
+		/* Ok, we just need to fixup the existing entry
+		 * and we will be all done... */
+		entry->sb.st_uid = uid;
+		entry->sb.st_gid = gid;
+		entry->sb.st_mode = mode;
+		if (major && minor) {
+			entry->sb.st_rdev = makedev(major, minor);
+		}
+	} else {
+		/* If parent is NULL (happens with device table entries),
+		 * try and find our parent now) */
+		tmp = strdup(name);
+		dir = dirname(tmp);
+		parent = find_filesystem_entry(root, dir, S_IFDIR);
+		free(tmp);
+		if (parent == NULL) {
+			error_msg ("skipping device_table entry '%s': no parent directory!", name);
+			free(name);
+			free(hostpath);
+			return 1;
+		}
+
+		switch (type) {
+			case 'd':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'f':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'p':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'c':
+			case 'b':
+				if (count > 0) {
+					dev_t rdev;
+					unsigned long i;
+					char *dname, *hpath;
+
+					for (i = start; i < count; i++) {
+						asprintf(&dname, "%s%lu", name, i);
+						asprintf(&hpath, "%s/%s%lu", rootdir, name, i);
+						rdev = makedev(major, minor + (i * increment - start));
+						add_host_filesystem_entry(dname, hpath, uid, gid,
+								mode, rdev, parent);
+						free(dname);
+						free(hpath);
+					}
+				} else {
+					dev_t rdev = makedev(major, minor);
+					add_host_filesystem_entry(name, hostpath, uid, gid,
+							mode, rdev, parent);
+				}
+				break;
+			default:
+				error_msg_and_die("Unsupported file type");
+		}
+	}
+	free(name);
+	free(hostpath);
+	return 0;
+}
+
+static int parse_device_table(struct filesystem_entry *root, FILE * file)
+{
+	char *line;
+	int status = 0;
+	size_t length = 0;
+
+	/* Turn off squash, since we must ensure that values
+	 * entered via the device table are not squashed */
+	squash_uids = 0;
+	squash_perms = 0;
+
+	/* Looks ok so far.  The general plan now is to read in one
+	 * line at a time, check for leading comment delimiters ('#'),
+	 * then try and parse the line as a device table.  If we fail
+	 * to parse things, try and help the poor fool to fix their
+	 * device table with a useful error msg... */
+	line = NULL;
+	while (getline(&line, &length, file) != -1) {
+		/* First trim off any whitespace */
+		int len = strlen(line);
+
+		/* trim trailing whitespace */
+		while (len > 0 && isspace(line[len - 1]))
+			line[--len] = '\0';
+		/* trim leading whitespace */
+		memmove(line, &line[strspn(line, " \n\r\t\v")], len);
+
+		/* How long are we after trimming? */
+		len = strlen(line);
+
+		/* If this is NOT a comment line, try to interpret it */
+		if (len && *line != '#') {
+			if (interpret_table_entry(root, line))
+				status = 1;
+		}
+
+		free(line);
+		line = NULL;
+	}
+	fclose(file);
+
+	return status;
+}
+
+static void cleanup(struct filesystem_entry *dir)
+{
+	struct filesystem_entry *e, *prev;
+
+	e = dir->files;
+	while (e) {
+		if (e->name)
+			free(e->name);
+		if (e->path)
+			free(e->path);
+		if (e->fullname)
+			free(e->fullname);
+		e->next = NULL;
+		e->name = NULL;
+		e->path = NULL;
+		e->fullname = NULL;
+		e->prev = NULL;
+		prev = e;
+		if (S_ISDIR(e->sb.st_mode)) {
+			cleanup(e);
+		}
+		e = e->next;
+		free(prev);
+	}
+}
+
+/* Here is where we do the actual creation of the file system */
+#include "mtd/jffs2-user.h"
+
+#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF
+#ifndef JFFS2_MAX_SYMLINK_LEN
+#define JFFS2_MAX_SYMLINK_LEN 254
+#endif
+
+static uint32_t ino = 0;
+static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
+static int out_ofs = 0;
+static int erase_block_size = 65536;
+static int pad_fs_size = 0;
+static int add_ebhs = 1;
+static struct jffs2_raw_ebh ebh;
+static int ebh_size = sizeof(ebh);
+static unsigned char ffbuf[16] =
+	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+/* We default to 4096, per x86.  When building a fs for
+ * 64-bit arches and whatnot, use the --pagesize=SIZE option */
+int page_size = 4096;
+
+#include "compr-old.h"
+
+char *comprcontrol = NULL;
+static void full_write(int fd, const void *buf, int len)
+{
+	int ret;
+
+	while (len > 0) {
+		ret = write(fd, buf, len);
+
+		if (ret < 0)
+			perror_msg_and_die("write");
+
+		if (ret == 0)
+			perror_msg_and_die("write returned zero");
+
+		len -= ret;
+		buf += ret;
+		out_ofs += ret;
+	}
+}
+
+static void padblock(void)
+{
+	while (out_ofs % erase_block_size) {
+		full_write(out_fd, ffbuf, min(sizeof(ffbuf),
+					erase_block_size - (out_ofs % erase_block_size)));
+	}
+}
+
+static void pad(int req)
+{
+	while (req) {
+		if (req > sizeof(ffbuf)) {
+			full_write(out_fd, ffbuf, sizeof(ffbuf));
+			req -= sizeof(ffbuf);
+		} else {
+			full_write(out_fd, ffbuf, req);
+			req = 0;
+		}
+	}
+}
+
+static inline void padword(void)
+{
+	if (out_ofs % 4) {
+		full_write(out_fd, ffbuf, 4 - (out_ofs % 4));
+	}
+}
+
+static inline void pad_block_if_less_than(int req)
+{
+	if (add_ebhs) {
+		if ((out_ofs % erase_block_size) == 0) {
+			full_write(out_fd, &ebh, sizeof(ebh));
+			pad(ebh_size - sizeof(ebh));
+			padword();
+		}
+	}
+	if ((out_ofs % erase_block_size) + req > erase_block_size) {
+		padblock();
+	}
+	if (add_ebhs) {
+		if ((out_ofs % erase_block_size) == 0) {
+			full_write(out_fd, &ebh, sizeof(ebh));
+			pad(ebh_size - sizeof(ebh));
+			padword();
+		}
+	}
+}
+
+static void write_dirent(struct filesystem_entry *e)
+{
+	char *name = e->name;
+	struct jffs2_raw_dirent rd;
+	struct stat *statbuf = &(e->sb);
+	static uint32_t version = 0;
+
+	memset(&rd, 0, sizeof(rd));
+
+	rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name));
+	rd.hdr_crc = cpu_to_je32(crc32(0, &rd,
+				sizeof(struct jffs2_unknown_node) - 4));
+	rd.pino = cpu_to_je32((e->parent) ? e->parent->sb.st_ino : 1);
+	rd.version = cpu_to_je32(version++);
+	rd.ino = cpu_to_je32(statbuf->st_ino);
+	rd.mctime = cpu_to_je32(statbuf->st_mtime);
+	rd.nsize = strlen(name);
+	rd.type = IFTODT(statbuf->st_mode);
+	//rd.unused[0] = 0;
+	//rd.unused[1] = 0;
+	rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd) - 8));
+	rd.name_crc = cpu_to_je32(crc32(0, name, strlen(name)));
+
+	pad_block_if_less_than(sizeof(rd) + rd.nsize);
+	full_write(out_fd, &rd, sizeof(rd));
+	full_write(out_fd, name, rd.nsize);
+	padword();
+}
+
+static void write_regular_file(struct filesystem_entry *e)
+{
+	int fd, len;
+	uint32_t ver;
+	unsigned int offset;
+	unsigned char *buf, *cbuf, *wbuf;
+	struct jffs2_raw_inode ri;
+	struct stat *statbuf;
+
+
+	statbuf = &(e->sb);
+	if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) {
+		error_msg("Skipping file \"%s\" too large.", e->path);
+		return;
+	}
+	fd = open(e->hostname, O_RDONLY);
+	if (fd == -1) {
+		perror_msg_and_die("%s: open file", e->hostname);
+	}
+
+	statbuf->st_ino = ++ino;
+	mkfs_debug_msg("writing file '%s'  ino=%lu  parent_ino=%lu",
+			e->name, (unsigned long) statbuf->st_ino,
+			(unsigned long) e->parent->sb.st_ino);
+	write_dirent(e);
+
+	buf = xmalloc(page_size);
+	cbuf = NULL;
+
+	ver = 0;
+	offset = 0;
+
+	memset(&ri, 0, sizeof(ri));
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+
+	ri.ino = cpu_to_je32(statbuf->st_ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+
+	while ((len = read(fd, buf, page_size))) {
+		unsigned char *tbuf = buf;
+
+		if (len < 0) {
+			perror_msg_and_die("read");
+		}
+
+		while (len) {
+			uint32_t dsize, space;
+                        uint16_t compression;
+
+			pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
+
+			dsize = len;
+			space =
+				erase_block_size - (out_ofs % erase_block_size) -
+				sizeof(ri);
+			if (space > dsize)
+				space = dsize;
+
+			compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
+                        ri.compr = compression & 0xff;
+                        ri.usercompr = (compression >> 8) & 0xff;
+
+			if (ri.compr) {
+				wbuf = cbuf;
+			} else {
+				wbuf = tbuf;
+				dsize = space;
+			}
+
+			ri.totlen = cpu_to_je32(sizeof(ri) + space);
+			ri.hdr_crc = cpu_to_je32(crc32(0,
+						&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+			ri.version = cpu_to_je32(++ver);
+			ri.offset = cpu_to_je32(offset);
+			ri.csize = cpu_to_je32(space);
+			ri.dsize = cpu_to_je32(dsize);
+			ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+			ri.data_crc = cpu_to_je32(crc32(0, wbuf, space));
+
+			full_write(out_fd, &ri, sizeof(ri));
+			full_write(out_fd, wbuf, space);
+			padword();
+
+			tbuf += dsize;
+			len -= dsize;
+			offset += dsize;
+
+                        if (tbuf!=cbuf) if (!cbuf) free(cbuf);
+		}
+	}
+	if (!je32_to_cpu(ri.version)) {
+		/* Was empty file */
+		pad_block_if_less_than(sizeof(ri));
+
+		ri.version = cpu_to_je32(++ver);
+		ri.totlen = cpu_to_je32(sizeof(ri));
+		ri.hdr_crc = cpu_to_je32(crc32(0,
+					&ri, sizeof(struct jffs2_unknown_node) - 4));
+		ri.csize = cpu_to_je32(0);
+		ri.dsize = cpu_to_je32(0);
+		ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+
+		full_write(out_fd, &ri, sizeof(ri));
+		padword();
+	}
+	free(buf);
+	close(fd);
+}
+
+static void write_symlink(struct filesystem_entry *e)
+{
+	int len;
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	statbuf->st_ino = ++ino;
+	mkfs_debug_msg("writing symlink '%s'  ino=%lu  parent_ino=%lu",
+			e->name, (unsigned long) statbuf->st_ino,
+			(unsigned long) e->parent->sb.st_ino);
+	write_dirent(e);
+
+	len = strlen(e->link);
+	if (len > JFFS2_MAX_SYMLINK_LEN) {
+		error_msg("symlink too large. Truncated to %d chars.",
+				JFFS2_MAX_SYMLINK_LEN);
+		len = JFFS2_MAX_SYMLINK_LEN;
+	}
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri) + len);
+	ri.hdr_crc = cpu_to_je32(crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(statbuf->st_ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(len);
+	ri.dsize = cpu_to_je32(len);
+	ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(crc32(0, e->link, len));
+
+	pad_block_if_less_than(sizeof(ri) + len);
+	full_write(out_fd, &ri, sizeof(ri));
+	full_write(out_fd, e->link, len);
+	padword();
+}
+
+static void write_pipe(struct filesystem_entry *e)
+{
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	statbuf->st_ino = ++ino;
+	if (S_ISDIR(statbuf->st_mode)) {
+		mkfs_debug_msg("writing dir '%s'  ino=%lu  parent_ino=%lu",
+				e->name, (unsigned long) statbuf->st_ino,
+				(unsigned long) (e->parent) ? e->parent->sb.  st_ino : 1);
+	}
+	write_dirent(e);
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri));
+	ri.hdr_crc = cpu_to_je32(crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(statbuf->st_ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(0);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(0);
+	ri.dsize = cpu_to_je32(0);
+	ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(0);
+
+	pad_block_if_less_than(sizeof(ri));
+	full_write(out_fd, &ri, sizeof(ri));
+	padword();
+}
+
+static void write_special_file(struct filesystem_entry *e)
+{
+	jint16_t kdev;
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	statbuf->st_ino = ++ino;
+	write_dirent(e);
+
+	kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) +
+			minor(statbuf->st_rdev));
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev));
+	ri.hdr_crc = cpu_to_je32(crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(statbuf->st_ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(sizeof(kdev));
+	ri.dsize = cpu_to_je32(sizeof(kdev));
+	ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(crc32(0, &kdev, sizeof(kdev)));
+
+	pad_block_if_less_than(sizeof(ri) + sizeof(kdev));
+	full_write(out_fd, &ri, sizeof(ri));
+	full_write(out_fd, &kdev, sizeof(kdev));
+	padword();
+}
+
+static void recursive_populate_directory(struct filesystem_entry *dir)
+{
+	struct filesystem_entry *e;
+
+	if (verbose) {
+		printf("%s\n", dir->fullname);
+	}
+	e = dir->files;
+	while (e) {
+
+		switch (e->sb.st_mode & S_IFMT) {
+			case S_IFDIR:
+				if (verbose) {
+					printf("\td %04o %9lu %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) (e->sb.st_uid), (int) (e->sb.st_gid),
+							e->name);
+				}
+				write_pipe(e);
+				break;
+			case S_IFSOCK:
+				if (verbose) {
+					printf("\ts %04o %9lu %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				write_pipe(e);
+				break;
+			case S_IFIFO:
+				if (verbose) {
+					printf("\tp %04o %9lu %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				write_pipe(e);
+				break;
+			case S_IFCHR:
+				if (verbose) {
+					printf("\tc %04o %4d,%4d %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+							minor(e->sb.st_rdev), (int) e->sb.st_uid,
+							(int) e->sb.st_gid, e->name);
+				}
+				write_special_file(e);
+				break;
+			case S_IFBLK:
+				if (verbose) {
+					printf("\tb %04o %4d,%4d %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+							minor(e->sb.st_rdev), (int) e->sb.st_uid,
+							(int) e->sb.st_gid, e->name);
+				}
+				write_special_file(e);
+				break;
+			case S_IFLNK:
+				if (verbose) {
+					printf("\tl %04o %9lu %5d:%-3d %s -> %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name,
+							e->link);
+				}
+				write_symlink(e);
+				break;
+			case S_IFREG:
+				if (verbose) {
+					printf("\tf %04o %9lu %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				write_regular_file(e);
+				break;
+			default:
+				error_msg("Unknown mode %o for %s", e->sb.st_mode,
+						e->fullname);
+				break;
+		}
+		e = e->next;
+	}
+
+	e = dir->files;
+	while (e) {
+		if (S_ISDIR(e->sb.st_mode)) {
+			if (e->files) {
+				recursive_populate_directory(e);
+			} else if (verbose) {
+				printf("%s\n", e->fullname);
+			}
+		}
+		e = e->next;
+	}
+}
+
+static void create_target_filesystem(struct filesystem_entry *root)
+{
+	ebh.magic    = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ebh.nodetype = cpu_to_je16(JFFS2_NODETYPE_ERASEBLOCK_HEADER);
+	ebh.totlen   = cpu_to_je32(sizeof(ebh));
+	ebh.hdr_crc  = cpu_to_je32(crc32(0, &ebh, sizeof(struct jffs2_unknown_node)-4));
+	ebh.reserved = 0;
+	ebh.compat_fset = JFFS2_EBH_COMPAT_FSET;
+	ebh.incompat_fset = JFFS2_EBH_INCOMPAT_FSET;
+	ebh.rocompat_fset = JFFS2_EBH_ROCOMPAT_FSET;
+	ebh.erase_count = cpu_to_je32(0);
+	ebh.node_crc = cpu_to_je32(crc32(0, (unsigned char *)&ebh + sizeof(struct jffs2_unknown_node) + 4,
+							sizeof(struct jffs2_raw_ebh) - sizeof(struct jffs2_unknown_node) - 4));
+
+	if (ino == 0)
+		ino = 1;
+
+	root->sb.st_ino = 1;
+	recursive_populate_directory(root);
+
+	if (pad_fs_size == -1) {
+		padblock();
+	} else {
+		if (pad_fs_size && add_ebhs){
+			padblock();
+			while (out_ofs < pad_fs_size) {
+				full_write(out_fd, &ebh, sizeof(ebh));
+				pad(ebh_size - sizeof(ebh));
+				padblock();
+			}
+		} else {
+			while (out_ofs < pad_fs_size) {
+				full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs));
+			}
+
+		}
+	}
+}
+
+static struct option long_options[] = {
+	{"pad", 2, NULL, 'p'},
+	{"root", 1, NULL, 'r'},
+	{"pagesize", 1, NULL, 's'},
+	{"eraseblock", 1, NULL, 'e'},
+	{"output", 1, NULL, 'o'},
+	{"help", 0, NULL, 'h'},
+	{"verbose", 0, NULL, 'v'},
+	{"version", 0, NULL, 'V'},
+	{"big-endian", 0, NULL, 'b'},
+	{"little-endian", 0, NULL, 'l'},
+	{"no-eraseblock-headers", 0, NULL, 'n'},
+	{"eraseblock-header", 1, NULL, 'c'},
+	{"squash", 0, NULL, 'q'},
+	{"squash-uids", 0, NULL, 'U'},
+	{"squash-perms", 0, NULL, 'P'},
+	{"faketime", 0, NULL, 'f'},
+	{"devtable", 1, NULL, 'D'},
+	{"compressors", 1, NULL, 'm'},
+	{"test-compression", 0, NULL, 't'},
+	{"incremental", 1, NULL, 'i'},
+	{NULL, 0, NULL, 0}
+};
+
+static char *helptext =
+	"Usage: mkfs.jffs2 [OPTIONS]\n"
+	"Make a JFFS2 file system image from an existing directory tree\n\n"
+	"Options:\n"
+	"  -p, --pad[=SIZE]        Pad output to SIZE bytes with 0xFF. If SIZE is\n"
+	"                          not specified, the output is padded to the end of\n"
+	"                          the final erase block\n"
+	"  -r, -d, --root=DIR      Build file system from directory DIR (default: cwd)\n"
+	"  -s, --pagesize=SIZE     Use page size (max data node size) SIZE (default: 4KiB)\n"
+	"  -e, --eraseblock=SIZE   Use erase block size SIZE (default: 64KiB)\n"
+	"  -c, --eraseblock-header=SIZE  Size of eraseblock header (default 28)\n"
+	"  -m, --compressors       Compressors control string, eg. " DEFAULT_COMPR_CONTROL " which is the default\n"
+	"  -L, --list-compressors  Show the list of the avaiable compressors\n"
+	"  -t, --test-compression  Call decompress and compare with the original (for test)\n"
+	"  -n, --no-eraseblock-headers   Don't add a eraseblock header to every eraseblock\n"
+	"  -o, --output=FILE       Output to FILE (default: stdout)\n"
+	"  -l, --little-endian     Create a little-endian filesystem\n"
+	"  -b, --big-endian        Create a big-endian filesystem\n"
+	"  -D, --devtable=FILE     Use the named FILE as a device table file\n"
+	"  -f, --faketime          Change all file times to '0' for regression testing\n"
+	"  -q, --squash            Squash permissions and owners making all files be owned by root\n"
+	"  -U, --squash-uids       Squash owners making all files be owned by root\n"
+	"  -P, --squash-perms      Squash permissions on all files\n"
+	"  -h, --help              Display this help text\n"
+	"  -v, --verbose           Verbose operation\n"
+	"  -V, --version           Display version information\n"
+	"  -i, --incremental=FILE  Parse FILE and generate appendage output for it\n\n";
+
+static char *revtext = "$Revision: 1.47 $";
+
+int load_next_block() {
+
+	int ret;
+	ret = read(in_fd, file_buffer, erase_block_size);
+
+	if(verbose)
+		printf("Load next block : %d bytes read\n",ret);
+
+	return ret;
+}
+
+void process_buffer(int inp_size) {
+	uint8_t		*p = file_buffer;
+	union jffs2_node_union 	*node;
+	uint16_t	type;
+	int		bitchbitmask = 0;
+	int		obsolete;
+
+	char	name[256];
+
+	while ( p < (file_buffer + inp_size)) {
+
+		node = (union jffs2_node_union *) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
+			if (!bitchbitmask++)
+    			    printf ("Wrong bitmask  at  0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
+			p += 4;
+			continue;
+		}
+
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else
+			obsolete = 0;
+
+		node->u.nodetype = cpu_to_je16(type);
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE:
+				if(verbose)
+					printf ("%8s Inode      node at 0x%08x, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+						je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+						je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				if ( je32_to_cpu (node->i.ino) > ino )
+					ino = je32_to_cpu (node->i.ino);
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+
+				if(verbose)
+					printf ("%8s Dirent     node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+						je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+						node->d.nsize, name);
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+				if (verbose) {
+					printf ("%8s Cleanmarker     at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_ERASEBLOCK_HEADER:
+				if (verbose) {
+					printf ("%8s Eraseblock header at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->eh.totlen));
+				}
+				p += PAD(je32_to_cpu (node->eh.totlen));
+				break;
+
+			case JFFS2_NODETYPE_PADDING:
+				if (verbose) {
+					printf ("%8s Padding    node at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case 0xffff:
+				p += 4;
+				break;
+
+			default:
+				if (verbose) {
+					printf ("%8s Unknown    node at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+		}
+	}
+}
+
+void parse_image(){
+	int ret;
+
+	file_buffer = malloc(erase_block_size);
+
+	if (!file_buffer) {
+		perror("out of memory");
+		close (in_fd);
+		close (out_fd);
+		exit(1);
+	}
+
+	while ((ret = load_next_block())) {
+		process_buffer(ret);
+	}
+
+	if (file_buffer)
+		free(file_buffer);
+
+	close(in_fd);
+}
+
+int main(int argc, char **argv)
+{
+	int c, opt;
+	char *cwd;
+	struct stat sb;
+	FILE *devtable = NULL;
+	struct filesystem_entry *root;
+	int ret;
+
+	jffs2_compressors_init();
+
+	while ((opt = getopt_long(argc, argv,
+					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:Lti:", long_options, &c)) >= 0)
+	{
+		switch (opt) {
+			case 'D':
+				devtable = xfopen(optarg, "r");
+				if (fstat(fileno(devtable), &sb) < 0)
+					perror_msg_and_die(optarg);
+				if (sb.st_size < 10)
+					error_msg_and_die("%s: not a proper device table file", optarg);
+				break;
+
+			case 'r':
+			case 'd':	/* for compatibility with mkfs.jffs, genext2fs, etc... */
+				if (rootdir != default_rootdir) {
+					error_msg_and_die("root directory specified more than once");
+				}
+				rootdir = xstrdup(optarg);
+				break;
+
+			case 's':
+				page_size = strtol(optarg, NULL, 0);
+				break;
+
+			case 'o':
+				if (out_fd != -1) {
+					error_msg_and_die("output filename specified more than once");
+				}
+				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+				if (out_fd == -1) {
+					perror_msg_and_die("open output file");
+				}
+				break;
+
+			case 'q':
+				squash_uids = 1;
+				squash_perms = 1;
+				break;
+
+			case 'U':
+				squash_uids = 1;
+				break;
+
+			case 'P':
+				squash_perms = 1;
+				break;
+
+			case 'f':
+				fake_times = 1;
+				break;
+
+			case 'h':
+			case '?':
+				error_msg_and_die(helptext);
+
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				error_msg_and_die("revision %.*s\n",
+						(int) strlen(revtext) - 13, revtext + 11);
+
+			case 'e': {
+				char *next;
+				unsigned units = 0;
+				erase_block_size = strtol(optarg, &next, 0);
+				if (!erase_block_size)
+					error_msg_and_die("Unrecognisable erase size\n");
+
+				if (*next) {
+					if (!strcmp(next, "KiB")) {
+						units = 1024;
+					} else if (!strcmp(next, "MiB")) {
+						units = 1024 * 1024;
+					} else {
+						error_msg_and_die("Unknown units in erasesize\n");
+					}
+				} else {
+					if (erase_block_size < 0x1000)
+						units = 1024;
+					else
+						units = 1;
+				}
+				erase_block_size *= units;
+
+				/* If it's less than 8KiB, they're not allowed */
+				if (erase_block_size < 0x2000) {
+					fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+						erase_block_size);
+					erase_block_size = 0x2000;
+				}
+				break;
+			}
+
+			case 'l':
+				target_endian = __LITTLE_ENDIAN;
+				break;
+
+			case 'b':
+				target_endian = __BIG_ENDIAN;
+				break;
+
+			case 'p':
+				if (optarg)
+					pad_fs_size = strtol(optarg, NULL, 0);
+				else
+					pad_fs_size = -1;
+				break;
+			case 'n':
+				add_ebhs = 0;
+				break;
+			case 'c':
+				ebh_size = strtol(optarg, NULL, 0);
+				if (ebh_size < sizeof(ebh)) {
+					error_msg_and_die("ebh size must be >= 28");
+				}
+				if (ebh_size >= erase_block_size) {
+					error_msg_and_die("ebh size must be < eraseblock size");
+				}
+				break;
+
+			case 'm':
+				comprcontrol = xstrdup(optarg);
+				break;
+
+			case 'L':
+				error_msg_and_die("\n%s",jffs2_list_compressors());
+				break;
+
+			case 't':
+				jffs2_compression_check_set(1);
+				break;
+
+			case 'i':
+				if (in_fd != -1) {
+					error_msg_and_die("(incremental) filename specified more than once");
+				}
+				in_fd = open(optarg, O_RDONLY);
+				if (in_fd == -1) {
+					perror_msg_and_die("cannot open (incremental) file");
+				}
+				break;
+		}
+	}
+
+	if (!comprcontrol) {
+		comprcontrol = malloc(sizeof(DEFAULT_COMPR_CONTROL));
+		strcpy(comprcontrol, DEFAULT_COMPR_CONTROL);
+	}
+
+	if (out_fd == -1) {
+		if (isatty(1)) {
+			error_msg_and_die(helptext);
+		}
+		out_fd = 1;
+	}
+	if (lstat(rootdir, &sb)) {
+		perror_msg_and_die("%s", rootdir);
+	}
+	if (chdir(rootdir))
+		perror_msg_and_die("%s", rootdir);
+
+	if (!(cwd = getcwd(0, GETCWD_SIZE)))
+		perror_msg_and_die("getcwd failed");
+
+	if(in_fd != -1)
+		parse_image();
+
+	ret = jffs2_setup_compression(comprcontrol);
+	if (ret)
+		perror_msg_and_die("Compression setup failed!\n");
+
+	root = recursive_add_host_directory(NULL, "/", cwd);
+
+	if (devtable)
+		parse_device_table(root, devtable);
+
+	create_target_filesystem(root);
+
+	cleanup(root);
+
+	if (rootdir != default_rootdir)
+		free(rootdir);
+
+	close(out_fd);
+
+	if (verbose) {
+		char *s = jffs2_stats();
+		fprintf(stderr,"\n\n%s",s);
+		free(s);
+	}
+	if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
+		fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
+	}
+
+	jffs2_compressors_exit();
+	free(comprcontrol);
+
+	return 0;
+}
diff -Narup Mtd-orig/util/mkfs.jffs2.c mtd/util/mkfs.jffs2.c
--- Mtd-orig/util/mkfs.jffs2.c	2005-11-28 10:26:55.000000000 +0100
+++ mtd/util/mkfs.jffs2.c	2005-11-29 09:31:55.000000000 +0100
@@ -64,11 +64,10 @@
 #include <time.h>
 #include <getopt.h>
 #include <byteswap.h>
-#define crc32 __complete_crap
-#include <zlib.h>
-#undef crc32
 #include "crc32.h"
 
+#define DEFAULT_COMPR_CONTROL "deflate"
+
 /* Do not use the wierd XPG version of basename */
 #undef basename
 
@@ -673,6 +672,9 @@ int page_size = 4096;
 
 #include "compr.h"
 
+char *comprcontrol = NULL;
+struct compress_ctx *ctx;
+
 static void full_write(int fd, const void *buf, int len)
 {
 	int ret;
@@ -774,7 +776,7 @@ static void write_dirent(struct filesyst
 
 static void write_regular_file(struct filesystem_entry *e)
 {
-	int fd, len;
+	int fd, len, ret;
 	uint32_t ver;
 	unsigned int offset;
 	unsigned char *buf, *cbuf, *wbuf;
@@ -826,7 +828,6 @@ static void write_regular_file(struct fi
 
 		while (len) {
 			uint32_t dsize, space;
-                        uint16_t compression;
 
 			pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
 
@@ -837,14 +838,21 @@ static void write_regular_file(struct fi
 			if (space > dsize)
 				space = dsize;
 
-			compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
-                        ri.compr = compression & 0xff;
-                        ri.usercompr = (compression >> 8) & 0xff;
-			if (ri.compr) {
+			cbuf = malloc(space);
+			if (!cbuf) {
+				perror_msg_and_die("Memory allocation error");
+			}
+
+			ret = compress(&ctx, tbuf, dsize, cbuf, &space);
+			if (ret > 0) {
+				ri.compr = JFFS2_COMPR_ENGINE;
+				ri.usercompr = ret;
 				wbuf = cbuf;
 			} else {
-				wbuf = tbuf;
+				ri.compr = JFFS2_COMPR_NONE;
+				ri.usercompr = 0;
 				dsize = space;
+				wbuf = tbuf;
 			}
 
 			ri.totlen = cpu_to_je32(sizeof(ri) + space);
@@ -866,7 +874,7 @@ static void write_regular_file(struct fi
 			len -= dsize;
 			offset += dsize;
 
-                        if (tbuf!=cbuf) if (!cbuf) free(cbuf);
+			free(cbuf);
 		}
 	}
 	if (!je32_to_cpu(ri.version)) {
@@ -1167,10 +1175,7 @@ static struct option long_options[] = {
 	{"squash-perms", 0, NULL, 'P'},
 	{"faketime", 0, NULL, 'f'},
 	{"devtable", 1, NULL, 'D'},
-	{"compression-mode", 1, NULL, 'm'},
-	{"disable-compressor", 1, NULL, 'x'},
-	{"test-compression", 0, NULL, 't'},
-	{"compressor-priority", 1, NULL, 'y'},
+	{"compressors", 1, NULL, 'm'},
 	{"incremental", 1, NULL, 'i'},
 	{NULL, 0, NULL, 0}
 };
@@ -1186,15 +1191,7 @@ static char *helptext =
 	"  -s, --pagesize=SIZE     Use page size (max data node size) SIZE (default: 4KiB)\n"
 	"  -e, --eraseblock=SIZE   Use erase block size SIZE (default: 64KiB)\n"
 	"  -c, --eraseblock-header=SIZE  Size of eraseblock header (default 28)\n"
-	"  -m, --compr-mode=MODE   Select compression mode (default: priortiry)\n"
-        "  -x, --disable-compressor=COMPRESSOR_NAME\n"
-        "                          Disable a compressor\n"
-        "  -X, --enable-compressor=COMPRESSOR_NAME\n"
-        "                          Enable a compressor\n"
-        "  -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n"
-        "                          Set the priority of a compressor\n"
-        "  -L, --list-compressors  Show the list of the avaiable compressors\n"
-        "  -t, --test-compression  Call decompress and compare with the original (for test)\n"
+	"  -m, --compressors       Compressors control string, eg. \"" DEFAULT_COMPR_CONTROL "\" which is the default\n"
 	"  -n, --no-eraseblock-headers   Don't add a eraseblock header to every eraseblock\n"
 	"  -o, --output=FILE       Output to FILE (default: stdout)\n"
 	"  -l, --little-endian     Create a little-endian filesystem\n"
@@ -1363,13 +1360,9 @@ int main(int argc, char **argv)
 	struct stat sb;
 	FILE *devtable = NULL;
 	struct filesystem_entry *root;
-        char *compr_name = NULL;
-        int compr_prior  = -1;
-
-        jffs2_compressors_init();
 
 	while ((opt = getopt_long(argc, argv,
-					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0)
+					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:i:", long_options, &c)) >= 0) 
 	{
 		switch (opt) {
 			case 'D':
@@ -1489,39 +1482,9 @@ int main(int argc, char **argv)
 					error_msg_and_die("ebh size must be < eraseblock size");
 				}
 				break;
-                        case 'm':
-                                if (jffs2_set_compression_mode_name(optarg)) {
-					error_msg_and_die("Unknown compression mode %s", optarg);
-				}
-                                break;
-                        case 'x':
-                                if (jffs2_disable_compressor_name(optarg)) {
-                                        error_msg_and_die("Unknown compressor name %s",optarg);
-                                }
-                                break;
-                        case 'X':
-                                if (jffs2_enable_compressor_name(optarg)) {
-                                        error_msg_and_die("Unknown compressor name %s",optarg);
-                                }
-                                break;
-                        case 'L':
-                                error_msg_and_die("\n%s",jffs2_list_compressors());
-                                break;
-                        case 't':
-                                jffs2_compression_check_set(1);
-                                break;
-                        case 'y':
-                                compr_name = malloc(strlen(optarg));
-                                sscanf(optarg,"%d:%s",&compr_prior,compr_name);
-                                if ((compr_prior>=0)&&(compr_name)) {
-                                        if (jffs2_set_compressor_priority(compr_name, compr_prior))
-	                                        exit(EXIT_FAILURE);
-                                }
-                                else {
-                                        error_msg_and_die("Cannot parse %s",optarg);
-                                }
-                                free(compr_name);
-                                break;
+			case 'm':
+				comprcontrol = xstrdup(optarg);
+				break;
 			case 'i':
 				if (in_fd != -1) {
 					error_msg_and_die("(incremental) filename specified more than once");
@@ -1533,6 +1496,10 @@ int main(int argc, char **argv)
 				break;
 		}
 	}
+	if (!comprcontrol) {
+		comprcontrol = (char *) malloc(sizeof(DEFAULT_COMPR_CONTROL));
+		strcpy(comprcontrol, DEFAULT_COMPR_CONTROL);
+	}
 	if (out_fd == -1) {
 		if (isatty(1)) {
 			error_msg_and_die(helptext);
@@ -1551,6 +1518,9 @@ int main(int argc, char **argv)
 	if(in_fd != -1)
 		parse_image();
 
+	if (!(ctx = create_compress_context(comprcontrol)))
+		perror_msg_and_die("compressor init failed");
+
 	root = recursive_add_host_directory(NULL, "/", cwd);
 
 	if (devtable)
@@ -1565,16 +1535,14 @@ int main(int argc, char **argv)
 
 	close(out_fd);
 
-        if (verbose) {
-                char *s = jffs2_stats();
-                fprintf(stderr,"\n\n%s",s);
-                free(s);
-        }
-        if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
-                fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
-        }
+	if (verbose) {
+		char *s = compress_stats(&ctx);
+		fprintf(stderr, "\n\n%s", s);
+		free(s);
+	}
 
-        jffs2_compressors_exit();
+	destroy_compress_context(&ctx);
+	free(comprcontrol);
 
 	return 0;
 }
