/******************************************************************************* 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: 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); }