wok rev 18894

fusecloop/create_compressed_fs: deduplicate
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sat Feb 13 18:33:57 2016 +0100 (2016-02-13)
parents 8fafe6486d97
children 624197d091b7
files fusecloop/stuff/fusecloop.u
line diff
     1.1 --- a/fusecloop/stuff/fusecloop.u	Sat Feb 13 10:39:15 2016 +0100
     1.2 +++ b/fusecloop/stuff/fusecloop.u	Sat Feb 13 18:33:57 2016 +0100
     1.3 @@ -176,7 +176,7 @@
     1.4   	if (handle < 0) {
     1.5   		perror("Opening compressed file\n");
     1.6   		exit(1);
     1.7 -@@ -24,44 +28,100 @@
     1.8 +@@ -24,66 +28,100 @@
     1.9   		exit(1);
    1.10   	}
    1.11   
    1.12 @@ -214,7 +214,7 @@
    1.13  +		table_size = ntohl(tail.table_size);
    1.14  +		table = malloc(table_size);
    1.15  +		len = i = num_blocks * (ntohl(tail.index_size) & 255);
    1.16 -+		lastlen = ntohl(tail.index_size) & ~0x1FF;
    1.17 ++		lastlen = ntohl(tail.index_size) / 256;
    1.18  +		offsets = malloc(num_blocks * sizeof(*offsets));
    1.19  +		if (!table || !offsets || 
    1.20  +		    read(handle, table, table_size) != table_size ||
    1.21 @@ -298,19 +298,42 @@
    1.22   
    1.23  -		fprintf(stderr, "Block %u length %u => %lu\n",
    1.24  -			i, size, destlen);
    1.25 -+		fprintf(stderr, "Block %u at %llu length %u => %lu\n",
    1.26 -+			i, offsets[i].offset, size, destlen);
    1.27 - 		if (i == 3) {
    1.28 - 			fprintf(stderr,
    1.29 - 				"Block head:%02X%02X%02X%02X%02X%02X%02X%02X\n",
    1.30 -@@ -105,12 +165,12 @@
    1.31 +-		if (i == 3) {
    1.32 +-			fprintf(stderr,
    1.33 +-				"Block head:%02X%02X%02X%02X%02X%02X%02X%02X\n",
    1.34 +-				buffer[0],
    1.35 +-				buffer[1],
    1.36 +-				buffer[2],
    1.37 +-				buffer[3],
    1.38 +-				buffer[4],
    1.39 +-				buffer[5],
    1.40 +-				buffer[6],
    1.41 +-				buffer[7]);
    1.42 +-			fprintf(stderr,
    1.43 +-				"Block tail:%02X%02X%02X%02X%02X%02X%02X%02X\n",
    1.44 +-				buffer[3063],
    1.45 +-				buffer[3064],
    1.46 +-				buffer[3065],
    1.47 +-				buffer[3066],
    1.48 +-				buffer[3067],
    1.49 +-				buffer[3068],
    1.50 +-				buffer[3069],
    1.51 +-				buffer[3070]);
    1.52 +-		}
    1.53 ++		fprintf(stderr, "Block %u at %llu length %u",
    1.54 ++			i, offsets[i].offset, size);
    1.55 + 		switch (uncompress(clear_buffer, &destlen,
    1.56 + 				   buffer, size)) {
    1.57 + 		case Z_OK:
    1.58 +@@ -105,12 +143,13 @@
    1.59   			fprintf(stderr, "Uncomp: unknown error %u\n", i);
    1.60   			exit(1);
    1.61   		}
    1.62  -		if (destlen != ntohl(head.block_size)) {
    1.63  -			fprintf(stderr, "Uncomp: bad len %u (%lu not %u)\n", i,
    1.64  -				destlen, ntohl(head.block_size));
    1.65 -+		if (destlen != block_size) {
    1.66 ++		fprintf(stderr, " => %lu\n", destlen);
    1.67 ++		if (destlen != block_size && i != num_blocks - 1) {
    1.68  +			fprintf(stderr, "Uncomp: bad len %u (%lu not %lu)\n", i,
    1.69  +				destlen, block_size);
    1.70   			exit(1);
    1.71 @@ -320,7 +343,6 @@
    1.72   	}
    1.73   	return 0;
    1.74   }
    1.75 -
    1.76  --- Makefile
    1.77  +++ Makefile
    1.78  @@ -1,16 +1,19 @@
    1.79 @@ -339,7 +361,7 @@
    1.80   extract_compressed_fs: extract_compressed_fs.c
    1.81   	${CC} ${CFLAGS} ${LDFLAGS} -lz extract_compressed_fs.c -o extract_compressed_fs
    1.82   
    1.83 -+create_compressed_fs: create_compressed_fs.c
    1.84 ++create_compressed_fs: create_compressed_fs.c md5sum.c
    1.85  +	${CC} ${CFLAGS} ${LDFLAGS} -lz create_compressed_fs.c -o create_compressed_fs
    1.86  +
    1.87   fusecloop: fusecloop.c cloopreader.o strver debug.o
    1.88 @@ -347,9 +369,258 @@
    1.89   
    1.90  
    1.91  
    1.92 +--- md5sum.c
    1.93 ++++ md5sum.c
    1.94 +@@ -0,0 +1,246 @@
    1.95 ++/*
    1.96 ++ * Based on busybox code.
    1.97 ++ *
    1.98 ++ * Compute MD5 checksum of strings according to the
    1.99 ++ * definition of MD5 in RFC 1321 from April 1992.
   1.100 ++ *
   1.101 ++ * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
   1.102 ++ *
   1.103 ++ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
   1.104 ++ * Copyright (C) 2001 Manuel Novoa III
   1.105 ++ * Copyright (C) 2003 Glenn L. McGrath
   1.106 ++ * Copyright (C) 2003 Erik Andersen
   1.107 ++ * Copyright (C) 2010 Denys Vlasenko
   1.108 ++ * Copyright (C) 2012 Pascal Bellard
   1.109 ++ *
   1.110 ++ * Licensed under GPLv2 or later
   1.111 ++ */
   1.112 ++
   1.113 ++#define ALIGN1
   1.114 ++
   1.115 ++static uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */
   1.116 ++static uint64_t total64;    /* must be directly before hash[] */
   1.117 ++static uint32_t hash[8];    /* 4 elements for md5, 5 for sha1, 8 for sha256 */
   1.118 ++
   1.119 ++/* Emit a string of hex representation of bytes */
   1.120 ++static char* bin2hex(char *p)
   1.121 ++{
   1.122 ++	static const char bb_hexdigits_upcase[] ALIGN1 = "0123456789abcdef";
   1.123 ++	int count = 16;
   1.124 ++	const char *cp = (const char *) hash;
   1.125 ++	while (count) {
   1.126 ++		unsigned char c = *cp++;
   1.127 ++		/* put lowercase hex digits */
   1.128 ++		*p++ = bb_hexdigits_upcase[c >> 4];
   1.129 ++		*p++ = bb_hexdigits_upcase[c & 0xf];
   1.130 ++		count--;
   1.131 ++	}
   1.132 ++	return p;
   1.133 ++}
   1.134 ++
   1.135 ++//#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
   1.136 ++static uint32_t rotl32(uint32_t x, unsigned n)
   1.137 ++{
   1.138 ++	return (x << n) | (x >> (32 - n));
   1.139 ++}
   1.140 ++
   1.141 ++static void md5_process_block64(void);
   1.142 ++
   1.143 ++/* Feed data through a temporary buffer.
   1.144 ++ * The internal buffer remembers previous data until it has 64
   1.145 ++ * bytes worth to pass on.
   1.146 ++ */
   1.147 ++static void common64_hash(const void *buffer, size_t len)
   1.148 ++{
   1.149 ++	unsigned bufpos = total64 & 63;
   1.150 ++
   1.151 ++	total64 += len;
   1.152 ++
   1.153 ++	while (1) {
   1.154 ++		unsigned remaining = 64 - bufpos;
   1.155 ++		if (remaining > len)
   1.156 ++			remaining = len;
   1.157 ++		/* Copy data into aligned buffer */
   1.158 ++		memcpy(wbuffer + bufpos, buffer, remaining);
   1.159 ++		len -= remaining;
   1.160 ++		buffer = (const char *)buffer + remaining;
   1.161 ++		bufpos += remaining;
   1.162 ++		/* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
   1.163 ++		bufpos -= 64;
   1.164 ++		if (bufpos != 0)
   1.165 ++			break;
   1.166 ++		/* Buffer is filled up, process it */
   1.167 ++		md5_process_block64();
   1.168 ++		/*bufpos = 0; - already is */
   1.169 ++	}
   1.170 ++}
   1.171 ++
   1.172 ++/* Process the remaining bytes in the buffer */
   1.173 ++static void common64_end(void)
   1.174 ++{
   1.175 ++	unsigned bufpos = total64 & 63;
   1.176 ++	/* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
   1.177 ++	wbuffer[bufpos++] = 0x80;
   1.178 ++
   1.179 ++	/* This loop iterates either once or twice, no more, no less */
   1.180 ++	while (1) {
   1.181 ++		unsigned remaining = 64 - bufpos;
   1.182 ++		memset(wbuffer + bufpos, 0, remaining);
   1.183 ++		/* Do we have enough space for the length count? */
   1.184 ++		if (remaining >= 8) {
   1.185 ++			/* Store the 64-bit counter of bits in the buffer */
   1.186 ++			uint64_t t = total64 << 3;
   1.187 ++			/* wbuffer is suitably aligned for this */
   1.188 ++			*(uint64_t *) (&wbuffer[64 - 8]) = t;
   1.189 ++		}
   1.190 ++		md5_process_block64();
   1.191 ++		if (remaining >= 8)
   1.192 ++			break;
   1.193 ++		bufpos = 0;
   1.194 ++	}
   1.195 ++}
   1.196 ++
   1.197 ++/* These are the four functions used in the four steps of the MD5 algorithm
   1.198 ++ * and defined in the RFC 1321.  The first function is a little bit optimized
   1.199 ++ * (as found in Colin Plumbs public domain implementation).
   1.200 ++ * #define FF(b, c, d) ((b & c) | (~b & d))
   1.201 ++ */
   1.202 ++#undef FF
   1.203 ++#undef FG
   1.204 ++#undef FH
   1.205 ++#undef FI
   1.206 ++#define FF(b, c, d) (d ^ (b & (c ^ d)))
   1.207 ++#define FG(b, c, d) FF(d, b, c)
   1.208 ++#define FH(b, c, d) (b ^ c ^ d)
   1.209 ++#define FI(b, c, d) (c ^ (b | ~d))
   1.210 ++
   1.211 ++/* Hash a single block, 64 bytes long and 4-byte aligned */
   1.212 ++static void md5_process_block64(void)
   1.213 ++{
   1.214 ++	/* Before we start, one word to the strange constants.
   1.215 ++	   They are defined in RFC 1321 as
   1.216 ++	   T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
   1.217 ++	 */
   1.218 ++	static const uint32_t C_array[] = {
   1.219 ++		/* round 1 */
   1.220 ++		0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
   1.221 ++		0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
   1.222 ++		0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
   1.223 ++		0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
   1.224 ++		/* round 2 */
   1.225 ++		0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
   1.226 ++		0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
   1.227 ++		0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
   1.228 ++		0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
   1.229 ++		/* round 3 */
   1.230 ++		0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
   1.231 ++		0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
   1.232 ++		0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
   1.233 ++		0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
   1.234 ++		/* round 4 */
   1.235 ++		0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
   1.236 ++		0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
   1.237 ++		0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
   1.238 ++		0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
   1.239 ++	};
   1.240 ++	static const char P_array[] ALIGN1 = {
   1.241 ++		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
   1.242 ++		1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
   1.243 ++		5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
   1.244 ++		0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9  /* 4 */
   1.245 ++	};
   1.246 ++	uint32_t *words = (void*) wbuffer;
   1.247 ++	uint32_t A = hash[0];
   1.248 ++	uint32_t B = hash[1];
   1.249 ++	uint32_t C = hash[2];
   1.250 ++	uint32_t D = hash[3];
   1.251 ++
   1.252 ++	static const char S_array[] ALIGN1 = {
   1.253 ++		7, 12, 17, 22,
   1.254 ++		5, 9, 14, 20,
   1.255 ++		4, 11, 16, 23,
   1.256 ++		6, 10, 15, 21
   1.257 ++	};
   1.258 ++	const uint32_t *pc;
   1.259 ++	const char *pp;
   1.260 ++	const char *ps;
   1.261 ++	int i;
   1.262 ++	uint32_t temp;
   1.263 ++
   1.264 ++
   1.265 ++	pc = C_array;
   1.266 ++	pp = P_array;
   1.267 ++	ps = S_array - 4;
   1.268 ++
   1.269 ++	for (i = 0; i < 64; i++) {
   1.270 ++		if ((i & 0x0f) == 0)
   1.271 ++			ps += 4;
   1.272 ++		temp = A;
   1.273 ++		switch (i >> 4) {
   1.274 ++		case 0:
   1.275 ++			temp += FF(B, C, D);
   1.276 ++			break;
   1.277 ++		case 1:
   1.278 ++			temp += FG(B, C, D);
   1.279 ++			break;
   1.280 ++		case 2:
   1.281 ++			temp += FH(B, C, D);
   1.282 ++			break;
   1.283 ++		case 3:
   1.284 ++			temp += FI(B, C, D);
   1.285 ++		}
   1.286 ++		temp += words[(int) (*pp++)] + *pc++;
   1.287 ++		temp = rotl32(temp, ps[i & 3]);
   1.288 ++		temp += B;
   1.289 ++		A = D;
   1.290 ++		D = C;
   1.291 ++		C = B;
   1.292 ++		B = temp;
   1.293 ++	}
   1.294 ++	/* Add checksum to the starting values */
   1.295 ++	hash[0] += A;
   1.296 ++	hash[1] += B;
   1.297 ++	hash[2] += C;
   1.298 ++	hash[3] += D;
   1.299 ++
   1.300 ++}
   1.301 ++#undef FF
   1.302 ++#undef FG
   1.303 ++#undef FH
   1.304 ++#undef FI
   1.305 ++
   1.306 ++/* Initialize structure containing state of computation.
   1.307 ++ * (RFC 1321, 3.3: Step 3)
   1.308 ++ */
   1.309 ++static void md5_begin(void)
   1.310 ++{
   1.311 ++	hash[0] = 0x67452301;
   1.312 ++	hash[1] = 0xefcdab89;
   1.313 ++	hash[2] = 0x98badcfe;
   1.314 ++	hash[3] = 0x10325476;
   1.315 ++	total64 = 0;
   1.316 ++}
   1.317 ++
   1.318 ++/* Used also for sha1 and sha256 */
   1.319 ++#define md5_hash common64_hash
   1.320 ++
   1.321 ++/* Process the remaining bytes in the buffer and put result from CTX
   1.322 ++ * in first 16 bytes following RESBUF.  The result is always in little
   1.323 ++ * endian byte order, so that a byte-wise output yields to the wanted
   1.324 ++ * ASCII representation of the message digest.
   1.325 ++ */
   1.326 ++#define md5_end common64_end
   1.327 ++
   1.328 ++typedef struct { char hash[16]; } md5hash;
   1.329 ++
   1.330 ++static md5hash md5sum(uint8_t *buffer, int len) 
   1.331 ++{
   1.332 ++	md5hash val;
   1.333 ++
   1.334 ++	md5_begin();
   1.335 ++	md5_hash(buffer, len);
   1.336 ++	md5_end();
   1.337 ++	memcpy(&val, hash, 16);
   1.338 ++
   1.339 ++	return val;
   1.340 ++}
   1.341  --- create_compressed_fs.c
   1.342  +++ create_compressed_fs.c
   1.343 -@@ -0,0 +1,148 @@
   1.344 +@@ -0,0 +1,203 @@
   1.345  +#ifdef FIND_BEST_COMPRESSION
   1.346  +#include <compress.h>
   1.347  +extern "C" {
   1.348 @@ -400,6 +671,8 @@
   1.349  +#define compress2(a,b,c,d,e) best_compress(a,b,c,d)
   1.350  +#endif
   1.351  +                        
   1.352 ++#include <signal.h>
   1.353 ++
   1.354  +/* Creates a compressed file */
   1.355  +#include "common_header.h"
   1.356  +
   1.357 @@ -427,16 +700,49 @@
   1.358  +	return i;
   1.359  +}
   1.360  +
   1.361 ++#ifdef FIND_BEST_COMPRESSION
   1.362 ++#include "md5sum.c"
   1.363 ++#endif
   1.364 ++
   1.365 ++static unsigned n;
   1.366 ++static unsigned long lastlen, pos, *block_index;
   1.367 ++static unsigned char *compressed;
   1.368 ++static unsigned long block_size = 0;
   1.369 ++static void flush_index(int sig)
   1.370 ++{
   1.371 ++	static char padding[512];
   1.372 ++	struct cloop_tail tail;
   1.373 ++	unsigned long len;
   1.374 ++
   1.375 ++	fprintf(stderr, "Write index for %lu blocks\n", n);
   1.376 ++	if (block_size >= 0x1000000) lastlen = 0;
   1.377 ++	tail.index_size = ntohl(sizeof(*block_index) + 256*(lastlen % 0xFFffFF));
   1.378 ++	tail.num_blocks = ntohl(n);
   1.379 ++	n *= sizeof(*block_index);
   1.380 ++	len = n + n/1000 + 12;
   1.381 ++	compressed = (unsigned char *) realloc(compressed, len);
   1.382 ++	if (!compressed || compress2(compressed, &len, (unsigned char *) block_index,
   1.383 ++				     n, Z_BEST_SPEED) != Z_OK)
   1.384 ++		quit("Index compression failed");
   1.385 ++	tail.table_size = ntohl(len);
   1.386 ++	pos += len + sizeof(tail);
   1.387 ++	n = pos & 511;
   1.388 ++	if (n) write(STDOUT_FILENO, padding, 512 - n);
   1.389 ++	write(STDOUT_FILENO, compressed, len);
   1.390 ++	write(STDOUT_FILENO, &tail, sizeof(tail));
   1.391 ++	exit(sig != 0);
   1.392 ++}
   1.393 ++
   1.394  +int main(int argc, char *argv[])
   1.395  +{
   1.396  +	struct cloop_head head;
   1.397 -+	struct cloop_tail tail;
   1.398 -+	unsigned long  block_size = 0;
   1.399 -+	unsigned char *compressed, *uncompressed;
   1.400 -+	unsigned long *index;
   1.401 -+	int n, indexmax, zlenmax;
   1.402 -+	unsigned long lastlen, len, pos;
   1.403 -+	static char padding[512];
   1.404 ++	unsigned char *uncompressed;
   1.405 ++	unsigned long len;
   1.406 ++	unsigned indexmax, zlenmax;
   1.407 ++#ifdef FIND_BEST_COMPRESSION
   1.408 ++	unsigned i, j, hashmax;
   1.409 ++	md5hash *hash;
   1.410 ++#endif
   1.411  +	
   1.412  +	if (argc > 1) {
   1.413  +		if (argv[1][0] < '0' || argv[1][0] > '9')
   1.414 @@ -457,48 +763,67 @@
   1.415  +	
   1.416  +	compressed = (unsigned char *) malloc(zlenmax);
   1.417  +	uncompressed = (unsigned char *) malloc(block_size);
   1.418 -+	index = (unsigned long *) malloc(indexmax = CHUNK);
   1.419 -+	if (!compressed || !uncompressed || !index)
   1.420 ++	block_index = (unsigned long *) malloc(indexmax = CHUNK);
   1.421 ++#ifdef FIND_BEST_COMPRESSION
   1.422 ++	hash = (md5hash *) malloc(hashmax = CHUNK);
   1.423 ++	if (!compressed || !uncompressed || !block_index || !hash)
   1.424 ++#else
   1.425 ++	if (!compressed || !uncompressed || !block_index)
   1.426 ++#endif
   1.427  +		quit("Malloc failed");
   1.428  +	
   1.429 ++	signal(SIGINT,flush_index);
   1.430 ++	signal(SIGQUIT,flush_index);
   1.431 ++	signal(SIGTERM,flush_index);
   1.432 ++
   1.433  +	for (n = 0; (len = readblock(uncompressed, block_size)) != 0; n++) {
   1.434  +		lastlen = len;
   1.435 -+		len = zlenmax;
   1.436 -+		if (compress2(compressed, &len, uncompressed, block_size, 
   1.437 -+				Z_BEST_COMPRESSION) != Z_OK)
   1.438 -+			quit("Compression failed");
   1.439 -+		fprintf(stderr, "Block %u length %lu => %lu\n",
   1.440 -+			n, block_size, len);
   1.441 -+		write(STDOUT_FILENO, compressed, len);
   1.442 -+		pos += len;
   1.443 -+		if (n * sizeof(*index) >= indexmax) {
   1.444 -+			index = (unsigned long *) realloc(index,
   1.445 ++		if (n * sizeof(*block_index) >= indexmax) {
   1.446 ++			block_index = (unsigned long *) realloc(block_index,
   1.447  +							  indexmax += CHUNK);
   1.448 -+			if (!index)
   1.449 ++			if (!block_index)
   1.450  +				quit("Realloc");
   1.451  +		}
   1.452 -+		index[n] = ntohl(len);
   1.453 ++#ifdef FIND_BEST_COMPRESSION
   1.454 ++		if (n * sizeof(*hash) >= hashmax) {
   1.455 ++			hash = (md5hash *) realloc(hash, hashmax += CHUNK);
   1.456 ++			if (!ihash)
   1.457 ++				quit("Realloc hash");
   1.458 ++		}
   1.459 ++		hash[n] = md5sum(uncompressed, len);
   1.460 ++		j = 0x7FFFFFFF;
   1.461 ++		if (n < j)
   1.462 ++			j = n;
   1.463 ++		for (i = 0; i < j; i++) {
   1.464 ++			if (* (uint32_t *) &hash[i] == * (uint32_t *) &hash[n]
   1.465 ++			    && !memcmp(&hash[i],&hash[n],sizeof(*hash)))
   1.466 ++				break;
   1.467 ++		}
   1.468 ++		if (i != j) {
   1.469 ++			block_index[n] = ntohl(0x80000000 | i);
   1.470 ++			fprintf(stderr, "Block %u length %lu => duplicate %lu\n",
   1.471 ++				n, block_size, i);
   1.472 ++		}
   1.473 ++		else
   1.474 ++#endif
   1.475 ++		{
   1.476 ++			len = zlenmax;
   1.477 ++			if (compress2(compressed, &len, uncompressed, lastlen, 
   1.478 ++					Z_BEST_SPEED) != Z_OK)
   1.479 ++				quit("Compression failed");
   1.480 ++			fprintf(stderr, "Block %u length %lu => %lu\n",
   1.481 ++				n, block_size, len);
   1.482 ++			write(STDOUT_FILENO, compressed, len);
   1.483 ++			pos += len;
   1.484 ++			block_index[n] = ntohl(len);
   1.485 ++		}
   1.486  +	}
   1.487 -+	tail.index_size = ntohl(sizeof(*index) + (lastlen & ~0x1FF));
   1.488 -+	tail.num_blocks = ntohl(n);
   1.489 -+	n *= sizeof(*index);
   1.490 -+	len = n + n/1000 + 12;
   1.491 -+	compressed = (unsigned char *) realloc(compressed, len);
   1.492 -+	if (!compressed || compress2(compressed, &len, (unsigned char *) index,
   1.493 -+				     n, Z_BEST_COMPRESSION) != Z_OK)
   1.494 -+		quit("Index compression failed");
   1.495 -+	tail.table_size = ntohl(len);
   1.496 -+	pos += len + sizeof(tail);
   1.497 -+	n = pos & 511;
   1.498 -+	if (n) write(STDOUT_FILENO, padding, 512 - n);
   1.499 -+	write(STDOUT_FILENO, compressed, len);
   1.500 -+	write(STDOUT_FILENO, &tail, sizeof(tail));
   1.501 ++	flush_index(0);
   1.502  +	return 0;
   1.503  +}
   1.504  +#ifdef FIND_BEST_COMPRESSION
   1.505  +}
   1.506  +#endif
   1.507 -
   1.508  --- fusecloop.c
   1.509  +++ fusecloop.c
   1.510  @@ -65,7 +65,7 @@