authenticationservices/authenticationserver/test/reftestplugin/pinplugin/pinplugindb.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 24 Nov 2009 09:06:03 +0200
changeset 29 ece3df019add
permissions -rw-r--r--
Revision: 200948 Kit: 200948

/*
* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
* CPinPluginDB pin plugin data store implementation
*
*/


/**
 @file 
*/

#include "pinplugindb.h"

_LIT(KPluginStoreName, "plugin.store");
_LIT(KFileDrive, "c:");

using namespace AuthServer;

CPinPluginDB* CPinPluginDB::NewL()
	{
	CPinPluginDB* self = CPinPluginDB::NewLC();
	CleanupStack::Pop(self);
	return self;
	}

CPinPluginDB* CPinPluginDB::NewLC()
	{
	CPinPluginDB* self = new(ELeave) CPinPluginDB();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}
	
CPinPluginDB::CPinPluginDB() :
	iRootStreamId(KNullStreamId),
	iIdentityStreamId(KNullStreamId)
	{
	}

CPinPluginDB::~CPinPluginDB()
	{
	if (iFileStore)
		{
		CompactStore();
		delete iFileStore;
		}

	iFile.Close(); 
	iFs.Close();

	iId.Reset();
	iId.Close();
	iIdKeyHash.ResetAndDestroy();
	iIdKeyHash.Close();
	}
	
		
void CPinPluginDB::ConstructL()
	{
	User::LeaveIfError(iFs.Connect());
	
	TFileName privatePath;
	iFs.PrivatePath(privatePath);
	iPluginDBName.Copy(KFileDrive);
	iPluginDBName.Append(privatePath);
	iPluginDBName.Append(KPluginStoreName);
	OpenStoreL();
	
	ReadIdKeysFromStoreL();
	}


void CPinPluginDB::AddPinL(const TIdentityId& aId, const TDesC8& aIdentityKeyHash)
	{
	if(IdIndex(aId) == KErrNotFound && IsUniquePin(aIdentityKeyHash))
		{
		// Add the IdentityId to the array, rewrite the identitystream and 
		// Only then commit the store
		HBufC8* keyHash = aIdentityKeyHash.AllocLC();
		TInt err = KErrNone;
		iIdKeyHash.AppendL(keyHash);
		err = iId.Append(aId);
		if(err != KErrNone)
			{
			iIdKeyHash.Remove(iIdKeyHash.Count() - 1);
			User::Leave(err);
			}
		TCleanupItem cleanupStore(RevertStore, iFileStore);
		// write the idkeys to the store.
		TRAP(err,
			CleanupStack::PushL(cleanupStore);
			WriteIdKeysToStoreL();
			CleanupStack::Pop(iFileStore));

		if (err != KErrNone)
			{
			iId.Remove(iId.Count() - 1);
			iIdKeyHash.Remove(iIdKeyHash.Count() - 1);
			User::Leave(err);
			}
		CleanupStack::Pop(keyHash); 
		}
	else
		{
		User::Leave(KErrAlreadyExists);
		}
 	}

void CPinPluginDB::UpdatePinL(const TIdentityId& aId, const TDesC8& aIdentityKeyHash)
	{
	if(IdIndex(aId) != KErrNotFound)
		{
		// Get the index of the existing id and key hash
		TInt index = IdIndex(aId);
		TInt err = KErrNone;
		HBufC8* keyHash = aIdentityKeyHash.AllocLC();
		// delete the old keyHash and store the new keyHash to the index
		delete iIdKeyHash[index];
		iIdKeyHash[index] = keyHash;

		TCleanupItem cleanupStore(RevertStore, iFileStore);
		// write the idkeys to the store.
		TRAP(err ,
			CleanupStack::PushL(cleanupStore);
			WriteIdKeysToStoreL();
			CleanupStack::Pop(iFileStore));
		if (err!= KErrNone)
			{
			CleanupStack::Pop(keyHash);
			ReadIdKeysFromStoreL();
			User::Leave(err);
			}
		CleanupStack::Pop(keyHash);
		}
	else
		{
		User::Leave(KErrNotFound);
		}
	}
	
