/**************************************************************************** Desc: Read a line from the ini file and store it in pszBuf ****************************************************************************/ RCODE F_IniFile::readLine( char * pszBuf, FLMUINT * puiBytes, FLMBOOL * pbMore) { RCODE rc = NE_FLM_OK; FLMUINT uiBytesRead = 0; FLMUINT uiBytesInLine = 0; FLMUINT uiEOLBytes = 0; FLMBOOL bEOL = FALSE; f_assert( m_pFileHdl); rc = m_pFileHdl->read( m_uiFileOffset, *puiBytes, (FLMBYTE *)pszBuf, &uiBytesRead); if ( RC_OK( rc) || rc == NE_FLM_IO_END_OF_FILE) { // Check to see if we got more than one line... while( !bEOL && (uiBytesInLine < uiBytesRead) ) { if( pszBuf[ uiBytesInLine] == 13 || pszBuf[ uiBytesInLine] == 10) { // NOTE: If we end up reading the first byte of a CR/LF pair, but // but the second byte is read on the next call, then it will get // counted as a new (but empty) line. We're not going to worry // about it though, because empty lines end up getting ignored // and this isn't likely to happen often enough to effect // performance. bEOL = TRUE; *puiBytes = uiBytesInLine; uiEOLBytes=1; // Check for a CR/LF pair (or a LF/CR pair...) if( (uiBytesInLine + 1 < uiBytesRead) && (pszBuf[ uiBytesInLine + 1] == 13 || pszBuf[ uiBytesInLine + 1] == 10)) { uiEOLBytes++; } } else { uiBytesInLine++; } } // Set the file position variable forward appropriately... m_uiFileOffset += uiBytesInLine + uiEOLBytes; } // If we read in more than one line, then don't want to return // NE_FLM_IO_END_OF_FILE... if( rc == NE_FLM_IO_END_OF_FILE && (uiBytesInLine + uiEOLBytes) < uiBytesRead) { rc = NE_FLM_OK; } // Last step - update pbMore *pbMore = (bEOL || (uiBytesRead == 0)) ? FALSE : TRUE; 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: Reads data from the file ****************************************************************************/ RCODE F_MultiFileHdl::read( FLMUINT64 ui64Offset, // Offset to begin reading FLMUINT uiLength, // Number of bytes to read void * pvBuffer, // Buffer FLMUINT * puiBytesRead) // [out] Number of bytes read { RCODE rc = NE_FLM_OK; FLMUINT uiFileNum = getFileNum( ui64Offset); FLMUINT uiFileOffset = getFileOffset( ui64Offset); FLMUINT uiTmp; FLMUINT uiTotalBytesRead = 0; FLMUINT uiBytesToRead; FLMUINT uiMaxReadLen; IF_FileHdl * pFileHdl; // Handle the case of a 0-byte read if( !uiLength) { if( ui64Offset >= m_ui64EOF) { rc = RC_SET( NE_FLM_IO_END_OF_FILE); } goto Exit; } // Read the data file(s), moving to new files as needed. for( ;;) { if( ui64Offset >= m_ui64EOF) { rc = RC_SET( NE_FLM_IO_END_OF_FILE); goto Exit; } uiMaxReadLen = m_uiMaxFileSize - uiFileOffset; f_assert( uiMaxReadLen != 0); uiTmp = (uiLength >= uiMaxReadLen ? uiMaxReadLen : uiLength); uiBytesToRead = (((FLMUINT64)uiTmp > (FLMUINT64)(m_ui64EOF - ui64Offset)) ? (FLMUINT)(m_ui64EOF - ui64Offset) : uiTmp); if( RC_BAD( rc = getFileHdl( uiFileNum, FALSE, &pFileHdl))) { if( rc == NE_FLM_IO_PATH_NOT_FOUND) { // Handle the case of a sparse file by filling the unread // portion of the buffer with zeros. f_memset( pvBuffer, 0, uiBytesToRead); uiTmp = uiBytesToRead; rc = NE_FLM_OK; } else { goto Exit; } } else { if( RC_BAD( rc = pFileHdl->read( uiFileOffset, uiBytesToRead, pvBuffer, &uiTmp))) { if( rc == NE_FLM_IO_END_OF_FILE) { // Handle the case of a sparse file by filling the unread // portion of the buffer with zeros. f_memset( &(((FLMBYTE *)(pvBuffer))[ uiTmp]), 0, (FLMUINT)(uiBytesToRead - uiTmp)); uiTmp = uiBytesToRead; rc = NE_FLM_OK; } else { goto Exit; } } } uiTotalBytesRead += uiTmp; uiLength -= uiTmp; if( !uiLength) { break; } // Set up for next read pvBuffer = ((FLMBYTE *)pvBuffer) + uiTmp; ui64Offset += uiTmp; uiFileNum = getFileNum( ui64Offset); uiFileOffset = getFileOffset( ui64Offset); } Exit: *puiBytesRead = uiTotalBytesRead; 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); }