zipnote.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. zipnote.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. * zipnote.c by Mark Adler.
  11. */
  12. #define __ZIPNOTE_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. /* Calculate size of static line buffer used in write (-w) mode. */
  21. #define WRBUFSIZ 2047
  22. /* The line buffer size should be at least as large as FNMAX. */
  23. #if FNMAX > WRBUFSIZ
  24. # undef WRBUFSIZ
  25. # define WRBUFSIZ FNMAX
  26. #endif
  27. /* Character to mark zip entry names in the comment file */
  28. #define MARK '@'
  29. #define MARKE " (comment above this line)"
  30. #define MARKZ " (zip file comment below this line)"
  31. /* Temporary zip file pointer */
  32. local FILE *tempzf;
  33. /* Local functions */
  34. local void handler OF((int));
  35. local void license OF((void));
  36. local void help OF((void));
  37. local void version_info OF((void));
  38. local void putclean OF((char *, extent));
  39. /* getline name conflicts with GNU getline() function */
  40. local char *zgetline OF((char *, extent));
  41. local int catalloc OF((char * far *, char *));
  42. int main OF((int, char **));
  43. /* keep compiler happy until implement long options - 11/4/2003 EG */
  44. struct option_struct far options[] = {
  45. /* short longopt value_type negatable ID name */
  46. {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
  47. /* the end of the list */
  48. {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
  49. };
  50. #ifdef MACOS
  51. #define ziperr(c, h) zipnoteerr(c, h)
  52. #define zipwarn(a, b) zipnotewarn(a, b)
  53. void zipnoteerr(int c, ZCONST char *h);
  54. void zipnotewarn(ZCONST char *a, ZCONST char *b);
  55. #endif
  56. #ifdef QDOS
  57. #define exit(p1) QDOSexit()
  58. #endif
  59. int set_filetype(out_path)
  60. char *out_path;
  61. {
  62. #ifdef __BEOS__
  63. /* Set the filetype of the zipfile to "application/zip" */
  64. setfiletype( out_path, "application/zip" );
  65. #endif
  66. #ifdef __ATHEOS__
  67. /* Set the filetype of the zipfile to "application/x-zip" */
  68. setfiletype(out_path, "application/x-zip");
  69. #endif
  70. #ifdef MACOS
  71. /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
  72. setfiletype(out_path, 'IZip', 'ZIP ');
  73. #endif
  74. #ifdef RISCOS
  75. /* Set the filetype of the zipfile to &DDC */
  76. setfiletype(out_path, 0xDDC);
  77. #endif
  78. return ZE_OK;
  79. }
  80. /* rename a split
  81. * A split has a tempfile name until it is closed, then
  82. * here rename it as out_path the final name for the split.
  83. */
  84. int rename_split(temp_name, out_path)
  85. char *temp_name;
  86. char *out_path;
  87. {
  88. int r;
  89. /* Replace old zip file with new zip file, leaving only the new one */
  90. if ((r = replace(out_path, temp_name)) != ZE_OK)
  91. {
  92. zipwarn("new zip file left as: ", temp_name);
  93. free((zvoid *)tempzip);
  94. tempzip = NULL;
  95. ZIPERR(r, "was replacing split file");
  96. }
  97. if (zip_attributes) {
  98. setfileattr(out_path, zip_attributes);
  99. }
  100. return ZE_OK;
  101. }
  102. void zipmessage_nl(a, nl)
  103. ZCONST char *a; /* message string to output */
  104. int nl; /* 1 = add nl to end */
  105. /* If nl false, print a message to mesg without new line.
  106. If nl true, print and add new line. If logfile is
  107. open then also write message to log file. */
  108. {
  109. if (noisy) {
  110. fprintf(mesg, "%s", a);
  111. if (nl) {
  112. fprintf(mesg, "\n");
  113. mesg_line_started = 0;
  114. } else {
  115. mesg_line_started = 1;
  116. }
  117. fflush(mesg);
  118. }
  119. }
  120. void zipmessage(a, b)
  121. ZCONST char *a, *b; /* message strings juxtaposed in output */
  122. /* Print a message to mesg and flush. Also write to log file if
  123. open. Write new line first if current line has output already. */
  124. {
  125. if (noisy) {
  126. if (mesg_line_started)
  127. fprintf(mesg, "\n");
  128. fprintf(mesg, "%s%s\n", a, b);
  129. mesg_line_started = 0;
  130. fflush(mesg);
  131. }
  132. }
  133. void ziperr(c, h)
  134. int c; /* error code from the ZE_ class */
  135. ZCONST char *h; /* message about how it happened */
  136. /* Issue a message for the error, clean up files and memory, and exit. */
  137. {
  138. if (PERR(c))
  139. perror("zipnote error");
  140. fprintf(mesg, "zipnote error: %s (%s)\n", ZIPERRORS(c), h);
  141. if (tempzf != NULL)
  142. fclose(tempzf);
  143. if (tempzip != NULL)
  144. {
  145. destroy(tempzip);
  146. free((zvoid *)tempzip);
  147. }
  148. if (zipfile != NULL)
  149. free((zvoid *)zipfile);
  150. EXIT(c);
  151. }
  152. local void handler(s)
  153. int s; /* signal number (ignored) */
  154. /* Upon getting a user interrupt, abort cleanly using ziperr(). */
  155. {
  156. #ifndef MSDOS
  157. putc('\n', mesg);
  158. #endif /* !MSDOS */
  159. ziperr(ZE_ABORT, "aborting");
  160. s++; /* keep some compilers happy */
  161. }
  162. void zipwarn(a, b)
  163. ZCONST char *a, *b; /* message strings juxtaposed in output */
  164. /* Print a warning message to mesg (usually stderr) and return. */
  165. {
  166. fprintf(mesg, "zipnote warning: %s%s\n", a, b);
  167. }
  168. local void license()
  169. /* Print license information to stdout. */
  170. {
  171. extent i; /* counter for copyright array */
  172. for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
  173. puts(swlicense[i]);
  174. }
  175. local void help()
  176. /* Print help (along with license info) to stdout. */
  177. {
  178. extent i; /* counter for help array */
  179. /* help array */
  180. static ZCONST char *text[] = {
  181. "",
  182. "ZipNote %s (%s)",
  183. #ifdef VM_CMS
  184. "Usage: zipnote [-w] [-q] [-b fm] zipfile",
  185. #else
  186. "Usage: zipnote [-w] [-q] [-b path] zipfile",
  187. #endif
  188. " the default action is to write the comments in zipfile to stdout",
  189. " -w write the zipfile comments from stdin",
  190. #ifdef VM_CMS
  191. " -b use \"fm\" as the filemode for the temporary zip file",
  192. #else
  193. " -b use \"path\" for the temporary zip file",
  194. #endif
  195. " -q quieter operation, suppress some informational messages",
  196. " -h show this help -v show version info -L show software license",
  197. "",
  198. "Example:",
  199. #ifdef VMS
  200. " define/user sys$output foo.tmp",
  201. " zipnote foo.zip",
  202. " edit foo.tmp",
  203. " ... then you edit the comments, save, and exit ...",
  204. " define/user sys$input foo.tmp",
  205. " zipnote -w foo.zip",
  206. #else
  207. #ifdef RISCOS
  208. " zipnote foo/zip > foo/tmp",
  209. " <!Edit> foo/tmp",
  210. " ... then you edit the comments, save, and exit ...",
  211. " zipnote -w foo/zip < foo/tmp",
  212. #else
  213. #ifdef VM_CMS
  214. " zipnote foo.zip > foo.tmp",
  215. " xedit foo tmp",
  216. " ... then you edit the comments, save, and exit ...",
  217. " zipnote -w foo.zip < foo.tmp",
  218. #else
  219. " zipnote foo.zip > foo.tmp",
  220. " ed foo.tmp",
  221. " ... then you edit the comments, save, and exit ...",
  222. " zipnote -w foo.zip < foo.tmp",
  223. #endif /* VM_CMS */
  224. #endif /* RISCOS */
  225. #endif /* VMS */
  226. "",
  227. " \"@ name\" can be followed by an \"@=newname\" line to change the name"
  228. };
  229. for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
  230. printf(copyright[i], "zipnote");
  231. putchar('\n');
  232. }
  233. for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  234. {
  235. printf(text[i], VERSION, REVDATE);
  236. putchar('\n');
  237. }
  238. }
  239. /*
  240. * XXX put this in version.c
  241. */
  242. local void version_info()
  243. /* Print verbose info about program version and compile time options
  244. to stdout. */
  245. {
  246. extent i; /* counter in text arrays */
  247. /* Options info array */
  248. static ZCONST char *comp_opts[] = {
  249. #ifdef DEBUG
  250. "DEBUG",
  251. #endif
  252. NULL
  253. };
  254. for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  255. {
  256. printf(copyright[i], "zipnote");
  257. putchar('\n');
  258. }
  259. for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
  260. {
  261. printf(versinfolines[i], "ZipNote", VERSION, REVDATE);
  262. putchar('\n');
  263. }
  264. version_local();
  265. puts("ZipNote special compilation options:");
  266. for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
  267. {
  268. printf("\t%s\n",comp_opts[i]);
  269. }
  270. if (i == 0)
  271. puts("\t[none]");
  272. }
  273. local void putclean(s, n)
  274. char *s; /* string to write to stdout */
  275. extent n; /* length of string */
  276. /* Write the string s to stdout, filtering out control characters that are
  277. not tab or newline (mainly to remove carriage returns), and prefix MARK's
  278. and backslashes with a backslash. Also, terminate with a newline if
  279. needed. */
  280. {
  281. int c; /* next character in string */
  282. int e; /* last character written */
  283. e = '\n'; /* if empty, write nothing */
  284. while (n--)
  285. {
  286. c = *(uch *)s++;
  287. if (c == MARK || c == '\\')
  288. putchar('\\');
  289. if (c >= ' ' || c == '\t' || c == '\n')
  290. { e=c; putchar(e); }
  291. }
  292. if (e != '\n')
  293. putchar('\n');
  294. }
  295. local char *zgetline(buf, size)
  296. char *buf;
  297. extent size;
  298. /* Read a line of text from stdin into string buffer 'buf' of size 'size'.
  299. In case of buffer overflow or EOF, a NULL pointer is returned. */
  300. {
  301. char *line;
  302. unsigned len;
  303. line = fgets(buf, size, stdin);
  304. if (line != NULL && (len = strlen(line)) > 0) {
  305. if (len == size-1 && line[len-1] != '\n') {
  306. /* buffer is full and record delimiter not seen -> overflow */
  307. line = NULL;
  308. } else {
  309. /* delete trailing record delimiter */
  310. if (line[len-1] == '\n') line[len-1] = '\0';
  311. }
  312. }
  313. return line;
  314. }
  315. local int catalloc(a, s)
  316. char * far *a; /* pointer to a pointer to a malloc'ed string */
  317. char *s; /* string to concatenate on a */
  318. /* Concatentate the string s to the malloc'ed string pointed to by a.
  319. Preprocess s by removing backslash escape characters. */
  320. {
  321. char *p; /* temporary pointer */
  322. char *q; /* temporary pointer */
  323. for (p = q = s; *q; *p++ = *q++)
  324. if (*q == '\\' && *(q+1))
  325. q++;
  326. *p = 0;
  327. if ((p = malloc(strlen(*a) + strlen(s) + 3)) == NULL)
  328. return ZE_MEM;
  329. strcat(strcat(strcpy(p, *a), **a ? "\r\n" : ""), s);
  330. free((zvoid *)*a);
  331. *a = p;
  332. return ZE_OK;
  333. }
  334. #ifndef USE_ZIPNOTEMAIN
  335. int main(argc, argv)
  336. #else
  337. int zipnotemain(argc, argv)
  338. #endif
  339. int argc; /* number of tokens in command line */
  340. char **argv; /* command line tokens */
  341. /* Write the comments in the zipfile to stdout, or read them from stdin. */
  342. {
  343. char abf[WRBUFSIZ+1]; /* input line buffer */
  344. char *a; /* pointer to line buffer or NULL */
  345. zoff_t c; /* start of central directory */
  346. int k; /* next argument type */
  347. char *q; /* steps through option arguments */
  348. int r; /* arg counter, temporary variable */
  349. zoff_t s; /* length of central directory */
  350. int t; /* attributes of zip file */
  351. int w; /* true if updating zip file from stdin */
  352. FILE *x; /* input file for testing if can write it */
  353. struct zlist far *z; /* steps through zfiles linked list */
  354. #ifdef THEOS
  355. setlocale(LC_CTYPE, "I");
  356. #endif
  357. #ifdef UNICODE_SUPPORT
  358. # ifdef UNIX
  359. /* For Unix, set the locale to UTF-8. Any UTF-8 locale is
  360. OK and they should all be the same. This allows seeing,
  361. writing, and displaying (if the fonts are loaded) all
  362. characters in UTF-8. */
  363. {
  364. char *loc;
  365. /*
  366. loc = setlocale(LC_CTYPE, NULL);
  367. printf(" Initial language locale = '%s'\n", loc);
  368. */
  369. loc = setlocale(LC_CTYPE, "en_US.UTF-8");
  370. /*
  371. printf("langinfo %s\n", nl_langinfo(CODESET));
  372. */
  373. if (loc != NULL) {
  374. /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
  375. using_utf8 = 1;
  376. /*
  377. printf(" Locale set to %s\n", loc);
  378. */
  379. } else {
  380. /*
  381. printf(" Could not set Unicode UTF-8 locale\n");
  382. */
  383. }
  384. }
  385. # endif
  386. #endif
  387. /* If no args, show help */
  388. if (argc == 1)
  389. {
  390. help();
  391. EXIT(ZE_OK);
  392. }
  393. /* Direct info messages to stderr; stdout is used for data output. */
  394. mesg = stderr;
  395. init_upper(); /* build case map table */
  396. /* Go through args */
  397. zipfile = tempzip = NULL;
  398. tempzf = NULL;
  399. signal(SIGINT, handler);
  400. #ifdef SIGTERM /* AMIGA has no SIGTERM */
  401. signal(SIGTERM, handler);
  402. #endif
  403. #ifdef SIGABRT
  404. signal(SIGABRT, handler);
  405. #endif
  406. #ifdef SIGBREAK
  407. signal(SIGBREAK, handler);
  408. #endif
  409. #ifdef SIGBUS
  410. signal(SIGBUS, handler);
  411. #endif
  412. #ifdef SIGILL
  413. signal(SIGILL, handler);
  414. #endif
  415. #ifdef SIGSEGV
  416. signal(SIGSEGV, handler);
  417. #endif
  418. k = w = 0;
  419. for (r = 1; r < argc; r++)
  420. if (*argv[r] == '-') {
  421. if (argv[r][1])
  422. for (q = argv[r]+1; *q; q++)
  423. switch (*q)
  424. {
  425. case 'b': /* Specify path for temporary file */
  426. if (k)
  427. ziperr(ZE_PARMS, "use -b before zip file name");
  428. else
  429. k = 1; /* Next non-option is path */
  430. break;
  431. case 'h': /* Show help */
  432. help(); EXIT(ZE_OK);
  433. case 'l': case 'L': /* Show copyright and disclaimer */
  434. license(); EXIT(ZE_OK);
  435. case 'q': /* Quiet operation, suppress info messages */
  436. noisy = 0; break;
  437. case 'v': /* Show version info */
  438. version_info(); EXIT(ZE_OK);
  439. case 'w':
  440. w = 1; break;
  441. default:
  442. ziperr(ZE_PARMS, "unknown option");
  443. }
  444. else
  445. ziperr(ZE_PARMS, "zip file cannot be stdin");
  446. } else
  447. if (k == 0)
  448. {
  449. if (zipfile == NULL)
  450. {
  451. if ((zipfile = ziptyp(argv[r])) == NULL)
  452. ziperr(ZE_MEM, "was processing arguments");
  453. }
  454. else
  455. ziperr(ZE_PARMS, "can only specify one zip file");
  456. }
  457. else
  458. {
  459. tempath = argv[r];
  460. k = 0;
  461. }
  462. if (zipfile == NULL)
  463. ziperr(ZE_PARMS, "need to specify zip file");
  464. if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
  465. ziperr(ZE_MEM, "input");
  466. }
  467. strcpy(in_path, zipfile);
  468. /* Read zip file */
  469. if ((r = readzipfile()) != ZE_OK)
  470. ziperr(r, zipfile);
  471. if (zfiles == NULL)
  472. ziperr(ZE_NAME, zipfile);
  473. /* Put comments to stdout, if not -w */
  474. if (!w)
  475. {
  476. for (z = zfiles; z != NULL; z = z->nxt)
  477. {
  478. printf("%c %s\n", MARK, z->zname);
  479. putclean(z->comment, z->com);
  480. printf("%c%s\n", MARK, MARKE);
  481. }
  482. printf("%c%s\n", MARK, MARKZ);
  483. putclean(zcomment, zcomlen);
  484. EXIT(ZE_OK);
  485. }
  486. /* If updating comments, make sure zip file is writeable */
  487. if ((x = fopen(zipfile, "a")) == NULL)
  488. ziperr(ZE_CREAT, zipfile);
  489. fclose(x);
  490. t = getfileattr(zipfile);
  491. /* Process stdin, replacing comments */
  492. z = zfiles;
  493. while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL &&
  494. (a[0] != MARK || strcmp(a + 1, MARKZ)))
  495. { /* while input and not file comment */
  496. if (a[0] != MARK || a[1] != ' ') /* better be "@ name" */
  497. ziperr(ZE_NOTE, "unexpected input");
  498. while (z != NULL && strcmp(a + 2, z->zname))
  499. z = z->nxt; /* allow missing entries in order */
  500. if (z == NULL)
  501. ziperr(ZE_NOTE, "unknown entry name");
  502. if ((a = zgetline(abf, WRBUFSIZ+1)) != NULL && a[0] == MARK && a[1] == '=')
  503. {
  504. if (z->name != z->iname)
  505. free((zvoid *)z->iname);
  506. if ((z->iname = malloc(strlen(a+1))) == NULL)
  507. ziperr(ZE_MEM, "was changing name");
  508. #ifdef EBCDIC
  509. strtoasc(z->iname, a+2);
  510. #else
  511. strcpy(z->iname, a+2);
  512. #endif
  513. /*
  514. * Don't update z->nam here, we need the old value a little later.....
  515. * The update is handled in zipcopy().
  516. */
  517. a = zgetline(abf, WRBUFSIZ+1);
  518. }
  519. if (z->com) /* change zip entry comment */
  520. free((zvoid *)z->comment);
  521. z->comment = malloc(1); *(z->comment) = 0;
  522. while (a != NULL && *a != MARK)
  523. {
  524. if ((r = catalloc(&(z->comment), a)) != ZE_OK)
  525. ziperr(r, "was building new zipentry comments");
  526. a = zgetline(abf, WRBUFSIZ+1);
  527. }
  528. z->com = strlen(z->comment);
  529. z = z->nxt; /* point to next entry */
  530. }
  531. if (a != NULL) /* change zip file comment */
  532. {
  533. zcomment = malloc(1); *zcomment = 0;
  534. while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL)
  535. if ((r = catalloc(&zcomment, a)) != ZE_OK)
  536. ziperr(r, "was building new zipfile comment");
  537. zcomlen = strlen(zcomment);
  538. }
  539. /* Open output zip file for writing */
  540. #if defined(UNIX) && !defined(NO_MKSTEMP)
  541. {
  542. int yd;
  543. int i;
  544. /* use mkstemp to avoid race condition and compiler warning */
  545. if (tempath != NULL)
  546. {
  547. /* if -b used to set temp file dir use that for split temp */
  548. if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
  549. ZIPERR(ZE_MEM, "allocating temp filename");
  550. }
  551. strcpy(tempzip, tempath);
  552. if (lastchar(tempzip) != '/')
  553. strcat(tempzip, "/");
  554. }
  555. else
  556. {
  557. /* create path by stripping name and appending template */
  558. if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
  559. ZIPERR(ZE_MEM, "allocating temp filename");
  560. }
  561. strcpy(tempzip, zipfile);
  562. for(i = strlen(tempzip); i > 0; i--) {
  563. if (tempzip[i - 1] == '/')
  564. break;
  565. }
  566. tempzip[i] = '\0';
  567. }
  568. strcat(tempzip, "ziXXXXXX");
  569. if ((yd = mkstemp(tempzip)) == EOF) {
  570. ZIPERR(ZE_TEMP, tempzip);
  571. }
  572. if ((tempzf = y = fdopen(yd, FOPW)) == NULL) {
  573. ZIPERR(ZE_TEMP, tempzip);
  574. }
  575. }
  576. #else
  577. if ((tempzf = y = fopen(tempzip = tempname(zipfile), FOPW)) == NULL)
  578. ziperr(ZE_TEMP, tempzip);
  579. #endif
  580. /* Open input zip file again, copy preamble if any */
  581. if ((in_file = fopen(zipfile, FOPR)) == NULL)
  582. ziperr(ZE_NAME, zipfile);
  583. if (zipbeg && (r = bfcopy(zipbeg)) != ZE_OK)
  584. ziperr(r, r == ZE_TEMP ? tempzip : zipfile);
  585. tempzn = zipbeg;
  586. /* Go through local entries, copying them over as is */
  587. fix = 3; /* needed for zipcopy if name changed */
  588. for (z = zfiles; z != NULL; z = z->nxt) {
  589. if ((r = zipcopy(z)) != ZE_OK)
  590. ziperr(r, "was copying an entry");
  591. }
  592. fclose(x);
  593. /* Write central directory and end of central directory with new comments */
  594. if ((c = zftello(y)) == (zoff_t)-1) /* get start of central */
  595. ziperr(ZE_TEMP, tempzip);
  596. for (z = zfiles; z != NULL; z = z->nxt)
  597. if ((r = putcentral(z)) != ZE_OK)
  598. ziperr(r, tempzip);
  599. if ((s = zftello(y)) == (zoff_t)-1) /* get end of central */
  600. ziperr(ZE_TEMP, tempzip);
  601. s -= c; /* compute length of central */
  602. if ((r = putend((zoff_t)zcount, s, c, zcomlen, zcomment)) != ZE_OK)
  603. ziperr(r, tempzip);
  604. tempzf = NULL;
  605. if (fclose(y))
  606. ziperr(ZE_TEMP, tempzip);
  607. if ((r = replace(zipfile, tempzip)) != ZE_OK)
  608. {
  609. zipwarn("new zip file left as: ", tempzip);
  610. free((zvoid *)tempzip);
  611. tempzip = NULL;
  612. ziperr(r, "was replacing the original zip file");
  613. }
  614. free((zvoid *)tempzip);
  615. tempzip = NULL;
  616. setfileattr(zipfile, t);
  617. #ifdef RISCOS
  618. /* Set the filetype of the zipfile to &DDC */
  619. setfiletype(zipfile,0xDDC);
  620. #endif
  621. free((zvoid *)zipfile);
  622. zipfile = NULL;
  623. /* Done! */
  624. RETURN(0);
  625. }