zipsplit.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /*
  2. zipsplit.c - Zip 3
  3. Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
  4. See the accompanying file LICENSE, version 2007-Mar-4 or later
  5. (the contents of which are also included in zip.h) for terms of use.
  6. If, for some reason, all these files are missing, the Info-ZIP license
  7. also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
  8. */
  9. /*
  10. * zipsplit.c by Mark Adler.
  11. */
  12. #define __ZIPSPLIT_C
  13. #ifndef UTIL
  14. #define UTIL
  15. #endif
  16. #include "zip.h"
  17. #define DEFCPYRT /* main module: enable copyright string defines! */
  18. #include "revision.h"
  19. #include <signal.h>
  20. #define DEFSIZ 36000L /* Default split size (change in help() too) */
  21. #ifdef MSDOS
  22. # define NL 2 /* Number of bytes written for a \n */
  23. #else /* !MSDOS */
  24. # define NL 1 /* Number of bytes written for a \n */
  25. #endif /* ?MSDOS */
  26. #ifdef RISCOS
  27. # define INDEX "zipspl/idx" /* Name of index file */
  28. # define TEMPL_FMT "%%0%dld"
  29. # define TEMPL_SIZ 13
  30. # define ZPATH_SEP '.'
  31. #else
  32. #ifdef QDOS
  33. # define ZPATH_SEP '_'
  34. # define INDEX "zipsplit_idx" /* Name of index file */
  35. # define TEMPL_FMT "%%0%dld_zip"
  36. # define TEMPL_SIZ 17
  37. # define exit(p1) QDOSexit()
  38. #else
  39. #ifdef VM_CMS
  40. # define INDEX "zipsplit.idx" /* Name of index file */
  41. # define TEMPL_FMT "%%0%dld.zip"
  42. # define TEMPL_SIZ 21
  43. # define ZPATH_SEP '.'
  44. #else
  45. # define INDEX "zipsplit.idx" /* Name of index file */
  46. # define TEMPL_FMT "%%0%dld.zip"
  47. # define TEMPL_SIZ 17
  48. # define ZPATH_SEP '.'
  49. #endif /* VM_CMS */
  50. #endif /* QDOS */
  51. #endif /* RISCOS */
  52. #ifdef MACOS
  53. #define ziperr(c, h) zipspliterr(c, h)
  54. #define zipwarn(a, b) zipsplitwarn(a, b)
  55. void zipsplitwarn(ZCONST char *a, ZCONST char *b);
  56. void zipspliterr(int c, ZCONST char *h);
  57. #endif /* MACOS */
  58. /* Local functions */
  59. local zvoid *talloc OF((extent));
  60. local void tfree OF((zvoid *));
  61. local void tfreeall OF((void));
  62. local void handler OF((int));
  63. local void license OF((void));
  64. local void help OF((void));
  65. local void version_info OF((void));
  66. local extent simple OF((uzoff_t *, extent, uzoff_t, uzoff_t));
  67. local int descmp OF((ZCONST zvoid *, ZCONST zvoid *));
  68. local extent greedy OF((uzoff_t *, extent, uzoff_t, uzoff_t));
  69. local int retry OF((void));
  70. int main OF((int, char **));
  71. /* Output zip files */
  72. local char template[TEMPL_SIZ]; /* name template for output files */
  73. local int zipsmade = 0; /* number of zip files made */
  74. local int indexmade = 0; /* true if index file made */
  75. local char *path = NULL; /* space for full name */
  76. local char *name; /* where name goes in path[] */
  77. /* The talloc() and tree() routines extend malloc() and free() to keep
  78. track of all allocated memory. Then the tfreeall() routine uses this
  79. information to free all allocated memory before exiting. */
  80. #define TMAX 6 /* set intelligently by examining the code */
  81. zvoid *talls[TMAX]; /* malloc'ed pointers to track */
  82. int talln = 0; /* number of entries in talls[] */
  83. int set_filetype(out_path)
  84. char *out_path;
  85. {
  86. #ifdef __BEOS__
  87. /* Set the filetype of the zipfile to "application/zip" */
  88. setfiletype( out_path, "application/zip" );
  89. #endif
  90. #ifdef __ATHEOS__
  91. /* Set the filetype of the zipfile to "application/x-zip" */
  92. setfiletype(out_path, "application/x-zip");
  93. #endif
  94. #ifdef MACOS
  95. /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
  96. setfiletype(out_path, 'IZip', 'ZIP ');
  97. #endif
  98. #ifdef RISCOS
  99. /* Set the filetype of the zipfile to &DDC */
  100. setfiletype(out_path, 0xDDC);
  101. #endif
  102. return ZE_OK;
  103. }
  104. /* rename a split
  105. * A split has a tempfile name until it is closed, then
  106. * here rename it as out_path the final name for the split.
  107. *
  108. * This is not used in zipsplit but is referenced by the generic split
  109. * writing code. If zipsplit is made split aware (so can write splits of
  110. * splits, if that makes sense) then this would get used. But if that
  111. * happens these utility versions should be dropped and the main ones
  112. * used.
  113. */
  114. int rename_split(temp_name, out_path)
  115. char *temp_name;
  116. char *out_path;
  117. {
  118. int r;
  119. /* Replace old zip file with new zip file, leaving only the new one */
  120. if ((r = replace(out_path, temp_name)) != ZE_OK)
  121. {
  122. zipwarn("new zip file left as: ", temp_name);
  123. free((zvoid *)tempzip);
  124. tempzip = NULL;
  125. ZIPERR(r, "was replacing split file");
  126. }
  127. if (zip_attributes) {
  128. setfileattr(out_path, zip_attributes);
  129. }
  130. return ZE_OK;
  131. }
  132. void zipmessage_nl(a, nl)
  133. ZCONST char *a; /* message string to output */
  134. int nl; /* 1 = add nl to end */
  135. /* If nl false, print a message to mesg without new line.
  136. If nl true, print and add new line. If logfile is
  137. open then also write message to log file. */
  138. {
  139. if (noisy) {
  140. fprintf(mesg, "%s", a);
  141. if (nl) {
  142. fprintf(mesg, "\n");
  143. mesg_line_started = 0;
  144. } else {
  145. mesg_line_started = 1;
  146. }
  147. fflush(mesg);
  148. }
  149. }
  150. void zipmessage(a, b)
  151. ZCONST char *a, *b; /* message strings juxtaposed in output */
  152. /* Print a message to mesg and flush. Also write to log file if
  153. open. Write new line first if current line has output already. */
  154. {
  155. if (noisy) {
  156. if (mesg_line_started)
  157. fprintf(mesg, "\n");
  158. fprintf(mesg, "%s%s\n", a, b);
  159. mesg_line_started = 0;
  160. fflush(mesg);
  161. }
  162. }
  163. local zvoid *talloc(s)
  164. extent s;
  165. /* does a malloc() and saves the pointer to free later (does not check
  166. for an overflow of the talls[] list) */
  167. {
  168. zvoid *p;
  169. if ((p = (zvoid *)malloc(s)) != NULL)
  170. talls[talln++] = p;
  171. return p;
  172. }
  173. local void tfree(p)
  174. zvoid *p;
  175. /* does a free() and also removes the pointer from the talloc() list */
  176. {
  177. int i;
  178. free(p);
  179. i = talln;
  180. while (i--)
  181. if (talls[i] == p)
  182. break;
  183. if (i >= 0)
  184. {
  185. while (++i < talln)
  186. talls[i - 1] = talls[i];
  187. talln--;
  188. }
  189. }
  190. local void tfreeall()
  191. /* free everything talloc'ed and not tfree'd */
  192. {
  193. while (talln)
  194. free(talls[--talln]);
  195. }
  196. void ziperr(c, h)
  197. int c; /* error code from the ZE_ class */
  198. ZCONST char *h; /* message about how it happened */
  199. /* Issue a message for the error, clean up files and memory, and exit. */
  200. {
  201. if (PERR(c))
  202. perror("zipsplit error");
  203. fprintf(mesg, "zipsplit error: %s (%s)\n", ZIPERRORS(c), h);
  204. if (indexmade)
  205. {
  206. strcpy(name, INDEX);
  207. destroy(path);
  208. }
  209. for (; zipsmade; zipsmade--)
  210. {
  211. sprintf(name, template, zipsmade);
  212. destroy(path);
  213. }
  214. tfreeall();
  215. if (zipfile != NULL)
  216. free((zvoid *)zipfile);
  217. EXIT(c);
  218. }
  219. local void handler(s)
  220. int s; /* signal number (ignored) */
  221. /* Upon getting a user interrupt, abort cleanly using ziperr(). */
  222. {
  223. #ifndef MSDOS
  224. putc('\n', mesg);
  225. #endif /* !MSDOS */
  226. ziperr(ZE_ABORT, "aborting");
  227. s++; /* keep some compilers happy */
  228. }
  229. void zipwarn(a, b)
  230. ZCONST char *a, *b; /* message strings juxtaposed in output */
  231. /* Print a warning message to mesg (usually stderr) and return. */
  232. {
  233. fprintf(mesg, "zipsplit warning: %s%s\n", a, b);
  234. }
  235. local void license()
  236. /* Print license information to stdout. */
  237. {
  238. extent i; /* counter for copyright array */
  239. for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
  240. puts(swlicense[i]);
  241. }
  242. local void help()
  243. /* Print help (along with license info) to stdout. */
  244. {
  245. extent i; /* counter for help array */
  246. /* help array */
  247. static ZCONST char *text[] = {
  248. "",
  249. "ZipSplit %s (%s)",
  250. #ifdef VM_CMS
  251. "Usage: zipsplit [-tipqs] [-n size] [-r room] [-b fm] zipfile",
  252. #else
  253. "Usage: zipsplit [-tipqs] [-n size] [-r room] [-b path] zipfile",
  254. #endif
  255. " -t report how many files it will take, but don't make them",
  256. #ifdef RISCOS
  257. " -i make index (" INDEX ") and count its size against first zip file",
  258. #else
  259. " -i make index (zipsplit.idx) and count its size against first zip file",
  260. #endif
  261. " -n make zip files no larger than \"size\" (default = 36000)",
  262. " -r leave room for \"room\" bytes on the first disk (default = 0)",
  263. #ifdef VM_CMS
  264. " -b use \"fm\" as the filemode for the output zip files",
  265. #else
  266. " -b use \"path\" for the output zip files",
  267. #endif
  268. " -q quieter operation, suppress some informational messages",
  269. " -p pause between output zip files",
  270. " -s do a sequential split even if it takes more zip files",
  271. " -h show this help -v show version info -L show software license"
  272. };
  273. for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
  274. printf(copyright[i], "zipsplit");
  275. putchar('\n');
  276. }
  277. for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  278. {
  279. printf(text[i], VERSION, REVDATE);
  280. putchar('\n');
  281. }
  282. }
  283. local void version_info()
  284. /* Print verbose info about program version and compile time options
  285. to stdout. */
  286. {
  287. extent i; /* counter in text arrays */
  288. /* Options info array */
  289. static ZCONST char *comp_opts[] = {
  290. #ifdef DEBUG
  291. "DEBUG",
  292. #endif
  293. NULL
  294. };
  295. for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
  296. {
  297. printf(versinfolines[i], "ZipSplit", VERSION, REVDATE);
  298. putchar('\n');
  299. }
  300. version_local();
  301. puts("ZipSplit special compilation options:");
  302. for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
  303. {
  304. printf("\t%s\n",comp_opts[i]);
  305. }
  306. if (i == 0)
  307. puts("\t[none]");
  308. }
  309. local extent simple(a, n, c, d)
  310. uzoff_t *a; /* items to put in bins, return value: destination bins */
  311. extent n; /* number of items */
  312. uzoff_t c; /* capacity of each bin */
  313. uzoff_t d; /* amount to deduct from first bin */
  314. /* Return the number of bins of capacity c that are needed to contain the
  315. integers in a[0..n-1] placed sequentially into the bins. The value d
  316. is deducted initially from the first bin (space for index). The entries
  317. in a[] are replaced by the destination bins. */
  318. {
  319. extent k; /* current bin number */
  320. uzoff_t t; /* space used in current bin */
  321. t = k = 0;
  322. while (n--)
  323. {
  324. if (*a + t > c - (k == 0 ? d : 0))
  325. {
  326. k++;
  327. t = 0;
  328. }
  329. t += *a;
  330. *(ulg huge *)a++ = k;
  331. }
  332. return k + 1;
  333. }
  334. local int descmp(a, b)
  335. ZCONST zvoid *a, *b; /* pointers to pointers to ulg's to compare */
  336. /* Used by qsort() in greedy() to do a descending sort. */
  337. {
  338. return **(uzoff_t **)a < **(uzoff_t **)b ? 1 :
  339. (**(uzoff_t **)a > **(uzoff_t **)b ? -1 : 0);
  340. }
  341. local extent greedy(a, n, c, d)
  342. uzoff_t *a; /* items to put in bins, return value: destination bins */
  343. extent n; /* number of items */
  344. uzoff_t c; /* capacity of each bin */
  345. uzoff_t d; /* amount to deduct from first bin */
  346. /* Return the number of bins of capacity c that are needed to contain the
  347. items with sizes a[0..n-1] placed non-sequentially into the bins. The
  348. value d is deducted initially from the first bin (space for index).
  349. The entries in a[] are replaced by the destination bins. */
  350. {
  351. uzoff_t *b; /* space left in each bin (malloc'ed for each m) */
  352. uzoff_t *e; /* copy of argument a[] (malloc'ed) */
  353. extent i; /* steps through items */
  354. extent j; /* steps through bins */
  355. extent k; /* best bin to put current item in */
  356. extent m; /* current number of bins */
  357. uzoff_t **s; /* pointers to e[], sorted descending (malloc'ed) */
  358. uzoff_t t; /* space left in best bin (index k) */
  359. /* Algorithm:
  360. 1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
  361. descending order.
  362. 2. Compute total of s[] and set m to the smallest number of bins of
  363. capacity c that can hold the total.
  364. 3. Allocate m bins.
  365. 4. For each item in s[], starting with the largest, put it in the
  366. bin with the smallest current capacity greater than or equal to the
  367. item's size. If no bin has enough room, increment m and go to step 4.
  368. 5. Else, all items ended up in a bin--return m.
  369. */
  370. /* Copy a[] to e[], put pointers to e[] in s[], and sort s[]. Also compute
  371. the initial number of bins (minus 1). */
  372. if ((e = (uzoff_t *)malloc(n * sizeof(uzoff_t))) == NULL ||
  373. (s = (uzoff_t **)malloc(n * sizeof(uzoff_t *))) == NULL)
  374. {
  375. if (e != NULL)
  376. free((zvoid *)e);
  377. ziperr(ZE_MEM, "was trying a smart split");
  378. return 0; /* only to make compiler happy */
  379. }
  380. memcpy((char *)e, (char *)a, n * sizeof(uzoff_t));
  381. for (t = i = 0; i < n; i++)
  382. t += *(s[i] = e + i);
  383. m = (extent)((t + c - 1) / c) - 1; /* pre-decrement for loop */
  384. qsort((char *)s, n, sizeof(ulg *), descmp);
  385. /* Stuff bins until successful */
  386. do {
  387. /* Increment the number of bins, allocate and initialize bins */
  388. if ((b = (uzoff_t *)malloc(++m * sizeof(uzoff_t))) == NULL)
  389. {
  390. free((zvoid *)s);
  391. free((zvoid *)e);
  392. ziperr(ZE_MEM, "was trying a smart split");
  393. }
  394. b[0] = c - d; /* leave space in first bin */
  395. for (j = 1; j < m; j++)
  396. b[j] = c;
  397. /* Fill the bins greedily */
  398. for (i = 0; i < n; i++)
  399. {
  400. /* Find smallest bin that will hold item i (size s[i]) */
  401. t = c + 1;
  402. for (k = j = 0; j < m; j++)
  403. if (*s[i] <= b[j] && b[j] < t)
  404. t = b[k = j];
  405. /* If no bins big enough for *s[i], try next m */
  406. if (t == c + 1)
  407. break;
  408. /* Diminish that bin and save where it goes */
  409. b[k] -= *s[i];
  410. a[(int)((uzoff_t huge *)(s[i]) - (uzoff_t huge *)e)] = k;
  411. }
  412. /* Clean up */
  413. free((zvoid *)b);
  414. /* Do until all items put in a bin */
  415. } while (i < n);
  416. /* Done--clean up and return the number of bins needed */
  417. free((zvoid *)s);
  418. free((zvoid *)e);
  419. return m;
  420. }
  421. /* keep compiler happy until implement long options - 11/4/2003 EG */
  422. struct option_struct far options[] = {
  423. /* short longopt value_type negatable ID name */
  424. {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
  425. /* the end of the list */
  426. {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
  427. };
  428. local int retry()
  429. {
  430. char m[10];
  431. fputs("Error writing to disk--redo entire disk? ", mesg);
  432. fgets(m, 10, stdin);
  433. return *m == 'y' || *m == 'Y';
  434. }
  435. #ifndef USE_ZIPSPLITMAIN
  436. int main(argc, argv)
  437. #else
  438. int zipsplitmain(argc, argv)
  439. #endif
  440. int argc; /* number of tokens in command line */
  441. char **argv; /* command line tokens */
  442. /* Split a zip file into several zip files less than a specified size. See
  443. the command help in help() above. */
  444. {
  445. uzoff_t *a; /* malloc'ed list of sizes, dest bins */
  446. extent *b; /* heads of bin linked lists (malloc'ed) */
  447. uzoff_t c; /* bin capacity, start of central directory */
  448. int d; /* if true, just report the number of disks */
  449. FILE *e; /* input zip file */
  450. FILE *f; /* output index and zip files */
  451. extent g; /* number of bins from greedy(), entry to write */
  452. int h; /* how to split--true means simple split, counter */
  453. zoff_t i = 0; /* size of index file plus room to leave */
  454. extent j; /* steps through zip entries, bins */
  455. int k; /* next argument type */
  456. extent *n = NULL; /* next item in bin list (heads in b) */
  457. uzoff_t *p; /* malloc'ed list of sizes, dest bins for greedy() */
  458. char *q; /* steps through option characters */
  459. int r; /* temporary variable, counter */
  460. extent s; /* number of bins needed */
  461. zoff_t t; /* total of sizes, end of central directory */
  462. int u; /* flag to wait for user on output files */
  463. struct zlist far **w; /* malloc'ed table for zfiles linked list */
  464. int x; /* if true, make an index file */
  465. struct zlist far *z; /* steps through zfiles linked list */
  466. #ifdef AMIGA
  467. char tailchar; /* temporary variable used in name generation below */
  468. #endif
  469. char errbuf[5000];
  470. #ifdef THEOS
  471. setlocale(LC_CTYPE, "I");
  472. #endif
  473. #ifdef UNICODE_SUPPORT
  474. # ifdef UNIX
  475. /* For Unix, set the locale to UTF-8. Any UTF-8 locale is
  476. OK and they should all be the same. This allows seeing,
  477. writing, and displaying (if the fonts are loaded) all
  478. characters in UTF-8. */
  479. {
  480. char *loc;
  481. /*
  482. loc = setlocale(LC_CTYPE, NULL);
  483. printf(" Initial language locale = '%s'\n", loc);
  484. */
  485. loc = setlocale(LC_CTYPE, "en_US.UTF-8");
  486. /*
  487. printf("langinfo %s\n", nl_langinfo(CODESET));
  488. */
  489. if (loc != NULL) {
  490. /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
  491. using_utf8 = 1;
  492. /*
  493. printf(" Locale set to %s\n", loc);
  494. */
  495. } else {
  496. /*
  497. printf(" Could not set Unicode UTF-8 locale\n");
  498. */
  499. }
  500. }
  501. # endif
  502. #endif
  503. /* If no args, show help */
  504. if (argc == 1)
  505. {
  506. help();
  507. EXIT(ZE_OK);
  508. }
  509. /* Informational messages are written to stdout. */
  510. mesg = stdout;
  511. init_upper(); /* build case map table */
  512. /* Go through args */
  513. signal(SIGINT, handler);
  514. #ifdef SIGTERM /* Amiga has no SIGTERM */
  515. signal(SIGTERM, handler);
  516. #endif
  517. #ifdef SIGABRT
  518. signal(SIGABRT, handler);
  519. #endif
  520. #ifdef SIGBREAK
  521. signal(SIGBREAK, handler);
  522. #endif
  523. #ifdef SIGBUS
  524. signal(SIGBUS, handler);
  525. #endif
  526. #ifdef SIGILL
  527. signal(SIGILL, handler);
  528. #endif
  529. #ifdef SIGSEGV
  530. signal(SIGSEGV, handler);
  531. #endif
  532. k = h = x = d = u = 0;
  533. c = DEFSIZ;
  534. for (r = 1; r < argc; r++)
  535. if (*argv[r] == '-')
  536. {
  537. if (argv[r][1])
  538. for (q = argv[r]+1; *q; q++)
  539. switch (*q)
  540. {
  541. case 'b': /* Specify path for output files */
  542. if (k)
  543. ziperr(ZE_PARMS, "options are separate and precede zip file");
  544. else
  545. k = 1; /* Next non-option is path */
  546. break;
  547. case 'h': /* Show help */
  548. help(); EXIT(ZE_OK);
  549. case 'i': /* Make an index file */
  550. x = 1;
  551. break;
  552. case 'l': case 'L': /* Show copyright and disclaimer */
  553. license(); EXIT(ZE_OK);
  554. case 'n': /* Specify maximum size of resulting zip files */
  555. if (k)
  556. ziperr(ZE_PARMS, "options are separate and precede zip file");
  557. else
  558. k = 2; /* Next non-option is size */
  559. break;
  560. case 'p':
  561. u = 1;
  562. break;
  563. case 'q': /* Quiet operation, suppress info messages */
  564. noisy = 0;
  565. break;
  566. case 'r':
  567. if (k)
  568. ziperr(ZE_PARMS, "options are separate and precede zip file");
  569. else
  570. k = 3; /* Next non-option is room to leave */
  571. break;
  572. case 's':
  573. h = 1; /* Only try simple */
  574. break;
  575. case 't': /* Just report number of disks */
  576. d = 1;
  577. break;
  578. case 'v': /* Show version info */
  579. version_info(); EXIT(ZE_OK);
  580. default:
  581. ziperr(ZE_PARMS, "Use option -h for help.");
  582. }
  583. else
  584. ziperr(ZE_PARMS, "zip file cannot be stdin");
  585. }
  586. else
  587. switch (k)
  588. {
  589. case 0:
  590. if (zipfile == NULL)
  591. {
  592. if ((zipfile = ziptyp(argv[r])) == NULL)
  593. ziperr(ZE_MEM, "was processing arguments");
  594. }
  595. else
  596. ziperr(ZE_PARMS, "can only specify one zip file");
  597. break;
  598. case 1:
  599. tempath = argv[r];
  600. k = 0;
  601. break;
  602. case 2:
  603. if ((c = (ulg)atol(argv[r])) < 100) /* 100 is smallest zip file */
  604. ziperr(ZE_PARMS, "invalid size given. Use option -h for help.");
  605. k = 0;
  606. break;
  607. default: /* k must be 3 */
  608. i = (ulg)atol(argv[r]);
  609. k = 0;
  610. break;
  611. }
  612. if (zipfile == NULL)
  613. ziperr(ZE_PARMS, "need to specify zip file");
  614. if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
  615. ziperr(ZE_MEM, "input");
  616. }
  617. strcpy(in_path, zipfile);
  618. /* Read zip file */
  619. if ((r = readzipfile()) != ZE_OK)
  620. ziperr(r, zipfile);
  621. if (zfiles == NULL)
  622. ziperr(ZE_NAME, zipfile);
  623. /* Make a list of sizes and check against capacity. Also compute the
  624. size of the index file. */
  625. c -= ENDHEAD + 4; /* subtract overhead/zipfile */
  626. if ((a = (uzoff_t *)talloc(zcount * sizeof(uzoff_t))) == NULL ||
  627. (w = (struct zlist far **)talloc(zcount * sizeof(struct zlist far *))) ==
  628. NULL)
  629. {
  630. ziperr(ZE_MEM, "was computing split");
  631. return 1;
  632. }
  633. t = 0;
  634. for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
  635. {
  636. w[j] = z;
  637. if (x)
  638. i += z->nam + 6 + NL;
  639. /* New scanzip_reg only reads central directory so use cext for ext */
  640. t += a[j] = 8 + LOCHEAD + CENHEAD +
  641. 2 * (zoff_t)z->nam + 2 * (zoff_t)z->cext + z->com + z->siz;
  642. if (a[j] > c) {
  643. sprintf(errbuf, "Entry is larger than max split size of: %s",
  644. zip_fzofft(c, NULL, "u"));
  645. zipwarn(errbuf, "");
  646. zipwarn("use -n to set split size", "");
  647. ziperr(ZE_BIG, z->zname);
  648. }
  649. }
  650. /* Decide on split to use, report number of files */
  651. if (h)
  652. s = simple(a, zcount, c, i);
  653. else
  654. {
  655. if ((p = (uzoff_t *)talloc(zcount * sizeof(uzoff_t))) == NULL)
  656. ziperr(ZE_MEM, "was computing split");
  657. memcpy((char *)p, (char *)a, zcount * sizeof(uzoff_t));
  658. s = simple(a, zcount, c, i);
  659. g = greedy(p, zcount, c, i);
  660. if (s <= g)
  661. tfree((zvoid *)p);
  662. else
  663. {
  664. tfree((zvoid *)a);
  665. a = p;
  666. s = g;
  667. }
  668. }
  669. printf("%ld zip files w%s be made (%s%% efficiency)\n",
  670. (ulg)s, d ? "ould" : "ill",
  671. zip_fzofft( ((200 * ((t + c - 1)/c)) / s + 1) / 2, NULL, "d"));
  672. if (d)
  673. {
  674. tfreeall();
  675. free((zvoid *)zipfile);
  676. zipfile = NULL;
  677. EXIT(ZE_OK);
  678. }
  679. /* Set up path for output files */
  680. /* Point "name" past the path, where the filename should go */
  681. if ((path = (char *)talloc(tempath == NULL ? 13 : strlen(tempath) + 14)) ==
  682. NULL)
  683. ziperr(ZE_MEM, "was making output file names");
  684. if (tempath == NULL)
  685. name = path;
  686. else
  687. {
  688. #ifndef VM_CMS
  689. /* Copy the output path to the target */
  690. strcpy(path, tempath);
  691. #endif
  692. #ifdef AMIGA
  693. tailchar = path[strlen(path) - 1]; /* last character */
  694. if (path[0] && (tailchar != '/') && (tailchar != ':'))
  695. strcat(path, "/");
  696. #else
  697. #ifdef RISCOS
  698. if (path[0] && path[strlen(path) - 1] != '.')
  699. strcat(path, ".");
  700. #else
  701. #ifdef QDOS
  702. if (path[0] && path[strlen(path) - 1] != '_')
  703. strcat(path, "_");
  704. #else
  705. #ifndef VMS
  706. if (path[0] && path[strlen(path) - 1] != '/')
  707. strcat(path, "/");
  708. #endif /* !VMS */
  709. #endif /* ?QDOS */
  710. #endif /* ?RISCOS */
  711. #endif /* ?AMIGA */
  712. name = path + strlen(path);
  713. }
  714. /* Make linked lists of results */
  715. if ((b = (extent *)talloc(s * sizeof(extent))) == NULL ||
  716. (n = (extent *)talloc(zcount * sizeof(extent))) == NULL)
  717. ziperr(ZE_MEM, "was computing split");
  718. for (j = 0; j < s; j++)
  719. b[j] = (extent)-1;
  720. j = zcount;
  721. while (j--)
  722. {
  723. g = (extent)a[j];
  724. n[j] = b[g];
  725. b[g] = j;
  726. }
  727. /* Make a name template for the zip files that is eight or less characters
  728. before the .zip, and that will not overwrite the original zip file. */
  729. for (k = 1, j = s; j >= 10; j /= 10)
  730. k++;
  731. if (k > 7)
  732. ziperr(ZE_PARMS, "way too many zip files must be made");
  733. /*
  734. * XXX, ugly ....
  735. */
  736. /* Find the final "path" separator character */
  737. #ifdef QDOS
  738. q = LastDir(zipfile);
  739. #else
  740. #ifdef VMS
  741. if ((q = strrchr(zipfile, ']')) != NULL)
  742. #else
  743. #ifdef AMIGA
  744. if (((q = strrchr(zipfile, '/')) != NULL)
  745. || ((q = strrchr(zipfile, ':'))) != NULL)
  746. #else
  747. #ifdef RISCOS
  748. if ((q = strrchr(zipfile, '.')) != NULL)
  749. #else
  750. #ifdef MVS
  751. if ((q = strrchr(zipfile, '.')) != NULL)
  752. #else
  753. if ((q = strrchr(zipfile, '/')) != NULL)
  754. #endif /* MVS */
  755. #endif /* RISCOS */
  756. #endif /* AMIGA */
  757. #endif /* VMS */
  758. q++;
  759. else
  760. q = zipfile;
  761. #endif /* QDOS */
  762. r = 0;
  763. while ((g = *q++) != '\0' && g != ZPATH_SEP && r < 8 - k)
  764. template[r++] = (char)g;
  765. if (r == 0)
  766. template[r++] = '_';
  767. else if (g >= '0' && g <= '9')
  768. template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
  769. sprintf(template + r, TEMPL_FMT, k);
  770. #ifdef VM_CMS
  771. /* For CMS, add the "path" as the filemode at the end */
  772. if (tempath)
  773. {
  774. strcat(template,".");
  775. strcat(template,tempath);
  776. }
  777. #endif
  778. /* Make the zip files from the linked lists of entry numbers */
  779. if ((e = fopen(zipfile, FOPR)) == NULL)
  780. ziperr(ZE_NAME, zipfile);
  781. free((zvoid *)zipfile);
  782. zipfile = NULL;
  783. for (j = 0; j < s; j++)
  784. {
  785. /* jump here on a disk retry */
  786. redobin:
  787. current_disk = 0;
  788. cd_start_disk = 0;
  789. cd_entries_this_disk = 0;
  790. /* prompt if requested */
  791. if (u)
  792. {
  793. char m[10];
  794. fprintf(mesg, "Insert disk #%ld of %ld and hit return: ",
  795. (ulg)j + 1, (ulg)s);
  796. fgets(m, 10, stdin);
  797. }
  798. /* write index file on first disk if requested */
  799. if (j == 0 && x)
  800. {
  801. strcpy(name, INDEX);
  802. printf("creating: %s\n", path);
  803. indexmade = 1;
  804. if ((f = fopen(path, "w")) == NULL)
  805. {
  806. if (u && retry()) goto redobin;
  807. ziperr(ZE_CREAT, path);
  808. }
  809. for (j = 0; j < zcount; j++)
  810. fprintf(f, "%5s %s\n",
  811. zip_fzofft( (a[j] + 1), NULL, "d"), w[j]->zname);
  812. if ((j = ferror(f)) != 0 || fclose(f))
  813. {
  814. if (j)
  815. fclose(f);
  816. if (u && retry()) goto redobin;
  817. ziperr(ZE_WRITE, path);
  818. }
  819. }
  820. /* create output zip file j */
  821. sprintf(name, template, j + 1L);
  822. printf("creating: %s\n", path);
  823. zipsmade = j + 1;
  824. if ((y = f = fopen(path, FOPW)) == NULL)
  825. {
  826. if (u && retry()) goto redobin;
  827. ziperr(ZE_CREAT, path);
  828. }
  829. bytes_this_split = 0;
  830. tempzn = 0;
  831. /* write local headers and copy compressed data */
  832. for (g = b[j]; g != (extent)-1; g = (extent)n[g])
  833. {
  834. if (zfseeko(e, w[g]->off, SEEK_SET))
  835. ziperr(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
  836. in_file = e;
  837. if ((r = zipcopy(w[g])) != ZE_OK)
  838. {
  839. if (r == ZE_TEMP)
  840. {
  841. if (u && retry()) goto redobin;
  842. ziperr(ZE_WRITE, path);
  843. }
  844. else
  845. ziperr(r, zipfile);
  846. }
  847. }
  848. /* write central headers */
  849. if ((c = zftello(f)) == (uzoff_t)-1)
  850. {
  851. if (u && retry()) goto redobin;
  852. ziperr(ZE_WRITE, path);
  853. }
  854. for (g = b[j], k = 0; g != (extent)-1; g = n[g], k++)
  855. if ((r = putcentral(w[g])) != ZE_OK)
  856. {
  857. if (u && retry()) goto redobin;
  858. ziperr(ZE_WRITE, path);
  859. }
  860. /* write end-of-central header */
  861. cd_start_offset = c;
  862. total_cd_entries = k;
  863. if ((t = zftello(f)) == (zoff_t)-1 ||
  864. (r = putend((zoff_t)k, t - c, c, (extent)0, (char *)NULL)) !=
  865. ZE_OK ||
  866. ferror(f) || fclose(f))
  867. {
  868. if (u && retry()) goto redobin;
  869. ziperr(ZE_WRITE, path);
  870. }
  871. #ifdef RISCOS
  872. /* Set the filetype to &DDC */
  873. setfiletype(path,0xDDC);
  874. #endif
  875. }
  876. fclose(e);
  877. /* Done! */
  878. if (u)
  879. fputs("Done.\n", mesg);
  880. tfreeall();
  881. RETURN(0);
  882. }