void CPinPluginDB::RemovePinL(const TIdentityId& aId)
	{
	if(IdIndex(aId) != KErrNotFound)
		{
		TInt err = KErrNone;
		TInt index = IdIndex(aId);

		// Delete the IdentityId from the array, rewrite the identitystream and 
	   	// Only then commit the store
		delete iIdKeyHash[index];
  		iIdKeyHash.Remove(index);
   		iId.Remove(index);
 
		TCleanupItem cleanupStore(RevertStore, iFileStore);
		// write the idkeys to the store.
		TRAP(err, 
			CleanupStack::PushL(cleanupStore);
			WriteIdKeysToStoreL();
			CleanupStack::Pop(iFileStore));
		if(err != KErrNone)
			{
			ReadIdKeysFromStoreL();
   			User::Leave(err);
			}
		}
	else
		{
		User::Leave(KErrNotFound);
		}
	}
	
TBool CPinPluginDB::IsUniquePin(const TDesC8& aIdentityKeyHash) const
	{
	//	Check each iIdKeyHash in the store to determine if aIdentityId already exists
	TInt count = iIdKeyHash.Count();
	TBool isUnique = ETrue;
	for (TInt index = 0; index < count; ++index)
		{
		if (aIdentityKeyHash.CompareF(*iIdKeyHash[index]) == 0)
			{
			isUnique = EFalse;
			break;
			}
		}
	return isUnique;
	}
	
TInt CPinPluginDB::IdIndex(const TIdentityId& aId) const
	{
	TInt count = iId.Count();
	for (TInt index = 0; index < count; ++index)
		{
		if (aId == iId[index])
			{
			return index;
			}
		}
	return KErrNotFound;
	}
	
TIdentityId CPinPluginDB::IdFromPin(const TDesC8& aIdentityKeyHash) const
	{
	TInt count = iIdKeyHash.Count();
	for (TInt index = 0; index < count; ++index)
		{
		if (aIdentityKeyHash.CompareF(*iIdKeyHash[index]) == 0)
			{
			return iId[index];
			}
		}
	return KUnknownIdentity;
	}
	
void CPinPluginDB::OpenStoreL()
	{
	//	Tries to Open a plugin store file on the private path of the process. 
	//	If it cannot find one, create a file with permanent file store
	//	it should initialise iFileStore unless it cannot
	//	create the file/store/streams
	
	TRAPD(result, OpenStoreInFileL(iPluginDBName));

	if (result == KErrNotFound || result == KErrPathNotFound) 
		{		
		// Not yet opened a valid store, either no file to be found, or no valid
		// store in it.
		CreateStoreInFileL(iPluginDBName);
		}
	else if (result != KErrNone)
		{
		// DB gets corrupted or File may be in use. Abort startup.
		User::Leave(result);
		}
	}


void CPinPluginDB::CreateStoreInFileL(const TDesC& aFile)
	{
	TInt r = iFs.MkDirAll(aFile);
	if ((r!=KErrNone) && (r!=KErrAlreadyExists))
		{
		User::Leave(r);
		}
	
	delete iFileStore;
	iFileStore = NULL;

	iFileStore = CPermanentFileStore::ReplaceL(iFs, aFile, EFileRead | EFileWrite | EFileStream | EFileShareExclusive);
	iFileStore->SetTypeL(KPermanentFileStoreLayoutUid);

	TCleanupItem cleanupStore(RevertStore, iFileStore);
	CleanupStack::PushL(cleanupStore);
	
	// Create Identity stream - Currently no Identity created, and no IdentityKeyHash
	RStoreWriteStream identityStream;
	iIdentityStreamId = identityStream.CreateLC(*iFileStore);
	identityStream.WriteUint32L(KNullStreamId.Value()); //contains the id of dataStream
	identityStream.WriteUint32L(0); // Write IdentityId count of zero
	identityStream.CommitL();
	CleanupStack::PopAndDestroy(&identityStream);

	// Create root stream - just contains id of Identity stream
	RStoreWriteStream rootStream;
	iRootStreamId = rootStream.CreateLC(*iFileStore);
	iFileStore->SetRootL(iRootStreamId);
	rootStream.WriteUint32L(iIdentityStreamId.Value());		
	rootStream.CommitL();
	CleanupStack::PopAndDestroy(&rootStream);
	
	iFileStore->CommitL();
	CleanupStack::Pop(iFileStore); 
	}

