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