⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jar.c

📁 kaffe Java 解释器语言,源码,Java的子集系统,开放源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * jar.c * Handle JAR input files. * * Copyright (c) 2000, 2001, 2002 The University of Utah and the Flux Group. * All rights reserved. * * This file is licensed under the terms of the GNU Public License.   * See the file "license.terms" for restrictions on redistribution  * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */#include "config.h"#include "debug.h"#include "config-std.h"#include "config-io.h"#include "config-mem.h"#include "gtypes.h"#include "jsyscall.h"#include "inflate.h"#include "jar.h"#include "gc.h"#include "stats.h"#include "files.h"/* Undefine this to make jar files mutable during the vm lifetime *//* #define STATIC_JAR_FILES */#if defined(KAFFEH)#undef ABORT#define ABORT() abort()#undef  initStaticLock#define initStaticLock(x)#undef  staticLockIsInitialized#define staticLockIsInitialized(x)	1#undef  lockStaticMutex#undef  unlockStaticMutex#define unlockStaticMutex(x)#define lockStaticMutex(x)#undef  lockMutex#undef  unlockMutex#define lockMutex(x)#define unlockMutex(x)#endif/* * Error messages. */static const char * JAR_ERROR_BAD_CENTRAL_RECORD_SIGNATURE = "Bad central record signature";static const char * JAR_ERROR_BAD_SIGNATURE                = "Bad signature";static const char * JAR_ERROR_DECOMPRESSION_FAILED         = "Decompression failed";static const char * JAR_ERROR_ENTRY_COUNT_MISMATCH         = "Entry count doesn't match directory size";static const char * JAR_ERROR_IMPOSSIBLY_LARGE_DIRECTORY   = "Impossibly large directory size";static const char * JAR_ERROR_IO                           = "I/O error";static const char * JAR_ERROR_NO_END                       = "Failed to find end of JAR record";static const char * JAR_ERROR_OUT_OF_MEMORY                = "Out of memory";static const char * JAR_ERROR_TRUNCATED_FILE               = "Truncated file";static const char * JAR_ERROR_UNSUPPORTED_COMPRESSION      = "Unsupported compression in JAR file";/* * The jarCache keeps a list of all the jarFiles cached in the system. * However, since some JAR files are opened and closed frequently we don't * actively flush unused files from the system unless there are more than * JAR_FILE_CACHE_MAX jarFiles in the system.  This means we'll keep some * jarFiles in memory longer than we should but it helps to avoid the * constant opening/closing some java code does. */static struct _jarCache {#if !defined(KAFFEH)	iStaticLock	lock;#endif	jarFile *files;#define JAR_FILE_CACHE_MAX 12	unsigned int count;} jarCache;/* * Hash a file name, the hash value is stored in what `hash' points to. */static unsigned int hashName(const char *name){	unsigned int hash = 0;	assert(name != 0);		for( hash = 0; *name; name++ )		hash = (31 * hash) + (*name);	return hash;}/* * Find a cached jarFile object.  If the file is found, it is returned and its * user count is incremented. * * XXX rename findCachedJarFile() */static jarFile *findJarFile(char *name){	jarFile *curr, **prev, *retval = 0;#if !defined(KAFFEH)	int iLockRoot;#endif	assert(name != 0);		lockStaticMutex(&jarCache.lock);	curr = jarCache.files;	prev = &jarCache.files;	while( curr && !retval )	{		assert(curr != NULL);		assert(curr->fileName != 0);				if( !strcmp(curr->fileName, name) )		{			/* unlink it... */			*prev = curr->next;			/* and move it to the front */			curr->next = jarCache.files;			jarCache.files = curr;			/* Return this node and increment the user count */			retval = curr;			retval->users++;			assert(retval->users >= 1);		}		prev = &curr->next;		curr = curr->next;	}	unlockStaticMutex(&jarCache.lock);	return( retval );}/* * Free the contents of the entry table. */static void collectEntryTable(jarFile *jf){	assert(jf != 0);	assert(jf->users == 0);		if( jf->table )	{		addToCounter(&jarmem, "vmmem-jar files",			     1, -(jlong)GCSIZEOF(jf->table));		gc_free(jf->table);		jf->table = 0;	}}/* * Free a jarFile structure and its child objects. */static void collectJarFile(jarFile *jf){	assert(jf != 0);	assert(jf->users == 0);	assert(!(jf->flags & JFF_CACHED));		collectEntryTable(jf);	/* Make sure we free everything */	if( jf->fd != -1 )	{		/* Close the file */		KCLOSE(jf->fd);		jf->fd = -1;	}#ifdef HAVE_MMAP	if( jf->data != MAP_FAILED )	{#if !defined(NDEBUG)		/* Only define rc for use in assert */		int rc = #endif /* defined(NDEBUG)  */		munmap(jf->data, jf->size);		assert(rc == 0);	}#endif	addToCounter(&jarmem, "vmmem-jar files", 1, -(jlong)GCSIZEOF(jf));	gc_free(jf);}/* * Cache a jarFile object, if the passed in object matches one in the cache * it will be thrown away, and the cached one is returned, with its user * count incremented. */static jarFile *cacheJarFile(jarFile *jf){	jarFile *curr, **prev, **lru = 0, *dead_jar = 0, *retval = jf;	int already_cached = 0;#if !defined(KAFFEH)	int iLockRoot;#endif	assert(jf != 0);	assert(!(jf->flags & JFF_CACHED));		lockStaticMutex(&jarCache.lock);	/*	 * Walk the cache, if the file we're trying to cache already matches	 * one in the cache then we can just use it.  Otherwise, we need to	 * make room in the cache and continue.	 */	curr = jarCache.files;	prev = &jarCache.files;	while( curr && !already_cached )	{		assert(curr != NULL);		assert(curr->fileName != 0);				/* Look for a matching JAR file */		if( !strcmp(curr->fileName, jf->fileName) )		{			/* Names match, check the dates */			if( curr->lastModified == jf->lastModified )			{				/*				 * They're the same, unlink it from the cache				 * so we can put it at the front later on.				 */				*prev = curr->next;				retval = curr;				retval->users++;			}			else			{				/*				 * The modified time is different, purge our				 * cached version and proclaim this one the				 * canonical version.				 *				 * XXX Hmm...  Do we care how the two dates				 * relate?  Since this is the one now being				 * loaded from disk it "must" be the one				 * the user wants.  Bleh, too bad the				 * semantics don't seem to have been defined.				 */				*prev = curr->next;				curr->flags &= ~JFF_CACHED;				dead_jar = curr;			}			/*			 * `jf' is redundant so the number of cached files			 * isn't going to change.			 */			already_cached = 1;			assert(retval->users >= 1);		}		else if( curr->users == 0 )		{			/*			 * Record the least recently used file in case we need			 * to eject someone.			 */			lru = prev;		}		prev = &curr->next;		curr = curr->next;	}	if( !already_cached )	{		/*		 * Cache the file if theres still room rather than ejecting		 * the lru or if theres no room and no lru.		 */		if( (jarCache.count < JAR_FILE_CACHE_MAX) || !lru )		{			/* Adding a new cache node */			jarCache.count++;		}		else		{			/*			 * Theres an unused jarFile, unlink the least			 * recently used one.			 */			dead_jar = *lru;			*lru = dead_jar->next;			dead_jar->flags &= ~JFF_CACHED;		}	}	/* Put the file at the start of the cache */	retval->next = jarCache.files;	jarCache.files = retval;	retval->flags |= JFF_CACHED;	unlockStaticMutex(&jarCache.lock);	/*	 * Free the redundant/excess files outside of the lock.	 *	 * NOTE: The dead_jar test must come first since the file could	 * already be cached and get superceded by a newer version of the	 * file.	 */	if( dead_jar )		collectJarFile(dead_jar);	else if( already_cached )		collectJarFile(jf);	assert(retval != 0);		return( retval );}/* * Remove a JAR file from the cache. */static void removeJarFile(jarFile *jf){	jarFile *curr, **prev;#if !defined(KAFFEH)	int iLockRoot;#endif	assert(jf != 0);	/* Make sure its actually in the cache. */	if( jf->flags & JFF_CACHED )	{		lockStaticMutex(&jarCache.lock);		{			curr = jarCache.files;			prev = &jarCache.files;			/* Find `jf' on the list and... */			while( curr != jf )			{				assert(curr != 0);								prev = &curr->next;				curr = curr->next;			}			/* unlink it */			*prev = curr->next;			jf->next = 0;			jf->flags &= ~JFF_CACHED;			jarCache.count--;		}		unlockStaticMutex(&jarCache.lock);	}}void flushJarCache(void){	jarFile **prev, *curr, *next;#if !defined(KAFFEH)	int iLockRoot;#endif	lockStaticMutex(&jarCache.lock);	curr = jarCache.files;	prev = &jarCache.files;	while( curr )	{		next = curr->next;		if( curr->users == 0 )		{			*prev = next;			curr->flags &= ~JFF_CACHED;			collectJarFile(curr);		}		else		{			prev = &curr->next;		}		curr = next;	}	unlockStaticMutex(&jarCache.lock);}/* * Convenient read function that operates on regular or mmap'ed files. * This also takes an `instantiation' function which is used to convert * any data into the proper byte order and alignment. */static inline int jarRead(jarFile *jf, uint8 *buf, size_t len,			  int (*ins_func)(uint8 *dest, uint8 *src)){	int retval = -1;	assert(jf != 0);	assert(buf != 0);	#ifdef HAVE_MMAP	if( jf->data != MAP_FAILED )	{		if((jf->offset + len) > jf->size )		{			jf->error = JAR_ERROR_TRUNCATED_FILE;		}		else if( ins_func )		{			/*			 * We optimize this to use the instantiation function			 * to do the copying instead of doing a memcpy and then			 * moving stuff around.			 */			jf->offset += ins_func(buf, jf->data + jf->offset);			retval = len;		}		else		{			/* Just copy the bits */			memcpy(buf, jf->data + jf->offset, len);			jf->offset += len;			retval = len;		}	}	else#endif	{		size_t bytes_left;		ssize_t bytes_read;		int rc = 0;		bytes_left = len;		/* XXX is this loop necessary? */		while( bytes_left &&		       !(rc = KREAD(jf->fd,				    &buf[len - bytes_left],				    bytes_left,				    &bytes_read)) &&		       bytes_read )		{			bytes_left -= bytes_read;		}		if( rc )		{			jf->error = SYS_ERROR(rc);		}		else if( bytes_left )		{			jf->error = JAR_ERROR_TRUNCATED_FILE;		}		else		{			/* Instantiate the memory */			if( ins_func )				ins_func(buf, buf);			retval = len;		}	}	return( retval );}/* * Instantiate a structure that was encoded in a flat file.  We use a define * to make sure the instantiation function is inlined. */#ifdef HAVE_MMAP#define jarInstantiate(jf, buf, ins_func) \{ \	if( jf->data != MAP_FAILED ) \	{ \		jf->offset += ins_func(buf, jf->data + jf->offset); \	} \	else \	{ \		ins_func(buf, buf); \	} \}#else#define jarInstantiate(jf, buf, ins_func) \{ \	ins_func(buf, buf); \}#endif/* * Convenient seek function that operates on regular or mmap'ed files. */static inline off_t jarSeek(jarFile *jf, off_t offset, int whence){	off_t retval = (off_t)-1;	assert(jf != 0);	#ifdef HAVE_MMAP	if( jf->data != (uint8*)-1 )	{		off_t pos;				switch( whence )		{		case SEEK_CUR:			pos = jf->offset + offset;			break;		case SEEK_SET:			pos = offset;			break;		case SEEK_END:			pos = jf->size + offset;			break;		default:			ABORT();			break;		}		if( (pos >= 0) && (pos < jf->size) )		{			jf->offset = pos;			retval = pos;		}	}	else#endif	{		off_t off;		int rc;				rc = KLSEEK(jf->fd, offset, whence, &off);		if( rc )			jf->error = SYS_ERROR(rc);		else			retval = off;	}	return( retval );}/* Macro used below to create a 32 bit value from a uint8 buffer */#define copy32le(dest, buf, index) \do { \	register uint32 tmp; \	\	tmp = (((buf)[(index) + 3] << 24) | \	       ((buf)[(index) + 2] << 16) | \	       ((buf)[(index) + 1] << 8) | \	       ((buf)[(index) + 0])); \	dest = tmp; \} while(0);/* Macro used below to create a 16 bit value from a uint8 buffer */#define copy16le(dest, buf, index) \do { \	register uint16 tmp; \	\	tmp = (((buf)[(index) + 1] << 8) | \	       ((buf)[(index) + 0])); \	dest = tmp; \} while(0);/* * Unfortunately, the data members of the zip headers aren't aligned properly * so we can't just blast the data into a structure.  So we have to use these * instantiation functions to copy the data and do any byte swapping. * * Note 1: These functions work from high to low memory so that we're * basically just shuffling the bits around and not using extra storage. * * Note 2: We're hoping that the compiler is smart enough to drop the unused * data members when inlining... */static inline intinstantiateCentralDir(uint8 *dest, uint8 *buf){	jarCentralDirectoryRecord *cdr = (jarCentralDirectoryRecord *)dest;	assert(dest != 0);	assert(buf != 0);		copy32le(cdr->relativeLocalHeaderOffset, buf, 42);	copy32le(cdr->externalFileAttribute, buf, 38); /* Not used */	copy16le(cdr->internalFileAttribute, buf, 36); /* Not used */	copy16le(cdr->diskNumberStart, buf, 34); /* Not used */	copy16le(cdr->fileCommentLength, buf, 32);	copy16le(cdr->extraFieldLength, buf, 30);	copy16le(cdr->fileNameLength, buf, 28);	copy32le(cdr->uncompressedSize, buf, 24);	copy32le(cdr->compressedSize, buf, 20);	copy32le(cdr->crc, buf, 16); /* Not used */	copy16le(cdr->lastModifiedDate, buf, 14);	copy16le(cdr->lastModifiedTime, buf, 12);	copy32le(cdr->compressionMethod, buf, 10);	copy16le(cdr->flags, buf, 8); /* Not used */	copy16le(cdr->versionExtract, buf, 6); /* Not used */	copy16le(cdr->versionMade, buf, 4); /* Not Used */	return( FILE_SIZEOF_CENTRALDIR );}static inline intinstantiateLocalHeader(uint8 *dest, uint8 *buf){	jarLocalHeader *lh = (jarLocalHeader *)dest;	assert(dest != 0);	assert(buf != 0);		copy16le(lh->extraFieldLength, buf, 28);	copy16le(lh->fileNameLength, buf, 26);	copy32le(lh->uncompressedSize, buf, 22); /* Not used */	copy32le(lh->compressedSize, buf, 18); /* Not used */	copy32le(lh->crc, buf, 14); /* Not used */	copy16le(lh->lastModifiedDate, buf, 12); /* Not used */	copy16le(lh->lastModifiedTime, buf, 10); /* Not used */	copy16le(lh->compressionMethod, buf, 8); /* Not used */	copy16le(lh->flags, buf, 6); /* Not used */	copy16le(lh->versionExtract, buf, 4); /* Not used */	return( FILE_SIZEOF_LOCALHEADER );}static inline intinstantiateCentralDirEnd(uint8 *dest, uint8 *buf){	jarCentralDirectoryEnd *cde = (jarCentralDirectoryEnd *)dest;	assert(dest != 0);	assert(buf != 0);		copy16le(cde->commentLength, buf, 18); /* Not used */	copy32le(cde->offsetOfDirectory, buf, 16);	copy32le(cde->sizeOfDirectory, buf, 12); /* Not used */	copy16le(cde->nrOfEntriesInDirectory, buf, 10);	copy16le(cde->nrOfEntriesInThisDirectory, buf, 8); /* Not used */	copy16le(cde->numberOfDiskWithDirectory, buf, 6); /* Not used */	copy16le(cde->numberOfDisk, buf, 4); /* Not used */	return( FILE_SIZEOF_CENTRALEND );}static inline int instantiateSignature(uint8 *dest, uint8 *buf){	uint32 *sig = (uint32 *)dest;	assert(dest != 0);	assert(buf != 0);	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -