|
|
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.