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

📄 pgpfiledb.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * pgpFileDB.c
 * Manage PGPKeyDB's based on RingFiles
 *
 * Copyright (C) 1996,1997 Network Associates Inc. and affiliated companies.
 * All rights reserved
 *
 * $Id: pgpFileDB.c,v 1.81.6.2 1999/06/10 23:08:59 hal Exp $
 */
#include <stdio.h>
#include <string.h>

#include "pgpConfig.h"
#include "pgpMemoryMgr.h"

#if HAVE_FCNTL_H
#include <fcntl.h>		/* For O_CREAT, O_EXCL */
#endif

#if HAVE_UNISTD_H
#include <unistd.h>
#endif

#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#ifndef W_OK
#define W_OK 2
#endif

#include "pgpKDBInt.h"
#include "pgpFileRef.h"
#include "pgpFileSpec.h"
#include "pgpFileUtilities.h"
#include "pgpStrings.h"
#include "pgpFileNames.h"
#include "pgpDebug.h"
#include "pgpFile.h"
#include "pgpRngRead.h"
#include "pgpContext.h"

/* Private data for RingFile type of PGPKeyDBRef */
typedef struct RingDB {
	PGPContextRef	context;
	RingFile *		ringFile;		/* RingFile for keys */
	PGPFile *		pgpFile;		/* PGPFile for keys */
	PFLFileSpecRef	mainFileRef;	/* Main keyring filename */
	PFLFileSpecRef	readFileRef;	/* Filename of keyring backing store */
	FILE *			mainStdFile;	/* Main keyring FILE (for locking only) */
	RingSet *		mutableSet;		/* Mutable ringset */
								/* mutableSet will be NULL if !bwriteable */
	RingSet const *	immutableSet;	/* Immutable ringset */
	RingSet *		frozenSet;		/* Frozen copy of mutableSet */
	PGPBoolean		bwriteable;		/* True if a writeable database */
	PGPBoolean		bdirty;			/* True if mutableSet has been changed */
	PGPBoolean		bprivate;		/* True if a private keyring */
	PGPBoolean		btrusted;		/* True if should get trust packets */
	PGPBoolean		bmembuf;		/* True if memory-buffer based */
	PGPBoolean		btempfile;		/* True if readFileRef is a temp file */
	PGPKeyRingOpenFlags	openFlags;	/* Flags used to open keyring */

	DEBUG_STRUCT_CONSTRUCTOR( RingDB )
} RingDB;


/***************************** File IO ****************************/

/*
 * Readers and writers can safely access the same key ring simultaneously.
 * The only constraint is that at most one writer can access the file at
 * the same time.
 * 
 * This wasn't possible before because the bulk of the key data is loaded
 * on demand using an in-memory index which is built on open. This requires
 * that the file used for backing store never change. Our solution is to
 * never use the main ring file for backing store, but instead use a static
 * copy of the file.
 * 
 * But copying the file is a lot of overhead to suffer every time the key
 * ring is opened. So we leave the copy lying around so the next user will
 * be spared the overhead, amortizing the cost over several accesses.
 * 
 * These static copies are also useful as backups, and that's how they're
 * named on disk. Every time a key ring is closed, old backups are purged.
 * Currently, all but the most recent 4 backups are removed.
 */

	static const char *
GetSeparator(
	PGPSize		maxFileLength )
{
#if PGP_MACINTOSH
	(void)maxFileLength;	/* Avoid warning */
	return " Backup ";
#else
	if ( maxFileLength >= 18 )
		return "-bak-";
	else
		return "-";
#endif
}

	static PGPError
