git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
829 lines
21 KiB
C++
829 lines
21 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Database upgrade.
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1999-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: flconvrt.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
/*API~***********************************************************************
|
|
Desc: Upgrades a database to the latest FLAIM version.
|
|
*END************************************************************************/
|
|
RCODE FlmDbUpgrade(
|
|
HFDB hDb,
|
|
FLMUINT uiNewVersion,
|
|
STATUS_HOOK fnStatusCallback,
|
|
void * UserData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FDB * pDb = (FDB *)hDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bWroteVersion = FALSE;
|
|
FLMBOOL bLockedDatabase = FALSE;
|
|
FLMBOOL bInitedDb = FALSE;
|
|
FLMUINT uiOldVersion = 0;
|
|
FFILE * pFile = pDb->pFile;
|
|
F_Rfl * pRfl = pFile->pRfl;
|
|
FLMBYTE * pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0];
|
|
FLMUINT uiRflFileNum = 0;
|
|
FLMUINT uiAddr;
|
|
FLMUINT uiMaxFileSize;
|
|
FLMUINT16 ui16Tmp;
|
|
FLMBOOL bExpandingFileCount = FALSE;
|
|
FLMBOOL bLoggingWasOff = FALSE;
|
|
FLMBOOL bRestoreLoggingOffFlag = FALSE;
|
|
FLMUINT uiSaveTransId;
|
|
FLMBYTE * pucWrappingKey = NULL;
|
|
FLMUINT32 ui32KeyLen = 0;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
if( RC_BAD( rc = flmCheckDatabaseState( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Lock the database if not already locked.
|
|
// Cannot lose exclusive access between the checkpoint and
|
|
// the update transaction that does the conversion.
|
|
|
|
if( (pDb->uiFlags & FDB_HAS_FILE_LOCK) == 0)
|
|
{
|
|
if( RC_BAD( rc = FlmDbLock( hDb, FLM_LOCK_EXCLUSIVE, 0, 15)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bLockedDatabase = TRUE;
|
|
}
|
|
|
|
// Cannot have any transaction already going.
|
|
|
|
if( pDb->uiTransType != FLM_NO_TRANS)
|
|
{
|
|
rc = RC_SET( FERR_TRANS_ACTIVE);
|
|
goto Exit;
|
|
}
|
|
|
|
// NOTE: Don't get the current version number until AFTER obtaining
|
|
// the exclusive lock - to make sure nobody else can or will do
|
|
// an upgrade while we are in here.
|
|
|
|
uiOldVersion = pFile->FileHdr.uiVersionNum;
|
|
|
|
switch (uiOldVersion)
|
|
{
|
|
case FLM_VER_3_0:
|
|
case FLM_VER_3_02:
|
|
case FLM_VER_4_0:
|
|
case FLM_VER_4_3:
|
|
case FLM_VER_4_31:
|
|
case FLM_VER_4_50:
|
|
case FLM_VER_4_51:
|
|
|
|
// Upgrades from these versions are supported.
|
|
|
|
break;
|
|
default:
|
|
rc = RC_SET( FERR_UNALLOWED_UPGRADE);
|
|
goto Exit;
|
|
}
|
|
|
|
switch (uiNewVersion)
|
|
{
|
|
case FLM_VER_4_3:
|
|
case FLM_VER_4_31:
|
|
case FLM_VER_4_50:
|
|
case FLM_VER_4_51:
|
|
case FLM_CURRENT_VERSION_NUM:
|
|
|
|
// Verify that we can do the upgrade
|
|
|
|
if (uiNewVersion < uiOldVersion)
|
|
{
|
|
rc = RC_SET( FERR_UNALLOWED_UPGRADE);
|
|
goto Exit;
|
|
}
|
|
else if (uiNewVersion == uiOldVersion)
|
|
{
|
|
|
|
// No need to do upgrade - already there.
|
|
|
|
goto Exit;
|
|
}
|
|
break;
|
|
default:
|
|
rc = RC_SET( FERR_UNALLOWED_UPGRADE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Save the state of RFL logging flag.
|
|
|
|
bLoggingWasOff = pRfl->loggingIsOff();
|
|
|
|
// Change state of logging OFF to TRUE - don't want anything
|
|
// logged during conversion except for the upgrade packet.
|
|
|
|
pRfl->setLoggingOffState( TRUE);
|
|
bRestoreLoggingOffFlag = TRUE;
|
|
pDb->uiFlags |= FDB_UPGRADING;
|
|
|
|
uiSaveTransId =
|
|
(FLMUINT)FB2UD( &pDb->pFile->ucLastCommittedLogHdr [LOG_CURR_TRANS_ID]);
|
|
|
|
// Flush everything do disk so that the roll forward log is empty.
|
|
// The upgrade doesn't put any special data in the roll forward log
|
|
// so if the roll forward log had stuff in it, it would roll forward
|
|
// on data that was a newer version - and never work!
|
|
// Start an update transaction and commit it, forcing it to be
|
|
// checkpointed.
|
|
|
|
bInitedDb = TRUE;
|
|
if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS,
|
|
0, FLM_NO_TIMEOUT | FLM_AUTO_TRANS,
|
|
&bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Don't want this transaction to change the transaction ID because
|
|
// we are only trying to force a checkpoint. We don't want to change
|
|
// the transaction ID until we have actually done the convert.
|
|
|
|
UD2FBA( (FLMUINT32)uiSaveTransId,
|
|
&pDb->pFile->ucUncommittedLogHdr [LOG_CURR_TRANS_ID]);
|
|
pDb->LogHdr.uiCurrTransID = uiSaveTransId;
|
|
|
|
// Set up things in the FDB to indicate where we should move the
|
|
// checkpoint file number and offset to. If we are in the middle
|
|
// of a recovery or restore operation, move the pointer forward
|
|
// to just BEFORE the upgrade packet. Down below when we do the
|
|
// checkpoint at the end of the upgrade, we will move the pointer
|
|
// forward to just AFTER the upgrade packet.
|
|
|
|
if (pDb->uiFlags & FDB_REPLAYING_RFL)
|
|
{
|
|
pDb->uiUpgradeCPFileNum = pRfl->getCurrFileNum();
|
|
pDb->uiUpgradeCPOffset = pRfl->getCurrPacketAddress();
|
|
|
|
}
|
|
|
|
// Commit the transaction, forcing it to be checkpointed.
|
|
|
|
if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = FALSE;
|
|
|
|
// Start an update transaction for the conversion.
|
|
|
|
if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS,
|
|
FLM_NO_TIMEOUT, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
|
|
// Make sure that commit does something.
|
|
|
|
pDb->bHadUpdOper = TRUE;
|
|
|
|
// If version is prior to 4.0, upgrade the non-leaf blocks in
|
|
// container B-Trees.
|
|
|
|
if (uiOldVersion < FLM_VER_4_0 && uiNewVersion >= FLM_VER_4_0)
|
|
{
|
|
|
|
// Upgrade non-leaf blocks in container B-Trees.
|
|
|
|
if (RC_BAD( rc = FSVersionConversion40( pDb, FLM_CURRENT_VERSION_NUM,
|
|
fnStatusCallback, UserData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If versions is pre-4.3, upgrade log header and RFL stuff.
|
|
|
|
if (uiOldVersion < FLM_VER_4_3 && uiNewVersion >= FLM_VER_4_3)
|
|
{
|
|
|
|
// Initialize backup options
|
|
|
|
UD2FBA( 0, &pucUncommittedLogHdr [LOG_LAST_BACKUP_TRANS_ID]);
|
|
UD2FBA( 0, &pucUncommittedLogHdr [LOG_BLK_CHG_SINCE_BACKUP]);
|
|
UD2FBA( 1, &pucUncommittedLogHdr [LOG_INC_BACKUP_SEQ_NUM]);
|
|
|
|
// Initialize unused parts to zero.
|
|
|
|
UW2FBA( 0, &pucUncommittedLogHdr [LOG_NU_152_153]);
|
|
|
|
// Set maximum RFL file size
|
|
|
|
UD2FBA( DEFAULT_MAX_RFL_FILE_SIZE,
|
|
&pucUncommittedLogHdr [LOG_RFL_MAX_FILE_SIZE]);
|
|
|
|
// Set the database serial number
|
|
|
|
if (RC_BAD( rc = f_createSerialNumber(
|
|
&pucUncommittedLogHdr [LOG_DB_SERIAL_NUM])))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set the RFL serial number
|
|
|
|
if (RC_BAD( rc = f_createSerialNumber(
|
|
&pucUncommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM])))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set the "next" RFL serial number
|
|
|
|
if (RC_BAD( rc = f_createSerialNumber(
|
|
&pucUncommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM])))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set the incremental backup serial number
|
|
|
|
if (RC_BAD( rc = f_createSerialNumber(
|
|
&pucUncommittedLogHdr [LOG_INC_BACKUP_SERIAL_NUM])))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// At this point, the last checkpoint offset and file number
|
|
// should be the same as the last transaction offset and
|
|
// file number.
|
|
|
|
flmAssert( FB2UD( &pucUncommittedLogHdr [LOG_RFL_FILE_NUM]) ==
|
|
FB2UD( &pucUncommittedLogHdr [LOG_RFL_LAST_CP_FILE_NUM]));
|
|
flmAssert( FB2UD( &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]) ==
|
|
FB2UD( &pucUncommittedLogHdr [LOG_RFL_LAST_CP_OFFSET]));
|
|
|
|
// Set the transaction offset to zero so that we will be forced to
|
|
// write the serial numbers into the RFL file on the next transaction
|
|
// begin operation.
|
|
|
|
UD2FBA( 0, &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]);
|
|
|
|
// Keep log files should be FALSE at this point - pre 4.3
|
|
// versions did not keep RFL files. Also, we should still
|
|
// be on log file #1. However, if this is not the case,
|
|
// we need to deal with it and set up to roll to the
|
|
// next log file. - We don't want to lose the current
|
|
// RFL file, but we need to have the serial numbers written
|
|
// out, so our only option is to go to the next one.
|
|
|
|
uiRflFileNum = FB2UD( &pucUncommittedLogHdr [LOG_RFL_FILE_NUM]);
|
|
if (pucUncommittedLogHdr [LOG_KEEP_RFL_FILES])
|
|
{
|
|
flmIncrUint( &pucUncommittedLogHdr [LOG_RFL_FILE_NUM], 1);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Checkpoint offset better already be 512 if we are not keeping
|
|
// RFL files - due to the checkpoint we executed above.
|
|
|
|
flmAssert(
|
|
FB2UD( &pucUncommittedLogHdr [LOG_RFL_LAST_CP_OFFSET]) == 512);
|
|
}
|
|
|
|
// Set the maximum file size. If we currently have more than
|
|
// one data file or rollback file, we must use the old file size
|
|
// limit.
|
|
|
|
uiMaxFileSize = gv_FlmSysData.uiMaxFileSize;
|
|
|
|
// A file number greater than one in the logical EOF means
|
|
// we have multiple data files.
|
|
|
|
uiAddr = (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_LOGICAL_EOF]);
|
|
if (FSGetFileNumber( uiAddr) > 1)
|
|
{
|
|
uiMaxFileSize = MAX_FILE_SIZE_VER40;
|
|
}
|
|
|
|
ui16Tmp = (FLMUINT16)(uiMaxFileSize >> 16);
|
|
flmAssert( ui16Tmp);
|
|
UW2FBA( ui16Tmp, &pucUncommittedLogHdr [LOG_MAX_FILE_SIZE]);
|
|
bExpandingFileCount = TRUE;
|
|
}
|
|
|
|
if (uiOldVersion < FLM_VER_4_31 && uiNewVersion >= FLM_VER_4_31)
|
|
{
|
|
|
|
// NOTE: We could really set the LOG_LAST_RFL_COMMIT_ID to anything,
|
|
// because the new transaction begin packet will not be logged until
|
|
// after we do this conversion, and it will log whatever we put
|
|
// in here.
|
|
|
|
UD2FBA( (FLMUINT32)pDb->LogHdr.uiCurrTransID,
|
|
&pucUncommittedLogHdr [LOG_LAST_RFL_COMMIT_ID]);
|
|
}
|
|
|
|
#ifdef FLM_USE_NICI
|
|
|
|
if (uiOldVersion < FLM_VER_4_60 && uiNewVersion >= FLM_VER_4_60)
|
|
{
|
|
|
|
if( RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = FALSE;
|
|
|
|
if (RC_BAD( rc = FlmEnableEncryption( hDb, &pucWrappingKey, &ui32KeyLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS,
|
|
FLM_NO_TIMEOUT, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
// NOTE: THIS TEST SHOULD BE DONE ONLY AFTER ALL CHANGES THAT COULD
|
|
// CAUSE BLOCKS TO BE LOGGED TO THE ROLLBACK LOG HAVE BEEN DONE.
|
|
// IT SHOULD ALSO BE DONE BEFORE WE CHANGE THE VERSION NUMBER ON
|
|
// THE DATABASE.
|
|
|
|
if (bExpandingFileCount)
|
|
{
|
|
|
|
// Force any keys to be committed so that all blocks that
|
|
// are going to be modified will have been modified by this
|
|
// point.
|
|
|
|
if (RC_BAD( rc = KYKeysCommit( pDb, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If this conversion requires a change in the total number
|
|
// of files then the file number scheme has changed. However,
|
|
// we cannot do it if we have more than a single rollback file,
|
|
// because the new file numbering scheme would be wrong - it
|
|
// would not support accessing the additional rollback file
|
|
// correctly.
|
|
// NOTE: Could have multiple rollback files if some aspect
|
|
// of the conversion that occurred prior to this caused us to
|
|
// have multiple rollback files.
|
|
|
|
uiAddr = (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_ROLLBACK_EOF]);
|
|
if (FSGetFileNumber( uiAddr))
|
|
{
|
|
rc = RC_SET( FERR_CANNOT_CONVERT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// NOTE: By this point, all conversions should be complete, except for
|
|
// committing and changing the version number.
|
|
|
|
// Log the upgrade packet to the RFL if we are not in the middle of a
|
|
// restore or recovery. Will need to re-enable logging temporarily
|
|
// and then turn it back off after logging the packet.
|
|
// NOTE: We can only do this if converting from 4.30 or greater.
|
|
// Makes no sense before that because prior to 4.30 there was no
|
|
// possibility of keeping RFL files and doing a restore from them.
|
|
|
|
if (!(pDb->uiFlags & FDB_REPLAYING_RFL) && uiOldVersion >= FLM_VER_4_3)
|
|
{
|
|
// We would have turned logging OFF above, so we need to
|
|
// turn it back on here.
|
|
|
|
pRfl->setLoggingOffState( FALSE);
|
|
|
|
// Log the upgrade packet.
|
|
|
|
rc = pRfl->logUpgrade( pDb->LogHdr.uiCurrTransID, uiOldVersion,
|
|
pucWrappingKey, ui32KeyLen);
|
|
|
|
// Turn logging back off.
|
|
|
|
pRfl->setLoggingOffState( TRUE);
|
|
if (RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Change the FLAIM version number to the new version number.
|
|
|
|
pFile->FileHdr.uiVersionNum = uiNewVersion;
|
|
UW2FBA( (FLMUINT16)uiNewVersion, &pucUncommittedLogHdr [LOG_FLAIM_VERSION]);
|
|
|
|
// Change the FLAIM version number on disk
|
|
|
|
if( RC_BAD( rc = flmWriteVersionNum( pDb->pSFileHdl, uiNewVersion)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bWroteVersion = TRUE;
|
|
|
|
// Commit and force a checkpoint by passing TRUE.
|
|
// Set up things in the FDB to indicate where we should move the
|
|
// checkpoint file number and offset to. If we are in the middle
|
|
// of a recovery or restore operation, move the pointer forward
|
|
// to just AFTER the upgrade packet.
|
|
|
|
if (pDb->uiFlags & FDB_REPLAYING_RFL)
|
|
{
|
|
pDb->uiUpgradeCPFileNum = pRfl->getCurrFileNum();
|
|
pDb->uiUpgradeCPOffset = pRfl->getCurrReadOffset();
|
|
}
|
|
if( RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = FALSE;
|
|
|
|
// Set up to use a new RFL directory. Must do this only after
|
|
// setting FileHdr.uiVersionNum above.
|
|
|
|
if (uiOldVersion < FLM_VER_4_3 && uiNewVersion >= FLM_VER_4_3)
|
|
{
|
|
char szTmpName [F_PATH_MAX_SIZE];
|
|
|
|
// Close the current RFL file.
|
|
|
|
pRfl->closeFile();
|
|
|
|
// At this point, there should be no RFL directory.
|
|
|
|
flmAssert( pRfl->isRflDirSameAsDbDir());
|
|
(void)pRfl->setRflDir( NULL);
|
|
|
|
// Attempt to delete the old RFL file - should only be
|
|
// one and it should be file #1 - we could assert that
|
|
// uiRflFileNum == 1, but we will be more lenient.
|
|
|
|
if (RC_OK( rc = rflGetFileName( uiOldVersion, pFile->pszDbPath,
|
|
NULL, uiRflFileNum, szTmpName)))
|
|
{
|
|
gv_FlmSysData.pFileSystem->Delete( szTmpName);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
|
|
// Failure condition, we jumped to exit
|
|
|
|
UW2FBA( (FLMUINT16)uiOldVersion,
|
|
&pucUncommittedLogHdr [LOG_FLAIM_VERSION]);
|
|
pFile->FileHdr.uiVersionNum = uiOldVersion;
|
|
|
|
// Change the FLAIM version number on disk to the original.
|
|
|
|
if (bWroteVersion)
|
|
{
|
|
|
|
// Need to initialize the database to do the following write.
|
|
// We don't care about the transaction, which will be aborted
|
|
// a couple of lines down.
|
|
|
|
(void) fdbInit( (FDB *)hDb, FLM_UPDATE_TRANS,
|
|
0, FLM_AUTO_TRANS, &bStartedTrans);
|
|
(void) flmWriteVersionNum( pDb->pSFileHdl, uiOldVersion);
|
|
(void) fdbExit( pDb);
|
|
}
|
|
(void) flmAbortDbTrans( pDb);
|
|
}
|
|
if (bInitedDb)
|
|
{
|
|
flmExit( FLM_DB_UPGRADE, pDb, rc);
|
|
}
|
|
|
|
if (bRestoreLoggingOffFlag)
|
|
{
|
|
pRfl->setLoggingOffState( bLoggingWasOff);
|
|
}
|
|
|
|
// Turn off the upgrade flag, in case it was turned on above.
|
|
|
|
pDb->uiFlags &= (~(FDB_UPGRADING));
|
|
|
|
if (bLockedDatabase)
|
|
{
|
|
(void) FlmDbUnlock( hDb);
|
|
}
|
|
|
|
if (pucWrappingKey)
|
|
{
|
|
f_free( &pucWrappingKey);
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
/*API~***********************************************************************
|
|
Desc : Adds an encryption key to the database.
|
|
*END************************************************************************/
|
|
RCODE FlmEnableEncryption(
|
|
HFDB hDb,
|
|
FLMBYTE ** ppucWrappingKeyRV,
|
|
FLMUINT32 * pui32KeyLen)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FDB * pDb = (FDB *)hDb;
|
|
FFILE * pFile = pDb->pFile;
|
|
F_Rfl * pRfl = pFile->pRfl;
|
|
FLMBYTE * pucWrappingKey = NULL;
|
|
FLMUINT32 ui32KeyLen = 0;
|
|
FLMBYTE * pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0];
|
|
FLMUINT uiFlags = FLM_GET_TRANS_FLAGS( FLM_UPDATE_TRANS);
|
|
FLMBOOL bTransBegun = FALSE;
|
|
|
|
// We must will start our own transaction. Then we will force a checkpoint
|
|
// when we commit the transaction
|
|
|
|
if ( pDb->uiTransType != FLM_NO_TRANS)
|
|
{
|
|
rc = RC_SET( FERR_TRANS_ACTIVE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Begin an update transaction.
|
|
|
|
if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS,
|
|
FLM_NO_TIMEOUT, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bTransBegun = TRUE;
|
|
|
|
// If we don't have a wrapping key, then create one. Normally
|
|
// this would be the case, since we are enabling encryption,
|
|
// but the test is "just to be sure" we don't
|
|
// overwrite an existing key.
|
|
|
|
if (!pFile->pDbWrappingKey)
|
|
{
|
|
if ((pFile->pDbWrappingKey = f_new F_CCS) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pFile->pDbWrappingKey->init( TRUE, FLM_NICI_AES)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pFile->pDbWrappingKey->generateWrappingKey()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pFile->pDbWrappingKey->getKeyToStore( &pucWrappingKey,
|
|
&ui32KeyLen, pFile->pszDbPassword, NULL, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_memcpy( &pucUncommittedLogHdr[ LOG_DATABASE_KEY], pucWrappingKey, ui32KeyLen);
|
|
UW2FBA( ui32KeyLen, &pucUncommittedLogHdr[ LOG_DATABASE_KEY_LEN]);
|
|
|
|
pFile->rcLimitedCode = FERR_OK;
|
|
pFile->bInLimitedMode = FALSE;
|
|
pFile->bHaveEncKey = TRUE;
|
|
|
|
// Log the upgrade packet. NOTE that if this is part of a standard DB
|
|
// upgrade this packet will not be logged. The upgrade will be logged by
|
|
// the FlmDbUpgrade function. No need to log it twice.
|
|
|
|
if( RC_BAD( rc = pRfl->logEnableEncryption( pDb->LogHdr.uiCurrTransID,
|
|
pucWrappingKey, ui32KeyLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Commit the transaction - force a checkpoint!
|
|
|
|
if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bTransBegun = FALSE;
|
|
|
|
if( ppucWrappingKeyRV)
|
|
{
|
|
// It is now the responsibility of the caller to
|
|
// free this buffer!!
|
|
|
|
*ppucWrappingKeyRV = pucWrappingKey;
|
|
pucWrappingKey = NULL;
|
|
}
|
|
|
|
if( pui32KeyLen)
|
|
{
|
|
*pui32KeyLen = ui32KeyLen;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bTransBegun)
|
|
{
|
|
RCODE rcTmp = FERR_OK;
|
|
|
|
rcTmp = flmAbortDbTrans( pDb);
|
|
if (RC_OK( rc))
|
|
{
|
|
rc = rcTmp;
|
|
}
|
|
}
|
|
|
|
if( pucWrappingKey)
|
|
{
|
|
f_free( &pucWrappingKey);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*API~***********************************************************************
|
|
Desc: Changes the way the database key is stored in the database. Either
|
|
it is encrypted using a password or it is wrapped in the server key.
|
|
*END************************************************************************/
|
|
RCODE FlmDbWrapKey(
|
|
HFDB hDb,
|
|
const char * pszPassword)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FDB * pDb = (FDB *)hDb;
|
|
FFILE * pFile = pDb->pFile;
|
|
F_Rfl * pRfl = pFile->pRfl;
|
|
FLMBYTE * pucWrappingKey = NULL;
|
|
FLMUINT32 ui32KeyLen = 0;
|
|
FLMBYTE * pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0];
|
|
FLMUINT uiFlags = FLM_GET_TRANS_FLAGS( FLM_UPDATE_TRANS);
|
|
FLMBOOL bTransBegun = FALSE;
|
|
FLMBOOL bLoggingIsOff = pRfl->loggingIsOff();
|
|
FLMBOOL bLockedDatabase = FALSE;
|
|
|
|
// Lock the database if not already locked.
|
|
// Cannot lose exclusive access between the checkpoint and
|
|
// the update transaction that does the conversion.
|
|
|
|
if( (pDb->uiFlags & FDB_HAS_FILE_LOCK) == 0)
|
|
{
|
|
if( RC_BAD( rc = FlmDbLock( hDb, FLM_LOCK_EXCLUSIVE, 0, 15)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bLockedDatabase = TRUE;
|
|
}
|
|
|
|
// Turn off logging. We only want to log the wrap key packet.
|
|
|
|
pRfl->setLoggingOffState( TRUE);
|
|
|
|
// We must will start our own transaction. Then we will force a checkpoint
|
|
// when we commit the transaction
|
|
|
|
if ( pDb->uiTransType != FLM_NO_TRANS)
|
|
{
|
|
rc = RC_SET( FERR_TRANS_ACTIVE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Begin an update transaction.
|
|
|
|
if( RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS,
|
|
FLM_NO_TIMEOUT, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pDb->bHadUpdOper = TRUE;
|
|
|
|
bTransBegun = TRUE;
|
|
|
|
// The wrapping key MUST exist!
|
|
|
|
flmAssert( pFile->bHaveEncKey);
|
|
|
|
if (!pFile->pDbWrappingKey)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pFile->pDbWrappingKey->getKeyToStore( &pucWrappingKey,
|
|
&ui32KeyLen, pszPassword, NULL, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_memcpy( &pucUncommittedLogHdr[ LOG_DATABASE_KEY], pucWrappingKey, ui32KeyLen);
|
|
UW2FBA( ui32KeyLen, &pucUncommittedLogHdr[ LOG_DATABASE_KEY_LEN]);
|
|
|
|
// Turn on logging. We only want to log the wrap key packet.
|
|
|
|
pRfl->setLoggingOffState( FALSE);
|
|
|
|
// Log a wrapped key packet to record that the key has been wrapped/encrypted.
|
|
|
|
if( RC_BAD( rc = pRfl->logWrappedKey( pDb->LogHdr.uiCurrTransID,
|
|
pucWrappingKey, ui32KeyLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Turn off logging. We only want to log the wrap key packet.
|
|
|
|
pRfl->setLoggingOffState( TRUE);
|
|
|
|
// Commit the transaction - force a checkpoint!
|
|
|
|
if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bTransBegun = FALSE;
|
|
|
|
// Delete the old password
|
|
|
|
if (pFile->pszDbPassword)
|
|
{
|
|
f_free( &pFile->pszDbPassword);
|
|
}
|
|
|
|
// Store the new password
|
|
|
|
if ( pszPassword)
|
|
{
|
|
if (RC_BAD( rc = f_calloc( f_strlen( pszPassword) + 1,
|
|
&pFile->pszDbPassword)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_memcpy( pFile->pszDbPassword, pszPassword, f_strlen( pszPassword));
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bTransBegun)
|
|
{
|
|
RCODE rcTmp = FERR_OK;
|
|
|
|
rcTmp = flmAbortDbTrans( pDb);
|
|
if (RC_OK( rc))
|
|
{
|
|
rc = rcTmp;
|
|
}
|
|
}
|
|
|
|
// Restore logging to its original state
|
|
|
|
pRfl->setLoggingOffState( bLoggingIsOff);
|
|
|
|
if( bLockedDatabase)
|
|
{
|
|
(void) FlmDbUnlock( hDb);
|
|
}
|
|
|
|
if( pucWrappingKey)
|
|
{
|
|
f_free( &pucWrappingKey);
|
|
}
|
|
|
|
return( rc);
|
|
}
|