123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- /*
- zipnote.c - Zip 3
- Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
- See the accompanying file LICENSE, version 2007-Mar-4 or later
- (the contents of which are also included in zip.h) for terms of use.
- If, for some reason, all these files are missing, the Info-ZIP license
- also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
- */
- /*
- * zipnote.c by Mark Adler.
- */
- #define __ZIPNOTE_C
- #ifndef UTIL
- #define UTIL
- #endif
- #include "zip.h"
- #define DEFCPYRT /* main module: enable copyright string defines! */
- #include "revision.h"
- #include <signal.h>
- /* Calculate size of static line buffer used in write (-w) mode. */
- #define WRBUFSIZ 2047
- /* The line buffer size should be at least as large as FNMAX. */
- #if FNMAX > WRBUFSIZ
- # undef WRBUFSIZ
- # define WRBUFSIZ FNMAX
- #endif
- /* Character to mark zip entry names in the comment file */
- #define MARK '@'
- #define MARKE " (comment above this line)"
- #define MARKZ " (zip file comment below this line)"
- /* Temporary zip file pointer */
- local FILE *tempzf;
- /* Local functions */
- local void handler OF((int));
- local void license OF((void));
- local void help OF((void));
- local void version_info OF((void));
- local void putclean OF((char *, extent));
- /* getline name conflicts with GNU getline() function */
- local char *zgetline OF((char *, extent));
- local int catalloc OF((char * far *, char *));
- int main OF((int, char **));
- /* keep compiler happy until implement long options - 11/4/2003 EG */
- struct option_struct far options[] = {
- /* short longopt value_type negatable ID name */
- {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
- /* the end of the list */
- {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
- };
- #ifdef MACOS
- #define ziperr(c, h) zipnoteerr(c, h)
- #define zipwarn(a, b) zipnotewarn(a, b)
- void zipnoteerr(int c, ZCONST char *h);
- void zipnotewarn(ZCONST char *a, ZCONST char *b);
- #endif
- #ifdef QDOS
- #define exit(p1) QDOSexit()
- #endif
- int set_filetype(out_path)
- char *out_path;
- {
- #ifdef __BEOS__
- /* Set the filetype of the zipfile to "application/zip" */
- setfiletype( out_path, "application/zip" );
- #endif
- #ifdef __ATHEOS__
- /* Set the filetype of the zipfile to "application/x-zip" */
- setfiletype(out_path, "application/x-zip");
- #endif
- #ifdef MACOS
- /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
- setfiletype(out_path, 'IZip', 'ZIP ');
- #endif
- #ifdef RISCOS
- /* Set the filetype of the zipfile to &DDC */
- setfiletype(out_path, 0xDDC);
- #endif
- return ZE_OK;
- }
- /* rename a split
- * A split has a tempfile name until it is closed, then
- * here rename it as out_path the final name for the split.
- */
- int rename_split(temp_name, out_path)
- char *temp_name;
- char *out_path;
- {
- int r;
- /* Replace old zip file with new zip file, leaving only the new one */
- if ((r = replace(out_path, temp_name)) != ZE_OK)
- {
- zipwarn("new zip file left as: ", temp_name);
- free((zvoid *)tempzip);
- tempzip = NULL;
- ZIPERR(r, "was replacing split file");
- }
- if (zip_attributes) {
- setfileattr(out_path, zip_attributes);
- }
- return ZE_OK;
- }
- void zipmessage_nl(a, nl)
- ZCONST char *a; /* message string to output */
- int nl; /* 1 = add nl to end */
- /* If nl false, print a message to mesg without new line.
- If nl true, print and add new line. If logfile is
- open then also write message to log file. */
- {
- if (noisy) {
- fprintf(mesg, "%s", a);
- if (nl) {
- fprintf(mesg, "\n");
- mesg_line_started = 0;
- } else {
- mesg_line_started = 1;
- }
- fflush(mesg);
- }
- }
- void zipmessage(a, b)
- ZCONST char *a, *b; /* message strings juxtaposed in output */
- /* Print a message to mesg and flush. Also write to log file if
- open. Write new line first if current line has output already. */
- {
- if (noisy) {
- if (mesg_line_started)
- fprintf(mesg, "\n");
- fprintf(mesg, "%s%s\n", a, b);
- mesg_line_started = 0;
- fflush(mesg);
- }
- }
- void ziperr(c, h)
- int c; /* error code from the ZE_ class */
- ZCONST char *h; /* message about how it happened */
- /* Issue a message for the error, clean up files and memory, and exit. */
- {
- if (PERR(c))
- perror("zipnote error");
- fprintf(mesg, "zipnote error: %s (%s)\n", ZIPERRORS(c), h);
- if (tempzf != NULL)
- fclose(tempzf);
- if (tempzip != NULL)
- {
- destroy(tempzip);
- free((zvoid *)tempzip);
- }
- if (zipfile != NULL)
- free((zvoid *)zipfile);
- EXIT(c);
- }
- local void handler(s)
- int s; /* signal number (ignored) */
- /* Upon getting a user interrupt, abort cleanly using ziperr(). */
- {
- #ifndef MSDOS
- putc('\n', mesg);
- #endif /* !MSDOS */
- ziperr(ZE_ABORT, "aborting");
- s++; /* keep some compilers happy */
- }
- void zipwarn(a, b)
- ZCONST char *a, *b; /* message strings juxtaposed in output */
- /* Print a warning message to mesg (usually stderr) and return. */
- {
- fprintf(mesg, "zipnote warning: %s%s\n", a, b);
- }
- local void license()
- /* Print license information to stdout. */
- {
- extent i; /* counter for copyright array */
- for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
- puts(swlicense[i]);
- }
- local void help()
- /* Print help (along with license info) to stdout. */
- {
- extent i; /* counter for help array */
- /* help array */
- static ZCONST char *text[] = {
- "",
- "ZipNote %s (%s)",
- #ifdef VM_CMS
- "Usage: zipnote [-w] [-q] [-b fm] zipfile",
- #else
- "Usage: zipnote [-w] [-q] [-b path] zipfile",
- #endif
- " the default action is to write the comments in zipfile to stdout",
- " -w write the zipfile comments from stdin",
- #ifdef VM_CMS
- " -b use \"fm\" as the filemode for the temporary zip file",
- #else
- " -b use \"path\" for the temporary zip file",
- #endif
- " -q quieter operation, suppress some informational messages",
- " -h show this help -v show version info -L show software license",
- "",
- "Example:",
- #ifdef VMS
- " define/user sys$output foo.tmp",
- " zipnote foo.zip",
- " edit foo.tmp",
- " ... then you edit the comments, save, and exit ...",
- " define/user sys$input foo.tmp",
- " zipnote -w foo.zip",
- #else
- #ifdef RISCOS
- " zipnote foo/zip > foo/tmp",
- " <!Edit> foo/tmp",
- " ... then you edit the comments, save, and exit ...",
- " zipnote -w foo/zip < foo/tmp",
- #else
- #ifdef VM_CMS
- " zipnote foo.zip > foo.tmp",
- " xedit foo tmp",
- " ... then you edit the comments, save, and exit ...",
- " zipnote -w foo.zip < foo.tmp",
- #else
- " zipnote foo.zip > foo.tmp",
- " ed foo.tmp",
- " ... then you edit the comments, save, and exit ...",
- " zipnote -w foo.zip < foo.tmp",
- #endif /* VM_CMS */
- #endif /* RISCOS */
- #endif /* VMS */
- "",
- " \"@ name\" can be followed by an \"@=newname\" line to change the name"
- };
- for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
- printf(copyright[i], "zipnote");
- putchar('\n');
- }
- for (i = 0; i < sizeof(text)/sizeof(char *); i++)
- {
- printf(text[i], VERSION, REVDATE);
- putchar('\n');
- }
- }
- /*
- * XXX put this in version.c
- */
- local void version_info()
- /* Print verbose info about program version and compile time options
- to stdout. */
- {
- extent i; /* counter in text arrays */
- /* Options info array */
- static ZCONST char *comp_opts[] = {
- #ifdef DEBUG
- "DEBUG",
- #endif
- NULL
- };
- for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
- {
- printf(copyright[i], "zipnote");
- putchar('\n');
- }
- for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
- {
- printf(versinfolines[i], "ZipNote", VERSION, REVDATE);
- putchar('\n');
- }
- version_local();
- puts("ZipNote special compilation options:");
- for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
- {
- printf("\t%s\n",comp_opts[i]);
- }
- if (i == 0)
- puts("\t[none]");
- }
- local void putclean(s, n)
- char *s; /* string to write to stdout */
- extent n; /* length of string */
- /* Write the string s to stdout, filtering out control characters that are
- not tab or newline (mainly to remove carriage returns), and prefix MARK's
- and backslashes with a backslash. Also, terminate with a newline if
- needed. */
- {
- int c; /* next character in string */
- int e; /* last character written */
- e = '\n'; /* if empty, write nothing */
- while (n--)
- {
- c = *(uch *)s++;
- if (c == MARK || c == '\\')
- putchar('\\');
- if (c >= ' ' || c == '\t' || c == '\n')
- { e=c; putchar(e); }
- }
- if (e != '\n')
- putchar('\n');
- }
- local char *zgetline(buf, size)
- char *buf;
- extent size;
- /* Read a line of text from stdin into string buffer 'buf' of size 'size'.
- In case of buffer overflow or EOF, a NULL pointer is returned. */
- {
- char *line;
- unsigned len;
- line = fgets(buf, size, stdin);
- if (line != NULL && (len = strlen(line)) > 0) {
- if (len == size-1 && line[len-1] != '\n') {
- /* buffer is full and record delimiter not seen -> overflow */
- line = NULL;
- } else {
- /* delete trailing record delimiter */
- if (line[len-1] == '\n') line[len-1] = '\0';
- }
- }
- return line;
- }
- local int catalloc(a, s)
- char * far *a; /* pointer to a pointer to a malloc'ed string */
- char *s; /* string to concatenate on a */
- /* Concatentate the string s to the malloc'ed string pointed to by a.
- Preprocess s by removing backslash escape characters. */
- {
- char *p; /* temporary pointer */
- char *q; /* temporary pointer */
- for (p = q = s; *q; *p++ = *q++)
- if (*q == '\\' && *(q+1))
- q++;
- *p = 0;
- if ((p = malloc(strlen(*a) + strlen(s) + 3)) == NULL)
- return ZE_MEM;
- strcat(strcat(strcpy(p, *a), **a ? "\r\n" : ""), s);
- free((zvoid *)*a);
- *a = p;
- return ZE_OK;
- }
- #ifndef USE_ZIPNOTEMAIN
- int main(argc, argv)
- #else
- int zipnotemain(argc, argv)
- #endif
- int argc; /* number of tokens in command line */
- char **argv; /* command line tokens */
- /* Write the comments in the zipfile to stdout, or read them from stdin. */
- {
- char abf[WRBUFSIZ+1]; /* input line buffer */
- char *a; /* pointer to line buffer or NULL */
- zoff_t c; /* start of central directory */
- int k; /* next argument type */
- char *q; /* steps through option arguments */
- int r; /* arg counter, temporary variable */
- zoff_t s; /* length of central directory */
- int t; /* attributes of zip file */
- int w; /* true if updating zip file from stdin */
- FILE *x; /* input file for testing if can write it */
- struct zlist far *z; /* steps through zfiles linked list */
- #ifdef THEOS
- setlocale(LC_CTYPE, "I");
- #endif
- #ifdef UNICODE_SUPPORT
- # ifdef UNIX
- /* For Unix, set the locale to UTF-8. Any UTF-8 locale is
- OK and they should all be the same. This allows seeing,
- writing, and displaying (if the fonts are loaded) all
- characters in UTF-8. */
- {
- char *loc;
- /*
- loc = setlocale(LC_CTYPE, NULL);
- printf(" Initial language locale = '%s'\n", loc);
- */
- loc = setlocale(LC_CTYPE, "en_US.UTF-8");
- /*
- printf("langinfo %s\n", nl_langinfo(CODESET));
- */
- if (loc != NULL) {
- /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
- using_utf8 = 1;
- /*
- printf(" Locale set to %s\n", loc);
- */
- } else {
- /*
- printf(" Could not set Unicode UTF-8 locale\n");
- */
- }
- }
- # endif
- #endif
- /* If no args, show help */
- if (argc == 1)
- {
- help();
- EXIT(ZE_OK);
- }
- /* Direct info messages to stderr; stdout is used for data output. */
- mesg = stderr;
- init_upper(); /* build case map table */
- /* Go through args */
- zipfile = tempzip = NULL;
- tempzf = NULL;
- signal(SIGINT, handler);
- #ifdef SIGTERM /* AMIGA has no SIGTERM */
- signal(SIGTERM, handler);
- #endif
- #ifdef SIGABRT
- signal(SIGABRT, handler);
- #endif
- #ifdef SIGBREAK
- signal(SIGBREAK, handler);
- #endif
- #ifdef SIGBUS
- signal(SIGBUS, handler);
- #endif
- #ifdef SIGILL
- signal(SIGILL, handler);
- #endif
- #ifdef SIGSEGV
- signal(SIGSEGV, handler);
- #endif
- k = w = 0;
- for (r = 1; r < argc; r++)
- if (*argv[r] == '-') {
- if (argv[r][1])
- for (q = argv[r]+1; *q; q++)
- switch (*q)
- {
- case 'b': /* Specify path for temporary file */
- if (k)
- ziperr(ZE_PARMS, "use -b before zip file name");
- else
- k = 1; /* Next non-option is path */
- break;
- case 'h': /* Show help */
- help(); EXIT(ZE_OK);
- case 'l': case 'L': /* Show copyright and disclaimer */
- license(); EXIT(ZE_OK);
- case 'q': /* Quiet operation, suppress info messages */
- noisy = 0; break;
- case 'v': /* Show version info */
- version_info(); EXIT(ZE_OK);
- case 'w':
- w = 1; break;
- default:
- ziperr(ZE_PARMS, "unknown option");
- }
- else
- ziperr(ZE_PARMS, "zip file cannot be stdin");
- } else
- if (k == 0)
- {
- if (zipfile == NULL)
- {
- if ((zipfile = ziptyp(argv[r])) == NULL)
- ziperr(ZE_MEM, "was processing arguments");
- }
- else
- ziperr(ZE_PARMS, "can only specify one zip file");
- }
- else
- {
- tempath = argv[r];
- k = 0;
- }
- if (zipfile == NULL)
- ziperr(ZE_PARMS, "need to specify zip file");
- if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
- ziperr(ZE_MEM, "input");
- }
- strcpy(in_path, zipfile);
- /* Read zip file */
- if ((r = readzipfile()) != ZE_OK)
- ziperr(r, zipfile);
- if (zfiles == NULL)
- ziperr(ZE_NAME, zipfile);
- /* Put comments to stdout, if not -w */
- if (!w)
- {
- for (z = zfiles; z != NULL; z = z->nxt)
- {
- printf("%c %s\n", MARK, z->zname);
- putclean(z->comment, z->com);
- printf("%c%s\n", MARK, MARKE);
- }
- printf("%c%s\n", MARK, MARKZ);
- putclean(zcomment, zcomlen);
- EXIT(ZE_OK);
- }
- /* If updating comments, make sure zip file is writeable */
- if ((x = fopen(zipfile, "a")) == NULL)
- ziperr(ZE_CREAT, zipfile);
- fclose(x);
- t = getfileattr(zipfile);
- /* Process stdin, replacing comments */
- z = zfiles;
- while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL &&
- (a[0] != MARK || strcmp(a + 1, MARKZ)))
- { /* while input and not file comment */
- if (a[0] != MARK || a[1] != ' ') /* better be "@ name" */
- ziperr(ZE_NOTE, "unexpected input");
- while (z != NULL && strcmp(a + 2, z->zname))
- z = z->nxt; /* allow missing entries in order */
- if (z == NULL)
- ziperr(ZE_NOTE, "unknown entry name");
- if ((a = zgetline(abf, WRBUFSIZ+1)) != NULL && a[0] == MARK && a[1] == '=')
- {
- if (z->name != z->iname)
- free((zvoid *)z->iname);
- if ((z->iname = malloc(strlen(a+1))) == NULL)
- ziperr(ZE_MEM, "was changing name");
- #ifdef EBCDIC
- strtoasc(z->iname, a+2);
- #else
- strcpy(z->iname, a+2);
- #endif
- /*
- * Don't update z->nam here, we need the old value a little later.....
- * The update is handled in zipcopy().
- */
- a = zgetline(abf, WRBUFSIZ+1);
- }
- if (z->com) /* change zip entry comment */
- free((zvoid *)z->comment);
- z->comment = malloc(1); *(z->comment) = 0;
- while (a != NULL && *a != MARK)
- {
- if ((r = catalloc(&(z->comment), a)) != ZE_OK)
- ziperr(r, "was building new zipentry comments");
- a = zgetline(abf, WRBUFSIZ+1);
- }
- z->com = strlen(z->comment);
- z = z->nxt; /* point to next entry */
- }
- if (a != NULL) /* change zip file comment */
- {
- zcomment = malloc(1); *zcomment = 0;
- while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL)
- if ((r = catalloc(&zcomment, a)) != ZE_OK)
- ziperr(r, "was building new zipfile comment");
- zcomlen = strlen(zcomment);
- }
- /* Open output zip file for writing */
- #if defined(UNIX) && !defined(NO_MKSTEMP)
- {
- int yd;
- int i;
- /* use mkstemp to avoid race condition and compiler warning */
- if (tempath != NULL)
- {
- /* if -b used to set temp file dir use that for split temp */
- if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
- ZIPERR(ZE_MEM, "allocating temp filename");
- }
- strcpy(tempzip, tempath);
- if (lastchar(tempzip) != '/')
- strcat(tempzip, "/");
- }
- else
- {
- /* create path by stripping name and appending template */
- if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
- ZIPERR(ZE_MEM, "allocating temp filename");
- }
- strcpy(tempzip, zipfile);
- for(i = strlen(tempzip); i > 0; i--) {
- if (tempzip[i - 1] == '/')
- break;
- }
- tempzip[i] = '\0';
- }
- strcat(tempzip, "ziXXXXXX");
- if ((yd = mkstemp(tempzip)) == EOF) {
- ZIPERR(ZE_TEMP, tempzip);
- }
- if ((tempzf = y = fdopen(yd, FOPW)) == NULL) {
- ZIPERR(ZE_TEMP, tempzip);
- }
- }
- #else
- if ((tempzf = y = fopen(tempzip = tempname(zipfile), FOPW)) == NULL)
- ziperr(ZE_TEMP, tempzip);
- #endif
- /* Open input zip file again, copy preamble if any */
- if ((in_file = fopen(zipfile, FOPR)) == NULL)
- ziperr(ZE_NAME, zipfile);
- if (zipbeg && (r = bfcopy(zipbeg)) != ZE_OK)
- ziperr(r, r == ZE_TEMP ? tempzip : zipfile);
- tempzn = zipbeg;
- /* Go through local entries, copying them over as is */
- fix = 3; /* needed for zipcopy if name changed */
- for (z = zfiles; z != NULL; z = z->nxt) {
- if ((r = zipcopy(z)) != ZE_OK)
- ziperr(r, "was copying an entry");
- }
- fclose(x);
- /* Write central directory and end of central directory with new comments */
- if ((c = zftello(y)) == (zoff_t)-1) /* get start of central */
- ziperr(ZE_TEMP, tempzip);
- for (z = zfiles; z != NULL; z = z->nxt)
- if ((r = putcentral(z)) != ZE_OK)
- ziperr(r, tempzip);
- if ((s = zftello(y)) == (zoff_t)-1) /* get end of central */
- ziperr(ZE_TEMP, tempzip);
- s -= c; /* compute length of central */
- if ((r = putend((zoff_t)zcount, s, c, zcomlen, zcomment)) != ZE_OK)
- ziperr(r, tempzip);
- tempzf = NULL;
- if (fclose(y))
- ziperr(ZE_TEMP, tempzip);
- if ((r = replace(zipfile, tempzip)) != ZE_OK)
- {
- zipwarn("new zip file left as: ", tempzip);
- free((zvoid *)tempzip);
- tempzip = NULL;
- ziperr(r, "was replacing the original zip file");
- }
- free((zvoid *)tempzip);
- tempzip = NULL;
- setfileattr(zipfile, t);
- #ifdef RISCOS
- /* Set the filetype of the zipfile to &DDC */
- setfiletype(zipfile,0xDDC);
- #endif
- free((zvoid *)zipfile);
- zipfile = NULL;
- /* Done! */
- RETURN(0);
- }
|