|
|
1.1 root 1: /*
2:
3: Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
4: Kai Uwe Rommel and Igor Mandrichenko.
5: Permission is granted to any individual or institution to use, copy, or
6: redistribute this software so long as all of the original files are included
7: unmodified, that it is not sold for profit, and that this copyright notice
8: is retained.
9:
10: */
11:
12: /*
13: * zipsplit.c by Mark Adler.
14: */
15:
16: #define UTIL
17: #include "revision.h"
18: #include "zip.h"
19: #include <signal.h>
20:
21: #define DEFSIZ 36000L /* Default split size (change in help() too) */
22: #ifdef MSDOS
23: # define NL 2 /* Number of bytes written for a \n */
24: #else /* !MSDOS */
25: # define NL 1 /* Number of bytes written for a \n */
26: #endif /* ?MSDOS */
27: #define INDEX "zipsplit.idx" /* Name of index file */
28:
29:
30: /* Local functions */
31: #ifdef PROTO
32: local void handler(int);
33: local void license(void);
34: local void help(void);
35: local extent simple(ulg *, extent, ulg, ulg);
36: local int descmp(voidp *, voidp *);
37: local extent greedy(ulg *, extent, ulg, ulg);
38: void main(int, char **);
39: #endif /* PROTO */
40:
41:
42: /* Output zip files */
43: local char template[16]; /* name template for output files */
44: local int zipsmade = 0; /* number of zip files made */
45: local int indexmade = 0; /* true if index file made */
46: local char *path = NULL; /* space for full name */
47: local char *name; /* where name goes in path[] */
48:
49:
50: void err(c, h)
51: int c; /* error code from the ZE_ class */
52: char *h; /* message about how it happened */
53: /* Issue a message for the error, clean up files and memory, and exit. */
54: {
55: if (PERR(c))
56: perror("zipsplit error");
57: fprintf(stderr, "zipsplit error: %s (%s)\n", errors[c-1], h);
58: if (indexmade)
59: {
60: strcpy(name, INDEX);
61: destroy(path);
62: }
63: for (; zipsmade; zipsmade--)
64: {
65: sprintf(name, template, zipsmade);
66: destroy(path);
67: }
68: if (path != NULL)
69: free((voidp *)path);
70: if (zipfile != NULL)
71: free((voidp *)zipfile);
72: #ifdef VMS
73: exit(0);
74: #else /* !VMS */
75: exit(c);
76: #endif /* ?VMS */
77: }
78:
79:
80:
81: local void handler(s)
82: int s; /* signal number (ignored) */
83: /* Upon getting a user interrupt, abort cleanly using err(). */
84: {
85: #ifndef MSDOS
86: putc('\n', stderr);
87: #endif /* !MSDOS */
88: err(ZE_ABORT, "aborting");
89: s++; /* keep some compilers happy */
90: }
91:
92:
93: void warn(a, b)
94: char *a, *b; /* message strings juxtaposed in output */
95: /* Print a warning message to stderr and return. */
96: {
97: fprintf(stderr, "zipsplit warning: %s%s\n", a, b);
98: }
99:
100:
101: local void license()
102: /* Print license information to stdout. */
103: {
104: extent i; /* counter for copyright array */
105:
106: for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
107: printf(copyright[i], "zipsplit");
108: putchar('\n');
109: }
110: for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
111: puts(disclaimer[i]);
112: }
113:
114:
115: local void help()
116: /* Print help (along with license info) to stdout. */
117: {
118: extent i; /* counter for help array */
119:
120: /* help array */
121: static char *text[] = {
122: "",
123: "ZipSplit %d.%d (%s)",
124: "Usage: zipsplit [-ti] [-n size] [-b path] zipfile",
125: " -t report how many files it will take, but don't make them",
126: " -i make index (zipsplit.idx) and count its size against first zip file",
127: " -n make zip files no larger than \"size\" (default = 36000)",
128: " -b use \"path\" for the output zip files",
129: " -s do a sequential split even if it takes more zip files",
130: " -h show this help -L show software license"
131: };
132:
133: for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
134: printf(copyright[i], "zipsplit");
135: putchar('\n');
136: }
137: for (i = 0; i < sizeof(text)/sizeof(char *); i++)
138: {
139: printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
140: putchar('\n');
141: }
142: }
143:
144:
145: local extent simple(a, n, c, d)
146: ulg *a; /* items to put in bins, return value: destination bins */
147: extent n; /* number of items */
148: ulg c; /* capacity of each bin */
149: ulg d; /* amount to deduct from first bin */
150: /* Return the number of bins of capacity c that are needed to contain the
151: integers in a[0..n-1] placed sequentially into the bins. The value d
152: is deducted initially from the first bin (space for index). The entries
153: in a[] are replaced by the destination bins. */
154: {
155: extent k; /* current bin number */
156: ulg t; /* space used in current bin */
157:
158: t = k = 0;
159: while (n--)
160: {
161: if (*a + t > c - (k == 0 ? d : 0))
162: {
163: k++;
164: t = 0;
165: }
166: t += *a;
167: *(ulg huge *)a++ = k;
168: }
169: return k + 1;
170: }
171:
172:
173: local int descmp(a, b)
174: voidp *a, *b; /* pointers to pointers to ulg's to compare */
175: /* Used by qsort() in greedy() to do a descending sort. */
176: {
177: return **(ulg **)a < **(ulg **)b ? 1 : (**(ulg **)a > **(ulg **)b ? -1 : 0);
178: }
179:
180:
181: local extent greedy(a, n, c, d)
182: ulg *a; /* items to put in bins, return value: destination bins */
183: extent n; /* number of items */
184: ulg c; /* capacity of each bin */
185: ulg d; /* amount to deduct from first bin */
186: /* Return the number of bins of capacity c that are needed to contain the
187: items with sizes a[0..n-1] placed non-sequentially into the bins. The
188: value d is deducted initially from the first bin (space for index).
189: The entries in a[] are replaced by the destination bins. */
190: {
191: ulg *b; /* space left in each bin (malloc'ed for each m) */
192: ulg *e; /* copy of argument a[] (malloc'ed) */
193: extent i; /* steps through items */
194: extent j; /* steps through bins */
195: extent k; /* best bin to put current item in */
196: extent m; /* current number of bins */
197: ulg **s; /* pointers to e[], sorted descending (malloc'ed) */
198: ulg t; /* space left in best bin (index k) */
199:
200: /* Algorithm:
201: 1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
202: descending order.
203: 2. Compute total of s[] and set m to the smallest number of bins of
204: capacity c that can hold the total.
205: 3. Allocate m bins.
206: 4. For each item in s[], starting with the largest, put it in the
207: bin with the smallest current capacity greater than or equal to the
208: item's size. If no bin has enough room, increment m and go to step 4.
209: 5. Else, all items ended up in a bin--return m.
210: */
211:
212: /* Copy a[] to e[], put pointers to e[] in s[], and sort s[]. Also compute
213: the initial number of bins (minus 1). */
214: if ((e = (ulg *)malloc(n * sizeof(ulg))) == NULL ||
215: (s = (ulg **)malloc(n * sizeof(ulg *))) == NULL)
216: {
217: if (e != NULL)
218: free((voidp *)e);
219: err(ZE_MEM, "was trying a smart split");
220: return 0; /* only to make compiler happy */
221: }
222: memcpy((char *)e, (char *)a, n * sizeof(ulg));
223: for (t = i = 0; i < n; i++)
224: t += *(s[i] = e + i);
225: m = (extent)((t + c - 1) / c) - 1; /* pre-decrement for loop */
226: qsort((char *)s, n, sizeof(ulg *), descmp);
227:
228: /* Stuff bins until successful */
229: do {
230: /* Increment the number of bins, allocate and initialize bins */
231: if ((b = (ulg *)malloc(++m * sizeof(ulg))) == NULL)
232: {
233: free((voidp *)s);
234: free((voidp *)e);
235: err(ZE_MEM, "was trying a smart split");
236: }
237: b[0] = c - d; /* leave space in first bin */
238: for (j = 1; j < m; j++)
239: b[j] = c;
240:
241: /* Fill the bins greedily */
242: for (i = 0; i < n; i++)
243: {
244: /* Find smallest bin that will hold item i (size s[i]) */
245: t = c + 1;
246: for (k = j = 0; j < m; j++)
247: if (*s[i] <= b[j] && b[j] < t)
248: t = b[k = j];
249:
250: /* If no bins big enough for *s[i], try next m */
251: if (t == c + 1)
252: break;
253:
254: /* Diminish that bin and save where it goes */
255: b[k] -= *s[i];
256: a[(int)((ulg huge *)(s[i]) - (ulg huge *)e)] = k;
257: }
258:
259: /* Clean up */
260: free((voidp *)b);
261:
262: /* Do until all items put in a bin */
263: } while (i < n);
264:
265: /* Done--clean up and return the number of bins needed */
266: free((voidp *)s);
267: free((voidp *)e);
268: return m;
269: }
270:
271:
272: void main(argc, argv)
273: int argc; /* number of tokens in command line */
274: char **argv; /* command line tokens */
275: /* Split a zip file into several zip files less than a specified size. See
276: the command help in help() above. */
277: {
278: ulg *a; /* malloc'ed list of sizes, dest bins */
279: extent *b; /* heads of bin linked lists (malloc'ed) */
280: ulg c; /* bin capacity, start of central directory */
281: int d; /* if true, just report the number of disks */
282: FILE *e; /* input zip file */
283: FILE *f; /* output index and zip files */
284: extent g; /* number of bins from greedy(), entry to write */
285: int h; /* how to split--true means simple split, counter */
286: ulg i; /* size of index file or zero if none */
287: extent j; /* steps through zip entries, bins */
288: int k; /* next argument type */
289: ulg *p; /* malloc'ed list of sizes, dest bins for greedy() */
290: char *q; /* steps through option characters */
291: int r; /* temporary variable, counter */
292: extent s; /* number of bins needed */
293: ulg t; /* total of sizes, end of central directory */
294: struct zlist far **w; /* malloc'ed table for zfiles linked list */
295: int x; /* if true, make an index file */
296: struct zlist far *z; /* steps through zfiles linked list */
297:
298:
299: /* If no args, show help */
300: if (argc == 1)
301: {
302: help();
303: exit(0);
304: }
305:
306: init_upper(); /* build case map table */
307:
308: /* Go through args */
309: signal(SIGINT, handler);
310: signal(SIGTERM, handler);
311: k = h = x = d = 0;
312: c = DEFSIZ;
313: for (r = 1; r < argc; r++)
314: if (*argv[r] == '-')
315: if (argv[r][1])
316: for (q = argv[r]+1; *q; q++)
317: switch(*q)
318: {
319: case 'b': /* Specify path for output files */
320: if (k)
321: err(ZE_PARMS, "options are separate and precede zip file");
322: else
323: k = 1; /* Next non-option is path */
324: break;
325: case 'h': /* Show help */
326: help(); exit(0);
327: case 'i': /* Make an index file */
328: x = 1;
329: break;
330: case 'l': case 'L': /* Show copyright and disclaimer */
331: license(); exit(0);
332: case 'n': /* Specify maximum size of resulting zip files */
333: if (k)
334: err(ZE_PARMS, "options are separate and precede zip file");
335: else
336: k = 2; /* Next non-option is size */
337: break;
338: case 's':
339: h = 1; /* Only try simple */
340: break;
341: case 't': /* Just report number of disks */
342: d = 1;
343: break;
344: default:
345: err(ZE_PARMS, "unknown option");
346: }
347: else
348: err(ZE_PARMS, "zip file cannot be stdin");
349: else
350: if (k == 0)
351: if (zipfile == NULL)
352: {
353: if ((zipfile = ziptyp(argv[r])) == NULL)
354: err(ZE_MEM, "was processing arguments");
355: }
356: else
357: err(ZE_PARMS, "can only specify one zip file");
358: else if (k == 1)
359: {
360: tempath = argv[r];
361: k = 0;
362: }
363: else /* k must be 2 */
364: {
365: if ((c = (ulg)atol(argv[r])) < 100) /* 100 is smallest zip file */
366: err(ZE_PARMS, "invalid size given");
367: k = 0;
368: }
369: if (zipfile == NULL)
370: err(ZE_PARMS, "need to specify zip file");
371:
372:
373: /* Read zip file */
374: if ((r = readzipfile()) != ZE_OK)
375: err(r, zipfile);
376: if (zfiles == NULL)
377: err(ZE_NAME, zipfile);
378:
379: /* Make a list of sizes and check against capacity. Also compute the
380: size of the index file. */
381: c -= ENDHEAD + 4; /* subtract overhead/zipfile */
382: if ((a = (ulg *)malloc(zcount * sizeof(ulg))) == NULL ||
383: (w = (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) ==
384: NULL)
385: {
386: if (a != NULL)
387: free((voidp *)a);
388: err(ZE_MEM, "was computing split");
389: return;
390: }
391: i = t = 0;
392: for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
393: {
394: w[j] = z;
395: if (x)
396: i += z->nam + 6 + NL;
397: t += a[j] = 8 + LOCHEAD + CENHEAD +
398: 2 * (ulg)z->nam + 2 * (ulg)z->ext + z->com + z->siz;
399: if (a[j] > c)
400: {
401: free((voidp *)w); free((voidp *)a);
402: err(ZE_BIG, z->zname);
403: }
404: }
405:
406: /* Decide on split to use, report number of files */
407: if (h)
408: s = simple(a, zcount, c, i);
409: else
410: {
411: if ((p = (ulg *)malloc(zcount * sizeof(ulg))) == NULL)
412: {
413: free((voidp *)w); free((voidp *)a);
414: err(ZE_MEM, "was computing split");
415: }
416: memcpy((char *)p, (char *)a, zcount * sizeof(ulg));
417: s = simple(a, zcount, c, i);
418: g = greedy(p, zcount, c, i);
419: if (s <= g)
420: free((voidp *)p);
421: else
422: {
423: free((voidp *)a);
424: a = p;
425: s = g;
426: }
427: }
428: printf("%d zip files w%s be made (%d%% efficiency)\n",
429: s, d ? "ould" : "ill", ((200 * ((t + c - 1)/c)) / s + 1) >> 1);
430: if (d)
431: {
432: free((voidp *)w); free((voidp *)a);
433: free((voidp *)zipfile);
434: zipfile = NULL;
435: return;
436: }
437:
438: /* Set up path for output files */
439: if ((path = malloc(tempath == NULL ? 13 : strlen(tempath) + 14)) == NULL)
440: err(ZE_MEM, "was making output file names");
441: if (tempath == NULL)
442: name = path;
443: else
444: {
445: strcpy(path, tempath);
446: if (path[0] && path[strlen(path) - 1] != '/')
447: strcat(path, "/");
448: name = path + strlen(path);
449: }
450:
451: /* Write the index file */
452: if (x)
453: {
454: strcpy(name, INDEX);
455: printf("creating %s\n", path);
456: indexmade = 1;
457: if ((f = fopen(path, "w")) == NULL)
458: {
459: free((voidp *)w); free((voidp *)a);
460: err(ZE_CREAT, path);
461: }
462: for (j = 0; j < zcount; j++)
463: fprintf(f, "%5ld %s\n", a[j] + 1, w[j]->zname);
464: if ((j = ferror(f)) != 0 || fclose(f))
465: {
466: if (j)
467: fclose(f);
468: free((voidp *)w); free((voidp *)a);
469: err(ZE_WRITE, path);
470: }
471: }
472:
473: /* Make linked lists of results */
474: if ((b = (extent *)malloc(s * sizeof(extent))) == NULL)
475: {
476: free((voidp *)w); free((voidp *)a);
477: err(ZE_MEM, "was computing split");
478: }
479: for (j = 0; j < s; j++)
480: b[j] = (extent)-1;
481: j = zcount;
482: while (j--)
483: {
484: g = (extent)a[j];
485: a[j] = b[g];
486: b[g] = j;
487: }
488:
489: /* Make a name template for the zip files that is eight or less characters
490: before the .zip, and that will not overwrite the original zip file. */
491: for (k = 1, j = s; j >= 10; j /= 10)
492: k++;
493: if (k > 7)
494: {
495: free((voidp *)b); free((voidp *)w); free((voidp *)a);
496: err(ZE_PARMS, "way too many zip files must be made");
497: }
498: #ifdef VMS
499: if ((q = strrchr(zipfile, ']')) != NULL)
500: #else /* !VMS */
501: if ((q = strrchr(zipfile, '/')) != NULL)
502: #endif /* ?VMS */
503: q++;
504: else
505: q = zipfile;
506: r = 0;
507: while ((g = *q++) != 0 && g != '.' && r < 8 - k)
508: template[r++] = (char)g;
509: if (r == 0)
510: template[r++] = '_';
511: else if (g >= '0' && g <= '9')
512: template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
513: sprintf(template + r, "%%0%dd.zip", k);
514:
515: /* Make the zip files from the linked lists of entry numbers */
516: if ((e = fopen(zipfile, FOPR)) == NULL)
517: {
518: free((voidp *)b); free((voidp *)w); free((voidp *)a);
519: err(ZE_NAME, zipfile);
520: }
521: free((voidp *)zipfile);
522: zipfile = NULL;
523: for (j = 0; j < s; j++)
524: {
525: sprintf(name, template, j + 1);
526: printf("creating %s\n", path);
527: zipsmade = j + 1;
528: if ((f = fopen(path, FOPW)) == NULL)
529: {
530: free((voidp *)b); free((voidp *)w); free((voidp *)a);
531: err(ZE_CREAT, path);
532: }
533: tempzn = 0;
534: for (g = b[j]; g != (extent)-1; g = (extent)a[g])
535: {
536: if (fseek(e, w[g]->off, SEEK_SET))
537: {
538: free((voidp *)b); free((voidp *)w); free((voidp *)a);
539: err(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
540: }
541: if ((r = zipcopy(w[g], e, f)) != ZE_OK)
542: {
543: free((voidp *)b); free((voidp *)w); free((voidp *)a);
544: if (r == ZE_TEMP)
545: err(ZE_WRITE, path);
546: else
547: err(r, zipfile);
548: }
549: }
550: if ((c = ftell(f)) == -1L)
551: {
552: free((voidp *)b); free((voidp *)w); free((voidp *)a);
553: err(ZE_WRITE, path);
554: }
555: for (g = b[j], k = 0; g != (extent)-1; g = (extent)a[g], k++)
556: if ((r = putcentral(w[g], f)) != ZE_OK)
557: {
558: free((voidp *)b); free((voidp *)w); free((voidp *)a);
559: err(ZE_WRITE, path);
560: }
561: if ((t = ftell(f)) == -1L)
562: {
563: free((voidp *)b); free((voidp *)w); free((voidp *)a);
564: err(ZE_WRITE, path);
565: }
566: if ((r = putend(k, t - c, c, (extent)0, (char *)NULL, f)) != ZE_OK)
567: {
568: free((voidp *)b); free((voidp *)w); free((voidp *)a);
569: err(ZE_WRITE, path);
570: }
571: if (ferror(f) || fclose(f))
572: {
573: free((voidp *)b); free((voidp *)w); free((voidp *)a);
574: err(ZE_WRITE, path);
575: }
576: }
577: free((voidp *)b); free((voidp *)w); free((voidp *)a);
578: fclose(e);
579:
580: /* Done! */
581: exit(0);
582: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.