Files
mars-flaim/flaim/src/f64bitfh.cpp

857 lines
19 KiB
C++

//-------------------------------------------------------------------------
// Desc: Abstraction class for 64 bit files.
// Tabs: 3
//
// Copyright (c) 2001,2003,2005-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: f64bitfh.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
//-------------------------------------------------------------------------
#include "flaimsys.h"
/****************************************************************************
Desc:
****************************************************************************/
F_64BitFileHandle::F_64BitFileHandle(
FLMUINT uiMaxFileSize)
{
m_bOpen = FALSE;
m_ucPath[ 0] = 0;
m_ui64EOF = 0;
m_pLockFileHdl = NULL;
f_memset( m_pFileHdlList, 0, sizeof( FH_INFO) * F_64BIT_FHDL_LIST_SIZE);
m_uiMaxFileSize = uiMaxFileSize;
if( !m_uiMaxFileSize)
{
m_uiMaxFileSize = F_64BIT_FHDL_DEFAULT_MAX_FILE_SIZE;
}
}
/****************************************************************************
Desc:
****************************************************************************/
F_64BitFileHandle::~F_64BitFileHandle()
{
if( m_bOpen)
{
Close();
}
flmAssert( !m_pLockFileHdl);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_64BitFileHandle::ReleaseLockFile(
const char * pszBasePath,
FLMBOOL bDelete)
{
#ifndef FLM_UNIX
F_UNREFERENCED_PARM( bDelete);
F_UNREFERENCED_PARM( pszBasePath);
#endif
if( m_pLockFileHdl)
{
// Release the lock file
(void)m_pLockFileHdl->Close();
m_pLockFileHdl->Release();
m_pLockFileHdl = NULL;
#ifdef FLM_UNIX
if( bDelete)
{
char szTmpPath[ F_PATH_MAX_SIZE];
// Delete the lock file
f_strcpy( szTmpPath, pszBasePath);
f_pathAppend( szTmpPath, "64.LCK");
gv_FlmSysData.pFileSystem->Delete( szTmpPath);
}
#endif
}
}
/****************************************************************************
Desc: Closes all data files associated with the object
****************************************************************************/
void F_64BitFileHandle::Close(
FLMBOOL bDelete)
{
RCODE rc = FERR_OK;
FLMUINT uiLoop;
F_DirHdl * pDir = NULL;
char szTmpPath[ F_PATH_MAX_SIZE];
if( !m_bOpen)
{
return;
}
for( uiLoop = 0; uiLoop < F_64BIT_FHDL_LIST_SIZE; uiLoop++)
{
if( m_pFileHdlList[ uiLoop].pFileHdl)
{
if( m_pFileHdlList[ uiLoop].bDirty)
{
(void)m_pFileHdlList[ uiLoop].pFileHdl->Flush();
}
m_pFileHdlList[ uiLoop].pFileHdl->Close();
m_pFileHdlList[ uiLoop].pFileHdl->Release();
f_memset( &m_pFileHdlList[ uiLoop], 0, sizeof( FH_INFO));
}
}
m_ui64EOF = 0;
m_bOpen = FALSE;
if( bDelete)
{
if( RC_OK( gv_FlmSysData.pFileSystem->OpenDir(
m_ucPath, "*.64", &pDir)))
{
// Remove all data files
for( rc = pDir->Next(); !RC_BAD( rc) ; rc = pDir->Next() )
{
pDir->CurrentItemPath( szTmpPath);
flmAssert( f_strstr( szTmpPath, ".64") != 0);
(void)gv_FlmSysData.pFileSystem->Delete( szTmpPath);
}
pDir->Release();
pDir = NULL;
}
// Release and delete the lock file
(void)ReleaseLockFile( m_ucPath, TRUE);
// Remove the directory
(void)gv_FlmSysData.pFileSystem->RemoveDir( m_ucPath);
}
else
{
(void)ReleaseLockFile( m_ucPath, FALSE);
}
}
/****************************************************************************
Desc: Removes a 64-bit file
****************************************************************************/
RCODE F_64BitFileHandle::Delete(
const char * pszPath)
{
RCODE rc = FERR_OK;
F_DirHdl * pDir = NULL;
char szTmpPath[ F_PATH_MAX_SIZE];
// Can't use this handle to delete something if we already
// have a file open.
if( m_bOpen)
{
// Can't jump to exit, because it calls ReleaseLockFile
return( RC_SET( FERR_FAILURE));
}
if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Exists( pszPath)))
{
goto Exit;
}
if( !gv_FlmSysData.pFileSystem->IsDir( pszPath))
{
// If the path specifies a single file rather than a
// 64-bit directory, just go ahead and delete the file.
rc = gv_FlmSysData.pFileSystem->Delete( pszPath);
goto Exit;
}
if( RC_BAD( rc = CreateLockFile( pszPath)))
{
goto Exit;
}
if( RC_OK( gv_FlmSysData.pFileSystem->OpenDir(
pszPath, "*.64", &pDir)))
{
// Remove all data files
for( rc = pDir->Next(); !RC_BAD( rc) ; rc = pDir->Next())
{
pDir->CurrentItemPath( szTmpPath);
flmAssert( f_strstr( szTmpPath, ".64") != 0);
(void)gv_FlmSysData.pFileSystem->Delete( szTmpPath);
}
pDir->Release();
pDir = NULL;
rc = FERR_OK;
}
// Release and delete the lock file
(void)ReleaseLockFile( pszPath, TRUE);
// Remove the directory
(void)gv_FlmSysData.pFileSystem->RemoveDir( pszPath);
Exit:
(void)ReleaseLockFile( pszPath, FALSE);
return( rc);
}
/****************************************************************************
Desc: Creates a new 64-bit "file"
****************************************************************************/
RCODE F_64BitFileHandle::Create(
const char * pszPath)
{
RCODE rc = FERR_OK;
FLMBOOL bCreatedDir = FALSE;
if( m_bOpen)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
if( RC_BAD( rc = gv_FlmSysData.pFileSystem->CreateDir( pszPath)))
{
goto Exit;
}
f_strcpy( m_ucPath, pszPath);
bCreatedDir = TRUE;
// Create the lock file
if( RC_BAD( rc = CreateLockFile( m_ucPath)))
{
goto Exit;
}
// Initialize the EOF to 0 and set the state to open
m_ui64EOF = 0;
m_bOpen = TRUE;
Exit:
// Release the lock file
if( RC_BAD( rc))
{
(void)ReleaseLockFile( m_ucPath, TRUE);
if( bCreatedDir)
{
(void)gv_FlmSysData.pFileSystem->RemoveDir( m_ucPath);
}
}
return( rc);
}
/****************************************************************************
Desc: Creates a new 64-bit file with a unique, generated name
****************************************************************************/
RCODE F_64BitFileHandle::CreateUnique(
char * pszPath,
const char * pszFileExtension)
{
RCODE rc = FERR_OK;
FLMUINT uiCount;
FLMBOOL bModext = TRUE;
FLMBOOL bCreatedDir = FALSE;
FLMUINT uiBaseTime = 0;
char ucHighByte = 0;
char szDirName[ F_FILENAME_SIZE];
char szTmpPath[ F_PATH_MAX_SIZE];
char szBasePath[ F_PATH_MAX_SIZE];
if( m_bOpen)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
if( !pszPath || pszPath[ 0] == '\0')
{
#if defined( FLM_UNIX)
f_strcpy( szBasePath, "./");
#elif defined( FLM_NLM)
f_strcpy( szBasePath, "SYS:_NETWARE");
#else
szBasePath[ 0] = '\0';
#endif
}
else
{
f_strcpy( szBasePath, pszPath);
}
if ((pszFileExtension) && (f_strlen( pszFileExtension) >= 3))
{
bModext = FALSE;
}
uiCount = 0;
szDirName[ 0] = '\0';
do
{
f_pathCreateUniqueName( &uiBaseTime, szDirName, pszFileExtension,
&ucHighByte, bModext);
f_strcpy( szTmpPath, szBasePath);
f_pathAppend( szTmpPath, szDirName);
rc = gv_FlmSysData.pFileSystem->CreateDir( szTmpPath);
} while ((rc != FERR_OK) && (uiCount++ < 20));
if( RC_BAD( rc))
{
goto Exit;
}
f_strcpy( m_ucPath, szTmpPath);
bCreatedDir = TRUE;
// Create the lock file
if( RC_BAD( rc = CreateLockFile( m_ucPath)))
{
goto Exit;
}
// Initialize the EOF to 0 and set the state to open
m_ui64EOF = 0;
m_bOpen = TRUE;
Exit:
// Release the lock file
if( RC_BAD( rc))
{
ReleaseLockFile( m_ucPath, TRUE);
if( bCreatedDir)
{
(void)gv_FlmSysData.pFileSystem->RemoveDir( m_ucPath);
}
}
return( rc);
}
/****************************************************************************
Desc: Opens an existing 64-bit file
****************************************************************************/
RCODE F_64BitFileHandle::Open(
const char * pszPath)
{
RCODE rc = FERR_OK;
F_DirHdl * pDir = NULL;
FLMUINT uiTmp;
FLMUINT uiHighFileNum = 0;
FLMUINT uiHighOffset = 0;
if( m_bOpen)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
if( RC_BAD( gv_FlmSysData.pFileSystem->Exists( pszPath)) ||
!gv_FlmSysData.pFileSystem->IsDir( pszPath))
{
rc = RC_SET( FERR_IO_PATH_NOT_FOUND);
goto Exit;
}
f_strcpy( m_ucPath, pszPath);
// Create the lock file
if( RC_BAD( rc = CreateLockFile( m_ucPath)))
{
goto Exit;
}
// Need to determine the current EOF
if( RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenDir(
m_ucPath, "*.64", &pDir)))
{
goto Exit;
}
// Find all data files to determine the EOF
for( rc = pDir->Next(); !RC_BAD( rc) ; rc = pDir->Next() )
{
if( RC_OK( GetFileNum( pDir->CurrentItemName(), &uiTmp)))
{
if( uiTmp >= uiHighFileNum)
{
uiHighFileNum = uiTmp;
uiHighOffset = pDir->CurrentItemSize();
}
}
}
rc = FERR_OK;
m_ui64EOF = (((FLMUINT64)uiHighFileNum) * (FLMUINT64)m_uiMaxFileSize) +
(FLMUINT64)uiHighOffset;
m_bOpen = TRUE;
Exit:
if( pDir)
{
pDir->Release();
}
// Release the lock file
if( RC_BAD( rc))
{
ReleaseLockFile( m_ucPath, FALSE);
}
return( rc);
}
/****************************************************************************
Desc: Flushes cached data to the data file(s)
****************************************************************************/
RCODE F_64BitFileHandle::Flush( void)
{
RCODE rc = FERR_OK;
FLMUINT uiLoop;
if( !m_bOpen)
{
rc = RC_SET( FERR_FAILURE);
goto Exit;
}
for( uiLoop = 0; uiLoop < F_64BIT_FHDL_LIST_SIZE; uiLoop++)
{
if( m_pFileHdlList[ uiLoop].bDirty)
{
if( RC_BAD( rc = m_pFileHdlList[ uiLoop].pFileHdl->Flush()))
{
goto Exit;
}
m_pFileHdlList[ uiLoop].bDirty = FALSE;
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Reads data from the file
****************************************************************************/
RCODE F_64BitFileHandle::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 = FERR_OK;
FLMUINT uiFileNum = GetFileNum( ui64Offset);
FLMUINT uiFileOffset = GetFileOffset( ui64Offset);
FLMUINT uiTmp;
FLMUINT uiTotalBytesRead = 0;
FLMUINT uiBytesToRead;
FLMUINT uiMaxReadLen;
F_FileHdl * pFileHdl;
// Handle the case of a 0-byte read
if( !uiLength)
{
if( ui64Offset >= m_ui64EOF)
{
rc = RC_SET( FERR_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( FERR_IO_END_OF_FILE);
goto Exit;
}
uiMaxReadLen = m_uiMaxFileSize - uiFileOffset;
flmAssert( 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 == FERR_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 = FERR_OK;
}
else
{
goto Exit;
}
}
else
{
if( RC_BAD( rc = pFileHdl->Read( uiFileOffset, uiBytesToRead,
pvBuffer, &uiTmp)))
{
if( rc == FERR_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 = FERR_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: Writes data to the file
****************************************************************************/
RCODE F_64BitFileHandle::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 = FERR_OK;
FLMUINT uiFileNum = GetFileNum( ui64Offset);
FLMUINT uiFileOffset = GetFileOffset( ui64Offset);
FLMUINT uiTmp;
FLMUINT uiTotalBytesWritten = 0;
FLMUINT uiBytesToWrite;
FLMUINT uiMaxWriteLen;
F_FileHdl * pFileHdl;
// Don't allow zero-length writes
flmAssert( 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;
flmAssert( 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: Returns the requested file handle
****************************************************************************/
RCODE F_64BitFileHandle::GetFileHdl(
FLMUINT uiFileNum,
FLMBOOL bGetForWrite,
F_FileHdl ** ppFileHdl)
{
RCODE rc = FERR_OK;
FLMUINT uiSlot;
F_FileHdl * pTmpHdl;
char ucPath[ F_PATH_MAX_SIZE];
flmAssert( m_bOpen);
*ppFileHdl = NULL;
uiSlot = uiFileNum % F_64BIT_FHDL_LIST_SIZE;
pTmpHdl = m_pFileHdlList[ uiSlot].pFileHdl;
if( pTmpHdl && m_pFileHdlList[ uiSlot].uiFileNum != uiFileNum)
{
if( RC_BAD( rc = pTmpHdl->Flush()))
{
goto Exit;
}
pTmpHdl->Close();
pTmpHdl->Release();
pTmpHdl = NULL;
f_memset( &m_pFileHdlList[ uiSlot], 0, sizeof( FH_INFO));
}
if( !pTmpHdl)
{
DataFilePath( uiFileNum, ucPath);
if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Open( ucPath, F_IO_RDWR,
&pTmpHdl)))
{
if( rc == FERR_IO_PATH_NOT_FOUND && bGetForWrite)
{
if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Create( ucPath,
F_IO_RDWR | F_IO_EXCL, &pTmpHdl)))
{
goto Exit;
}
}
else
{
goto Exit;
}
}
m_pFileHdlList[ uiSlot].pFileHdl = pTmpHdl;
m_pFileHdlList[ uiSlot].uiFileNum = uiFileNum;
flmAssert( !m_pFileHdlList[ uiSlot].bDirty);
}
*ppFileHdl = m_pFileHdlList[ uiSlot].pFileHdl;
if( bGetForWrite)
{
m_pFileHdlList[ uiSlot].bDirty = TRUE;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Given a data file name, returns the file's number
****************************************************************************/
RCODE F_64BitFileHandle::GetFileNum(
const char * pucFileName,
FLMUINT * puiFileNum)
{
RCODE rc = FERR_OK;
FLMUINT uiCnt = 0;
FLMUINT uiDigit;
FLMUINT uiFileNum = 0;
if( f_strlen( pucFileName) != 11) // XXXXXXXX.64
{
rc = RC_SET( FERR_IO_INVALID_PATH);
goto Exit;
}
if( f_strcmp( &pucFileName[ 8], ".64") != 0)
{
rc = RC_SET( FERR_IO_INVALID_PATH);
goto Exit;
}
while( uiCnt < 8)
{
uiDigit = pucFileName[ uiCnt];
if( uiDigit >= NATIVE_LOWER_A && uiDigit <= NATIVE_LOWER_F)
{
uiDigit = (FLMUINT)(uiDigit - NATIVE_LOWER_A) + 10;
}
else if( uiDigit >= NATIVE_UPPER_A && uiDigit <= NATIVE_UPPER_F)
{
uiDigit = (FLMUINT)(uiDigit - NATIVE_UPPER_A) + 10;
}
else if( uiDigit >= NATIVE_ZERO && uiDigit <= NATIVE_NINE)
{
uiDigit -= NATIVE_ZERO;
}
else
{
// Invalid character found in the file name
rc = RC_SET( FERR_IO_INVALID_PATH);
goto Exit;
}
uiFileNum <<= 4;
uiFileNum += uiDigit;
uiCnt++;
}
*puiFileNum = uiFileNum;
Exit:
return( rc);
}
/****************************************************************************
Desc: This routine obtains exclusive access to a 64-bit file by creating
a .lck file. The object holds the .lck file open as long as the
64-bit file is open.
****************************************************************************/
RCODE F_64BitFileHandle::CreateLockFile(
const char * pszBasePath)
{
RCODE rc = FERR_OK;
char szLockPath [F_PATH_MAX_SIZE];
F_FileHdlImp * pLockFileHdl = NULL;
f_strcpy( szLockPath, pszBasePath);
f_pathAppend( szLockPath, "64.LCK");
// Attempt to create the lock file. If it fails, the lock file
// may have been left because of a crash. Hence, we first try
// to delete the file. If that succeeds, we then attempt to
// create the file again. If it, or the 2nd create fail, we simply
// return an access denied error.
#ifndef FLM_UNIX
if( RC_BAD( gv_FlmSysData.pFileSystem->Create( szLockPath,
F_IO_RDWR | F_IO_EXCL | F_IO_SH_DENYRW | F_IO_DELETE_ON_CLOSE,
(F_FileHdl **)&pLockFileHdl)))
{
if( RC_BAD( gv_FlmSysData.pFileSystem->Delete( szLockPath)))
{
rc = RC_SET( FERR_IO_ACCESS_DENIED);
goto Exit;
}
else if (RC_BAD( gv_FlmSysData.pFileSystem->Create( szLockPath,
F_IO_RDWR | F_IO_EXCL | F_IO_SH_DENYRW | F_IO_DELETE_ON_CLOSE,
(F_FileHdl **)&pLockFileHdl)))
{
rc = RC_SET( FERR_IO_ACCESS_DENIED);
goto Exit;
}
}
#else
if( RC_BAD( gv_FlmSysData.pFileSystem->Create( szLockPath,
F_IO_RDWR | F_IO_EXCL | F_IO_SH_DENYRW,
(F_FileHdl **)&pLockFileHdl)))
{
if( RC_BAD( gv_FlmSysData.pFileSystem->Open( szLockPath,
F_IO_RDWR | F_IO_SH_DENYRW,
(F_FileHdl **)&pLockFileHdl)))
{
rc = RC_SET( FERR_IO_ACCESS_DENIED);
goto Exit;
}
}
if( RC_BAD( pLockFileHdl->Lock()))
{
rc = RC_SET( FERR_IO_ACCESS_DENIED);
goto Exit;
}
#endif
m_pLockFileHdl = pLockFileHdl;
pLockFileHdl = NULL;
Exit:
if (pLockFileHdl)
{
(void)pLockFileHdl->Close();
pLockFileHdl->Release();
pLockFileHdl = NULL;
}
return( rc);
}