/********************************************************************
Desc: Edit a field
*********************************************************************/
FLMBOOL ViewEdit(
	FLMBOOL	bWriteEntireBlock
	)
{
	FLMUINT			uiBytesToWrite;
	FLMUINT			uiBytesWritten;
	FLMUINT			uiNum;
	FLMUINT64		ui64Num;
	FLMUINT32		ui32Num;
	FLMUINT16		ui16Num;
	char				szTempBuf[ 100];
	F_BLK_HDR *		pBlkHdr = NULL;
	RCODE				rc;
	FLMUINT			uiFileOffset;
	FLMUINT			uiFileNumber;
	FLMBOOL			bValEntered;
	FLMUINT			uiBytesRead;
	IF_FileHdl *	pFileHdl;
	FLMUINT32		ui32CRC;
	FLMUINT			uiBlockOffset;
	FLMUINT			uiBlkAddress = 0;
	FLMBYTE			ucSENValue[ 9];
	FLMBYTE *		pucSENBuffer = &ucSENValue[0];
	FLMUINT			uiSENLen = 0;

	if ((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_DISABLED)
	{
		ViewShowError( "Cannot modify this value");
		return( FALSE);
	}
	uiFileOffset = gv_pViewMenuCurrItem->uiModFileOffset;
	uiFileNumber = gv_pViewMenuCurrItem->uiModFileNumber;

	switch (gv_pViewMenuCurrItem->uiModType & 0x0F)
	{
		case MOD_SEN5:
			// The SEN value is at most 5 bytes.
			ui64Num = 0;
			if (!ViewEditNum( &ui64Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 5,
						~((FLMUINT64)0)))
			{
				return( FALSE);
			}

			// Need to know make a SEN out of this first.
			uiSENLen = f_encodeSEN( ui64Num, &pucSENBuffer);
			break;

		case MOD_SEN9:
			// The SEN value is at most 5 bytes.
			ui64Num = 0;
			if (!ViewEditNum( &ui64Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 9,
						~((FLMUINT64)0)))
			{
				return( FALSE);
			}

			// Need to know make a SEN out of this first.
			uiSENLen = f_encodeSEN( ui64Num, &pucSENBuffer);
			break;

		case MOD_FLMUINT64:
			uiBytesToWrite = 8;
			if (!ViewEditNum( &ui64Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 8,
						~((FLMUINT64)0)))
			{
				return( FALSE);
			}

			if (gv_pViewMenuCurrItem->uiModType & MOD_NATIVE)
			{
				f_memcpy( szTempBuf, &ui64Num, 8);
			}
			else
			{
				U642FBA( ui64Num, (FLMBYTE *)szTempBuf);
			}
			break;
		case MOD_FLMUINT32:
			uiBytesToWrite = 4;
			if (!ViewEditNum( &ui32Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 4,
						(FLMUINT64)0xFFFFFFFF))
			{
				return( FALSE);
			}
			if (gv_pViewMenuCurrItem->uiModType & MOD_NATIVE)
			{
				f_memcpy( szTempBuf, &ui32Num, 4);
			}
			else
			{
				UD2FBA( ui32Num, (FLMBYTE *)szTempBuf);
			}
			break;
		case MOD_FLMUINT16:
			uiBytesToWrite = 2;
			if (!ViewEditNum( &ui16Num,
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 2,
						(FLMUINT64)0xFFFF))
			{
				return( FALSE);
			}
			if (gv_pViewMenuCurrItem->uiModType & MOD_NATIVE)
			{
				f_memcpy( szTempBuf, &ui16Num, 2);
			}
			else
			{
				UW2FBA( ui16Num, (FLMBYTE *)szTempBuf);
			}
			break;
		case MOD_FLMBYTE:
			uiBytesToWrite = 1;
			if (!ViewEditNum( &szTempBuf [0],
					((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX), 1,
					(FLMUINT64)0xFF))
			{
				return( FALSE);
			}
			break;
		case MOD_BINARY:
			uiBytesToWrite = gv_pViewMenuCurrItem->uiModBufLen;
			if (HAVE_HORIZ_CUR( gv_pViewMenuCurrItem))
			{
				uiFileOffset += gv_pViewMenuCurrItem->uiHorizCurPos;
				uiBytesToWrite -= gv_pViewMenuCurrItem->uiHorizCurPos;
			}
			if (!ViewEditBinary( NULL, (FLMBYTE *)szTempBuf,
							&uiBytesToWrite, &bValEntered) ||
				 !bValEntered)
			{
				return( FALSE);
			}
			break;
		case MOD_TEXT:
			if (!ViewEditText( "Enter Value: ", 
						szTempBuf, gv_pViewMenuCurrItem->uiModBufLen,
						&bValEntered) ||
				 !bValEntered)
			{
				return( FALSE);
			}
			uiBytesToWrite = gv_pViewMenuCurrItem->uiModBufLen;
			break;
		case MOD_LANGUAGE:
			if( !ViewEditLanguage( &uiNum))
			{
				return( FALSE);
			}
			szTempBuf[0] = (FLMBYTE)uiNum;
			uiBytesToWrite = 1;
			break;
		case MOD_CHILD_BLK:
			if( !ViewEditNum( &uiNum, TRUE, 4, (FLMUINT64)0xFFFFFFFF))
			{
				return( FALSE);
			}
			uiBytesToWrite = 4;
			UD2FBA( (FLMUINT32)uiNum, (FLMBYTE *)szTempBuf);
			break;
		case MOD_BITS:
			if (!ViewEditBits( (FLMBYTE *)&szTempBuf[ 0],
						((gv_pViewMenuCurrItem->uiModType & 0xF0) == MOD_HEX),
						(FLMBYTE)gv_pViewMenuCurrItem->uiModBufLen))
			{
				return( FALSE);
			}
			uiBytesToWrite = 1;
			break;
	}

	// Read in the block if necessary

	if (!bWriteEntireBlock)
	{
		pBlkHdr = (F_BLK_HDR *)(&szTempBuf [0]);
	}
	else
	{
		uiBlockOffset = (FLMUINT)(uiFileOffset %
						(FLMUINT)gv_ViewDbHdr.ui16BlockSize);
		uiBlkAddress = FSBlkAddress( uiFileNumber, 
											uiFileOffset - uiBlockOffset);
		uiFileOffset = uiFileOffset - uiBlockOffset;

		// Don't convert the block if the address is zero - means we
		// are updating the database header.

		if (!ViewBlkRead( uiBlkAddress, &pBlkHdr,
									!uiBlkAddress ? FALSE : TRUE,
									(FLMUINT)gv_ViewDbHdr.ui16BlockSize,
									NULL, NULL, &uiBytesRead, FALSE))
		{
			return( FALSE);
		}

		uiBytesToWrite = uiBytesRead;

		// Convert to native format

		if (!uiBlkAddress)
		{
			if (hdrIsNonNativeFormat( (XFLM_DB_HDR *)pBlkHdr))
			{
				convertDbHdr( (XFLM_DB_HDR *)pBlkHdr);
			}
		}
		else
		{
			if (blkIsNonNativeFormat( pBlkHdr))
			{
				convertBlk( (FLMUINT)gv_ViewDbHdr.ui16BlockSize, pBlkHdr);
			}
		}

		// Put the data in the appropriate place in the block

		if ((gv_pViewMenuCurrItem->uiModType & 0x0F) == MOD_BITS)
		{
			FLMBYTE		ucMask = (FLMBYTE)gv_pViewMenuCurrItem->uiModBufLen;
			FLMBYTE *	pucBuf = (FLMBYTE *)pBlkHdr;

			// Unset the bits, then OR in the new bits

			pucBuf [uiBlockOffset] &= (~(ucMask));
			pucBuf [uiBlockOffset] |= szTempBuf[ 0];
		}
		else if ((gv_pViewMenuCurrItem->uiModType & 0x0F) == MOD_SEN5 ||
					(gv_pViewMenuCurrItem->uiModType & 0x0F) == MOD_SEN9)
		{
			// Need to make sure the size of the original SEN is the same as the
			// new SEN.
			const FLMBYTE *	pucOrigSEN = (FLMBYTE *)pBlkHdr + uiBlockOffset;
			FLMBYTE				ucBuffer[9];
			FLMBYTE *			pucBuffer = &ucBuffer[0];
			FLMUINT64			ui64Value;
			FLMUINT				uiOrigSENLen;

			if (RC_BAD( rc = f_decodeSEN64( &pucOrigSEN,
													 (FLMBYTE *)pBlkHdr +
															gv_ViewDbHdr.ui16BlockSize,
													 &ui64Value)))
			{
				ViewShowRCError( "Decoding original SEN value", rc);
			}
			uiOrigSENLen = f_encodeSEN( ui64Value, &pucBuffer);

			if (uiOrigSENLen != uiSENLen)
			{
				ViewShowRCError( "SEN Length does not match original",
									  NE_XFLM_FAILURE);
			}
			else
			{
				f_memcpy( (FLMBYTE *)pBlkHdr + uiBlockOffset, ucSENValue,
							uiSENLen);
			}
		}
		else
		{
			f_memcpy( (FLMBYTE *)pBlkHdr + uiBlockOffset, szTempBuf,
							uiBytesToWrite);
		}

		// Calculate CRC

		if (!uiBlkAddress)
		{
			ui32CRC = calcDbHdrCRC( (XFLM_DB_HDR *)pBlkHdr);
			((XFLM_DB_HDR *)pBlkHdr)->ui32HdrCRC = ui32CRC;
			uiBytesToWrite = sizeof( XFLM_DB_HDR);
		}
		else
		{
			FLMUINT	uiBlkLen;
			uiBlkLen = gv_ViewDbHdr.ui16BlockSize;

#if 0
			if ((FLMUINT)pBlkHdr->ui16BlkBytesAvail >
					(FLMUINT)gv_ViewDbHdr.ui16BlockSize - blkHdrSize( pBlkHdr))
			{
				uiBlkLen = blkHdrSize( pBlkHdr);
			}
			else
			{
				uiBlkLen = (FLMUINT)(gv_ViewDbHdr.ui16BlockSize - 
											pBlkHdr->ui16BlkBytesAvail);
			}
#endif
			// Calculate and set the block CRC.

			ui32CRC = calcBlkCRC( pBlkHdr, uiBlkLen);
			pBlkHdr->ui32BlkCRC = ui32CRC;
		}
	}
	
	if (RC_BAD( rc = gv_pSFileHdl->getFileHdl( uiFileNumber, TRUE, &pFileHdl)))
	{
		ViewShowRCError( "getting file handle", rc);
	}

	// Write the data out to the file

	else if (RC_BAD( rc = pFileHdl->write( uiFileOffset, uiBytesToWrite,
							pBlkHdr, &uiBytesWritten)))
	{
		ViewShowRCError( "updating file", rc);
	}
	else if (RC_BAD( rc = pFileHdl->flush()))
	{
		ViewShowRCError( "flushing data to file", rc);
	}
	else if (bWriteEntireBlock && !uiBlkAddress)
	{
		f_memcpy( &gv_ViewDbHdr, pBlkHdr, sizeof( XFLM_DB_HDR));
	}

	// Free any memory used to read in the data block

	if (pBlkHdr && pBlkHdr != (F_BLK_HDR *)(&szTempBuf [0]))
	{
		f_free( &pBlkHdr);
	}
	return( TRUE);
}
/****************************************************************************
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;
}
Exemple #3
0
/****************************************************************************
Desc: Writes data to the file
****************************************************************************/
RCODE F_MultiFileHdl::write(
	FLMUINT64	ui64Offset,				// Offset
	FLMUINT		uiLength,				// Number of bytes to write.
	void *		pvBuffer,				// Buffer that contains bytes to be written
	FLMUINT *	puiBytesWritten)		// Number of bytes written.
{
	RCODE				rc = NE_FLM_OK;
	FLMUINT			uiFileNum = getFileNum( ui64Offset);
	FLMUINT			uiFileOffset = getFileOffset( ui64Offset);
	FLMUINT			uiTmp;
	FLMUINT			uiTotalBytesWritten = 0;
	FLMUINT			uiBytesToWrite;
	FLMUINT			uiMaxWriteLen;
	IF_FileHdl *	pFileHdl;

	// Don't allow zero-length writes

	f_assert( uiLength);

	// Write to the data file(s), moving to new files as needed.

	for( ;;)
	{
		if( RC_BAD( rc = getFileHdl( uiFileNum, TRUE, &pFileHdl)))
		{
			goto Exit;
		}

		uiMaxWriteLen = m_uiMaxFileSize - uiFileOffset;
		f_assert( uiMaxWriteLen != 0);
		uiBytesToWrite = uiLength >= uiMaxWriteLen ? uiMaxWriteLen : uiLength;

		uiTmp = 0;
		rc = pFileHdl->write( uiFileOffset, uiBytesToWrite, pvBuffer, &uiTmp);

		uiTotalBytesWritten += uiTmp;
		uiLength -= uiTmp;
		ui64Offset += uiTmp;

		if( RC_BAD( rc))
		{
			goto Exit;
		}

		if( !uiLength)
		{
			break;
		}

		// Set up for next write

		pvBuffer = ((FLMBYTE *)pvBuffer) + uiTmp;
		uiFileNum = getFileNum( ui64Offset);
		uiFileOffset = getFileOffset( ui64Offset);
	}

Exit:

	if( ui64Offset > m_ui64EOF)
	{
		m_ui64EOF = ui64Offset;
	}

	*puiBytesWritten = uiTotalBytesWritten;
	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);
}
Exemple #5
0
/****************************************************************************
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);
}