void CPinPluginDB::OpenStoreInFileL(const TDesC& aFile)
	{
	// Make sure the file isn't write protected
	User::LeaveIfError(iFs.SetAtt(aFile, 0, KEntryAttReadOnly));
	
	User::LeaveIfError(iFile.Open(iFs, aFile, EFileRead | EFileWrite | EFileStream | EFileShareExclusive));
	
	delete iFileStore;
	iFileStore = NULL;

	iFileStore = CPermanentFileStore::FromL(iFile);		

	// Get the root StreamId
	iRootStreamId = iFileStore->Root();
	if (iRootStreamId == KNullStreamId)
		{
		User::Leave(KErrCorrupt);
		}
	
	RStoreReadStream rootStream;
	rootStream.OpenLC(*iFileStore, iRootStreamId);
	iIdentityStreamId = (TStreamId)(rootStream.ReadUint32L());
	CleanupStack::PopAndDestroy(&rootStream);
	}

// Rewrites the Identity stream (ie the array of IdentityId) to the store
void CPinPluginDB::WriteIdKeysToStoreL()
	{
	TInt count = iId.Count();
	TInt hashCount = iIdKeyHash.Count();
	if (count != hashCount)
		{
		User::Leave(KErrCorrupt);
		}
	
	TStreamId dataStreamId = KNullStreamId;
	if (count > 0)
		{
		RStoreWriteStream dataStream;
		dataStreamId = dataStream.CreateLC(*iFileStore);
		//write the Identity Id key to a data stream
		for (TInt index = 0; index < count; ++index)
			{
			dataStream.WriteUint32L(iId[index]);
			dataStream.WriteUint32L((*iIdKeyHash[index]).Length());
			dataStream.WriteL(*iIdKeyHash[index]);
			}
		dataStream.CommitL();
		CleanupStack::PopAndDestroy(&dataStream); 	
		}
	RStoreReadStream readStream;
	readStream.OpenLC(*iFileStore, iIdentityStreamId);
	TStreamId oldDataStreamId = (TStreamId)(readStream.ReadInt32L());
	CleanupStack::PopAndDestroy(&readStream);
		
	iFileStore->DeleteL(oldDataStreamId);
	
	RStoreWriteStream writeStream;
	writeStream.OpenLC(*iFileStore, iIdentityStreamId);
	writeStream.WriteUint32L(dataStreamId.Value());
	writeStream.WriteInt32L(count);
	writeStream.CommitL();
	CleanupStack::PopAndDestroy(&writeStream); 	
	iFileStore->CommitL();
	CompactStore();
	}
	
void CPinPluginDB::ReadIdKeysFromStoreL()
	{
	iId.Reset();
	iIdKeyHash.ResetAndDestroy();
	
	RStoreReadStream readStream;
	readStream.OpenLC(*iFileStore, iIdentityStreamId);
	TStreamId dataStreamId = (TStreamId)(readStream.ReadInt32L());
	TInt count = readStream.ReadInt32L();
	CleanupStack::PopAndDestroy(&readStream);
	
	if (count > 0)
		{
		RStoreReadStream dataStream;
		dataStream.OpenLC(*iFileStore, dataStreamId);
		for (TInt index = 0; index < count; ++index)
			{
			TIdentityId identityId = (TIdentityId)(dataStream.ReadInt32L());
			iId.AppendL(identityId);
			TInt length = dataStream.ReadInt32L();
			HBufC8* idKeyHash = HBufC8::NewMaxLC(length);
			TPtr8 idKeyHashPtr = idKeyHash->Des();
			dataStream.ReadL(idKeyHashPtr, length);
			iIdKeyHash.AppendL(idKeyHash);
			CleanupStack::Pop(idKeyHash);
			}
		CleanupStack::PopAndDestroy(&dataStream);
		}
	}

void CPinPluginDB::RevertStore(TAny* aStore)
	{
	CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore*>(aStore);
	TRAP_IGNORE(store->RevertL());
	// We're ignoring the leave code from this becuase there's no way we can
	// handle this sensibly.  This shouldn't be a problem in practice - this
	// will leave if for example the file store is on removable which is
	// unexpectedly remove, and this is never the case for us.
	}


void CPinPluginDB::CompactStore()
	{
	ASSERT(iFileStore);
	TRAP_IGNORE(iFileStore->ReclaimL(); iFileStore->CompactL());
	}