/*************************************************************************** Desc: This routine reads the header information in a FLAIM database, verifies the password, and returns the file header and log header information. *****************************************************************************/ RCODE flmGetHdrInfo( F_SuperFileHdl * pSFileHdl, XFLM_DB_HDR * pDbHdr, FLMUINT32 * pui32CalcCRC) { RCODE rc = NE_XFLM_OK; IF_FileHdl * pCFileHdl = NULL; if( RC_BAD( rc = pSFileHdl->getFileHdl( 0, FALSE, &pCFileHdl))) { goto Exit; } if( RC_BAD( rc = flmReadAndVerifyHdrInfo( NULL, pCFileHdl, pDbHdr, pui32CalcCRC))) { goto Exit; } Exit: if( pCFileHdl) { pCFileHdl->Release(); } return( rc); }
/**************************************************************************** Desc: This routine obtains exclusive access to a database by creating a .lck file. FLAIM holds the .lck file open as long as the database is open. When the database is finally closed, it deletes the .lck file. This is only used for 3.x databases. ****************************************************************************/ RCODE flmCreateLckFile( const char * pszFilePath, IF_FileHdl ** ppLockFileHdlRV) { RCODE rc = NE_XFLM_OK; char szLockPath [F_PATH_MAX_SIZE]; char szDbBaseName [F_FILENAME_SIZE]; char * pszFileExt; IF_FileHdl * pLockFileHdl = NULL; char szFilePathStr[ F_PATH_MAX_SIZE]; if( RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathToStorageString( pszFilePath, szFilePathStr))) { goto Exit; } // Extract the 8.3 name and put a .lck extension on it to create // the full path for the .lck file. if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathReduce( szFilePathStr, szLockPath, szDbBaseName))) { goto Exit; } pszFileExt = &szDbBaseName [0]; while ((*pszFileExt) && (*pszFileExt != '.')) pszFileExt++; f_strcpy( pszFileExt, ".lck"); if( RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathAppend( szLockPath, szDbBaseName))) { goto Exit; } if( RC_BAD( rc = gv_XFlmSysData.pFileSystem->createLockFile( szLockPath, &pLockFileHdl))) { goto Exit; } *ppLockFileHdlRV = (IF_FileHdl *)pLockFileHdl; pLockFileHdl = NULL; Exit: if (pLockFileHdl) { (void)pLockFileHdl->closeFile(); pLockFileHdl->Release(); pLockFileHdl = NULL; } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE ArgList::expandFileArgs( const char * pszFilename) { RCODE rc = FERR_OK; char token[64]; IF_FileHdl * pFileHdl = NULL; if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszFilename, FLM_IO_RDWR, &pFileHdl))) { goto Exit; } while( RC_OK( rc = getTokenFromFile(token, pFileHdl))) { if( token[0] == '@') { if( RC_BAD( rc = expandFileArgs( &token[1]))) { goto Exit; } } else { flmAssert(*token); if( RC_BAD( rc = addArg( token))) { goto Exit; } } } if( rc == FERR_IO_END_OF_FILE) { rc = FERR_OK; } Exit: if( pFileHdl) { pFileHdl->Release(); } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE F_FSRestore::openRflFile( FLMUINT uiFileNum) { RCODE rc = NE_SFLM_OK; char szRflPath[ F_PATH_MAX_SIZE]; char szBaseName[ F_FILENAME_SIZE]; FLMUINT uiBaseNameSize; SFLM_DB_HDR dbHdr; IF_FileHdl * pFileHdl = NULL; flmAssert( m_bSetupCalled); flmAssert( uiFileNum); flmAssert( !m_pFileHdl); // Read the database header to determine the version number if( !m_uiDbVersion) { if( RC_BAD( rc = gv_SFlmSysData.pFileSystem->openFile( m_szDbPath, FLM_IO_RDWR | FLM_IO_SH_DENYNONE | FLM_IO_DIRECT, &pFileHdl))) { goto Exit; } if( RC_BAD( rc = flmReadAndVerifyHdrInfo( NULL, pFileHdl, &dbHdr))) { goto Exit; } pFileHdl->Release(); pFileHdl = NULL; m_uiDbVersion = (FLMUINT)dbHdr.ui32DbVersion; } // Generate the log file name. if( RC_BAD( rc = rflGetDirAndPrefix( m_szDbPath, m_szRflDir, szRflPath))) { goto Exit; } uiBaseNameSize = sizeof( szBaseName); rflGetBaseFileName( uiFileNum, szBaseName, &uiBaseNameSize, NULL); gv_SFlmSysData.pFileSystem->pathAppend( szRflPath, szBaseName); // Open the file. if( RC_BAD( rc = gv_SFlmSysData.pFileSystem->openFile( szRflPath, FLM_IO_RDWR | FLM_IO_SH_DENYNONE | FLM_IO_DIRECT, &m_pFileHdl))) { goto Exit; } m_bOpen = TRUE; m_ui64Offset = 0; Exit: if( pFileHdl) { pFileHdl->Release(); } return( rc); }
/**************************************************************************** Desc: Returns disk space usage for the database ****************************************************************************/ RCODE XFLAPI F_Db::getDiskSpaceUsage( FLMUINT64 * pui64DataSize, FLMUINT64 * pui64RollbackSize, FLMUINT64 * pui64RflSize) { RCODE rc = NE_XFLM_OK; FLMBOOL bStartedTrans = FALSE; FLMUINT uiEndAddress; FLMUINT uiLastFileNumber; FLMUINT64 ui64LastFileSize; char szTmpName [F_PATH_MAX_SIZE]; char szRflDir [F_PATH_MAX_SIZE]; IF_FileHdl * pFileHdl = NULL; IF_DirHdl * pDirHdl = NULL; if (m_eTransType == XFLM_READ_TRANS) { rc = RC_SET( NE_XFLM_ILLEGAL_TRANS_OP); goto Exit; } else if (m_eTransType != XFLM_NO_TRANS) { if (!okToCommitTrans()) { rc = RC_SET( NE_XFLM_ABORT_TRANS); goto Exit; } } else { if (RC_BAD( rc = beginTrans( XFLM_UPDATE_TRANS))) { goto Exit; } bStartedTrans = TRUE; } // See if they want the database files sizes. if (pui64DataSize) { uiEndAddress = m_uiLogicalEOF; uiLastFileNumber = FSGetFileNumber( uiEndAddress); // Last file number better be in the proper range. flmAssert( uiLastFileNumber >= 1 && uiLastFileNumber <= MAX_DATA_BLOCK_FILE_NUMBER); // Get the actual size of the last file. if (RC_BAD( rc = m_pSFileHdl->getFileSize( uiLastFileNumber, &ui64LastFileSize))) { if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME) { if (uiLastFileNumber > 1) { rc = NE_XFLM_OK; ui64LastFileSize = 0; } else { // Should always be a data file #1 RC_UNEXPECTED_ASSERT( rc); goto Exit; } } else { goto Exit; } } // One of two situations exists with respect to the last // file: 1) it has not been fully written out yet (blocks // are still cached, or 2) it has been written out and // extended beyond what the logical EOF shows. We want // the larger of these two possibilities. if (FSGetFileOffset( uiEndAddress) > ui64LastFileSize) { ui64LastFileSize = FSGetFileOffset( uiEndAddress); } if (uiLastFileNumber == 1) { // Only one file - use last file's size. *pui64DataSize = ui64LastFileSize; } else { // Size is the sum of full size for all files except the last one, // plus the calculated (or actual) size of the last one. (*pui64DataSize) = (FLMUINT64)(uiLastFileNumber - 1) * (FLMUINT64)m_pDatabase->m_uiMaxFileSize + ui64LastFileSize; } } // See if they want the rollback files sizes. if (pui64RollbackSize) { uiEndAddress = (FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RblEOF; uiLastFileNumber = FSGetFileNumber( uiEndAddress); // Last file number better be in the proper range. flmAssert( !uiLastFileNumber || (uiLastFileNumber >= FIRST_LOG_BLOCK_FILE_NUMBER && uiLastFileNumber <= MAX_LOG_BLOCK_FILE_NUMBER)); // Get the size of the last file number. if (RC_BAD( rc = m_pSFileHdl->getFileSize( uiLastFileNumber, &ui64LastFileSize))) { if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME) { if (uiLastFileNumber) { rc = NE_XFLM_OK; ui64LastFileSize = 0; } else { // Should always have rollback file #0 RC_UNEXPECTED_ASSERT( rc); goto Exit; } } else { goto Exit; } } // If the EOF offset for the last file is greater than the // actual file size, use it instead of the actual file size. if (FSGetFileOffset( uiEndAddress) > ui64LastFileSize) { ui64LastFileSize = FSGetFileOffset( uiEndAddress); } // Special case handling here because rollback file numbers start with // zero and then skip to a file number that is one beyond the // highest data file number - so the calculation for file size needs // to account for this. if (!uiLastFileNumber) { *pui64RollbackSize = ui64LastFileSize; } else { FLMUINT uiFirstLogFileNum = FIRST_LOG_BLOCK_FILE_NUMBER; // Add full size of file zero plus a full size for every file // except the last one. (*pui64RollbackSize) = (FLMUINT64)(uiLastFileNumber - uiFirstLogFileNum + 1) * (FLMUINT64)m_pDatabase->m_uiMaxFileSize + ui64LastFileSize; } } // See if they want the roll-forward log file sizes. if (pui64RflSize) { char * pszDbFileName = m_pDatabase->m_pszDbPath; *pui64RflSize = 0; // Scan the RFL directory for // RFL files. The call below to rflGetDirAndPrefix is done // to get the prefix. It will not return the correct // RFL directory name, because we are passing in a NULL // RFL directory path (which may or may not be correct). // That's OK, because we get the RFL directory directly // from the F_Rfl object anyway. if (RC_BAD( rc = rflGetDirAndPrefix( pszDbFileName, NULL, szRflDir))) { goto Exit; } // We need to get the RFL directory from the F_Rfl object. m_pDatabase->lockMutex(); f_strcpy( szRflDir, m_pDatabase->m_pRfl->getRflDirPtr()); m_pDatabase->unlockMutex(); // See if the directory exists. If not, we are done. if (gv_XFlmSysData.pFileSystem->isDir( szRflDir)) { // Open the directory and scan for RFL files. if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->openDir( szRflDir, "*", &pDirHdl))) { goto Exit; } for (;;) { if (RC_BAD( rc = pDirHdl->next())) { if (rc == NE_FLM_IO_NO_MORE_FILES) { rc = NE_XFLM_OK; break; } else { goto Exit; } } pDirHdl->currentItemPath( szTmpName); // If the item looks like an RFL file name, get // its size. if (!pDirHdl->currentItemIsDir() && rflGetFileNum( szTmpName, &uiLastFileNumber)) { // Open the file and get its size. if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->openFile( szTmpName, gv_XFlmSysData.uiFileOpenFlags, &pFileHdl))) { if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME) { rc = NE_XFLM_OK; ui64LastFileSize = 0; } else { goto Exit; } } else { if (RC_BAD( rc = pFileHdl->size( &ui64LastFileSize))) { goto Exit; } } if (pFileHdl) { pFileHdl->Release(); pFileHdl = NULL; } (*pui64RflSize) += ui64LastFileSize; } } } } Exit: if (pFileHdl) { pFileHdl->Release(); } if (pDirHdl) { pDirHdl->Release(); } if (bStartedTrans) { abortTrans(); } return( rc); }
/*************************************************************************** Desc: This routine reads the header information for an existing flaim database and makes sure we have a valid database. *****************************************************************************/ RCODE F_Database::readDbHdr( const char * pszDbPath, XFLM_DB_STATS * pDbStats, FLMBYTE * pszPassword, FLMBOOL bAllowLimited) { RCODE rc = NE_XFLM_OK; IF_FileHdl * pFileHdl = NULL; if( RC_BAD( rc = gv_XFlmSysData.pFileSystem->openFile( pszDbPath, gv_XFlmSysData.uiFileOpenFlags, &pFileHdl))) { goto Exit; } // Read and verify the database header. if (RC_BAD( rc = flmReadAndVerifyHdrInfo( pDbStats, pFileHdl, &m_lastCommittedDbHdr))) { goto Exit; } m_uiBlockSize = (FLMUINT)m_lastCommittedDbHdr.ui16BlockSize; m_uiDefaultLanguage = (FLMUINT)m_lastCommittedDbHdr.ui8DefaultLanguage; m_uiMaxFileSize = (FLMUINT)m_lastCommittedDbHdr.ui32MaxFileSize; m_uiSigBitsInBlkSize = calcSigBits( m_uiBlockSize); // Initialize the master database key from the database header m_bAllowLimitedMode = bAllowLimited; if (pszPassword && *pszPassword) { if (m_pszDbPasswd) { f_free( &m_pszDbPasswd); } if ( RC_BAD( rc = f_alloc( (f_strlen( (const char *)pszPassword) + 1), &m_pszDbPasswd))) { goto Exit; } f_strcpy( (char *)m_pszDbPasswd, (const char *)pszPassword); } if( RC_BAD( rc = flmAllocCCS( &m_pWrappingKey))) { goto Exit; } if( RC_OK( rc = m_pWrappingKey->init( TRUE, FLM_NICI_AES))) { // If the key was encrypted in a password, then the pszPassword parameter better // be the key used to encrypt it. If the key was not encrypted in a password, // then pszPassword parameter should be NULL. rc = m_pWrappingKey->setKeyFromStore( m_lastCommittedDbHdr.DbKey, pszPassword, NULL); } if( RC_BAD( rc)) { if ((rc == NE_XFLM_ENCRYPTION_UNAVAILABLE) || bAllowLimited) { m_bInLimitedMode = TRUE; rc = NE_XFLM_OK; } else { goto Exit; } } // Note that we might still end up in limited mode if we can't verify all the keys // that are stored in the dictionary. Exit: if( pFileHdl) { pFileHdl->Release(); } return( rc); }
/**************************************************************************** Desc: *****************************************************************************/ RCODE F_DynamicList::dumpToFile() { RCODE rc = NE_FLM_OK; DLIST_NODE * pTmp; FLMUINT uiLoop; IF_FileHdl * pFileHdl = NULL; #define DLST_RESP_SIZE 256 char szResponse[ DLST_RESP_SIZE]; FLMUINT uiTermChar; FTX_SCREEN * pScreen; IF_FileSystem * pFileSystem = NULL; if( RC_BAD( rc = FlmGetFileSystem( &pFileSystem))) { goto Exit; } f_strcpy( szResponse, (const char *)DLIST_DUMPFILE_PATH); FTXWinGetScreen( m_pListWin, &pScreen); FTXGetInput( pScreen, "enter filename to dump to", szResponse, DLST_RESP_SIZE-1, &uiTermChar); if ( uiTermChar != FKB_ENTER) { goto Exit; } if (RC_BAD( rc = pFileSystem->doesFileExist( szResponse))) { //create file if it doesn't already exist if ( rc == NE_FLM_IO_PATH_NOT_FOUND) { rc = pFileSystem->createFile( szResponse, FLM_IO_RDWR, &pFileHdl); } else { goto Exit_local; } } else { rc = pFileSystem->openFile( szResponse, FLM_IO_RDWR, &pFileHdl); } TEST_RC_LOCAL( rc); { FLMUINT64 ui64FileSize = 0; FLMUINT uiBytesWritten = 0; //figure out size of file currently, so you can append to it pFileHdl->size( &ui64FileSize); pTmp = m_pFirst; uiLoop = 0; while( pTmp) { FLMBYTE * pszNextLine = (FLMBYTE*)(pTmp->pvData); TEST_RC_LOCAL( rc = pFileHdl->write( ui64FileSize, //offset to current file size f_strlen( (const char *)pszNextLine), pszNextLine, &uiBytesWritten)); ui64FileSize += uiBytesWritten; TEST_RC_LOCAL( rc = pFileHdl->write( ui64FileSize, //add in newline 1, (FLMBYTE*)"\n", &uiBytesWritten)); ui64FileSize += uiBytesWritten; pTmp = pTmp->pNext; } (void)pFileHdl->closeFile(); } Exit_local: {//give success/fail message char szMessage[ 256]; FLMUINT uiChar; FTXWinGetScreen( m_pListWin, &pScreen); if ( RC_OK( rc)) { f_sprintf( szMessage, "contents of focused list appended to %s", DLIST_DUMPFILE_PATH); } else { f_sprintf( szMessage, "error rc=%u dumping to file %s", (unsigned)rc, DLIST_DUMPFILE_PATH); } FTXDisplayMessage( pScreen, FLM_RED, FLM_WHITE, szMessage, "press ESC or ENTER to close dialog", &uiChar); } Exit: if (pFileHdl) { pFileHdl->Release(); pFileHdl = NULL; } if( pFileSystem) { pFileSystem->Release(); } return rc; }
/******************************************************************************* Desc: Renames a database *******************************************************************************/ FLMEXP RCODE FLMAPI FlmDbRename( const char * pszDbName, const char * pszDataDir, const char * pszRflDir, const char * pszNewDbName, FLMBOOL bOverwriteDestOk, STATUS_HOOK fnStatusCallback, void * UserData) { RCODE rc = FERR_OK; IF_FileHdl * pFileHdl = NULL; FLMUINT uiFileNumber; FILE_HDR FileHdr; LOG_HDR LogHdr; DBRenameInfo * pRenameList = NULL; FLMBOOL bFileFound; FLMBYTE * pucBuffer = NULL; FLMBYTE * pucLogHdr; char * pszOldName; char * pszNewName; char * pszOldDataName; char * pszNewDataName; char * pszFullNewName; char szOldBase[ F_FILENAME_SIZE]; char szNewBase[ F_FILENAME_SIZE]; char * pszExtOld; char * pszExtNew; char * pszDataExtOld; char * pszDataExtNew; // Cannot handle empty database name. flmAssert( pszDbName && *pszDbName); flmAssert( pszNewDbName && *pszNewDbName); // Allocate memory for a read buffer, the log header, and various // file names. if( RC_BAD( rc = f_allocAlignedBuffer( 2048 + LOG_HEADER_SIZE + F_PATH_MAX_SIZE * 5, &pucBuffer))) { goto Exit; } pucLogHdr = pucBuffer + 2048; pszOldName = (char *)(pucLogHdr + LOG_HEADER_SIZE); pszNewName = pszOldName + F_PATH_MAX_SIZE; pszOldDataName = pszNewName + F_PATH_MAX_SIZE; pszNewDataName = pszOldDataName + F_PATH_MAX_SIZE; pszFullNewName = pszNewDataName + F_PATH_MAX_SIZE; // There must be either no directory specified for the new name, or // it must be identical to the old directory. if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathReduce( pszDbName, pszOldName, szOldBase))) { goto Exit; } if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathReduce( pszNewDbName, pszNewName, szNewBase))) { goto Exit; } // Directories must be the same. if (*pszNewName && f_stricmp( pszOldName, pszNewName) != 0) { rc = RC_SET( FERR_INVALID_PARM); goto Exit; } f_strcpy( pszNewName, pszOldName); if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( pszNewName, szNewBase))) { goto Exit; } f_strcpy( pszFullNewName, pszNewName); f_strcpy( pszOldName, pszDbName); if( pszDataDir && *pszDataDir) { f_strcpy( pszOldDataName, pszDataDir); f_strcpy( pszNewDataName, pszDataDir); if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( pszOldDataName, szOldBase))) { goto Exit; } if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( pszNewDataName, szNewBase))) { goto Exit; } } else { f_strcpy( pszNewDataName, pszNewName); f_strcpy( pszOldDataName, pszOldName); } // First make sure we have closed the databases and gotten rid of // them from our internal memory tables - in case they had been open. if( RC_BAD( rc = FlmConfig( FLM_CLOSE_FILE, (void *)pszDbName, (void *)pszDataDir))) { goto Exit; } if( RC_BAD( rc = FlmConfig( FLM_CLOSE_FILE, (void *)pszFullNewName, (void *)pszDataDir))) { goto Exit; } gv_FlmSysData.pFileHdlCache->closeUnusedFiles(); // Open the file so we can get the log header. if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszDbName, gv_FlmSysData.uiFileOpenFlags, &pFileHdl))) { goto Exit; } // Read the header to get the low and high RFL log // file numbers. if (RC_BAD( flmReadAndVerifyHdrInfo( NULL, pFileHdl, pucBuffer, &FileHdr, &LogHdr, pucLogHdr))) { goto Exit; } // Close the file. pFileHdl->Release(); pFileHdl = NULL; // Start renaming files, beginning with the main DB file. if( RC_BAD( rc = flmRenameFile( pszDbName, pszFullNewName, bOverwriteDestOk, FALSE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } // Find where the extension of the old and new database names are pszExtOld = pszOldName + f_strlen( pszOldName) - 1; pszDataExtOld = pszOldDataName + f_strlen( pszOldDataName) - 1; while (pszExtOld != pszOldName && *pszExtOld != '.') { pszExtOld--; // Both the old db name and old data name have the same // base name, so we can decrement pszDataExtOld // at the same time we decrement pszExtOld. pszDataExtOld--; } if (*pszExtOld != '.') { pszExtOld = pszOldName + f_strlen( pszOldName); pszDataExtOld = pszOldDataName + f_strlen( pszOldDataName); } pszExtNew = pszNewName + f_strlen( pszNewName) - 1; pszDataExtNew = pszNewDataName + f_strlen( pszNewDataName) - 1; while (pszExtNew != pszOldName && *pszExtNew != '.') { pszExtNew--; // Both the new db name and new data name have the same // base name, so we can decrement pszDataExtNew // at the same time we decrement pszExtNew. pszDataExtNew--; } if (*pszExtNew != '.') { pszExtNew = pszNewName + f_strlen( pszNewName); pszDataExtNew = pszNewDataName + f_strlen( pszNewDataName); } // Rename the .lck file, if any. This is necessary for UNIX. f_strcpy( pszExtOld, ".lck"); f_strcpy( pszExtNew, ".lck"); if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } // Rename block (data) files. uiFileNumber = 1; for (;;) { F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszDataExtOld); F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszDataExtNew); if (RC_BAD( rc = flmRenameFile( pszOldDataName, pszNewDataName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } if (!bFileFound) { break; } if (uiFileNumber == MAX_DATA_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum)) { break; } uiFileNumber++; } // Rename rollback log files. uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER (FileHdr.uiVersionNum); for (;;) { F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszExtOld); F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum, uiFileNumber, pszExtNew); if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } if (!bFileFound) { break; } if (uiFileNumber == MAX_LOG_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum)) { break; } uiFileNumber++; } // Rename roll-forward log files. if (FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { // For pre-4.3 versions, only need to rename one RFL file. if (RC_BAD( rc = rflGetFileName( FileHdr.uiVersionNum, pszDbName, pszRflDir, 1, pszOldName))) { goto Exit; } if (RC_BAD( rc = rflGetFileName( FileHdr.uiVersionNum, pszFullNewName, pszRflDir, 1, pszNewName))) { goto Exit; } if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } } else { // For 4.3 and greater, rename the RFL directory. if (RC_BAD( rc = rflGetDirAndPrefix( FileHdr.uiVersionNum, pszDbName, pszRflDir, pszOldName, szOldBase))) { goto Exit; } if (RC_BAD( rc = rflGetDirAndPrefix( FileHdr.uiVersionNum, pszFullNewName, pszRflDir, pszNewName, szNewBase))) { goto Exit; } if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName, bOverwriteDestOk, TRUE, &pRenameList, &bFileFound, fnStatusCallback, UserData))) { goto Exit; } } Exit: if( pFileHdl) { pFileHdl->Release(); } if( pucBuffer) { f_freeAlignedBuffer( &pucBuffer); } // Free the list of renamed files. while( pRenameList) { DBRenameInfo * pRenameFile; pRenameFile = pRenameList; pRenameList = pRenameList->pNext; // If we had an error of some sort, attempt to un-rename // the file that had been renamed. if (RC_BAD( rc)) { gv_FlmSysData.pFileSystem->renameFile( pRenameFile->Info.szDstFileName, pRenameFile->Info.szSrcFileName); } f_free( &pRenameFile); } return( rc); }
/**************************************************************************** Desc: Copies the data stored in the INI_LINE structs to the ini file ****************************************************************************/ RCODE FTKAPI F_IniFile::write( void) { RCODE rc = NE_FLM_OK; FLMUINT uiBytesWritten; INI_LINE * pCurLine = NULL; FLMUINT uiFileOffset = 0; IF_FileSystem * pFileSystem = f_getFileSysPtr(); f_assert( m_bReady); if (!m_bModified) { // Nothing needs to be written goto Exit; } // Open the file f_assert( !m_pFileHdl); if (RC_BAD( rc = pFileSystem->createFile( m_pszFileName, FLM_IO_RDWR, &m_pFileHdl))) { goto Exit; } pCurLine = m_pFirstLine; while (pCurLine) { if (pCurLine->pszParamName) { // Output the param name if (RC_BAD (rc = m_pFileHdl->write( uiFileOffset, f_strlen( pCurLine->pszParamName), pCurLine->pszParamName, &uiBytesWritten))) { goto Exit; } uiFileOffset += uiBytesWritten; if (pCurLine->pszParamValue) { // Output the "=" and the value if (RC_BAD (rc = m_pFileHdl->write( uiFileOffset, 1, (void *)"=", &uiBytesWritten))) { goto Exit; } uiFileOffset += uiBytesWritten; if (RC_BAD (rc = m_pFileHdl->write( uiFileOffset, f_strlen( pCurLine->pszParamValue), pCurLine->pszParamValue, &uiBytesWritten))) { goto Exit; } uiFileOffset += uiBytesWritten; } } if (pCurLine->pszComment) { // Output the comment if (pCurLine->pszParamName) { if (RC_BAD (rc = m_pFileHdl->write( uiFileOffset, 2, (void *)" #", &uiBytesWritten))) { goto Exit; } } else { if (RC_BAD (rc = m_pFileHdl->write( uiFileOffset, 1, (void *)"#", &uiBytesWritten))) { goto Exit; } } uiFileOffset += uiBytesWritten; if (RC_BAD (rc = m_pFileHdl->write( uiFileOffset, f_strlen( pCurLine->pszComment), pCurLine->pszComment, &uiBytesWritten))) { goto Exit; } uiFileOffset += uiBytesWritten; } // Write out a newline... if (RC_BAD (rc = m_pFileHdl->write( uiFileOffset, f_strlen( "\n"), (void *)"\n", &uiBytesWritten))) { goto Exit; } uiFileOffset += uiBytesWritten; pCurLine = pCurLine->pNext; } m_bModified = FALSE; Exit: if (m_pFileHdl) { m_pFileHdl->closeFile(); m_pFileHdl->Release(); m_pFileHdl = NULL; } return( rc); }
/**************************************************************************** Desc: Read the ini file and parse its contents ****************************************************************************/ RCODE FTKAPI F_IniFile::read( const char * pszFileName) { RCODE rc = NE_FLM_OK; FLMBOOL bMore = FALSE; FLMBOOL bEOF = FALSE; #define INITIAL_READ_BUF_SIZE 100 FLMUINT uiReadBufSize = 0; FLMUINT uiBytesAvail = 0; FLMUINT uiBytesInLine = 0; char * pszReadBuf = NULL; FLMUINT uiLineNum = 0; IF_FileSystem * pFileSystem = f_getFileSysPtr(); f_assert( m_bReady); f_assert( !m_pFileHdl); // Open the file if (RC_BAD( rc = f_alloc( f_strlen( pszFileName) + 1, &m_pszFileName))) { goto Exit; } f_strcpy( m_pszFileName, pszFileName); // It's not an error if the file doesn't exist. If it does exist, // we'll read in its data. if( RC_BAD( pFileSystem->openFile( pszFileName, FLM_IO_RDONLY, &m_pFileHdl))) { goto Exit; } m_uiFileOffset = 0; // Read in and parse the file uiReadBufSize = INITIAL_READ_BUF_SIZE; if (RC_BAD( rc = f_alloc( uiReadBufSize, &pszReadBuf))) { goto Exit; } // Read in and parse each line in the file... while (!bEOF) { uiLineNum++; uiBytesAvail = uiReadBufSize; if( RC_BAD( rc = readLine( pszReadBuf, &uiBytesAvail, &bMore)) && rc != NE_FLM_IO_END_OF_FILE) { goto Exit; } if (rc == NE_FLM_IO_END_OF_FILE) { bEOF = TRUE; } // While there are more bytes in the line, re-alloc the buffer, and do // another read. uiBytesInLine = uiBytesAvail; while( bMore) { uiBytesAvail = uiReadBufSize; uiReadBufSize *= 2; if (RC_BAD( rc = f_realloc( uiReadBufSize, &pszReadBuf))) { goto Exit; } if (RC_BAD( rc = readLine( pszReadBuf+uiBytesAvail, &uiBytesAvail, &bMore)) && (rc != NE_FLM_IO_END_OF_FILE) ) { goto Exit; } if( rc == NE_FLM_IO_END_OF_FILE) { bEOF = TRUE; } uiBytesInLine += uiBytesAvail; } if ( (RC_OK( rc) || (rc == NE_FLM_IO_END_OF_FILE)) && (uiBytesInLine > 0) ) { // NumBytes will be 0 if the line was blank. No need // to call parseBuffer in this case if (RC_BAD( rc = parseBuffer( pszReadBuf, uiBytesInLine))) { if (rc == NE_FLM_SYNTAX) { rc = NE_FLM_OK; } else { goto Exit; } } } } Exit: // Close the file if( m_pFileHdl) { m_pFileHdl->closeFile(); m_pFileHdl->Release(); m_pFileHdl = NULL; } // Free the buffer if (pszReadBuf) { f_free( &pszReadBuf); } if (rc == NE_FLM_IO_END_OF_FILE) { rc = NE_FLM_OK; } return rc; }
/**************************************************************************** Desc: Returns the requested file handle ****************************************************************************/ RCODE F_MultiFileHdl::getFileHdl( FLMUINT uiFileNum, FLMBOOL bGetForWrite, IF_FileHdl ** ppFileHdl) { RCODE rc = NE_FLM_OK; IF_FileSystem * pFileSystem = f_getFileSysPtr(); FLMUINT uiSlot; IF_FileHdl * pTmpHdl; char szPath[ F_PATH_MAX_SIZE]; f_assert( m_bOpen); *ppFileHdl = NULL; uiSlot = uiFileNum % F_MULTI_FHDL_LIST_SIZE; pTmpHdl = m_pFileHdlList[ uiSlot].pFileHdl; if( pTmpHdl && m_pFileHdlList[ uiSlot].uiFileNum != uiFileNum) { if( RC_BAD( rc = pTmpHdl->flush())) { goto Exit; } pTmpHdl->closeFile(); pTmpHdl->Release(); pTmpHdl = NULL; f_memset( &m_pFileHdlList[ uiSlot], 0, sizeof( FH_INFO)); } if( !pTmpHdl) { dataFilePath( uiFileNum, szPath); if( RC_BAD( rc = pFileSystem->openFile( szPath, FLM_IO_RDWR, &pTmpHdl))) { if( rc == NE_FLM_IO_PATH_NOT_FOUND && bGetForWrite) { if( RC_BAD( rc = pFileSystem->createFile( szPath, FLM_IO_RDWR, &pTmpHdl))) { goto Exit; } } else { goto Exit; } } m_pFileHdlList[ uiSlot].pFileHdl = pTmpHdl; m_pFileHdlList[ uiSlot].uiFileNum = uiFileNum; f_assert( !m_pFileHdlList[ uiSlot].bDirty); } *ppFileHdl = m_pFileHdlList[ uiSlot].pFileHdl; if( bGetForWrite) { m_pFileHdlList[ uiSlot].bDirty = TRUE; } Exit: return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE createUnitTest( const char * configPath, const char * buildNum, const char * environment, const char * user, unitTestData * uTD) { RCODE rc = FERR_OK; IF_FileHdl * pConfigFileHdl = NULL; IF_FileHdl * pCSVFileHdl = NULL; FLMBYTE buffer[ MAX_BUFFER_SIZE] = ""; FLMUINT uiSize = MAX_BUFFER_SIZE; FLMUINT64 ui64Tmp; char * strPos1 = NULL; char * strPos2 = NULL; IF_FileSystem * pFileSystem = NULL; if( !configPath || !buildNum || !environment || !uTD || !user) { flmAssert(0); } if( f_strlen(user) > MAX_SMALL_BUFFER_SIZE) { rc = RC_SET( FERR_CONV_DEST_OVERFLOW); goto Exit; } else { f_strcpy( uTD->userName, user); } if( f_strlen(environment) > MAX_SMALL_BUFFER_SIZE) { rc = RC_SET( FERR_CONV_DEST_OVERFLOW); goto Exit; } else { f_strcpy( uTD->environment, environment); } if( f_strlen( buildNum) > MAX_SMALL_BUFFER_SIZE) { rc = RC_SET( FERR_CONV_DEST_OVERFLOW); goto Exit; } else { f_strcpy( uTD->buildNumber, buildNum); } if( RC_BAD( rc = FlmGetFileSystem( &pFileSystem))) { goto Exit; } if( configPath[ 0]) { if( RC_BAD( rc = pFileSystem->openFile( configPath, FLM_IO_RDONLY | FLM_IO_SH_DENYNONE, &pConfigFileHdl))) { goto Exit; } if( RC_BAD( rc = pConfigFileHdl->size( &ui64Tmp))) { goto Exit; } uiSize = (FLMUINT)ui64Tmp; if( RC_BAD( rc = pConfigFileHdl->read( 0, uiSize, buffer, &uiSize))) { goto Exit; } #ifdef FLM_WIN { char szTemp[ MAX_BUFFER_SIZE]; char * pszTemp = szTemp; FLMUINT uiNewSize = uiSize; for( unsigned int i = 0; i < uiSize; i++) { if( ((i + 1) < uiSize) && (buffer[i] == 0x0D && buffer[ i + 1] == 0x0A)) { *pszTemp++ = 0x0A; i++; uiNewSize--; } else { *pszTemp++ = buffer[ i]; } } f_memcpy( buffer, szTemp, uiNewSize); uiSize = uiNewSize; } #endif // Get the FOLDER strPos1 = f_strchr( (const char *)buffer, ':'); strPos2 = f_strchr( (const char *)strPos1, '\n'); if( !strPos1 || !strPos2) { rc = RC_SET( FERR_FAILURE); goto Exit; } for( strPos1++; *strPos1 == ' ' || *strPos1 == '\t'; strPos1++); if( strPos2-strPos1 > MAX_SMALL_BUFFER_SIZE) { rc = RC_SET( FERR_CONV_DEST_OVERFLOW); goto Exit; } f_strncpy( uTD->folder, strPos1, strPos2-strPos1); uTD->folder[ strPos2 - strPos1] = '\0'; // Get the ATTRIBUTES strPos1 = f_strchr( (const char *)strPos1, ':'); strPos2 = f_strchr( (const char *)strPos1, '\n'); if( !strPos1 || !strPos2) { rc = RC_SET( FERR_FAILURE); goto Exit; } for( strPos1++;*strPos1 == ' ' || *strPos1 == '\t';strPos1++); if( strPos2-strPos1 > MAX_SMALL_BUFFER_SIZE) { rc = RC_SET( FERR_FAILURE); goto Exit; } f_strncpy( uTD->attrs, strPos1, strPos2-strPos1); uTD->attrs[strPos2-strPos1] = '\0'; // Get the CSVFILE strPos1 = f_strchr( (const char *)strPos1, ':'); strPos2 = f_strchr( (const char *)strPos1, '\n'); // Allow for possible \r if( *( --strPos2) != '\r') { strPos2++; } if( !strPos1 || !strPos2) { rc = RC_SET( FERR_FAILURE); goto Exit; } for( strPos1++;*strPos1 == ' ' || *strPos1 == '\t';strPos1++); if( strPos2-strPos1 > MAX_SMALL_BUFFER_SIZE) { rc = RC_SET( FERR_FAILURE); goto Exit; } f_strncpy( uTD->csvFilename, strPos1, strPos2-strPos1); uTD->csvFilename[ strPos2 - strPos1] = '\0'; if( RC_BAD( rc = pFileSystem->openFile( uTD->csvFilename, FLM_IO_RDWR | FLM_IO_SH_DENYNONE, &pCSVFileHdl))) { if ( rc == FERR_IO_PATH_NOT_FOUND) { // Create the file and write the header if( RC_BAD( rc = f_filecat( uTD->csvFilename, DATA_ORDER))) { goto Exit; } } } else { goto Exit; } } Exit: if( pConfigFileHdl) { pConfigFileHdl->Release(); } if( pCSVFileHdl) { pCSVFileHdl->Release(); } if( pFileSystem) { pFileSystem->Release(); } return( rc); }
/**************************************************************************** Desc: Copy a file that is one of the files of the database. *****************************************************************************/ FSTATIC RCODE flmCopyFile( IF_FileSystem * pFileSystem, FLMUINT uiStartOffset, FLMUINT uiEndOffset, DB_COPY_INFO * pDbCopyInfo, COPIED_NAME ** ppCopiedListRV, FLMBYTE * pucInMemLogHdr, FLMBOOL bOkToTruncate, STATUS_HOOK fnStatusCallback, void * UserData) { RCODE rc = FERR_OK; FLMBYTE * pucBuffer = NULL; IF_FileHdl * pSrcFileHdl = NULL; IF_FileHdl * pDestFileHdl = NULL; FLMUINT uiBufferSize = 32768; FLMUINT uiBytesToRead; FLMUINT uiBytesRead; FLMUINT uiBytesWritten; FLMUINT uiOffset; FLMBYTE * pucLogHdr = NULL; FLMUINT uiNewChecksum; FLMBOOL bCreatedDestFile = FALSE; // Open the source file. if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pDbCopyInfo->szSrcFileName, gv_FlmSysData.uiFileOpenFlags, &pSrcFileHdl))) { goto Exit; } // First attempt to open the destination file. If it does // not exist, attempt to create it. if (RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pDbCopyInfo->szDestFileName, gv_FlmSysData.uiFileOpenFlags, &pDestFileHdl))) { if (rc != FERR_IO_PATH_NOT_FOUND && rc != FERR_IO_INVALID_PATH) { goto Exit; } if( RC_BAD( rc = gv_FlmSysData.pFileSystem->createFile( pDbCopyInfo->szDestFileName, gv_FlmSysData.uiFileCreateFlags, &pDestFileHdl))) { goto Exit; } bCreatedDestFile = TRUE; } // Allocate a buffer for reading and writing if( RC_BAD( rc = f_allocAlignedBuffer( uiBufferSize, &pucBuffer))) { goto Exit; } // Allocate a buffer for the log header if( RC_BAD( rc = f_allocAlignedBuffer( 2048, &pucLogHdr))) { goto Exit; } // If uiStartOffset is 2048, it is the special case of // the control file, and we are not copying the first 2K. // However, we need to set up the first 2K so that if // someone reads the first 2K, it will return them a // maintenance in progress error. if (uiStartOffset == 2048) { // Read the first 2K of the source file. if (RC_BAD( rc = pSrcFileHdl->read( 0, 2048, pucBuffer, &uiBytesRead))) { if (rc == FERR_IO_END_OF_FILE) { rc = FERR_OK; } else { goto Exit; } } // Zero out whatever part of the 2K we didn't get on the read. if (uiBytesRead < 2048) { f_memset( &pucBuffer[ uiBytesRead], 0, (int)(2048 - uiBytesRead)); } // Attempt to read the log header from the destination file. // It is OK if we can't read it, because if we created the // destination file, these bytes may not be present. if( bCreatedDestFile || RC_BAD( pDestFileHdl->read( 0, 2048, pucLogHdr, &uiBytesRead))) { f_memset( pucLogHdr, 0, sizeof( 2048)); } // Set the transaction ID to zero. MUST ALSO SET THE TRANS ACTIVE FLAG // TO FALSE - OTHERWISE READERS WILL ATTEMPT TO DECREMENT THE // TRANSACTION ID AND WILL END UP WITH 0xFFFFFFFF - very bad! // We must use zero, because it is the only transaction ID that will not // appear on ANY block. UD2FBA( 0, &pucLogHdr[ 16 + LOG_CURR_TRANS_ID]); // Recalculate the log header checksum so that readers will not get a // checksum error. uiNewChecksum = lgHdrCheckSum( &pucLogHdr[ 16], FALSE); UW2FBA( (FLMUINT16)uiNewChecksum, &pucLogHdr[ 16 + LOG_HDR_CHECKSUM]); f_memcpy( &pucBuffer[ 16], &pucLogHdr[ 16], LOG_HEADER_SIZE); // Write this "special" first 2K into the destination file. // The real first 2K from the source file will be copied in // at a later time. if (RC_BAD( rc = pDestFileHdl->write( 0, 2048, pucBuffer, &uiBytesWritten))) { goto Exit; } // Save the log header to the in-memory version of the log // header as well - if pucInMemLogHdr is NULL, it is pointing // to the pFile->ucLastCommittedLogHdr buffer. if (pucInMemLogHdr) { f_memcpy( pucInMemLogHdr, &pucLogHdr[ 16], LOG_HEADER_SIZE); } } // Read from source file until we hit EOF in the file or // we hit the end offset. uiOffset = uiStartOffset; for (;;) { uiBytesToRead = (FLMUINT)((uiEndOffset - uiOffset >= uiBufferSize) ? uiBufferSize : (FLMUINT)(uiEndOffset - uiOffset)); // Read data from source file. if (RC_BAD( rc = pSrcFileHdl->read( uiOffset, uiBytesToRead, pucBuffer, &uiBytesRead))) { if (rc == FERR_IO_END_OF_FILE) { rc = FERR_OK; if (!uiBytesRead) { break; } } else { goto Exit; } } // Write data to destination file. if (RC_BAD( rc = pDestFileHdl->write( uiOffset, uiBytesRead, pucBuffer, &uiBytesWritten))) { goto Exit; } // See if we wrote out the buffer that has the log header // If so, we need to copy it back to the in-memory log // header. if ((pucInMemLogHdr) && (uiOffset <= 16) && (uiOffset + uiBytesWritten >= 16 + LOG_HEADER_SIZE)) { f_memcpy( pucInMemLogHdr, &pucBuffer[ 16 - uiOffset], LOG_HEADER_SIZE); } uiOffset += uiBytesWritten; // Do callback to report progress. if (fnStatusCallback) { pDbCopyInfo->ui64BytesCopied += (FLMUINT64)uiBytesWritten; if (RC_BAD( rc = (*fnStatusCallback)( FLM_DB_COPY_STATUS, (void *)pDbCopyInfo, (void *)0, UserData))) { goto Exit; } pDbCopyInfo->bNewSrcFile = FALSE; } // Quit once we reach the end offset or we read fewer bytes // than we asked for. if (uiOffset >= uiEndOffset || uiBytesRead < uiBytesToRead) { break; } } // If we overwrote the destination file, as opposed to creating // it, truncate it in case it was larger than the number of // bytes we actually copied. if (!bCreatedDestFile && bOkToTruncate) { if (RC_BAD( rc = pDestFileHdl->truncateFile( uiOffset))) { goto Exit; } } // If the copy succeeded, add the destination name to a list // of destination files. This is done so we can clean up // copied files if we fail somewhere in the overall database // copy. if (ppCopiedListRV) { COPIED_NAME * pCopyName; if( RC_BAD( rc = f_alloc( (FLMUINT)sizeof( COPIED_NAME), &pCopyName))) { goto Exit; } f_strcpy( pCopyName->szPath, pDbCopyInfo->szDestFileName); pCopyName->pNext = *ppCopiedListRV; *ppCopiedListRV = pCopyName; } Exit: if( pucBuffer) { f_freeAlignedBuffer( &pucBuffer); } if( pucLogHdr) { f_freeAlignedBuffer( &pucLogHdr); } if( pSrcFileHdl) { pSrcFileHdl->Release(); } if( pDestFileHdl) { pDestFileHdl->flush(); pDestFileHdl->Release(); } // Attempt to delete the destination file if // we didn't successfully copy it. if( RC_BAD( rc)) { (void)pFileSystem->deleteFile( pDbCopyInfo->szDestFileName); } return( rc); }
/**************************************************************************** Desc: Copy a database's files, including roll-forward log files. *****************************************************************************/ FSTATIC RCODE flmCopyDb( FLMUINT uiDbVersion, const char * pszSrcDbName, const char * pszSrcDataDir, const char * pszSrcRflDir, const char * pszDestDbName, const char * pszDestDataDir, const char * pszDestRflDir, STATUS_HOOK fnStatusCallback, void * UserData) { RCODE rc = FERR_OK; DB_COPY_INFO DbCopyInfo; F_SuperFileHdl * pSrcSFileHdl = NULL; F_SuperFileHdl * pDestSFileHdl = NULL; F_SuperFileClient * pSrcSFileClient = NULL; F_SuperFileClient * pDestSFileClient = NULL; FLMUINT uiFileNumber; FLMUINT uiHighFileNumber; FLMUINT uiHighLogFileNumber; FLMUINT64 ui64FileSize; FFILE * pFile = NULL; FLMBOOL bMutexLocked = FALSE; IF_FileHdl * pLockFileHdl = NULL; IF_FileHdl * pTmpFileHdl = NULL; IF_DirHdl * pDirHdl = NULL; FLMBOOL bFileLocked = FALSE; FLMBOOL bWriteLocked = FALSE; IF_LockObject * pWriteLockObj = NULL; IF_LockObject * pFileLockObj = NULL; COPIED_NAME * pCopiedList = NULL; FLMBOOL bUsedFFile = FALSE; FLMBYTE * pucInMemLogHdr = NULL; eLockType currLockType; FLMUINT uiLockThreadId; char * pszActualSrcRflPath = NULL; char * pszSrcPrefix = NULL; char * pszActualDestRflPath = NULL; char * pszDestPrefix = NULL; FLMBOOL bCreatedDestRflDir = FALSE; F_SEM hWaitSem = F_SEM_NULL; f_memset( &DbCopyInfo, 0, sizeof( DbCopyInfo)); // Should not do anything if the source and destination names // are the same. if (f_stricmp( pszSrcDbName, pszDestDbName) == 0) { goto Exit; } // Allocate a semaphore if( RC_BAD( rc = f_semCreate( &hWaitSem))) { goto Exit; } // Allocate memory for paths we don't want to push onto the stack. if (RC_BAD( rc = f_calloc( (F_PATH_MAX_SIZE + F_FILENAME_SIZE) * 2, &pszActualSrcRflPath))) { goto Exit; } pszSrcPrefix = &pszActualSrcRflPath[ F_PATH_MAX_SIZE]; pszActualDestRflPath = &pszSrcPrefix[ F_FILENAME_SIZE]; pszDestPrefix = &pszActualDestRflPath[ F_PATH_MAX_SIZE]; // Set up the super file object for the source database. // Must at least open the control file. if( (pSrcSFileClient = f_new F_SuperFileClient) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pSrcSFileClient->setup( pszSrcDbName, pszSrcDataDir, uiDbVersion))) { goto Exit; } if( (pSrcSFileHdl = f_new F_SuperFileHdl) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pSrcSFileHdl->setup( pSrcSFileClient, gv_FlmSysData.pFileHdlCache, gv_FlmSysData.uiFileOpenFlags, 0))) { goto Exit; } // Lock the destination database, if not already locked. // This is so we can overwrite it without necessarily // deleting it. May unlock and re-lock the global mutex. f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; if (RC_BAD( rc = flmFindFile( pszDestDbName, pszDestDataDir, &pFile))) { goto Exit; } // If we didn't find an FFILE structure, get an // exclusive lock on the file. if (!pFile) { f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; // Attempt to get an exclusive lock on the file. if (RC_BAD( rc = flmCreateLckFile( pszDestDbName, &pLockFileHdl))) { goto Exit; } } else { // The call to flmVerifyFileUse will wait if the file is in // the process of being opened by another thread. if (RC_BAD( rc = flmVerifyFileUse( gv_FlmSysData.hShareMutex, &pFile))) { goto Exit; } // Increment the use count on the FFILE so it will not // disappear while we are copying the file. if (++pFile->uiUseCount == 1) { flmUnlinkFileFromNUList( pFile); } bUsedFFile = TRUE; f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; pucInMemLogHdr = &pFile->ucLastCommittedLogHdr [0]; // Lock the destination file object and transaction // object, if not already locked. pFile->pFileLockObj->getLockInfo( 0, &currLockType, &uiLockThreadId, NULL); if (currLockType != FLM_LOCK_EXCLUSIVE || uiLockThreadId != f_threadId()) { pFileLockObj = pFile->pFileLockObj; pFileLockObj->AddRef(); if (RC_BAD( rc = pFileLockObj->lock( hWaitSem, TRUE, FLM_NO_TIMEOUT, 0))) { goto Exit; } bFileLocked = TRUE; } // Lock the write object, if not already locked pFile->pWriteLockObj->getLockInfo( 0, &currLockType, &uiLockThreadId, NULL); if( currLockType != FLM_LOCK_EXCLUSIVE || uiLockThreadId != f_threadId()) { pWriteLockObj = pFile->pWriteLockObj; pWriteLockObj->AddRef(); // Only contention here is with the checkpoint thread - wait // forever until the checkpoint thread gives it up. if( RC_BAD( rc = pWriteLockObj->lock( hWaitSem, TRUE, FLM_NO_TIMEOUT, 0))) { goto Exit; } bWriteLocked = TRUE; } } // Set up the super file object for the destination database. if( (pDestSFileClient = f_new F_SuperFileClient) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pDestSFileClient->setup( pszDestDbName, pszDestDataDir, uiDbVersion))) { goto Exit; } if( (pDestSFileHdl = f_new F_SuperFileHdl) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = pDestSFileHdl->setup( pDestSFileClient, gv_FlmSysData.pFileHdlCache, gv_FlmSysData.uiFileOpenFlags, gv_FlmSysData.uiFileCreateFlags))) { goto Exit; } // See how many files we have and calculate the total size. uiHighFileNumber = 0; for (;;) { if( RC_BAD( rc = pSrcSFileHdl->getFileSize( uiHighFileNumber, &ui64FileSize)) || !ui64FileSize) { if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH || !ui64FileSize) { // If the control file doesn't exist, we will return // path not found. if (!uiHighFileNumber) { goto Exit; } uiHighFileNumber--; rc = FERR_OK; break; } goto Exit; } DbCopyInfo.ui64BytesToCopy += ui64FileSize; if (uiHighFileNumber == MAX_DATA_BLOCK_FILE_NUMBER( uiDbVersion)) { break; } uiHighFileNumber++; } // See how many rollback log files we have, and calculate // their total size. uiHighLogFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion); for (;;) { if ((RC_BAD( rc = pSrcSFileHdl->getFileSize( uiHighLogFileNumber, &ui64FileSize))) || !ui64FileSize) { if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH || !ui64FileSize) { if (uiHighLogFileNumber == FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion)) { uiHighLogFileNumber = 0; } else { uiHighLogFileNumber--; } rc = FERR_OK; break; } goto Exit; } DbCopyInfo.ui64BytesToCopy += ui64FileSize; if (uiHighLogFileNumber == MAX_LOG_BLOCK_FILE_NUMBER( uiDbVersion)) { break; } uiHighLogFileNumber++; } // Get the sizes of the roll-forward log files if( uiDbVersion < FLM_FILE_FORMAT_VER_4_3) { // For pre-4.3 versions, only need to copy one RFL file. if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszSrcDbName, pszSrcRflDir, 1, pszActualSrcRflPath))) { goto Exit; } if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszActualSrcRflPath, gv_FlmSysData.uiFileOpenFlags, &pTmpFileHdl))) { if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) { rc = FERR_OK; } else { goto Exit; } } else { if (RC_BAD( rc = pTmpFileHdl->size( &ui64FileSize))) { goto Exit; } DbCopyInfo.ui64BytesToCopy += ui64FileSize; pTmpFileHdl->Release(); pTmpFileHdl = NULL; } } else { if( RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszSrcDbName, pszSrcRflDir, pszActualSrcRflPath, pszSrcPrefix))) { goto Exit; } if (RC_BAD( rc = gv_FlmSysData.pFileSystem->openDir( pszActualSrcRflPath, (char *)"*", &pDirHdl))) { goto Exit; } for (;;) { if( RC_BAD( rc = pDirHdl->next())) { if (rc == FERR_IO_NO_MORE_FILES) { rc = FERR_OK; break; } else { goto Exit; } } // If the current file is an RFL file, increment ui64BytesToCopy if( rflGetFileNum( uiDbVersion, pszSrcPrefix, pDirHdl->currentItemName(), &uiFileNumber)) { DbCopyInfo.ui64BytesToCopy += pDirHdl->currentItemSize(); } } pDirHdl->Release(); pDirHdl = NULL; } // Close all file handles in the source and destination pSrcSFileHdl->releaseFiles(); pDestSFileHdl->releaseFiles(); // Copy the database files. for (uiFileNumber = 0; uiFileNumber <= uiHighFileNumber; uiFileNumber++) { // Get the source file path and destination file path. if( RC_BAD( rc = pSrcSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szSrcFileName))) { goto Exit; } if( RC_BAD( rc = pDestSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szDestFileName))) { goto Exit; } // For the control file, don't copy first 2K - it will be set up // to show maintenance in progress. Then the first 2K will be copied // later. if (!uiFileNumber) { DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 2048, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, pucInMemLogHdr, TRUE, fnStatusCallback, UserData))) { goto Exit; } } else { DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } } // Copy the additional rollback log files, if any. for (uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion); uiFileNumber <= uiHighLogFileNumber; uiFileNumber++) { // Get the source file path and destination file path. if (RC_BAD( rc = pSrcSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = pDestSFileHdl->getFilePath( uiFileNumber, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } // Copy the RFL files if( uiDbVersion < FLM_FILE_FORMAT_VER_4_3) { // Get the source file path and the destination file path. if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszSrcDbName, pszSrcRflDir, 1, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszDestDbName, pszDestRflDir, 1, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } else { // Create the destination RFL directory, if needed. The purpose of this // code is two-fold: 1) We want to keep track of the fact that we tried // to create the destination RFL directory so we can try to remove it // if the copy fails; 2) If the destination RFL directory path specifies // a directory with existing files, we want to remove them. if( RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszDestDbName, pszDestRflDir, pszActualDestRflPath, pszDestPrefix))) { goto Exit; } if( RC_OK( gv_FlmSysData.pFileSystem->doesFileExist( pszActualDestRflPath))) { if( gv_FlmSysData.pFileSystem->isDir( pszActualDestRflPath)) { // Remove the existing directory and all files, etc. (void)gv_FlmSysData.pFileSystem->removeDir( pszActualDestRflPath, TRUE); } else { (void)gv_FlmSysData.pFileSystem->deleteFile( pszActualDestRflPath); } } // Try to create the destination RFL directory. This might fail if // another process was accessing the directory for some reason // (i.e., from a command prompt), when we tried to remove it above. // We really don't care if the call to CreateDir is sucessful, because // when we try to create the destination files (below), the FLAIM file // file system code will try to create any necessary directories. (void)gv_FlmSysData.pFileSystem->createDir( pszActualDestRflPath); bCreatedDestRflDir = TRUE; // Copy the RFL files. NOTE: We need to copy all of the RFL files // in the source RFL directory so that they will be available // when performing a database restore operation. if (RC_BAD( rc = gv_FlmSysData.pFileSystem->openDir( pszActualSrcRflPath, (char *)"*", &pDirHdl))) { goto Exit; } for (;;) { if( RC_BAD( rc = pDirHdl->next())) { if (rc == FERR_IO_NO_MORE_FILES) { rc = FERR_OK; break; } else { goto Exit; } } // If the current file is an RFL file, copy it to the destination if( rflGetFileNum( uiDbVersion, pszSrcPrefix, pDirHdl->currentItemName(), &uiFileNumber)) { // Get the source file path and the destination file path. if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszSrcDbName, pszSrcRflDir, uiFileNumber, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszDestDbName, pszDestRflDir, uiFileNumber, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = TRUE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 0xFFFFFFFF, &DbCopyInfo, &pCopiedList, NULL, TRUE, fnStatusCallback, UserData))) { goto Exit; } } } pDirHdl->Release(); pDirHdl = NULL; } // Do one final copy on the control file to copy just the first 2K if (RC_BAD( rc = pSrcSFileHdl->getFilePath( 0, DbCopyInfo.szSrcFileName))) { goto Exit; } if (RC_BAD( rc = pDestSFileHdl->getFilePath( 0, DbCopyInfo.szDestFileName))) { goto Exit; } DbCopyInfo.bNewSrcFile = FALSE; if (RC_BAD( rc = flmCopyFile( gv_FlmSysData.pFileSystem, 0, 2048, &DbCopyInfo, NULL, pucInMemLogHdr, FALSE, fnStatusCallback, UserData))) { goto Exit; } Exit: if (bUsedFFile) { if (!bMutexLocked) { f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; } if (!(--pFile->uiUseCount)) { flmLinkFileToNUList( pFile); } } if (bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; } if (bWriteLocked) { if( RC_BAD( rc = pWriteLockObj->unlock())) { goto Exit; } bWriteLocked = FALSE; } if (bFileLocked) { RCODE rc3; if (RC_BAD( rc3 = pFileLockObj->unlock())) { if (RC_OK( rc)) rc = rc3; } bFileLocked = FALSE; } if (pWriteLockObj) { pWriteLockObj->Release(); pWriteLockObj = NULL; } if (pFileLockObj) { pFileLockObj->Release(); pFileLockObj = NULL; } if (pLockFileHdl) { pLockFileHdl->Release(); pLockFileHdl = NULL; } if( pTmpFileHdl) { pTmpFileHdl->Release(); } if( pDirHdl) { pDirHdl->Release(); } // Free all the names of files that were copied. // If the copy didn't finish, try to delete any files // that were copied. while (pCopiedList) { COPIED_NAME * pNext = pCopiedList->pNext; // If the overall copy failed, delete the copied file. if (RC_BAD( rc)) { (void)gv_FlmSysData.pFileSystem->deleteFile( pCopiedList->szPath); } f_free( &pCopiedList); pCopiedList = pNext; } if( RC_BAD( rc) && bCreatedDestRflDir) { (void)gv_FlmSysData.pFileSystem->removeDir( pszActualDestRflPath); } if( pszActualSrcRflPath) { f_free( &pszActualSrcRflPath); } if( hWaitSem != F_SEM_NULL) { f_semDestroy( &hWaitSem); } if( pSrcSFileHdl) { pSrcSFileHdl->Release(); } if( pSrcSFileClient) { pSrcSFileClient->Release(); } if( pDestSFileHdl) { pDestSFileHdl->Release(); } if( pDestSFileClient) { pDestSFileClient->Release(); } return( rc); }
/******************************************************************** Desc: ? *********************************************************************/ FSTATIC RCODE bldGetCreateOpts( const char * pszFileName, CREATE_OPTS * pCreateOpts) { RCODE rc = FERR_OK; char szBuf[ 80]; FLMBYTE ucLogHdr [LOG_HEADER_SIZE]; HDR_INFO HdrInfo; FLMUINT uiVersion; IF_FileHdl * pCFileHdl = NULL; f_memset( pCreateOpts, 0, sizeof( CREATE_OPTS)); if( gv_bFixHdrInfo) { f_memcpy( pCreateOpts, &gv_DefaultCreateOpts, sizeof( CREATE_OPTS)); goto Exit; } if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszFileName, FLM_IO_RDWR | FLM_IO_SH_DENYNONE | FLM_IO_DIRECT, &pCFileHdl))) { goto Exit; } if( (rc = flmGetHdrInfo( pCFileHdl, &HdrInfo.FileHdr, &HdrInfo.LogHdr, ucLogHdr)) == FERR_NOT_FLAIM) { uiVersion = gv_DefaultCreateOpts.uiVersionNum; f_memcpy( pCreateOpts, &gv_DefaultCreateOpts, sizeof( CREATE_OPTS)); rc = FERR_OK; } else { uiVersion = HdrInfo.FileHdr.uiVersionNum; flmGetCreateOpts( &HdrInfo.FileHdr, ucLogHdr, pCreateOpts); } if (rc != FERR_OK && rc != FERR_INCOMPLETE_LOG && rc != FERR_BLOCK_CHECKSUM) { if (((rc == FERR_UNSUPPORTED_VERSION) || (rc == FERR_NEWER_FLAIM)) && (uiVersion == 999)) { rc = FERR_OK; } else { f_strcpy( szBuf, "Error reading header info from "); f_strcpy( &szBuf[ f_strlen( szBuf)], pszFileName); f_strcpy( &szBuf[ f_strlen( szBuf)], ": "); f_strcpy( &szBuf[ f_strlen( szBuf)], FlmErrorString( rc)); bldShowError( szBuf); if( gv_bLoggingEnabled) { bldLogString( szBuf); } goto Exit; } } else { rc = FERR_OK; } Exit: if( pCFileHdl) { pCFileHdl->Release(); } return( rc); }