FindMatchingBackup(
	PFLFileSpecRef		mainFileRef,
	PFLFileSpecRef *	readFileRef )
{
	PGPError			err = kPGPError_NoErr;
	PGPSize				maxFileLength;
	char *				mainFileName = NULL;
	PFLFileInfo			mainFileInfo;
	PFLDirectoryIterRef	dirIter = kInvalidPFLDirectoryIterRef;
	PFLFileSpecRef		fileRef = kInvalidPFLFileSpecRef;
	char *				fileName = NULL;
	const char *		separator;
	PFLFileInfo			fileInfo;
	PFLFileSpecRef		newestFileRef = kInvalidPFLFileSpecRef;
	time_t				newestFileModTime = 0;	/* Avoid warning */
	PGPBoolean			valid;
	PGPUInt32			number;

	*readFileRef = NULL;

	err = PFLGetFileSpecName( mainFileRef, &mainFileName );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = PFLGetMaxFileSpecNameLength( mainFileRef, &maxFileLength );
	if ( IsPGPError( err ) )
		goto cleanup;

	separator = GetSeparator( maxFileLength );

	err = PFLGetFileInfo( mainFileRef, &mainFileInfo );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = PFLGetParentDirectory( mainFileRef, &fileRef );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = PFLNewDirectoryIter( fileRef, &dirIter );
	if ( IsPGPError( err ) )
		goto cleanup;

	PFLFreeFileSpec( fileRef );
	fileRef = NULL;

	while ( IsntPGPError( err = PFLNextFileInDirectory( dirIter, &fileRef ) ) )
	{
		err = PFLGetFileSpecName( fileRef, &fileName );
		if ( IsPGPError( err ) )
			goto cleanup;

		err = PGPVerifyNumberFileName( mainFileName, separator, fileName,
					maxFileLength + 1, &valid, &number );
		if ( IsPGPError( err ) )
			goto cleanup;

		if ( valid )
		{
			err = PFLGetFileInfo( fileRef, &fileInfo );
			if ( IsPGPError( err ) )
				goto cleanup;

			/*
			 * XXX: We may want to rethink this heuristic.
			 *      In particular, what happens if a backup file
			 *      exists which is newer than the current time?
			 *      Also, it would be nice to check file meta
			 *      info (like creator/type on the Mac) to make
			 *      sure it matches.
			 */
			if ( ( fileInfo.flags & kPGPFileInfo_IsPlainFile ) &&
				 fileInfo.dataLength == mainFileInfo.dataLength &&
				 fileInfo.modificationTime >= mainFileInfo.modificationTime &&
				 ( newestFileRef == kInvalidPFLFileSpecRef ||
				   newestFileModTime < fileInfo.modificationTime ) )
			{
				if ( newestFileRef != kInvalidPFLFileSpecRef )
					PFLFreeFileSpec( newestFileRef );
				newestFileRef = fileRef;
				fileRef = kInvalidPFLFileSpecRef;
				newestFileModTime = fileInfo.modificationTime;
			}
		}

		if ( fileRef != kInvalidPFLFileSpecRef )
		{
			PFLFreeFileSpec( fileRef );
			fileRef = NULL;
		}

		PGPFreeData( fileName );
		fileName = NULL;
	}
	if ( err != kPGPError_EndOfIteration )
		goto cleanup;

	if ( newestFileRef == kInvalidPFLFileSpecRef )
	{
		err = kPGPError_FileNotFound;
		goto cleanup;
	}

	/* XXX: Maybe check file contents here, just to be sure? */

	err = kPGPError_NoErr;
	*readFileRef = newestFileRef;
	/* We're no longer responsible for this */
	newestFileRef = kInvalidPFLFileSpecRef;	
	
cleanup:
	if ( fileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( fileRef );
	if ( newestFileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( newestFileRef );
	if ( dirIter != kInvalidPFLDirectoryIterRef )
		PFLFreeDirectoryIter( dirIter );
	if ( IsntNull( mainFileName ) )
		PGPFreeData( mainFileName );
	if ( IsntNull( fileName ) )
		PGPFreeData( fileName );
	return err;
}

	static PGPError
CopyStdFile(
	PGPMemoryMgrRef	memoryMgr,
	FILE *			origFile,
	FILE *			destFile )
{
	int			stdErr;
	PGPError	err = kPGPError_NoErr;
	char *		buffer = NULL;
	PGPSize		bufferSize = 16 * 1024L;
	PGPSize		length;

	rewind( origFile );
	rewind( destFile );

	buffer = (char *)PGPNewData( memoryMgr, bufferSize, 0 );
	if ( IsNull( buffer ) )
	{
		err = kPGPError_OutOfMemory;
		goto cleanup;
	}

	while ( ( length = fread( buffer, 1, bufferSize, origFile ) ) > 0 )
	{
		if ( length != fwrite( buffer, 1, length, destFile ) )
		{
			stdErr = ferror( destFile );
			if (
					0
#ifdef ENOSPC
					|| stdErr == ENOSPC
#endif
#ifdef EFBIG
					|| stdErr == EFBIG
#endif
					)
			{
				err = kPGPError_DiskFull;
			}
			else
			{
				err = kPGPError_WriteFailed;
			}
			goto cleanup;
		}
	}
	if ( !feof( origFile ) )
	{
		err = kPGPError_ReadFailed;
		goto cleanup;
	}

cleanup:
	if ( IsntNull( buffer ) )
		PGPFreeData( buffer );
	return err;
}



/* Copy permissions, group and owner from main keyring file */
/* Only implemented for Unix at present */
static PGPError
pgpCopyFilePerms( PFLFileSpecRef oldFileRef, PFLFileSpecRef newFileRef )
{
#if !PGP_UNIX
	(void) oldFileRef;
	(void) newFileRef;
	return kPGPError_NoErr;
#else
	char *oldName;
	char *newName;
	struct stat oldStat;
	PGPError err;

	err = PFLGetFullPathFromFileSpec( oldFileRef, &oldName );		
	if ( IsPGPError( err ) )
		return err;
	err = PFLGetFullPathFromFileSpec( newFileRef, &newName );		
	if ( IsPGPError( err ) ) {
		PGPFreeData( oldName );
		return err;
	}
	if (stat (oldName, &oldStat) < 0) {
		err = kPGPError_FileOpFailed;
		PGPFreeData( oldName );
		PGPFreeData( newName );
		return err;
	}

	/* Try to set newup file perms, group, owner; ignore errors */
	chmod (newName, oldStat.st_mode);
	chown (newName, -1, oldStat.st_gid);
	chown (newName, oldStat.st_uid, -1);

	PGPFreeData( oldName );
	PGPFreeData( newName );
	return kPGPError_NoErr;
#endif
}


	static PGPError
MakeMatchingBackup(
	PFLFileSpecRef		mainFileRef,
	FILE *				mainStdFile,
	PGPFileType			fileType,
	PFLFileSpecRef *	readFileRef )
{
	PGPError			err = kPGPError_NoErr;
	PGPMemoryMgrRef		memoryMgr = PFLGetFileSpecMemoryMgr( mainFileRef );
	PFLFileSpecRef		fileRef = kInvalidPFLFileSpecRef;
	PFLFileSpecRef		tempFileRef = kInvalidPFLFileSpecRef;
	char *				mainFileName = NULL;
	char *				fileName = NULL;
	PGPSize				maxFileLength;
	const char *		separator;
	PGPUInt32			number;
	PGPBoolean			exists;
	PGPBoolean			weOpenedMainFile = FALSE;
	FILE *				stdFile = NULL;

	*readFileRef = NULL;

	/* First copy the ring to a temp file in the backup directory */

	err = PFLFileSpecGetUniqueSpec( mainFileRef, &tempFileRef );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = pgpFileRefStdIOOpen( tempFileRef, kPGPFileOpenStdWriteFlags,
							   fileType, &stdFile );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = pgpCopyFilePerms( mainFileRef, tempFileRef );
	if ( IsPGPError( err ) )
		goto cleanup;

	if ( IsNull( mainStdFile ) )
	{
		err = pgpFileRefStdIOOpen( mainFileRef, kPGPFileOpenReadPerm,
								   kPGPFileTypeNone, &mainStdFile );
		if ( IsPGPError( err ) )
			goto cleanup;

		weOpenedMainFile = TRUE;
	}

	err = CopyStdFile( memoryMgr, mainStdFile, stdFile );
	if ( IsPGPError( err ) )
		goto cleanup;
	
	pgpStdIOClose( stdFile );
	stdFile = NULL;


	/* Next, we find a new backup name to rename to */

	err = PFLGetMaxFileSpecNameLength( mainFileRef, &maxFileLength );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = PFLCopyFileSpec( mainFileRef, &fileRef );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = PFLGetFileSpecName( mainFileRef, &mainFileName );
	if ( IsPGPError( err ) )
		goto cleanup;

	separator = GetSeparator( maxFileLength );

	fileName = (char *)PGPNewData( memoryMgr, maxFileLength + 1, 0 );
	if ( IsNull( fileName ) )
	{
		err = kPGPError_OutOfMemory;
		goto cleanup;
	}

	for (number = 1; ; number++ )
	{
		err = PGPNewNumberFileName( mainFileName, separator, number,
									maxFileLength + 1, fileName );
		if ( IsPGPError( err ) )
			goto cleanup;

		err = PFLSetFileSpecName( fileRef, fileName );
		if ( IsPGPError( err ) )
			goto cleanup;

		err = PFLFileSpecExists( fileRef, &exists );
		if ( IsPGPError( err ) )
			goto cleanup;

		if ( !exists )
		{
			err = PFLFileSpecRename( tempFileRef, fileName );
			if ( IsntPGPError( err ) )
				break;
			else if ( err != kPGPError_ItemNotFound )
				goto cleanup;
		}
	}

	*readFileRef = fileRef;
	fileRef = NULL;		/* We're no longer responsible for it */

cleanup:
	if ( tempFileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( tempFileRef );
	if ( fileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( fileRef );
	if ( IsntNull( mainFileName ) )
		PGPFreeData( mainFileName );
	if ( IsntNull( fileName ) )
		PGPFreeData( fileName );
	if ( IsntNull( stdFile ) )
		pgpStdIOClose( stdFile );
	if ( weOpenedMainFile && IsntNull( mainStdFile ) )
		pgpStdIOClose( mainStdFile );
	return err;
}

	static PGPError
MakeTempCopy(
	PFLFileSpecRef			mainFileRef,
	FILE *					mainStdFile,
	PGPFileType				fileType,
	PFLFileSpecRef *		readFileRef )
{
	PGPError			err = kPGPError_NoErr;
	PGPMemoryMgrRef		context = PFLGetFileSpecMemoryMgr( mainFileRef );
	PFLFileSpecRef		fileRef = kInvalidPFLFileSpecRef;
	FILE *				stdFile = NULL;
	PGPBoolean			weOpenedMainFile = FALSE;

	err = PFLGetTempFileSpec( context, kInvalidPFLFileSpecRef, &fileRef );
	if ( IsPGPError( err ) )
		goto cleanup;

	err = pgpFileRefStdIOOpen( fileRef, kPGPFileOpenStdWriteFlags,
							   fileType, &stdFile );
	if ( IsPGPError( err ) )
		goto cleanup;

	if ( IsNull( mainStdFile ) )
	{
		err = pgpFileRefStdIOOpen( mainFileRef, kPGPFileOpenReadPerm,
								   kPGPFileTypeNone, &mainStdFile );
		if ( IsPGPError( err ) )
			goto cleanup;

		weOpenedMainFile = TRUE;
	}

	err = CopyStdFile( context, mainStdFile, stdFile );
	if ( IsPGPError( err ) )
		goto cleanup;

	*readFileRef = fileRef;
	fileRef = NULL;		/* We're no longer responsible for it */

cleanup:
	if ( fileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( fileRef );
	if ( IsntNull( stdFile ) )
		pgpStdIOClose( stdFile );
	if ( weOpenedMainFile && IsntNull( mainStdFile ) )
		pgpStdIOClose( mainStdFile );
	return err;
}

/* This struct is only used by PurgeOldBackups() */
typedef struct
{
	PFLFileSpecRef	fileRef;
	time_t			modTime;
} PGPFileTimeInfo;

	static PGPError
PurgeOldBackups(
	PFLFileSpecRef		mainFileRef )
{
	PGPError			err = kPGPError_NoErr;

⌨️ 快捷键说明

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