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

📄 pgpfiledb.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	const char *		separator;
	PGPSize				maxFileLength;
	char *				mainFileName = NULL;
	PFLFileInfo			mainFileInfo;
	PFLDirectoryIterRef	dirIter = kInvalidPFLDirectoryIterRef;
	PFLFileSpecRef		fileRef = kInvalidPFLFileSpecRef;
	char *				fileName = NULL;
	PFLFileInfo			fileInfo;
	PGPFileTimeInfo		newestFiles[4];
	int					maxNewest = sizeof(newestFiles) /
									sizeof(newestFiles[0]);
	PGPFileTimeInfo		olderFiles[2][2];
	long				olderFileAges[2] = { 60 * 60L, 24 * 60 * 60L };
	int					maxOlder = sizeof(olderFiles) / sizeof(olderFiles[0]);
	PFLFileSpecRef		filesToDelete[32];
	int					maxFilesToDelete = sizeof(filesToDelete) /
										   sizeof(filesToDelete[0]);
	int					numFilesToDelete = 0;
	int					i;
	time_t				now = time( NULL );
	PGPBoolean			valid;
	PGPBoolean			deleteThisFile;
	PGPUInt32			number;

	pgpAssert( maxOlder == sizeof(olderFileAges) / sizeof(olderFileAges[0]) );
	(void)olderFileAges;

	for (i = 0; i < maxNewest; i++)
		newestFiles[i].fileRef = kInvalidPFLFileSpecRef;
	for (i = 0; i < maxOlder; i++)
		olderFiles[i][0].fileRef = olderFiles[i][1].fileRef =
				kInvalidPFLFileSpecRef;
	
	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;

			deleteThisFile = TRUE;

			if ( fileInfo.modificationTime <= now )
			{
				i = 0;
				while ( i < maxNewest &&
						newestFiles[i].fileRef != kInvalidPFLFileSpecRef &&
						newestFiles[i].modTime > fileInfo.modificationTime )
					i++;
				if ( i < maxNewest )
				{
					if ( newestFiles[ maxNewest - 1 ].fileRef
							!= kInvalidPFLFileSpecRef )
					{
						if ( numFilesToDelete >= maxFilesToDelete )
							goto overflow;
						filesToDelete[ numFilesToDelete++ ] =
								newestFiles[ maxNewest - 1 ].fileRef;
					}
					pgpCopyMemory( newestFiles + i, newestFiles + i + 1,
								   ( maxNewest - i - 1 )
									   * sizeof( newestFiles[0] ) );

					newestFiles[i].modTime = fileInfo.modificationTime;
					err = PFLCopyFileSpec( fileRef, 
							&newestFiles[ i ].fileRef );
					if ( IsPGPError( err ) )
						goto cleanup;
					deleteThisFile = FALSE;
				}
			}
			if ( deleteThisFile )
			{
				if ( numFilesToDelete >= maxFilesToDelete )
					goto overflow;
				err = PFLCopyFileSpec( fileRef,
						&filesToDelete[ numFilesToDelete ] );
				if ( IsPGPError( err ) )
					goto cleanup;
				numFilesToDelete++;
			}
		}

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

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

overflow:	/* Overflowing is currently ignored, we'll delete the rest later */
	err = kPGPError_NoErr;
	goto cleanup;

cleanup:
	if ( fileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( fileRef );
	if ( dirIter != kInvalidPFLDirectoryIterRef )
		PFLFreeDirectoryIter( dirIter );
	if ( IsntNull( mainFileName ) )
		PGPFreeData( mainFileName );
	if ( IsntNull( fileName ) )
		PGPFreeData( fileName );
	for ( i = 0; i < maxNewest; i++ )
		if ( newestFiles[i].fileRef != kInvalidPFLFileSpecRef )
			PFLFreeFileSpec( newestFiles[i].fileRef );
	for ( i = 0; i < numFilesToDelete; i++ )
	{
		if ( filesToDelete[i] != kInvalidPFLFileSpecRef )
		{
			PFLFileSpecDelete( filesToDelete[i] );
			PFLFreeFileSpec( filesToDelete[i] );
		}
	}
	return err;
}

