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>
45 #include <string.h>
47 #ifdef WIN32
48 #include <process.h>
49 #endif
50 /*=========================================================================
51 * Globals and extern declarations
52 *=======================================================================*/
54 //extern int errno;
57 JAR file */
59 /* if true, indicates that a temp dir exists
60 with classes to be verified */
63 verified classes */
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
82 {
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
112 {
118 }
119 }
122 /*=========================================================================
123 * FUNCTION: ensure_tmpdir_exists
124 * OVERVIEW: Validates to ensure that the tmpdir exists using the
125 * system-specific directory delimiters.
126 *
127 * INTERFACE:
128 * parameters: char* dir name
129 * returns: nothing
130 *=======================================================================*/
132 {
138 }
144 }
148 }
149 #ifdef WIN32
151 #endif
152 #ifdef UNIX
154 #endif
155 }
157 }
160 /*=========================================================================
161 * FUNCTION: JARname2fname
162 * OVERVIEW: Converts JAR name to the system-specific file name with
163 * the correct directory delimiters.
164 *
165 * INTERFACE:
166 * parameters: char* source JAR name
167 * char* dest file name
168 * int size
169 * returns: char*
170 *=======================================================================*/
179 }
180 }
181 dst++;
184 }
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 *
203 /* create the zip entry for loading the ZIP file */
208 }
220 }
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.
234 *
235 * Note that *locpos pointer is the logical "0" of the file.
236 * All offsets extracted need to have this value added to them.
237 *
238 * INTERFACE:
239 * parameters: entry: zipFileEntry
240 * statbuf: pointer to the stat buffer
241 * returns: boolean type
242 *=======================================================================*/
244 bool_t
246 {
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 */
263 }
268 }
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 */
275 }
276 /* Get the position in the file stored into buffer[0] */
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. */
295 * start at least 4 back
296 */
306 }
307 }
308 /* FALL THROUGH */
310 * the header must start at least four chars back */
312 }
315 /* We've moved outside our window into the file. We must
316 * move the window backwards */
319 /* Nothing left to read. Time to give up */
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 */
330 }
331 }
332 /* Back up, while keeping our virtual position the same */
339 }
340 }
343 done:
346 }
348 }
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
369 }
370 }
372 }
375 /*=========================================================================
376 * FUNCTION: loadJARfile()
377 * TYPE: load JAR file
378 * OVERVIEW: Internal function used by openClassfileInternal().
379 *
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.
383 *
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
392 {
404 }
411 /* add the .class to the filename */
418 /* Conversion for Japanese filenames */
421 /* allocate fname large enough to hold .class + '\0' terminator */
431 /* Go to the start of the central headers */
437 /* Read the bytes */
439 /* Make sure it is a header */
442 }
444 /* Get the nameLength */
452 }
458 }
459 }
461 /* Set offset to the next central header */
466 /* p points at the central header for the file */
467 {
476 /* Make sure file is not encrypted */
480 }
483 jdstream =
489 /* Read it */
491 /* Skip over name and extension, if any */
494 }
500 }
505 bool_t inflateOK;
511 }
513 }
519 }
524 }
526 done:
529 }
533 }
542 }
545 }
546 }
549 /*=========================================================================
550 * FUNCTION: ReadFromZip()
551 * TYPE: Reads and verifies ZIP file entries
552 * OVERVIEW: Internal function used by ProcessInputs() and recurse_dir.
553 *
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.
559 *
560 * INTERFACE:
561 * parameters: ZipEntry: name of the zip file entry.
562 * returns: nothing
563 *=======================================================================*/
565 void
567 {
582 }
588 /* initialize */
591 /* Go to the start of the central headers */
597 /* Read the bytes */
599 /* Make sure it is a header */
602 }
603 /* Get the nameLength */
609 }
612 /* initialize the filename with nulls every time */
619 }
624 /* We have to calculate nextOffset now, because VerifyFile bashes
625 * str_buffer
626 */
633 /* extract the .class from the filename */
636 /* Verify the class file */
648 /* call VerifyFile to verify the class */
651 /* Read and copy over the file to tmpdir */
652 /* p points at the central header for the file */
664 /* Make sure file is not encrypted */
668 }
670 jdstream =
676 /* Read it */
678 /* Skip over name and extension, if any */
681 }
689 }
694 bool_t inflateOK;
700 }
702 }
708 }
713 }
715 /* create the tempdir if it doesn't already exist */
716 {
730 filename);
737 /*
738 * convert JAR name to the system-specific file name
739 */
758 }
762 /* Attempt to stat or open only if this is NOT a directory */
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 */
785 #ifdef UNIX
787 #endif
789 #ifdef WIN32
791 #endif
795 }
801 /* write the file to the tmpdir just created */
804 /* check for the JAR Manifest.mf file */
807 /* save it for using it later to create
808 * the JAR file
809 */
815 manifestfile);
816 }
819 }
820 }
821 }
825 }
826 }
828 /* Set offset to the next central header */
832 }
833 done:
836 }
844 }
848 }
851 /*=========================================================================
852 * FUNCTION: remove_dir()
853 * TYPE: Handles removing files from recursive directories
854 * OVERVIEW: Internal function called by ProcessJARfile().
855 *
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.
859 *
860 * INTERFACE:
861 * parameters: dirname name of the directory entry.
862 * pkgname name of the package
863 * returns: nothing
864 *=======================================================================*/
866 {
878 /* Initialize the buffers to 0 */
888 }
896 }
900 /* concatenate '/' to the package name */
902 }
908 /* we just have a class file that needs to be removed */
912 /* append the dirname and name */
920 /* remove if this is a file and not a directory */
931 }
939 /* handle the recursive directory found */
949 }
950 }
952 }
954 /* close the directory to free the dirp first */
958 #ifdef WIN32
959 /* remove the trailing '\' from the directory */
960 {
963 }
964 #endif
966 /* Remove the directory by calling rmdir() or remove() API as appropriate */
974 #ifdef WIN32
982 }
983 }
984 #endif
986 #ifdef UNIX
994 }
995 }
996 #endif
998 }
999 /*=========================================================================
1000 * FUNCTION: ProcessJARfile()
1001 * TYPE: Processes ZIP file entries
1002 * OVERVIEW: Internal function called by ProcessInputs().
1003 *
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.
1010 *
1011 * INTERFACE:
1012 * parameters: buf: JAR file name.
1013 * len: size of the file
1014 * returns: boolean type
1015 *=======================================================================*/
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 */
1046 /* search for the JAR directories */
1048 /* the JAR directories were found */
1056 }
1060 /* Read and Verify the classes from the ZIP file */
1071 /* Ensure that the output_dir also exists or create it if it
1072 * does not already exist
1073 */
1080 output_dir);
1084 }
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 */
1094 /* Allocate enough space to hold the JAR name */
1100 }
1104 /* search for the last '/' to get the actual JAR file name */
1114 }
1116 /* no directories in path, get the individual JAR name */
1121 }
1122 }
1124 /* move the verified classes into a JAR file */
1126 /* Be sure to allocate enough space to hold the sprintfs below */
1132 }
1140 }
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 */
1153 }
1157 /* use existing manifest if one exists */
1168 }
1170 /* Run jar in non-verbose mode, and log errors in a file */
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 */
1184 #else
1189 #endif
1191 #ifdef UNIX
1192 /* create JAR with no manifest since none exists */
1193 /* Redirect errors and stdout to jarlog.txt */
1198 #else
1202 #endif
1204 }
1205 }
1208 }
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 */
1225 }
1231 /* Save stderr and stdout*/
1234 }
1237 }
1243 }
1248 }
1253 }
1259 }
1265 /* Restore stderr and stdout */
1270 }
1271 #else
1273 #endif
1276 /* jar file creation failed - return back the error */
1284 /* remove the jar log file if no error occurred */
1293 }
1301 }
1303 /* prepare to remove the tmp directory */
1304 /* copy the tmp directory name to a buffer */
1308 /* Append dir separator if it does not yet exist */
1313 }
1315 /* remove the tmp_dir and all its contents recursively */
1318 }
1328 }
1344 }
1347 }