root/morphix/trunk/cloop/advancecomp-1.9_create_compressed_fs/advfs.cc

Revision 2, 7.7 kB (checked in by nextime, 2 years ago)

Initial import, branching from morphix svn

Line 
1 /* Creates a compressed image, given a file as an argument.
2  * (c)1999 Paul `Rusty' Russell.  GPL.
3  *
4  * CHANGELOG:
5  * * Sat Deb 14 22:49:20 CEST 2004 Christian Leber
6  * - Changed to work with the advancecomp packages, so that it's
7  *   better algorithms may be used
8  * * Sun Okt 26 01:05:29 CEST 2003 Klaus Knopper
9  * - Changed format of index pointers to network byte order
10  * * Sat Sep 29 2001 Klaus Knopper <knopper@knopper.net>
11  * - changed compression to Z_BEST_COMPRESSION,
12  * * Sat Jun 17 2000 Klaus Knopper <knopper@knopper.net>
13  * - Support for reading file from stdin,
14  * - Changed Preamble.
15  * * Sat Jul 28 2001 Klaus Knopper <knopper@knopper.net>
16  * - cleanup and gcc 2.96 / glibc checking
17  */
18
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <asm/byteorder.h>
25 #include <fcntl.h>
26 #include <zlib.h>
27 #include "compressed_loop.h"
28 #include "portable.h"
29 #include "pngex.h"
30 #include "utility.h"
31 #include "compress.h"
32 #include "siglock.h"
33 #include <netinet/in.h>
34
35 #include "lib/mng.h"
36 #include "lib/endianrw.h"
37
38 #include <iostream>
39 #include <iomanip>
40
41 #include <cstdio>
42
43 #define MAX_KMALLOC_SIZE 2L<<17
44
45 #define CLOOP_PREAMBLE "#!/bin/sh\n" "#V2.0 Format\n" "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n" "exit $?\n"
46
47 struct cb_list
48 {
49         struct cb_list *next;
50         size_t size;
51         char data[0];
52 };
53
54 void free_cb_list(struct cb_list *cbl)
55 {
56  if(cbl->next) free_cb_list(cbl->next);
57  free(cbl);
58 }
59
60 /* Now using the goto style because it is quicker to read */
61 static struct cb_list *create_compressed_blocks(int handle, unsigned long
62                           blocksize, unsigned long *numblocks, int method)
63 /* method==0: Use "gzip -9", method==-1: Try best (very slow). */
64 {
65  struct cb_list *cbl,**cbp=&cbl;
66  unsigned long i=0,j;
67  const int maxalg=11;
68  unsigned int last, took[maxalg];
69  unsigned long long total_uncompressed=0,total_compressed=0;
70  unsigned long maxlen = blocksize + blocksize/1000 + 12;
71  char *compressed[maxalg], *uncompressed;
72  if((uncompressed=(char *)malloc(blocksize))==NULL)
73   {
74    fprintf(stderr, "*** Can't malloc(%ld).\n",blocksize);
75    return NULL;
76   }
77  for(i=0; i<maxalg; i++) compressed[i] = (char *)malloc(maxlen), took[i]=0;
78
79  for(i=0,last=0; !last; i++)
80   {
81    int z_error;
82    unsigned long total=0;
83    unsigned len[maxalg];
84    unsigned int best;
85    //memset(compressed,0,len); memset(uncompressed,0,blocksize);
86    for(j=0; j<maxalg; j++) memset(compressed[j],0,maxlen), len[j]=maxlen;
87    memset(uncompressed,0,blocksize);
88    while(total<blocksize) /* Read a complete block */
89     {
90      ssize_t r=read(handle, uncompressed+total, blocksize-total);
91      if(r<=0) { last=1; break; }
92      total+=r;
93     }
94    total_uncompressed += total;
95    if (total != blocksize)
96     {
97      last=1;
98      fprintf(stderr, "Partial read (%lu bytes of %lu), padding with zeros.\n",
99                                         total, blocksize);
100     }
101    if(method==-1)
102     {
103      for(j=0; j<maxalg-1; j++) /* Try ZLIB compression first. */
104       {
105        if((z_error=compress2((Bytef*)compressed[j], (uLongf*)&len[j], (Bytef*)uncompressed, blocksize, j)) != Z_OK)
106         {
107          fprintf(stderr, "*** Error %d compressing block %lu! (compressed=%p, len=%lu, uncompressed=%p, blocksize=%lu)\n", z_error, i, compressed,len,uncompressed,blocksize);
108          goto error_free_cb_list;
109         }
110       }
111
112      /* Try 7ZIP compression now. */
113      if(!compress_zlib(shrink_extreme, (unsigned char *)compressed[maxalg-1], len[maxalg-1], (unsigned char *)uncompressed, blocksize))
114       {
115        fprintf(stderr, "*** Error %d compressing block %lu! (compressed=%p, len=%lu, uncompressed=%p, blocksize=%lu)\n", z_error, i, compressed,len,uncompressed,blocksize);
116        goto error_free_cb_list;
117       }
118  
119      for(best=0,j=1; j<maxalg; j++)
120       {
121        if(len[best] >= len[j]) best=j;
122       }
123     } /* COMPRESSION_BEST */
124    else
125     {
126      best=Z_BEST_COMPRESSION;
127      if((z_error=compress2((Bytef*)compressed[best], (uLongf*)&len[best], (Bytef*)uncompressed, blocksize, best)) != Z_OK)
128       {
129        fprintf(stderr, "*** Error %d compressing block %lu! (compressed=%p, len=%lu, uncompressed=%p, blocksize=%lu)\n", z_error, i, compressed,len,uncompressed,blocksize);
130        goto error_free_cb_list;
131       }
132     }
133    ++took[best]; 
134    
135    if((*cbp = (cb_list *)malloc(sizeof(struct cb_list)+len[best]))==NULL) /* get another block */
136     {
137      fprintf(stderr, "*** Out of memory allocating block ptrs (virtual memory exhausted).\n");
138      goto error_free_cb_list;
139     }
140    total_compressed+=len[best];
141    /* Print status */
142    fprintf(stderr, "[%2d] Block# %5lu size %6lu -> %6lu [compression ratio %3lu%%, overall: %3Lu%%]\n", best, i, total, len[best], total>0?((len[best]*100)/total):100,total_uncompressed>0?((total_compressed*100)/total_uncompressed):100);
143    (*cbp)->size = len[best];
144    memcpy((*cbp)->data, compressed[best], len[best]);
145    (*cbp)->next=NULL;
146    cbp=&((*cbp)->next);
147   } /* for */
148  goto free_compressed;
149
150  error_free_cb_list:
151     if(cbl) { free_cb_list(cbl); cbl=NULL; i=0; }
152
153  free_compressed:
154     for(j=0; j<maxalg; j++) free(compressed[j]);
155  free_uncompressed:
156     free(uncompressed);
157  
158  *numblocks=i;
159  fprintf(stderr,"\nStatistics:\n");
160  for(j=0; j<maxalg-1; j++) fprintf(stderr,"gzip(%d): %5d (%5.2g%%)\n", j, took[j], 100.0F*(float)took[j]/(float)i);
161  fprintf(stderr,"7zip: %5d (%5.2g%%)\n\n", took[maxalg-1], 100.0F*(float)took[maxalg-1]/(float)i);
162  return cbl;
163 }
164
165 int usage(char *progname)
166 {
167  fprintf(stderr, "Usage: %s [-b|--best] filename blocksize(bytes).\n",progname);
168  fprintf(stderr, "Use '-' as filename for stdin.\n");
169  return 1;
170 }
171
172 int main(int argc, char **argv)
173 {
174  int in=-1;
175  unsigned long blocksize=0,b;
176  struct cloop_head head;
177  unsigned long numblocks;
178  unsigned long long bytes_so_far;
179  unsigned long i;
180  int method=0;
181  struct cb_list *compressed_blocks,*cbp;
182
183  if(argc<3) return usage(argv[0]);
184
185  for(i=1;i<argc;i++)
186   {
187    if(!(strcmp(argv[i],"-b")&&strcmp(argv[i],"--best"))) method=-1;
188    else if((b=atoi(argv[i]))>0) blocksize=b;
189    else if(in<0) in=strcmp(argv[i],"-")==0?dup(fileno(stdin)):open(argv[i], O_RDONLY);
190    else
191     {
192      return usage(argv[0]);
193     }
194   }
195
196  if (blocksize == 0 || blocksize % 512 != 0)
197   {
198    fprintf(stderr, "*** Blocksize must be a multiple of 512.\n");
199    return 1;
200   }
201
202  if (blocksize > MAX_KMALLOC_SIZE)
203   {
204    fprintf(stderr, "WARNING: Blocksize %lu may be too big for a kmalloc() (%lu max).\n",blocksize,MAX_KMALLOC_SIZE);
205    sleep(2);
206   }
207
208  if (sizeof(CLOOP_PREAMBLE) > CLOOP_HEADROOM)
209   {
210    fprintf(stderr, "*** Preamble (%u chars) > headroom (%u)\n",
211                         sizeof(CLOOP_PREAMBLE), CLOOP_HEADROOM);
212    return 1;
213   }
214                
215  if (in < 0)
216   {
217    perror("Opening input");
218    return 1;
219   }
220
221  compressed_blocks = create_compressed_blocks(in, blocksize, &numblocks, method);
222
223  close(in);
224
225  memset(head.preamble, 0, sizeof(head.preamble));
226  memcpy(head.preamble, CLOOP_PREAMBLE, sizeof(CLOOP_PREAMBLE));
227  head.block_size = htonl(blocksize);
228  head.num_blocks = htonl(numblocks);
229
230  fprintf(stderr, "Block size %lu, number of blocks %lu.\n",
231          blocksize, numblocks);
232
233  bytes_so_far = sizeof(head) + sizeof(loff_t) * (numblocks + 1);
234
235  /* Write out head... */
236  write(STDOUT_FILENO, &head, sizeof(head));
237
238  if (!compressed_blocks) return 1;
239
240  /* Write offsets */
241  for (i=0,cbp=compressed_blocks; i < numblocks+1; i++)
242   {
243    loff_t tmp;
244    tmp = __cpu_to_be64(bytes_so_far);
245    write(STDOUT_FILENO, &tmp, sizeof(tmp));
246    if(cbp) { bytes_so_far += cbp->size; cbp=cbp->next; }
247   }
248
249  /* Now write blocks and free them. */
250  for (i = 0, cbp=compressed_blocks; cbp && i < numblocks; i++)
251   {
252    if (write(STDOUT_FILENO, cbp->data, cbp->size) != cbp->size)
253     {
254      perror("writing block");
255      free_cb_list(compressed_blocks);
256      return 1;
257     }
258    cbp=cbp->next;
259    free(compressed_blocks); compressed_blocks=cbp;
260   }
261  fprintf(stderr,"Done.\n");
262  return 0;
263 }
Note: See TracBrowser for help on using the browser.