/* 
 * Open the specified ringfile.  If writeable flag is clear, it will be
 * forced read-only, otherwise whether it is writeable will depend on
 * permissions.  Returns a filled-in rdb structure.
 * Note that "private" is not a concept of the underlying library, but
 * is used in the add function to decide which objects to accept.
 */
	static PGPError
OpenKeyRing (
	PGPContextRef	cdkContext,
	PFLConstFileSpecRef fileRef, PGPKeyRingOpenFlags openFlags,
	RingPool *ringpool, RingDB *rdb)
{
	PFLFileSpecRef	mainFileRef = kInvalidPFLFileSpecRef;	/* Main ring */
	PFLFileSpecRef	readFileRef = kInvalidPFLFileSpecRef;	/* Latest backup */
	FILE *			mainStdFile	= NULL;	/* Stdio file of main ring */
	FILE *			readStdFile	= NULL;	/* Stdio file of latest backup */
	PGPFile *		pgpFile		= NULL;
	RingFile *		ringFile	= NULL;
	RingSet const *	immutableSet = NULL;
	RingSet *		mutableSet	= NULL;
	PGPError		err			= kPGPError_NoErr;
	PGPBoolean		fileExists;
	
	PGPBoolean	trusted		= !!( openFlags & kPGPKeyRingOpenFlags_Trusted );
	PGPBoolean	priv		= !!( openFlags & kPGPKeyRingOpenFlags_Private );
	PGPBoolean	writeable	= !!( openFlags & kPGPKeyRingOpenFlags_Mutable );
	PGPFileType	fileType = priv ? kPGPFileTypePrivRing : kPGPFileTypePubRing;

	if( ( openFlags & kPGPKeyRingOpenFlags_Create ) != 0 && ! writeable )
	{
		pgpDebugMsg( "OpenKeyRing(): Cannot create read-only keyring" );
		err = kPGPError_BadParams;
		goto cleanup;
	}
	
	err = PFLFileSpecExists( (PFLFileSpecRef) fileRef, &fileExists );
	if( IsntPGPError( err ) && ! fileExists )
	{
		if( ( openFlags & kPGPKeyRingOpenFlags_Create ) == 0 )
		{
			err = kPGPError_FileNotFound;
		}
	}
	if ( IsPGPError( err ) )
		goto cleanup;

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

	if ( writeable )
	{
		PGPFileOpenFlags	fileOpenFlags;
		
		mutableSet = ringSetCreate (ringpool);
		if ( IsNull( mutableSet ) )
		{
			err = kPGPError_OutOfMemory;
			goto cleanup;
		}

		/* Lock the main keyring file to ensure exclusive access */
		fileOpenFlags = kPGPFileOpenReadWritePerm | kPGPFileOpenLockFile;

		err = pgpFileRefStdIOOpen( mainFileRef, fileOpenFlags, fileType,
								   &mainStdFile );

		if ( IsPGPError( err ) )
		{
			if ( err == kPGPError_FileNotFound &&
				 ( openFlags & kPGPKeyRingOpenFlags_Create ) )
			{
				err = pgpCreateFile( mainFileRef, fileType );
				if ( IsPGPError( err ) )
					goto cleanup;

				err = pgpFileRefStdIOOpen( mainFileRef, fileOpenFlags,
										   fileType, &mainStdFile );
			}
			if ( IsPGPError( err ) )
				goto cleanup;
		}
	}
	else
	{
		/* Immutable keydb's don't need mutableSet */
		mutableSet = NULL;
	}


	err = FindMatchingBackup( mainFileRef, &readFileRef );
	if ( IsPGPError( err ) )
	{
		err = MakeMatchingBackup( mainFileRef, mainStdFile, fileType,
								  &readFileRef );
		if ( err == kPGPError_FileLocked )
			goto cleanup;
	}

	if ( IsPGPError( err ) || ( !writeable && PFL_PLATFORM_UNSAFE_DELETE ) )
	{
		/*
		 * If we failed to create a matching backup file, or
		 * if deletes aren't safe on this platform and we're not a writer,
		 * then we need to make a local copy of the keyring as backing store.
		 */
		err = MakeTempCopy( mainFileRef, mainStdFile, fileType, &readFileRef );
		if ( IsPGPError( err ) )
			goto cleanup;
		rdb->btempfile = TRUE;
	}
	else
	{
		rdb->btempfile = FALSE;
	}

	/* Open the read-only file which will be used for backing store */
	err = pgpFileRefStdIOOpen( readFileRef, kPGPFileOpenReadPerm,
							   kPGPFileTypeNone, &readStdFile );
	if ( IsPGPError( err ) )
		goto cleanup;

	pgpFile = pgpFileReadOpen ( cdkContext, readStdFile, NULL, NULL );
	if ( IsNull( pgpFile ) )
	{
		err = kPGPError_OutOfMemory;	/* XXX: Return better error */
		goto cleanup;
	}
	readStdFile = NULL;		/* pgpFile is now responsible for closing it */

	ringFile = ringFileOpen( ringpool, pgpFile, trusted, &err );
	if ( IsNull( ringFile ) )
		goto cleanup;

	immutableSet = ringFileSet( ringFile );
	if ( IsntNull( mutableSet ) )
		ringSetAddSet( mutableSet, immutableSet );

	rdb->mainFileRef	= mainFileRef;
	rdb->mainStdFile	= mainStdFile;
	rdb->readFileRef	= readFileRef;
	rdb->pgpFile		= pgpFile;
	rdb->ringFile		= ringFile;
	rdb->immutableSet	= immutableSet;
	rdb->mutableSet		= mutableSet;
	rdb->openFlags		= openFlags;
	rdb->bwriteable		= writeable;
	rdb->bdirty			= ringFileIsDirty( ringFile );
	rdb->btrusted		= trusted;
	rdb->bprivate		= priv;

	return kPGPError_NoErr;

cleanup:
	if ( IsntNull( mutableSet ) )
		ringSetDestroy( mutableSet );
	if ( IsntNull( ringFile ) )
	{
		if( IsPGPError( ringFileClose( ringFile ) ) )
			pgpDebugMsg( "Failed to close ringFile" );
	}
	if ( IsntNull( pgpFile ) )
		pgpFileClose( pgpFile );
	if ( IsntNull( readStdFile ) )
		pgpStdIOClose( readStdFile );
	if ( readFileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( readFileRef );
	if ( IsntNull( mainStdFile ) )
		pgpStdIOClose( mainStdFile );
	if ( mainFileRef != kInvalidPFLFileSpecRef )
		PFLFreeFileSpec( mainFileRef );
	return err;
}

	static PGPError
WriteKeyRing( RingDB *	rdb )
{
	PGPContextRef	cdkContext	= rdb->context;
	PGPError		err			= kPGPError_NoErr;

	PGPFile *		oldPGPFile	= rdb->pgpFile;
	RingFile *		oldRingFile	= rdb->ringFile;

	PFLFileSpecRef	tempFileRef	= kInvalidPFLFileSpecRef;
	FILE *			tempStdFile	= NULL;		/* Stdio file for temp file */
	PGPFile *		tempPGPFile	= NULL;		/* PGPFile for temp file */

	PFLFileSpecRef	newFileRef	= kInvalidPFLFileSpecRef;
	FILE *			newStdFile	= NULL;		/* Stdio file for new backup */
	PGPFile *		newPGPFile	= NULL;		/* PGPFile for new backup file */
	RingFile *		newRingFile	= NULL;		/* RingFile for new backup file */

	char *			mainFileName = NULL;
	PGPFileType		fileType = rdb->bprivate ? kPGPFileTypePrivRing
											 : kPGPFileTypePubRing;
	int             flags	= ( rdb->btrusted && !rdb->bprivate )
									? PGP_RINGSETWRITE_PUBTRUST : 0;


	/* Find a unique temporary file name */
	err = PFLFileSpecGetUniqueSpec( rdb->mainFileRef, &tempFileRef );
	if ( IsPGPError( err ) )
		goto cleanup;

	/* Create and open the temp file */
	err = pgpFileRefStdIOOpen( tempFileRef,
							   kPGPFileOpenStdUpdateFlags
								   | kPGPFileOpenLockFile,
							   fileType,
							   &tempStdFile );
	if ( IsPGPError( err ) )
		goto cleanup;

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

	/* Create a PGPFile object for the temp file */
	tempPGPFile = pgpFileWriteOpen( cdkContext, tempStdFile, NULL );
	if ( IsNull( tempPGPFile ) )
	{
		pgpStdIOClose( tempStdFile );
		err = kPGPError_OutOfMemory;	/* XXX: Return better error */
		goto cleanup;
	}

	/* Write the key ring to the temp file, creating newRingFile */
	err = ringSetWrite( rdb->mutableSet, tempPGPFile, &newRingFile,
						PGPVERSION_4, flags );
	if ( IsPGPError( err ) )
		goto cleanup;

	/* Make sure the data is written to disk */
	err = pgpFileFlush( tempPGPFile );
	if ( IsPGPError( err ) )
		goto cleanup;


	/*
	 * Make a new read-only backup from the newly written temp file
	 */
	err = MakeMatchingBackup( rdb->mainFileRef, tempStdFile, fileType,
							  &newFileRef );
	if ( IsPGPError( err ) )
		goto cleanup;

	/* Open the new backup file which will be used for backing store */
	err = pgpFileRefStdIOOpen( newFileRef, kPGPFileOpenReadPerm,
							   kPGPFileTypeNone, &newStdFile );
	if ( IsPGPError( err ) )
		goto cleanup;

	/* Create a PGPFile object for the new backup file */
	newPGPFile = pgpFileReadOpen( cdkContext, newStdFile, NULL, NULL );
	if ( IsNull( newPGPFile ) )
	{
		pgpStdIOClose( newStdFile );
		err = kPGPError_OutOfMemory;	/* XXX: Return better error */
		goto cleanup;
	}

	/*
	 * Switch the ringfile's backing store
	 * from the temp file to the new backup file.
	 */
	ringFileSwitchFile( newRingFile, newPGPFile );

	pgpFileClose( tempPGPFile );
	tempPGPFile = NULL;


	/*
	 * Delete the main ring file and move the temp file into its place.
	 *
	 * XXX: Race condition here, we must release the lock momentarily
	 */
	{
		/* We'll need this for renaming */
		err = PFLGetFileSpecName( rdb->mainFileRef, &mainFileName );
		if ( IsPGPError( err ) )
			goto cleanup;

		/* Close the main ring file, releasing our lock */
		if ( IsntNull( rdb->mainStdFile ) )
		{
			err = pgpStdIOClose( rdb->mainStdFile );
			if ( IsPGPError( err ) )
				goto cleanup;
			rdb->mainStdFile = NULL;
		}

		/* Try to delete the main ring file, ignoring errors */
		(void)PFLFileSpecDelete( rdb->mainFileRef );

		/* Move the temp file into the main ring's place */
		err = PFLFileSpecRename( tempFileRef, mainFileName );
		if ( IsPGPError( err ) )
			goto cleanup;

		/* Relock the main keyring file to ensure exclusive access */
		err = pgpFileRefStdIOOpen( rdb->mainFileRef,
								   kPGPFileOpenReadWritePerm |
									   kPGPFileOpenLockFile,
								   fileType,
								   &rdb->mainStdFile );
		if ( IsPGPError( err ) )
			goto cleanup;

		/* XXX: We should swap fileIDs here on the Mac */
	}


	/* We must close mutableSet in order to cleanly close oldRingFile */
	ringSetDestroy( rdb->mutableSet );
	rdb->mutableSet = NULL;

	/* Now close the old backup or temp file */
	err = ringFileClose( oldRingFile );
	pgpFileClose( oldPGPFile );		/* Close the PGPFile regardless */
	if ( IsPGPError( err ) )
	{
		/*
		 * We shouldn't get here.  Probably due to a pesky RingSet leak!
		 */
		pgpDebugMsg( "Failed to close oldRingFile" );
	}

	/* If it was a local temp file, delete it immediately */
	if ( rdb->btempfile )
	{
		PFLFileSpecDelete( rdb->readFileRef );
		rdb->btempfile = FALSE;
	}

	PGPFreeData( mainFileName );

	PFLFreeFileSpec( rdb->readFileRef );
	rdb->readFileRef = newFileRef;
	newFileRef = NULL;

	PFLFreeFileSpec( tempFileRef );
	tempFileRef = NULL;

	rdb->ringFile = newRingFile;
	rdb->pgpFile = newPGPFile;

	PurgeOldBackups( rdb->mainFileRef );

	return kPGPError_NoErr;

cleanup:
	if ( IsNull( rdb->mainStdFile ) )
	{
		/* If we lost our exclusive lock, we must forfeit write access */

⌨️ 快捷键说明

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