DEADSOFTWARE

Patched for Linux
[mp3cc.git] / MPC.3.5.LINUX / preverifier / jar_support.c
1 /* * @(#)jar_support.c 1.24 01/07/19
2 *
3 * Copyright 1997, 1998 by Sun Microsystems, Inc.,
4 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
5 * All rights reserved.
6 *
7 * This software is the confidential and proprietary information
8 * of Sun Microsystems, Inc. ("Confidential Information"). You
9 * shall not disclose such Confidential Information and shall use
10 * it only in accordance with the terms of the license agreement
11 * you entered into with Sun.
12 * Use is subject to license terms.
13 */
15 /*=========================================================================
16 * SYSTEM: Verifier
17 * SUBSYSTEM: JAR support routines for the verifier.
18 * FILE: jar_support.c
19 * OVERVIEW: JAR support routines for verifying class files from a ZIP or
20 * JAR file.
21 * Note that the JAR file reader used is based on the KVM
22 * implementation with some modifications.
23 * AUTHOR: Tasneem Sayeed, Java Consumer Technologies, Sun Microsystems
24 *=======================================================================*/
26 /*=========================================================================
27 * Include files
28 *=======================================================================*/
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <string.h>
38 #include "sys_api.h"
39 #include "path_md.h"
40 #include "path.h"
41 #include "oobj.h"
42 #include "jar.h"
43 #include "convert_md.h"
45 #include <string.h>
47 #ifdef WIN32
48 #include <process.h>
49 #endif
50 /*=========================================================================
51 * Globals and extern declarations
52 *=======================================================================*/
54 //extern int errno;
55 char str_buffer[STRINGBUFFERSIZE]; /* shared string buffer */
56 bool_t JARfile = FALSE; /* if true, indicates that output is in a
57 JAR file */
58 extern bool_t tmpDirExists;
59 /* if true, indicates that a temp dir exists
60 with classes to be verified */
61 char *zipFileName = NULL; /* stores name of the zip file */
62 extern char tmp_dir[32]; /* temporary directory for storing
63 verified classes */
64 extern char *output_dir; /* output directory */
66 char manifestfile[1024]; /* used for saving the JAR manifest file name */
68 extern void VerifyFile(register char *fn);
71 /*=========================================================================
72 * FUNCTION: isJARfile
73 * OVERVIEW: Determines if the given file is a JAR or ZIP file.
74 * Returns true if the suffix ends with ".jar" or ".zip".
75 * INTERFACE:
76 * parameters: fn: name of the JAR file
77 * length: length of data, in bytes
78 * returns: boolean type
79 *=======================================================================*/
80 bool_t
81 isJARfile (char *fn, int length)
82 {
83 char *suffix;
86 if (length >= 4 &&
87 (( suffix = fn + length - 4)[0] == '.') &&
88 ((( _toupper(suffix[1]) == 'Z') &&
89 ( _toupper(suffix[2]) == 'I') &&
90 ( _toupper(suffix[3]) == 'P')) ||
91 (( _toupper(suffix[1]) == 'J') &&
92 ( _toupper(suffix[2]) == 'A') &&
93 ( _toupper(suffix[3]) == 'R')))) {
94 return TRUE;
95 } else {
96 return FALSE;
97 }
98 }
101 /*=========================================================================
102 * FUNCTION: isManifestfile
103 * OVERVIEW: Determines if the given file is a JAR Manifest file.
104 * Returns true if the file ends with "MANIFEST.MF".
105 * INTERFACE:
106 * parameters: fn: name of the JAR manifest file
107 * length: length of data, in bytes
108 * returns: boolean type
109 *=======================================================================*/
110 bool_t
111 isManifestfile (char *fn, int length)
113 if ((length >= 11) &&
114 (strcmp(fn + length - 11, "MANIFEST.MF") == 0)) {
115 return TRUE;
116 } else {
117 return FALSE;
122 /*=========================================================================
123 * FUNCTION: ensure_tmpdir_exists
124 * OVERVIEW: Validates to ensure that the tmpdir exists using the
125 * system-specific directory delimiters.
127 * INTERFACE:
128 * parameters: char* dir name
129 * returns: nothing
130 *=======================================================================*/
131 void ensure_tmpdir_exists(char *dir)
133 struct stat stat_buf;
134 char *parent;
135 char *q;
136 if (dir[0] == 0) {
137 return;
139 parent = strdup(dir);
140 q = strrchr(parent, (char)LOCAL_DIR_SEPARATOR);
141 if (q) {
142 *q = 0;
143 ensure_tmpdir_exists(parent);
145 if (stat(dir, &stat_buf) < 0) {
146 if (JAR_DEBUG && verbose) {
147 jio_fprintf(stderr, "Creating output directory [%s]\n", dir);
149 #ifdef WIN32
150 mkdir(dir);
151 #endif
152 #ifdef UNIX
153 mkdir(dir, 0755);
154 #endif
156 free(parent);
160 /*=========================================================================
161 * FUNCTION: JARname2fname
162 * OVERVIEW: Converts JAR name to the system-specific file name with
163 * the correct directory delimiters.
165 * INTERFACE:
166 * parameters: char* source JAR name
167 * char* dest file name
168 * int size
169 * returns: char*
170 *=======================================================================*/
171 char*
172 JARname2fname(char *src, char *dst, int size) {
173 char *buf = dst;
174 for (; (--size > 0) && (*src != '\0') ; src++, dst++) {
175 if (*src == '/') {
176 *dst = (char)LOCAL_DIR_SEPARATOR;
177 } else {
178 *dst = *src;
181 dst++;
182 *dst = '\0';
183 return buf;
187 /*=========================================================================
188 * FUNCTION: getZipEntry
189 * OVERVIEW: Converts a zip file to a Zip entry type.
190 * INTERFACE:
191 * parameters: zipFile: name of the JAR file
192 * len: length of data, in bytes
193 * returns: zip entry type
194 *=======================================================================*/
195 zip_t *
196 getZipEntry (char *zipFile, int len) {
197 zip_t * zipEntry = NULL; /* for processing errors */
199 if (JAR_DEBUG && verbose)
200 jio_fprintf(stderr,
201 "getZipEntry: JAR file [%s] Size [%d]\n", zipFile, len);
203 /* create the zip entry for loading the ZIP file */
204 zipEntry = (zip_t *) sysMalloc(sizeof(zip_t) + len);
205 if (zipEntry == NULL) {
206 fprintf(stderr, "getZipEntry: Out of memory\n");
207 exit(1);
210 memcpy(zipEntry->name, zipFile, len);
212 zipEntry->name[len] = '\0';
214 if (JAR_DEBUG && verbose)
215 jio_fprintf(stderr, "getZipEntry: Zip Entry Name [%s]\n", zipEntry->name);
218 zipEntry->type = '\0';
219 return zipEntry;
223 /*=========================================================================
224 * FUNCTION: findJARDirectories
225 * OVERVIEW: Helper function used for JAR loading for locating JAR
226 * directories.
227 * It returns TRUE if it is successful in locating the
228 * JAR directory headers, false otherwise.
229 * If successful,
230 * entry->jar.locpos is set to the position of the first
231 * local header.
232 * entry->jar.cenpos is set to the position of the first
233 * central header.
235 * Note that *locpos pointer is the logical "0" of the file.
236 * All offsets extracted need to have this value added to them.
238 * INTERFACE:
239 * parameters: entry: zipFileEntry
240 * statbuf: pointer to the stat buffer
241 * returns: boolean type
242 *=======================================================================*/
244 bool_t
245 findJARDirectories(zip_t *entry, struct stat *statbuf)
247 bool_t result = FALSE;
248 long length = statbuf->st_size;
249 long position, minPosition;
250 char *bp;
251 FILE *file;
253 char *buffer = str_buffer;
254 unsigned const int bufferSize = STRINGBUFFERSIZE;
256 /* Calculate the smallest possible position for the end header. It
257 * can be at most 0xFFFF + ENDHDRSIZ bytes from the end of the file, but
258 * the file must also have a local header and a central header
259 */
260 minPosition = length - (0xFFFF + ENDHDRSIZ);
261 if (minPosition < LOCHDRSIZ + CENHDRSIZ) {
262 minPosition = LOCHDRSIZ + CENHDRSIZ;
265 file = fopen(entry->name, "rb");
266 if (file == NULL) {
267 goto done;
270 /* Read in the last ENDHDRSIZ bytes into the buffer. 99% of the time,
271 * the file won't have a comment, and this is the only read we'll need */
272 if ( (fseek(file, -ENDHDRSIZ, SEEK_END) < 0)
273 || (fread(buffer, sizeof(char), ENDHDRSIZ, file) != ENDHDRSIZ)) {
274 goto done;
276 /* Get the position in the file stored into buffer[0] */
277 position = length - ENDHDRSIZ; /* Position in file of buffer[0] */
278 bp = buffer; /* Where to start looking */
279 for (;;) {
280 /* "buffer" contains a block of data from the file, starting at
281 * position "position" in the file.
282 * We investigate whether position + (bp - buffer) is the start
283 * of the end header in the zip file. This file position is at
284 * position bp in the buffer.
285 */
286 /* Use simplified version of Knuth Morris Pratt search algorithm. */
287 switch(bp[0]) {
288 case '\006': /* The header must start at least 3 bytes back */
289 bp -= 3; break;
290 case '\005': /* The header must start at least 2 bytes back */
291 bp -= 2; break;
292 case 'K': /* The header must start at least 1 byte back */
293 bp -= 1; break;
294 case 'P': /* Either this is the header, or the header must
295 * start at least 4 back
296 */
297 if (bp[1] == 'K' && bp[2] == 5 && bp[3] == 6) {
298 int endpos = position + (bp - buffer);
299 if (endpos + ENDHDRSIZ + ENDCOM(bp) == length) {
300 unsigned long cenpos = endpos - ENDSIZ(bp);
301 unsigned long locpos = cenpos - ENDOFF(bp);
302 entry->jar.cenpos = cenpos;
303 entry->jar.locpos = locpos;
304 result = TRUE;
305 goto done;
308 /* FALL THROUGH */
309 default: /* This char isn't in the header signature, so
310 * the header must start at least four chars back */
311 bp -= 4;
314 if (bp < buffer) {
315 /* We've moved outside our window into the file. We must
316 * move the window backwards */
317 int count = position - minPosition; /* Bytes left in file */
318 if (count == 0) {
319 /* Nothing left to read. Time to give up */
320 goto done;
321 } else {
322 /* up to ((bp - buffer) + ENDHDRSIZ) bytes in the buffer might
323 * still be part of the end header, so the most bytes we can
324 * actually read are
325 * bufferSize - ((bp - buffer) + ENDHDRSIZE).
326 */
327 int available = (bufferSize - ENDHDRSIZ) + (buffer - bp);
328 if (count > available) {
329 count = available;
332 /* Back up, while keeping our virtual position the same */
333 position -= count;
334 bp += count;
335 memmove(buffer + count, buffer, bufferSize - count);
336 if ( (fseek(file, position, SEEK_SET) < 0)
337 || (fread(buffer, sizeof(char), count, file) != (unsigned)count)) {
338 goto done;
341 } /* end of for loop */
343 done:
344 if (file != NULL) {
345 fclose(file);
347 return result;
351 /*=========================================================================
352 * FUNCTION: jarCRC32
353 * OVERVIEW: Returns the CRC of an array of bytes, using the same
354 * algorithm as used by the JAR reader.
355 * INTERFACE:
356 * parameters: data: pointer to the array of bytes
357 * length: length of data, in bytes
358 * returns: CRC
359 *=======================================================================*/
361 static unsigned long
362 jarCRC32(unsigned char *data, unsigned long length) {
363 unsigned long crc = 0xFFFFFFFF;
364 unsigned int j;
365 for ( ; length > 0; length--, data++) {
366 crc ^= *data;
367 for (j = 8; j > 0; --j) {
368 crc = (crc & 1) ? ((crc >> 1) ^ 0xedb88320) : (crc >> 1);
371 return ~crc;
375 /*=========================================================================
376 * FUNCTION: loadJARfile()
377 * TYPE: load JAR file
378 * OVERVIEW: Internal function used by openClassfileInternal().
380 * This function reads the specified class file from the JAR file. The
381 * result is returned as a JAR_DataStream*. NULL is returned if it
382 * cannot find the file, or there is some error.
384 * INTERFACE:
385 * parameters: entry: zip file entry for the JAR file
386 * filename: class file name to search for
387 * returns: JAR_DataStream* for saving the JAR file info, or NULL.
388 *=======================================================================*/
390 JAR_DataStreamPtr
391 loadJARfile(zip_t *entry, const char* filename)
393 JAR_DataStreamPtr jdstream = NULL; /* result on error */
394 unsigned int filenameLength;
395 unsigned int nameLength;
396 char buff[BUFSIZ];
397 char *UTFfilename = &buff[0];
398 char *p = str_buffer; /* temporary storage */
399 int offset;
400 char *fname = NULL;
401 FILE *file = fopen(entry->name, "rb");
402 if (file == NULL) {
403 goto done;
406 if (JAR_DEBUG && verbose)
407 jio_fprintf(stderr,
408 "loadJARfile: Opening zip file %s to search for [%s]\n",
409 entry->name, filename);
411 /* add the .class to the filename */
414 if (JAR_DEBUG && verbose)
415 jio_fprintf(stderr,
416 "loadJARfile: Adding '.class' to %s size [%d]\n", filename, strlen(filename));
418 /* Conversion for Japanese filenames */
419 native2utf8(filename, UTFfilename, BUFSIZ);
421 /* allocate fname large enough to hold .class + '\0' terminator */
422 fname = (char *)malloc(strlen(UTFfilename) + 6 + 1);
423 sprintf(fname, "%s.class", UTFfilename);
424 filenameLength=strlen(fname);
425 fname[filenameLength]='\0';
427 if (JAR_DEBUG && verbose)
428 jio_fprintf(stderr,
429 "loadJARfile: Searching for filename [%s]\n", fname);
431 /* Go to the start of the central headers */
432 offset = entry->jar.cenpos;
433 for (;;) {
435 if (/* Go to the next central header */
436 (fseek(file, offset, SEEK_SET) < 0)
437 /* Read the bytes */
438 || (fread(p, sizeof(char), CENHDRSIZ, file) != CENHDRSIZ)
439 /* Make sure it is a header */
440 || (GETSIG(p) != CENSIG)) {
441 goto done;
444 /* Get the nameLength */
445 nameLength = CENNAM(p);
448 if (nameLength == filenameLength) {
449 if (fread(p + CENHDRSIZ, sizeof(char), nameLength, file)
450 != nameLength) {
451 goto done;
453 if (memcmp(p + CENHDRSIZ, fname, nameLength) == 0) {
455 if (JAR_DEBUG && verbose)
456 jio_fprintf(stderr, "loadJARfile: Class name found [%s]...\n", fname);
457 break;
461 /* Set offset to the next central header */
462 offset += CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p);
464 } /* end loop */
466 /* p points at the central header for the file */
468 unsigned long decompLen = CENLEN(p); /* the decompressed length */
469 unsigned long compLen = CENSIZ(p); /* the compressed length */
470 unsigned long method = CENHOW(p); /* how it is stored */
471 unsigned long expectedCRC = CENCRC(p); /* expected CRC */
472 unsigned long actualCRC;
474 unsigned char *decompData;
476 /* Make sure file is not encrypted */
477 if ((CENFLG(p) & 1) == 1) {
478 fprintf(stderr, "Entry is encrypted");
479 goto done;
483 jdstream =
484 (JAR_DataStreamPtr)sysMalloc(sizeof(JAR_DataStream) + decompLen);
485 decompData = (unsigned char *)(jdstream + 1);
487 if (/* Go to the beginning of the LOC header */
488 (fseek(file, entry->jar.locpos + CENOFF(p), SEEK_SET) < 0)
489 /* Read it */
490 || (fread(p, sizeof(char), LOCHDRSIZ, file) != LOCHDRSIZ)
491 /* Skip over name and extension, if any */
492 || (fseek(file, LOCNAM(p) + LOCEXT(p), SEEK_CUR) < 0)) {
493 goto done;
496 switch (method) {
497 case STORED:
498 if (compLen != decompLen) {
499 return NULL;
501 fread(decompData, sizeof(char), decompLen, file);
502 break;
504 case DEFLATED: {
505 bool_t inflateOK;
506 inflateOK = inflate(file, compLen, decompData, decompLen);
508 if (!inflateOK) {
509 sysFree(jdstream);
510 jdstream = NULL;
512 break;
515 default:
516 sysFree(jdstream);
517 jdstream = NULL;
518 break;
521 actualCRC = jarCRC32(decompData, decompLen);
522 if (actualCRC != expectedCRC) {
523 printf("Unexpected CRC value");
526 done:
527 if (file != NULL) {
528 fclose(file);
531 if (fname != NULL) {
532 sysFree(fname);
535 if (jdstream != NULL) {
537 jdstream->type = JAR_RESOURCE;
538 jdstream->data = decompData;
539 jdstream->dataLen = decompLen;
540 jdstream->dataIndex = 0;
541 jdstream->mode = JAR_READ;
543 return jdstream;
549 /*=========================================================================
550 * FUNCTION: ReadFromZip()
551 * TYPE: Reads and verifies ZIP file entries
552 * OVERVIEW: Internal function used by ProcessInputs() and recurse_dir.
554 * This function reads all the Zip entries, and stores them temporarily in
555 * tmpdir. If the ZIP entry read is a class file, then VerifyFile is invoked
556 * to verify the class file. Otherwise, the file read is simply copied over
557 * temporarily to the tmpdir. These are later used for generating a new JAR
558 * file.
560 * INTERFACE:
561 * parameters: ZipEntry: name of the zip file entry.
562 * returns: nothing
563 *=======================================================================*/
565 void
566 ReadFromZip(zip_t *entry)
568 unsigned int nameLength;
569 char *filename = NULL;
570 char *p = str_buffer; /* temporary storage */
571 int offset, nextOffset;
572 int fd;
573 int status;
574 JAR_DataStreamPtr jdstream = NULL;
575 struct stat stat_buf;
576 unsigned char *decompData;
577 unsigned long decompLen; /* the decompressed length */
579 FILE *file = fopen(entry->name, "rb");
580 if (file == NULL) {
581 goto done;
584 if (JAR_DEBUG && verbose)
585 jio_fprintf(stderr,
586 "ReadFromZip: Opened zip file to read classes \n");
588 /* initialize */
589 memset(manifestfile, 0, 1024);
591 /* Go to the start of the central headers */
592 offset = entry->jar.cenpos;
593 for (;;) {
595 if (/* Go to the next central header */
596 (fseek(file, offset, SEEK_SET) < 0)
597 /* Read the bytes */
598 || (fread(p, sizeof(char), CENHDRSIZ, file) != CENHDRSIZ)
599 /* Make sure it is a header */
600 || (GETSIG(p) != CENSIG)) {
601 goto done;
603 /* Get the nameLength */
604 nameLength = CENNAM(p);
606 if (fread(p + CENHDRSIZ, sizeof(char), nameLength, file)
607 != nameLength) {
608 goto done;
612 /* initialize the filename with nulls every time */
614 filename = (char *) sysCalloc(STRINGBUFFERSIZE, nameLength);
616 if (filename == NULL) {
617 fprintf(stderr, "ReadFromZip: Out of memory \n");
618 exit(1);
621 memcpy(filename, p + CENHDRSIZ, nameLength);
624 /* We have to calculate nextOffset now, because VerifyFile bashes
625 * str_buffer
626 */
627 nextOffset = offset + CENHDRSIZ + nameLength + CENEXT(p) + CENCOM(p);
629 if (JAR_DEBUG && verbose)
630 jio_fprintf(stderr,
631 "ReadFromZip: filename read %s\n", filename);
633 /* extract the .class from the filename */
634 if (nameLength > 6 &&
635 strcmp(filename + nameLength - 6, ".class") == 0) {
636 /* Verify the class file */
638 if (JAR_DEBUG && verbose)
639 jio_fprintf(stderr,
640 "ReadFromZip: Extracted '.class' from %s\n", filename);
642 filename[nameLength-6] = 0;
644 if (JAR_DEBUG && verbose)
645 jio_fprintf(stderr,
646 "ReadFromZip: Verifying classfile %s\n", filename);
648 /* call VerifyFile to verify the class */
649 VerifyFile(filename);
650 } else {
651 /* Read and copy over the file to tmpdir */
652 /* p points at the central header for the file */
653 unsigned long compLen = CENSIZ(p); /* the compressed length */
654 unsigned long method = CENHOW(p); /* how it is stored */
655 unsigned long expectedCRC = CENCRC(p); /* expected CRC */
656 unsigned long actualCRC;
658 decompLen = CENLEN(p);
660 if (JAR_DEBUG && verbose)
661 jio_fprintf(stderr,
662 "READFROMZIP: Reading file [%s]...\n", filename);
664 /* Make sure file is not encrypted */
665 if ((CENFLG(p) & 1) == 1) {
666 jio_fprintf(stderr, "Entry is encrypted\n");
667 goto done;
670 jdstream =
671 (JAR_DataStreamPtr)sysMalloc(sizeof(JAR_DataStream) + decompLen);
672 decompData = (unsigned char *)(jdstream + 1);
674 if (/* Go to the beginning of the LOC header */
675 (fseek(file, entry->jar.locpos + CENOFF(p), SEEK_SET) < 0)
676 /* Read it */
677 || (fread(p, sizeof(char), LOCHDRSIZ, file) != LOCHDRSIZ)
678 /* Skip over name and extension, if any */
679 || (fseek(file, LOCNAM(p) + LOCEXT(p), SEEK_CUR) < 0)) {
680 goto done;
683 switch (method) {
684 case STORED:
685 if (compLen != decompLen) {
686 sysFree(jdstream);
687 jdstream = NULL;
688 goto done;
690 fread(decompData, sizeof(char), decompLen, file);
691 break;
693 case DEFLATED: {
694 bool_t inflateOK;
695 inflateOK = inflate(file, compLen, decompData, decompLen);
697 if (!inflateOK) {
698 sysFree(jdstream);
699 jdstream = NULL;
701 break;
704 default:
705 sysFree(jdstream);
706 jdstream = NULL;
707 break;
710 actualCRC = jarCRC32(decompData, decompLen);
711 if (actualCRC != expectedCRC) {
712 jio_fprintf(stderr, "Unexpected CRC value\n");
715 /* create the tempdir if it doesn't already exist */
717 char fname[1024]; /* file name restored from JAR */
718 char *dir;
719 char *q;
720 char *sfname = fname; /* system-specific file name */
721 char *dname = fname; /* destination file name */
724 if (JAR_DEBUG && verbose)
725 jio_fprintf(stderr,
726 "Reading filename [%s] from JAR \n", filename);
728 sprintf(fname, "%s%c%s", tmp_dir,
729 (char) LOCAL_DIR_SEPARATOR,
730 filename);
732 if (JAR_DEBUG && verbose)
733 jio_fprintf(stderr,
734 "Before conversion: fname [%s] sfname [%s]\n",
735 fname, sfname);
737 /*
738 * convert JAR name to the system-specific file name
739 */
741 sfname = JARname2fname(fname, dname, strlen(fname)+1);
743 if (JAR_DEBUG && verbose)
744 jio_fprintf(stderr,
745 "After conversion: Converted [%s] to [%s]\n",
746 fname, sfname);
749 if (JAR_DEBUG && verbose)
750 jio_fprintf(stderr,
751 "Preparing to write file [%s]\n", sfname);
753 dir = strdup(sfname);
754 q = strrchr(dir, (char)LOCAL_DIR_SEPARATOR);
755 if (q) {
756 *q = 0;
757 ensure_tmpdir_exists(dir);
759 free(dir);
762 /* Attempt to stat or open only if this is NOT a directory */
764 if (!(sfname[strlen(sfname)-1] == (char)LOCAL_DIR_SEPARATOR)) {
765 if (JAR_DEBUG && verbose)
766 jio_fprintf(stderr,
767 "Attempting stat on dir [%s]\n", sfname);
769 status = stat(sfname, &stat_buf);
771 if (JAR_DEBUG && verbose)
772 jio_fprintf(stderr,
773 "Status from stat of [%s] is %d\n", sfname, status);
775 /* Attempt to open only if the file does not already exist.
776 * This is indicated by the stat command returning -1.
777 * And this is not a directory.
778 */
780 if ((status < 0) || !(stat_buf.st_mode & S_IFDIR)) {
782 if (JAR_DEBUG && verbose)
783 jio_fprintf(stderr,
784 "Opening file [%s]\n", sfname);
785 #ifdef UNIX
786 fd = open(sfname, O_WRONLY | O_CREAT | O_TRUNC , 0644);
787 #endif
789 #ifdef WIN32
790 fd = open(sfname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
791 #endif
793 if (fd < 0) {
794 panic("failed to open %s", sfname);
797 if (JAR_DEBUG && verbose)
798 jio_fprintf(stderr,
799 "Writing file [%s]...\n", sfname);
801 /* write the file to the tmpdir just created */
802 write(fd, decompData, decompLen);
804 /* check for the JAR Manifest.mf file */
806 if (isManifestfile(sfname, strlen(sfname))) {
807 /* save it for using it later to create
808 * the JAR file
809 */
810 memcpy(manifestfile, sfname + strlen(tmp_dir), strlen(sfname));
812 if (JAR_DEBUG && verbose)
813 jio_fprintf(stderr,
814 "Saving JAR manifest file [%s]\n",
815 manifestfile);
818 close(fd);
822 if (jdstream != NULL) {
823 sysFree(jdstream);
824 jdstream = NULL;
828 /* Set offset to the next central header */
829 offset = nextOffset;
830 sysFree(filename);
831 filename = NULL;
833 done:
834 if (file != NULL) {
835 fclose(file);
838 if (jdstream != NULL) {
839 jdstream->type = JAR_RESOURCE;
840 jdstream->data = decompData;
841 jdstream->dataLen = decompLen;
842 jdstream->dataIndex = 0;
843 jdstream->mode = JAR_READ;
846 if (filename != NULL)
847 sysFree(filename);
851 /*=========================================================================
852 * FUNCTION: remove_dir()
853 * TYPE: Handles removing files from recursive directories
854 * OVERVIEW: Internal function called by ProcessJARfile().
856 * This function reads a directory, searching for either another directory,
857 * or an individual class name that is to be removed using the remove()
858 * API call.
860 * INTERFACE:
861 * parameters: dirname name of the directory entry.
862 * pkgname name of the package
863 * returns: nothing
864 *=======================================================================*/
865 static void remove_dir(char *dirname, char *pkgname)
867 struct dirent *ent;
868 char buf[MAXPACKAGENAME];
869 char pkgbuf[MAXPACKAGENAME];
870 char tmpbuf[MAXPACKAGENAME];
871 char tmppkg[MAXPACKAGENAME];
872 char tmppkgbuf[MAXPACKAGENAME];
873 char *name = NULL;
874 DIR *dir = opendir(dirname);
875 int err = 0;
876 int status;
878 /* Initialize the buffers to 0 */
879 memset(buf, 0, sizeof(buf));
880 memset(pkgbuf, 0, sizeof(pkgbuf));
881 memset(tmpbuf, 0, sizeof(tmpbuf));
882 memset(tmppkg, 0, sizeof(tmppkg));
883 memset(tmppkgbuf, 0, sizeof(tmppkgbuf));
885 if (dir == NULL) {
886 fprintf(stderr, "Can't open dir %s\n", dirname);
887 exit(1);
889 for (ent = readdir(dir); ent; ent = readdir(dir)) {
890 struct stat stat_buf;
891 int len;
892 name = ent->d_name;
894 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
895 continue;
898 strcpy(pkgbuf, pkgname);
899 if (pkgname[0] != 0) {
900 /* concatenate '/' to the package name */
901 sprintf(tmppkgbuf, "%s%c", pkgbuf, (char)LOCAL_DIR_SEPARATOR);
903 if (JAR_DEBUG && verbose)
904 jio_fprintf(stderr,
905 "remove_dir: Reading filename [%s] from directory [%s]\n",
906 name, dirname);
908 /* we just have a class file that needs to be removed */
910 len = strlen(name);
912 /* append the dirname and name */
913 strcpy(buf, dirname);
914 strcat(buf, name);
917 status = stat(buf, &stat_buf);
919 if ((status == 0) && !(stat_buf.st_mode & S_IFDIR)) {
920 /* remove if this is a file and not a directory */
922 if (JAR_DEBUG && verbose)
923 jio_fprintf(stderr,
924 "remove_dir: Removing file [%s] \n", buf);
926 err = remove(buf);
928 if (JAR_DEBUG && verbose) {
929 jio_fprintf(stderr,
930 "remove_dir: remove() returned error %d\n", err);
933 } else {
934 strcat(tmppkgbuf, name);
935 stat(buf, &stat_buf);
936 len = strlen(buf);
938 if (stat_buf.st_mode & S_IFDIR) {
939 /* handle the recursive directory found */
941 sprintf(tmpbuf, "%s%c", buf, (char)LOCAL_DIR_SEPARATOR);
943 if (JAR_DEBUG && verbose)
944 jio_fprintf(stderr,
945 "remove_dir: Recursive dir, calling remove_dir [%s,%s]\n",
946 tmpbuf, tmppkgbuf);
947 remove_dir(tmpbuf, tmppkgbuf);
948 continue;
954 /* close the directory to free the dirp first */
955 closedir(dir);
958 #ifdef WIN32
959 /* remove the trailing '\' from the directory */
961 int tmppkglen = strlen(dirname);
962 dirname[tmppkglen-1] = '\0';
964 #endif
966 /* Remove the directory by calling rmdir() or remove() API as appropriate */
968 sprintf(tmppkg,"%s", dirname);
970 if (JAR_DEBUG && verbose)
971 jio_fprintf(stderr,
972 "remove_dir: Removing [%s]\n", tmppkg);
974 #ifdef WIN32
975 err = rmdir(tmppkg);
977 if (JAR_DEBUG && verbose) {
978 if (err != 0) {
979 jio_fprintf(stderr,
980 "remove_dir: rmdir(%s) failed with error %d\n",
981 tmppkg, err);
984 #endif
986 #ifdef UNIX
987 err = remove (tmppkg);
989 if (JAR_DEBUG && verbose) {
990 if (err != 0) {
991 jio_fprintf(stderr,
992 "remove_dir: remove(%s) failed with error %d\n",
993 tmppkg, err);
996 #endif
999 /*=========================================================================
1000 * FUNCTION: ProcessJARfile()
1001 * TYPE: Processes ZIP file entries
1002 * OVERVIEW: Internal function called by ProcessInputs().
1004 * This function processes a JAR file by first creating a zip entry for
1005 * reading JAR directories, then calls ReadFromZip() to read the Zip
1006 * class names and verifies them. It finally creates a new JAR file and
1007 * places all the verified classes into it.
1008 * It returns a boolean type to indicate if a valid JAR file was found
1009 * and the contents of the JAR file were processed without errors.
1011 * INTERFACE:
1012 * parameters: buf: JAR file name.
1013 * len: size of the file
1014 * returns: boolean type
1015 *=======================================================================*/
1016 bool_t ProcessJARfile(char *buf, int len) {
1018 zip_t *zipEntry;
1019 struct stat stat_buf;
1020 char *fname = NULL;
1021 char *buffer = NULL;
1022 char *jarName = NULL;
1023 char dirdelim = '\0'; /* directory delimiter */
1024 int err = 0;
1025 int tmpdir_len = 0;
1026 int statcode;
1027 char tmpdir_buf[MAXPACKAGENAME];
1029 if (JAR_DEBUG && verbose)
1030 jio_fprintf(stderr,
1031 "ProcessJARfile: JAR file [%s] Size [%d]\n", buf, len);
1033 statcode = stat(buf, &stat_buf);
1035 /* Create the zip entry for searching the JAR directories.
1036 * If the zip entry is NULL, it would indicate that we ran
1037 * out of memory and would have exited already.
1038 */
1040 zipEntry = getZipEntry (buf, len);
1042 if (JAR_DEBUG && verbose)
1043 jio_fprintf(stderr, "Searching for JAR directories...\n");
1046 /* search for the JAR directories */
1047 if (findJARDirectories(zipEntry, &stat_buf)) {
1048 /* the JAR directories were found */
1050 JARfile = TRUE;
1051 zipFileName = buf;
1052 if (JAR_DEBUG && verbose) {
1053 jio_fprintf(stderr,
1054 "ProcessJARfile: JAR directory [%s] found \n",
1055 zipEntry->name);
1058 zipEntry->type = 'j';
1060 /* Read and Verify the classes from the ZIP file */
1062 if (JAR_DEBUG && verbose)
1063 jio_fprintf(stderr, "ProcessJARfile: Verifying Zip class names...\n");
1065 pushJarFileOntoClassPath(zipEntry);
1067 ReadFromZip(zipEntry);
1069 popClassPath();
1071 /* Ensure that the output_dir also exists or create it if it
1072 * does not already exist
1073 */
1075 if (output_dir != NULL) {
1076 char *dir = strdup(output_dir);
1078 if (JAR_DEBUG && verbose)
1079 jio_fprintf(stderr, "ProcessJARfile: Checking if output [%s] exists\n",
1080 output_dir);
1081 ensure_dir_exists(dir);
1082 ensure_dir_writable(dir);
1083 free(dir);
1086 /* Create a JAR file only if the input parameter was a JAR file,
1087 * the tmp_dir was created with classes verified and an output
1088 * dir also exists.
1089 */
1091 if (JARfile && tmpDirExists && tmp_dir && output_dir) {
1092 const char *p;
1094 /* Allocate enough space to hold the JAR name */
1095 jarName = (char *)sysCalloc(len+32, len);
1097 if (jarName == NULL) {
1098 fprintf(stderr, "ProcessJARfile: Out of memory");
1099 exit(1);
1102 if (JAR_DEBUG && verbose)
1103 jio_fprintf(stderr, "ProcessJARfile: Creating JAR file of verified classes...\n");
1104 /* search for the last '/' to get the actual JAR file name */
1105 for (p = buf+len; ;) {
1106 --p;
1108 if (*p == '/' || *p == '\\') {
1109 dirdelim = *p;
1110 memcpy(jarName, p+1, (len-1)-(p-buf));
1111 if (JAR_DEBUG && verbose)
1112 jio_fprintf(stderr, "ProcessJARfile: JAR file [%s]\n", jarName);
1113 break;
1115 if (p == buf) {
1116 /* no directories in path, get the individual JAR name */
1117 strncpy(jarName, buf, len);
1118 if (JAR_DEBUG && verbose)
1119 jio_fprintf(stderr, "ProcessJARfile: JAR filename [%s]\n", jarName);
1120 break;
1124 /* move the verified classes into a JAR file */
1126 /* Be sure to allocate enough space to hold the sprintfs below */
1127 fname = (char *)malloc(strlen(output_dir)+ len+32);
1129 if (fname == NULL) {
1130 fprintf(stderr, "ProcessJARfile: Out of memory");
1131 exit(1);
1134 if (dirdelim != '\0') {
1135 sprintf(fname, "%s%c%s", output_dir,
1136 dirdelim, jarName);
1137 } else {
1138 sprintf(fname, "%s%c%s", output_dir,
1139 (char)LOCAL_DIR_SEPARATOR, jarName);
1142 /* Be sure to allocate enough space to hold the sprintfs below */
1143 /* The size here must be adjusted anytime the buffer used in the
1144 * sprintfs is extended.
1145 */
1147 buffer = (char *)malloc(strlen(output_dir)+strlen(fname) +
1148 strlen(tmp_dir) + strlen(manifestfile) +
1149 strlen(tmp_dir) + 51);
1150 if (buffer == NULL) {
1151 fprintf(stderr, "ProcessJARfile: Out of memory");
1152 exit(1);
1155 if (verbose) {
1156 if (isManifestfile(manifestfile, strlen(manifestfile))) {
1157 /* use existing manifest if one exists */
1158 sprintf(buffer, "jar -cvfm \"%s\" %s%c%s -C %s .",
1159 fname, tmp_dir,
1160 (char)LOCAL_DIR_SEPARATOR,
1161 manifestfile, tmp_dir);
1163 } else {
1165 sprintf(buffer, "jar -cvfM \"%s\" -C %s .",
1166 fname, tmp_dir);
1169 } else {
1170 /* Run jar in non-verbose mode, and log errors in a file */
1172 if (isManifestfile(manifestfile, strlen(manifestfile))) {
1173 /* use existing manifest if one exists */
1175 #ifdef UNIX
1176 /* create JAR with existing manifest file */
1177 /* Redirect errors and stdout to jarlog.txt */
1178 sprintf(buffer,
1179 "sh -c \"jar -cfm \\\"%s\\\" %s%c%s -C %s .\" > \"%s%c\"%s",
1180 fname, tmp_dir, (char)LOCAL_DIR_SEPARATOR,
1181 manifestfile, tmp_dir, output_dir,
1182 (char)LOCAL_DIR_SEPARATOR,"jarlog.txt 2>&1");
1184 #else
1185 sprintf(buffer,
1186 "jar -cfm \"%s\" %s%c%s -C %s . ",
1187 fname, tmp_dir, (char)LOCAL_DIR_SEPARATOR,
1188 manifestfile, tmp_dir);
1189 #endif
1190 } else {
1191 #ifdef UNIX
1192 /* create JAR with no manifest since none exists */
1193 /* Redirect errors and stdout to jarlog.txt */
1194 sprintf(buffer,
1195 "sh -c \"jar -cfM \\\"%s\\\" -C %s .\" > \"%s%c\"%s",
1196 fname, tmp_dir, output_dir,
1197 (char)LOCAL_DIR_SEPARATOR,"jarlog.txt 2>&1");
1198 #else
1199 sprintf(buffer,
1200 "jar -cfM \"%s\" -C %s . ",
1201 fname, tmp_dir);
1202 #endif
1206 if (verbose) {
1207 jio_fprintf(stderr, "Executing command [%s]\n", buffer);
1210 #ifdef WIN32
1211 /* system() function does not return the exit code of the child
1212 * process under Windows98.
1213 * The documentation states:
1214 * "If command is not NULL, system returns the value that is
1215 * returned by the command interpreter.".
1216 * Thus it is probably a bug within 'command.com'.
1217 * Note that _spawnlp correctly returns the exit status of the
1218 * new process.
1219 */
1220 if (verbose) {
1221 err = _spawnlp(_P_WAIT, "jar", "jar", buffer+4, NULL);
1222 if (err != 0) {
1223 fprintf(stderr, "%s\n", buffer);
1224 perror("Error");
1226 } else {
1227 int cstderr;
1228 int cstdout;
1229 FILE *logfile;
1231 /* Save stderr and stdout*/
1232 if ((cstderr = dup(_fileno(stderr))) == -1) {
1233 fprintf(stderr, "Cannot copy dup stderr\n");
1235 if ((cstdout = dup(_fileno(stdout))) == -1) {
1236 fprintf(stderr, "Cannot copy dup stdout\n");
1239 sprintf(tmpdir_buf, "%s\\%s", output_dir, "jarlog.txt");
1240 if ((logfile = fopen(tmpdir_buf, "w")) == NULL) {
1241 fprintf(stderr, "Cannot create output file\n");
1242 exit(1);
1245 if (_dup2(_fileno(logfile), _fileno(stderr)) == -1) {
1246 fprintf(stderr, "dup2 failed for stderr\n");
1247 exit(1);
1250 if (_dup2(_fileno(logfile), _fileno(stdout)) == -1) {
1251 fprintf(stderr, "dup2 failed for stdout\n");
1252 exit(1);
1255 err = _spawnlp(_P_WAIT, "jar", "jar", buffer+4, NULL);
1256 if (err != 0) {
1257 fprintf(stderr, "%s\n", buffer);
1258 perror("Error");
1261 fflush(stderr);
1262 fflush(stdout);
1263 fclose(logfile);
1265 /* Restore stderr and stdout */
1266 _dup2(cstderr, _fileno(stderr));
1267 _dup2(cstdout, _fileno(stdout));
1269 memset(tmpdir_buf,0,sizeof(tmpdir_buf));
1271 #else
1272 err = system(buffer);
1273 #endif
1275 if (err != 0) {
1276 /* jar file creation failed - return back the error */
1277 fprintf(stderr, "JAR file creation failed with error %d\n", err);
1278 if (!verbose)
1279 fprintf(stderr,
1280 "The preverified classes if any are in %s. See jar log of errors in %s%c%s \n",
1281 tmp_dir, output_dir, (char)LOCAL_DIR_SEPARATOR, "jarlog.txt");
1282 } else {
1283 if (!verbose) {
1284 /* remove the jar log file if no error occurred */
1285 char *jarfn = NULL;
1286 int error;
1288 jarfn = (char *)malloc(strlen(output_dir)+10+1+1);
1290 if (jarfn == NULL) {
1291 fprintf(stderr, "ProcessJARfile: Out of memory");
1292 exit(1);
1295 sprintf(jarfn, "%s%c%s", output_dir,
1296 (char)LOCAL_DIR_SEPARATOR, "jarlog.txt");
1297 error = remove(jarfn); /* remove the file */
1299 if (jarfn != NULL)
1300 sysFree(jarfn);
1303 /* prepare to remove the tmp directory */
1304 /* copy the tmp directory name to a buffer */
1305 strcpy(tmpdir_buf, tmp_dir);
1306 tmpdir_len = strlen(tmp_dir);
1308 /* Append dir separator if it does not yet exist */
1309 if (tmpdir_buf[tmpdir_len - 1] != LOCAL_DIR_SEPARATOR &&
1310 tmpdir_buf[tmpdir_len - 1] != DIR_SEPARATOR) {
1311 tmpdir_buf[tmpdir_len] = LOCAL_DIR_SEPARATOR;
1312 tmpdir_buf[tmpdir_len + 1] = 0;
1315 /* remove the tmp_dir and all its contents recursively */
1316 remove_dir(tmpdir_buf, "");
1317 } /* jar creation returned no error */
1319 } else {
1320 if (JAR_DEBUG && verbose)
1321 jio_fprintf(stderr, "JAR directories not found for JAR file [%s]\n", buf);
1322 if (fname != NULL)
1323 sysFree(fname);
1324 if (zipEntry != NULL)
1325 sysFree(zipEntry);
1327 return FALSE; /* could not locate JAR directories - invalid JAR file */
1330 if (fname != NULL)
1331 sysFree(fname);
1333 if (zipEntry != NULL)
1334 sysFree(zipEntry);
1336 if (buffer != NULL)
1337 sysFree(buffer);
1339 if (jarName != NULL)
1340 sysFree(jarName);
1342 if ( err!=0 ) {
1343 exit(errorCode = 1);
1346 return JARfile;