📄 jar_support.c
字号:
/* * @(#)jar_support.c 1.24 01/07/19 * * Copyright 1997, 1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. * Use is subject to license terms. *//*========================================================================= * SYSTEM: Verifier * SUBSYSTEM: JAR support routines for the verifier. * FILE: jar_support.c * OVERVIEW: JAR support routines for verifying class files from a ZIP or * JAR file. * Note that the JAR file reader used is based on the KVM * implementation with some modifications. * AUTHOR: Tasneem Sayeed, Java Consumer Technologies, Sun Microsystems *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/types.h>#include <string.h>#include <sys_api.h>#include <path_md.h>#include <path.h>#include <oobj.h>#include <jar.h>#include <convert_md.h>#include <string.h>#ifdef WIN32#include <process.h>#endif/*========================================================================= * Globals and extern declarations *=======================================================================*/extern int errno;char str_buffer[STRINGBUFFERSIZE]; /* shared string buffer */bool_t JARfile = FALSE; /* if true, indicates that output is in a JAR file */extern bool_t tmpDirExists; /* if true, indicates that a temp dir exists with classes to be verified */char *zipFileName = NULL; /* stores name of the zip file */extern char tmp_dir[32]; /* temporary directory for storing verified classes */extern char *output_dir; /* output directory */char manifestfile[1024]; /* used for saving the JAR manifest file name */extern void VerifyFile(register char *fn);/*========================================================================= * FUNCTION: isJARfile * OVERVIEW: Determines if the given file is a JAR or ZIP file. * Returns true if the suffix ends with ".jar" or ".zip". * INTERFACE: * parameters: fn: name of the JAR file * length: length of data, in bytes * returns: boolean type *=======================================================================*/bool_tisJARfile (char *fn, int length){ char *suffix; if (length >= 4 && (( suffix = fn + length - 4)[0] == '.') && ((( _toupper(suffix[1]) == 'Z') && ( _toupper(suffix[2]) == 'I') && ( _toupper(suffix[3]) == 'P')) || (( _toupper(suffix[1]) == 'J') && ( _toupper(suffix[2]) == 'A') && ( _toupper(suffix[3]) == 'R')))) { return TRUE; } else { return FALSE; }}/*========================================================================= * FUNCTION: isManifestfile * OVERVIEW: Determines if the given file is a JAR Manifest file. * Returns true if the file ends with "MANIFEST.MF". * INTERFACE: * parameters: fn: name of the JAR manifest file * length: length of data, in bytes * returns: boolean type *=======================================================================*/bool_tisManifestfile (char *fn, int length){ if ((length >= 11) && (strcmp(fn + length - 11, "MANIFEST.MF") == 0)) { return TRUE; } else { return FALSE; }}/*========================================================================= * FUNCTION: ensure_tmpdir_exists * OVERVIEW: Validates to ensure that the tmpdir exists using the * system-specific directory delimiters. * * INTERFACE: * parameters: char* dir name * returns: nothing *=======================================================================*/void ensure_tmpdir_exists(char *dir){ struct stat stat_buf; char *parent; char *q; if (dir[0] == 0) { return; } parent = strdup(dir); q = strrchr(parent, (char)LOCAL_DIR_SEPARATOR); if (q) { *q = 0; ensure_tmpdir_exists(parent); } if (stat(dir, &stat_buf) < 0) { if (JAR_DEBUG && verbose) { jio_fprintf(stderr, "Creating output directory [%s]\n", dir); }#ifdef WIN32 mkdir(dir);#endif#ifdef UNIX mkdir(dir, 0755);#endif } free(parent);}/*========================================================================= * FUNCTION: JARname2fname * OVERVIEW: Converts JAR name to the system-specific file name with * the correct directory delimiters. * * INTERFACE: * parameters: char* source JAR name * char* dest file name * int size * returns: char* *=======================================================================*/char*JARname2fname(char *src, char *dst, int size) { char *buf = dst; for (; (--size > 0) && (*src != '\0') ; src++, dst++) { if (*src == '/') { *dst = (char)LOCAL_DIR_SEPARATOR; } else { *dst = *src; } } dst++; *dst = '\0'; return buf;}/*========================================================================= * FUNCTION: getZipEntry * OVERVIEW: Converts a zip file to a Zip entry type. * INTERFACE: * parameters: zipFile: name of the JAR file * len: length of data, in bytes * returns: zip entry type *=======================================================================*/zip_t *getZipEntry (char *zipFile, int len) { zip_t * zipEntry = NULL; /* for processing errors */ if (JAR_DEBUG && verbose) jio_fprintf(stderr, "getZipEntry: JAR file [%s] Size [%d]\n", zipFile, len); /* create the zip entry for loading the ZIP file */ zipEntry = (zip_t *) sysMalloc(sizeof(zip_t) + len); if (zipEntry == NULL) { fprintf(stderr, "getZipEntry: Out of memory\n"); exit(1); } memcpy(zipEntry->name, zipFile, len); zipEntry->name[len] = '\0'; if (JAR_DEBUG && verbose) jio_fprintf(stderr, "getZipEntry: Zip Entry Name [%s]\n", zipEntry->name); zipEntry->type = '\0'; return zipEntry;}/*========================================================================= * FUNCTION: findJARDirectories * OVERVIEW: Helper function used for JAR loading for locating JAR * directories. * It returns TRUE if it is successful in locating the * JAR directory headers, false otherwise. * If successful, * entry->jar.locpos is set to the position of the first * local header. * entry->jar.cenpos is set to the position of the first * central header. * * Note that *locpos pointer is the logical "0" of the file. * All offsets extracted need to have this value added to them. * * INTERFACE: * parameters: entry: zipFileEntry * statbuf: pointer to the stat buffer * returns: boolean type *=======================================================================*/bool_tfindJARDirectories(zip_t *entry, struct stat *statbuf){ bool_t result = FALSE; long length = statbuf->st_size; long position, minPosition; char *bp; FILE *file; char *buffer = str_buffer; unsigned const int bufferSize = STRINGBUFFERSIZE; /* Calculate the smallest possible position for the end header. It * can be at most 0xFFFF + ENDHDRSIZ bytes from the end of the file, but * the file must also have a local header and a central header */ minPosition = length - (0xFFFF + ENDHDRSIZ); if (minPosition < LOCHDRSIZ + CENHDRSIZ) { minPosition = LOCHDRSIZ + CENHDRSIZ; } file = fopen(entry->name, "rb"); if (file == NULL) { goto done; } /* Read in the last ENDHDRSIZ bytes into the buffer. 99% of the time, * the file won't have a comment, and this is the only read we'll need */ if ( (fseek(file, -ENDHDRSIZ, SEEK_END) < 0) || (fread(buffer, sizeof(char), ENDHDRSIZ, file) != ENDHDRSIZ)) { goto done; } /* Get the position in the file stored into buffer[0] */ position = length - ENDHDRSIZ; /* Position in file of buffer[0] */ bp = buffer; /* Where to start looking */ for (;;) { /* "buffer" contains a block of data from the file, starting at * position "position" in the file. * We investigate whether position + (bp - buffer) is the start * of the end header in the zip file. This file position is at * position bp in the buffer. */ /* Use simplified version of Knuth Morris Pratt search algorithm. */ switch(bp[0]) { case '\006': /* The header must start at least 3 bytes back */ bp -= 3; break; case '\005': /* The header must start at least 2 bytes back */ bp -= 2; break; case 'K': /* The header must start at least 1 byte back */ bp -= 1; break; case 'P': /* Either this is the header, or the header must * start at least 4 back */ if (bp[1] == 'K' && bp[2] == 5 && bp[3] == 6) { int endpos = position + (bp - buffer); if (endpos + ENDHDRSIZ + ENDCOM(bp) == length) { unsigned long cenpos = endpos - ENDSIZ(bp); unsigned long locpos = cenpos - ENDOFF(bp); entry->jar.cenpos = cenpos; entry->jar.locpos = locpos; result = TRUE; goto done; } } /* FALL THROUGH */ default: /* This char isn't in the header signature, so * the header must start at least four chars back */ bp -= 4; } if (bp < buffer) { /* We've moved outside our window into the file. We must * move the window backwards */ int count = position - minPosition; /* Bytes left in file */ if (count == 0) { /* Nothing left to read. Time to give up */ goto done; } else { /* up to ((bp - buffer) + ENDHDRSIZ) bytes in the buffer might * still be part of the end header, so the most bytes we can * actually read are * bufferSize - ((bp - buffer) + ENDHDRSIZE). */ int available = (bufferSize - ENDHDRSIZ) + (buffer - bp); if (count > available) { count = available; } } /* Back up, while keeping our virtual position the same */ position -= count; bp += count; memmove(buffer + count, buffer, bufferSize - count); if ( (fseek(file, position, SEEK_SET) < 0) || (fread(buffer, sizeof(char), count, file) != (unsigned)count)) { goto done; } } } /* end of for loop */ done: if (file != NULL) { fclose(file); } return result;}/*========================================================================= * FUNCTION: jarCRC32 * OVERVIEW: Returns the CRC of an array of bytes, using the same * algorithm as used by the JAR reader. * INTERFACE: * parameters: data: pointer to the array of bytes * length: length of data, in bytes * returns: CRC *=======================================================================*/static unsigned longjarCRC32(unsigned char *data, unsigned long length) { unsigned long crc = 0xFFFFFFFF; unsigned int j; for ( ; length > 0; length--, data++) { crc ^= *data; for (j = 8; j > 0; --j) { crc = (crc & 1) ? ((crc >> 1) ^ 0xedb88320) : (crc >> 1); } } return ~crc;}/*========================================================================= * FUNCTION: loadJARfile() * TYPE: load JAR file * OVERVIEW: Internal function used by openClassfileInternal(). * * This function reads the specified class file from the JAR file. The * result is returned as a JAR_DataStream*. NULL is returned if it * cannot find the file, or there is some error. * * INTERFACE: * parameters: entry: zip file entry for the JAR file * filename: class file name to search for * returns: JAR_DataStream* for saving the JAR file info, or NULL. *=======================================================================*/JAR_DataStreamPtrloadJARfile(zip_t *entry, const char* filename){ JAR_DataStreamPtr jdstream = NULL; /* result on error */ unsigned int filenameLength; unsigned int nameLength; char buff[BUFSIZ]; char *UTFfilename = &buff[0]; char *p = str_buffer; /* temporary storage */ int offset; char *fname = NULL; FILE *file = fopen(entry->name, "rb"); if (file == NULL) { goto done; } if (JAR_DEBUG && verbose) jio_fprintf(stderr, "loadJARfile: Opening zip file %s to search for [%s]\n", entry->name, filename); /* add the .class to the filename */ if (JAR_DEBUG && verbose) jio_fprintf(stderr, "loadJARfile: Adding '.class' to %s size [%d]\n", filename, strlen(filename)); /* Conversion for Japanese filenames */ native2utf8(filename, UTFfilename, BUFSIZ); /* allocate fname large enough to hold .class + '\0' terminator */ fname = (char *)malloc(strlen(UTFfilename) + 6 + 1); sprintf(fname, "%s.class", UTFfilename); filenameLength=strlen(fname); fname[filenameLength]='\0'; if (JAR_DEBUG && verbose) jio_fprintf(stderr, "loadJARfile: Searching for filename [%s]\n", fname); /* Go to the start of the central headers */ offset = entry->jar.cenpos; for (;;) { if (/* Go to the next central header */ (fseek(file, offset, SEEK_SET) < 0) /* Read the bytes */ || (fread(p, sizeof(char), CENHDRSIZ, file) != CENHDRSIZ) /* Make sure it is a header */ || (GETSIG(p) != CENSIG)) { goto done; } /* Get the nameLength */ nameLength = CENNAM(p); if (nameLength == filenameLength) { if (fread(p + CENHDRSIZ, sizeof(char), nameLength, file) != nameLength) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -