/* Creates a compressed image, given a file as an argument. * (c)1999 Paul `Rusty' Russell. GPL. * * CHANGELOG: * * Sun Okt 26 01:05:29 CEST 2003 Klaus Knopper * - Changed format of index pointers to network byte order * * Sat Sep 29 2001 Klaus Knopper * - changed compression to Z_BEST_COMPRESSION, * * Sat Jun 17 2000 Klaus Knopper * - Support for reading file from stdin, * - Changed Preamble. * * Sat Jul 28 2001 Klaus Knopper * - cleanup and gcc 2.96 / glibc checking */ #include #include #include #include #include #if defined(__FreeBSD__) #include #include typedef uint64_t loff_t; #ifndef htobe64 static __inline __uint64_t __bswap64(__uint64_t _x) { return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) | ((_x >> 8) & 0xff000000) | ((_x << 8) & ((__uint64_t)0xff << 32)) | ((_x << 24) & ((__uint64_t)0xff << 40)) | ((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56))); } #if BYTE_ORDER == LITTLE_ENDIAN #define htobe64(x) __bswap64(x) #else #define htobe64(x) #endif #endif #define __cpu_to_be64 htobe64 #else #include #if BYTE_ORDER == LITTLE_ENDIAN #include #else #include #endif #endif #include #include #include #include "cloop.h" #define MAX_KMALLOC_SIZE 2L<<17 #define CLOOP_PREAMBLE "#!/bin/sh\n#" CLOOP4_SIGNATURE " Format\n" "insmod cloop.ko file=$0 && mount -r -t iso9660 /dev/cloop $1\n" "exit $?\n" struct cb_list { struct cb_list *next; size_t size; int compress_type; char data[0]; }; void free_cb_list(struct cb_list *cbl) { if(cbl->next) free_cb_list(cbl->next); free(cbl); } /* Now using the goto style because it is quicker to read */ static struct cb_list *create_compressed_blocks(int handle, unsigned long blocksize, unsigned long *numblocks) { struct cb_list *cbl,**cbp=&cbl; unsigned long i=0; unsigned int last; unsigned long long total_uncompressed=0,total_compressed=0; unsigned long maxlen = LZ4_compressBound(blocksize); char *compressed, *uncompressed; if((uncompressed=malloc(blocksize))==NULL) { fprintf(stderr, "*** Can't malloc(%ld).\n",blocksize); return NULL; } if((compressed=malloc(maxlen))==NULL) { fprintf(stderr, "*** Can't malloc(%ld).\n",blocksize); goto free_uncompressed; } for(i=0,last=0; !last; i++) { int z_error; unsigned long total=0, len = maxlen; memset(compressed,0,len); memset(uncompressed,0,blocksize); while(total %6lu [compression ratio %3lu%%, overall: %3Lu%%]\n", i, total, len, total>0?((len*100)/total):100,total_uncompressed>0?((total_compressed*100)/total_uncompressed):100); (*cbp)->size = len; memcpy((*cbp)->data, compressed, len); (*cbp)->next=NULL; cbp=&((*cbp)->next); } /* for */ goto free_compressed; error_free_cb_list: if(cbl) { free_cb_list(cbl); cbl=NULL; i=0; } free_compressed: free(compressed); free_uncompressed: free(uncompressed); *numblocks=i; return cbl; } int main(int argc, char **argv) { int in; unsigned long blocksize; struct cloop_head head; unsigned long numblocks; unsigned long long bytes_so_far; unsigned long i; struct cb_list *compressed_blocks,*cbp; if (argc != 3) { fprintf(stderr, "Usage: %s filename blocksize(bytes).\n",argv[0]); fprintf(stderr, "Use '-' as filename for stdin.\n"); return 1; } blocksize = atoi(argv[2]); if (blocksize == 0 || blocksize % 512 != 0) { fprintf(stderr, "*** Blocksize must be a multiple of 512.\n"); return 1; } if (blocksize > MAX_KMALLOC_SIZE) { fprintf(stderr, "WARNING: Blocksize %lu may be too big for a kmalloc() (%lu max).\n",blocksize,MAX_KMALLOC_SIZE); sleep(2); } if (sizeof(CLOOP_PREAMBLE) > CLOOP_HEADROOM) { fprintf(stderr, "*** Preamble (%u chars) > headroom (%u)\n", sizeof(CLOOP_PREAMBLE), CLOOP_HEADROOM); return 1; } in=strcmp(argv[1],"-")==0?dup(fileno(stdin)):open(argv[1], O_RDONLY); if (in < 0) { perror("Opening input"); return 1; } compressed_blocks = create_compressed_blocks(in, blocksize, &numblocks); close(in); memset(head.preamble, 0, sizeof(head.preamble)); memcpy(head.preamble, CLOOP_PREAMBLE, sizeof(CLOOP_PREAMBLE)); head.block_size = htonl(blocksize); head.num_blocks = htonl(numblocks); fprintf(stderr, "Block size %lu, number of blocks %lu.\n", blocksize, numblocks); bytes_so_far = sizeof(head) + sizeof(loff_t) * (numblocks + 1); /* Write out head... */ write(STDOUT_FILENO, &head, sizeof(head)); if (!compressed_blocks) return 1; /* Write offsets */ for (i=0,cbp=compressed_blocks; i < numblocks+1; i++) { cloop_block_ptr tmp = __cpu_to_be64((uint64_t)CLOOP_COMPRESSOR_LZ4 << 60 | bytes_so_far); write(STDOUT_FILENO, &tmp, sizeof(tmp)); if(cbp) { bytes_so_far += cbp->size; cbp=cbp->next; } } /* Now write blocks and free them. */ for (i = 0, cbp=compressed_blocks; cbp && i < numblocks; i++) { if (write(STDOUT_FILENO, cbp->data, cbp->size) != cbp->size) { perror("writing block"); free_cb_list(compressed_blocks); return 1; } cbp=cbp->next; free(compressed_blocks); compressed_blocks=cbp; } #if defined(__FreeBSD__) /* * FreeBSD requires padding to 512 byte boundary */ bytes_so_far = lseek(STDOUT_FILENO, 0, SEEK_END); if (bytes_so_far % 512) { static char padding[512]; off_t len = 512 - bytes_so_far % 512; if (write(STDOUT_FILENO, padding, len) != len) { perror("writing padding block"); return 1; } } #endif fprintf(stderr,"Done.\n"); return 0; }