root/morphix/trunk/cloop/create_compressed_fs.c

Revision 2, 6.4 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  * * Sun Okt 26 01:05:29 CEST 2003 Klaus Knopper
6  * - Changed format of index pointers to network byte order
7  * * Sat Sep 29 2001 Klaus Knopper <knopper@knopper.net>
8  * - changed compression to Z_BEST_COMPRESSION,
9  * * Sat Jun 17 2000 Klaus Knopper <knopper@knopper.net>
10  * - Support for reading file from stdin,
11  * - Changed Preamble.
12  * * Sat Jul 28 2001 Klaus Knopper <knopper@knopper.net>
13  * - cleanup and gcc 2.96 / glibc checking
14  */
15
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/stat.h>
21 #if defined(__FreeBSD__)
22 #include <sys/endian.h>
23 #include <netinet/in.h>
24 typedef uint64_t loff_t;
25 #ifndef htobe64
26 static __inline __uint64_t
27 __bswap64(__uint64_t _x)
28 {
29
30         return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) |
31             ((_x >> 8) & 0xff000000) | ((_x << 8) & ((__uint64_t)0xff << 32)) |
32             ((_x << 24) & ((__uint64_t)0xff << 40)) |
33             ((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56)));
34 }
35 #if BYTE_ORDER == LITTLE_ENDIAN
36 #define htobe64(x)      __bswap64(x)
37 #else
38 #define htobe64(x)
39 #endif
40 #endif
41 #define __cpu_to_be64 htobe64
42 #else
43 #include <asm/byteorder.h>
44 #endif
45 #include <fcntl.h>
46 #include <zlib.h>
47 #include "compressed_loop.h"
48
49 #define MAX_KMALLOC_SIZE 2L<<17
50
51 #define CLOOP_PREAMBLE "#!/bin/sh\n" "#V2.0 Format\n" "insmod cloop.o file=$0 && mount -r -t iso9660 /dev/cloop $1\n" "exit $?\n"
52
53 struct cb_list
54 {
55         struct cb_list *next;
56         size_t size;
57         char data[0];
58 };
59
60 void free_cb_list(struct cb_list *cbl)
61 {
62  if(cbl->next) free_cb_list(cbl->next);
63  free(cbl);
64 }
65
66 /* Now using the goto style because it is quicker to read */
67 static struct cb_list *create_compressed_blocks(int handle, unsigned long
68                           blocksize, unsigned long *numblocks)
69 {
70  struct cb_list *cbl,**cbp=&cbl;
71  unsigned long i=0;
72  unsigned int last;
73  unsigned long long total_uncompressed=0,total_compressed=0;
74  unsigned long maxlen = blocksize + blocksize/1000 + 12;
75  char *compressed, *uncompressed;
76  if((uncompressed=malloc(blocksize))==NULL)
77   {
78    fprintf(stderr, "*** Can't malloc(%ld).\n",blocksize);
79    return NULL;
80   }
81  if((compressed=malloc(maxlen))==NULL)
82   {
83    fprintf(stderr, "*** Can't malloc(%ld).\n",blocksize);
84    goto free_uncompressed;
85   }
86  for(i=0,last=0; !last; i++)
87   {
88    int z_error;
89    unsigned long total=0, len = maxlen;
90    memset(compressed,0,len); memset(uncompressed,0,blocksize);
91    while(total<blocksize) /* Read a complete block */
92     {
93      ssize_t r=read(handle, uncompressed+total, blocksize-total);
94      if(r<=0) { last=1; break; }
95      total+=r;
96     }
97    total_uncompressed += total;
98    if (total != blocksize)
99     {
100      last=1;
101      fprintf(stderr, "Partial read (%lu bytes of %lu), padding with zeros.\n",
102                                         total, blocksize);
103     }
104    if((z_error=compress2(compressed, &len, uncompressed, blocksize, Z_BEST_COMPRESSION)) != Z_OK)
105     {
106      fprintf(stderr, "*** Error %d compressing block %lu! (compressed=%p, len=%lu, uncompressed=%p, blocksize=%lu)\n", z_error, i, compressed,len,uncompressed,blocksize);
107      goto error_free_cb_list;
108     }
109    if((*cbp = malloc(sizeof(struct cb_list)+len))==NULL) /* get another block */
110     {
111      fprintf(stderr, "*** Out of memory allocating block ptrs (virtual memory exhausted).\n");
112      goto error_free_cb_list;
113     }
114    total_compressed+=len;
115    /* Print status */
116    fprintf(stderr, "Block# %5lu size %6lu -> %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);
117    (*cbp)->size = len;
118    memcpy((*cbp)->data, compressed, len);
119    (*cbp)->next=NULL;
120    cbp=&((*cbp)->next);
121   } /* for */
122  goto free_compressed;
123
124  error_free_cb_list:
125     if(cbl) { free_cb_list(cbl); cbl=NULL; i=0; }
126
127  free_compressed:
128     free(compressed);
129  free_uncompressed:
130     free(uncompressed);
131  
132  *numblocks=i;
133  return cbl;
134 }
135
136 int main(int argc, char **argv)
137 {
138  int in;
139  unsigned long blocksize;
140  struct cloop_head head;
141  unsigned long numblocks;
142  unsigned long long bytes_so_far;
143  unsigned long i;
144  struct cb_list *compressed_blocks,*cbp;
145
146  if (argc != 3)
147   {
148    fprintf(stderr, "Usage: %s filename blocksize(bytes).\n",argv[0]);
149    fprintf(stderr, "Use '-' as filename for stdin.\n");
150    return 1;
151   }
152
153  blocksize = atoi(argv[2]);
154  if (blocksize == 0 || blocksize % 512 != 0)
155   {
156    fprintf(stderr, "*** Blocksize must be a multiple of 512.\n");
157    return 1;
158   }
159
160  if (blocksize > MAX_KMALLOC_SIZE)
161   {
162    fprintf(stderr, "WARNING: Blocksize %lu may be too big for a kmalloc() (%lu max).\n",blocksize,MAX_KMALLOC_SIZE);
163    sleep(2);
164   }
165
166  if (sizeof(CLOOP_PREAMBLE) > CLOOP_HEADROOM)
167   {
168    fprintf(stderr, "*** Preamble (%u chars) > headroom (%u)\n",
169                         sizeof(CLOOP_PREAMBLE), CLOOP_HEADROOM);
170    return 1;
171   }
172                
173  in=strcmp(argv[1],"-")==0?dup(fileno(stdin)):open(argv[1], O_RDONLY);
174
175  if (in < 0)
176   {
177    perror("Opening input");
178    return 1;
179   }
180
181  compressed_blocks = create_compressed_blocks(in, blocksize, &numblocks);
182
183  close(in);
184
185  memset(head.preamble, 0, sizeof(head.preamble));
186  memcpy(head.preamble, CLOOP_PREAMBLE, sizeof(CLOOP_PREAMBLE));
187  head.block_size = htonl(blocksize);
188  head.num_blocks = htonl(numblocks);
189
190  fprintf(stderr, "Block size %lu, number of blocks %lu.\n",
191          blocksize, numblocks);
192
193  bytes_so_far = sizeof(head) + sizeof(loff_t) * (numblocks + 1);
194
195  /* Write out head... */
196  write(STDOUT_FILENO, &head, sizeof(head));
197
198  if (!compressed_blocks) return 1;
199
200  /* Write offsets */
201  for (i=0,cbp=compressed_blocks; i < numblocks+1; i++)
202   {
203    loff_t tmp;
204    tmp = __cpu_to_be64(bytes_so_far);
205    write(STDOUT_FILENO, &tmp, sizeof(tmp));
206    if(cbp) { bytes_so_far += cbp->size; cbp=cbp->next; }
207   }
208
209  /* Now write blocks and free them. */
210  for (i = 0, cbp=compressed_blocks; cbp && i < numblocks; i++)
211   {
212    if (write(STDOUT_FILENO, cbp->data, cbp->size) != cbp->size)
213     {
214      perror("writing block");
215      free_cb_list(compressed_blocks);
216      return 1;
217     }
218    cbp=cbp->next;
219    free(compressed_blocks); compressed_blocks=cbp;
220   }
221 #if defined(__FreeBSD__)
222  /*
223   * FreeBSD requires padding to 512 byte boundary
224   */
225  bytes_so_far = lseek(STDOUT_FILENO, 0, SEEK_END);
226  if (bytes_so_far % 512)
227   {
228    static char padding[512];
229    off_t len = 512 - bytes_so_far % 512;
230
231    if (write(STDOUT_FILENO, padding, len) != len)
232     {
233      perror("writing padding block");
234      return 1;
235     }
236   }
237 #endif
238  fprintf(stderr,"Done.\n");
239  return 0;
240 }
Note: See TracBrowser for help on using the browser.