git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@658 0109f412-320b-0410-ab79-c3e0c5ffbbe6
924 lines
20 KiB
C++
924 lines
20 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: Contains the methods for the F_FileHdl class on Windows platforms.
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1999-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: fwin.cpp 3115 2006-01-19 13:24:39 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "ftksys.h"
|
|
|
|
#if defined( FLM_WIN)
|
|
|
|
extern FLMATOMIC gv_openFiles;
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
F_FileHdl::F_FileHdl()
|
|
{
|
|
initCommonData();
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
m_bFlushRequired = FALSE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
F_FileHdl::~F_FileHdl()
|
|
{
|
|
close();
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Open or create a file.
|
|
***************************************************************************/
|
|
RCODE F_FileHdl::openOrCreate(
|
|
const char * pszFileName,
|
|
FLMUINT uiIoFlags,
|
|
FLMBOOL bCreateFlag)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
DWORD udAccessMode = 0;
|
|
DWORD udShareMode = 0;
|
|
DWORD udCreateMode = 0;
|
|
DWORD udAttrFlags = 0;
|
|
DWORD udErrCode;
|
|
FLMBOOL bOpenInAsyncMode = FALSE;
|
|
FLMBOOL bDoDirectIO;
|
|
IF_FileSystem * pFileSystem = f_getFileSysPtr();
|
|
|
|
f_assert( !m_bFileOpened);
|
|
f_assert( !m_pszFileName);
|
|
|
|
bDoDirectIO = (uiIoFlags & FLM_IO_DIRECT) ? TRUE : FALSE;
|
|
|
|
// Save the file name
|
|
|
|
if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE, &m_pszFileName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_strcpy( m_pszFileName, pszFileName);
|
|
|
|
// If doing direct IO, need to get the sector size.
|
|
|
|
if( bDoDirectIO)
|
|
{
|
|
if( RC_BAD( rc = pFileSystem->getSectorSize(
|
|
pszFileName, &m_uiBytesPerSector)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_ui64NotOnSectorBoundMask = m_uiBytesPerSector - 1;
|
|
m_ui64GetSectorBoundMask = ~m_ui64NotOnSectorBoundMask;
|
|
}
|
|
|
|
// Only enable asynchronous writes if direct I/O is enabled.
|
|
|
|
if( bDoDirectIO && f_getFileSysPtr()->canDoAsync())
|
|
{
|
|
bOpenInAsyncMode = TRUE;
|
|
}
|
|
|
|
// Set up the file characteristics requested by caller.
|
|
|
|
if( uiIoFlags & FLM_IO_SH_DENYRW)
|
|
{
|
|
udShareMode = 0;
|
|
uiIoFlags &= ~FLM_IO_SH_DENYRW;
|
|
}
|
|
else if( uiIoFlags & FLM_IO_SH_DENYWR)
|
|
{
|
|
udShareMode = FILE_SHARE_READ;
|
|
uiIoFlags &= ~FLM_IO_SH_DENYWR;
|
|
}
|
|
else if (uiIoFlags & FLM_IO_SH_DENYNONE)
|
|
{
|
|
udShareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
uiIoFlags &= ~FLM_IO_SH_DENYNONE;
|
|
}
|
|
else
|
|
{
|
|
udShareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
}
|
|
|
|
// Begin setting the CreateFile flags and fields
|
|
|
|
udAttrFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
|
|
|
|
if( bDoDirectIO)
|
|
{
|
|
// Specifying FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH
|
|
// results in the data being immediately flushed to disk without
|
|
// going through the system cache. The operating system also
|
|
// requests a write-through the hard disk cache to persistent
|
|
// media. However, not all hardware supports this write-through
|
|
// capability.
|
|
|
|
udAttrFlags |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
|
|
}
|
|
|
|
if( bOpenInAsyncMode)
|
|
{
|
|
udAttrFlags |= FILE_FLAG_OVERLAPPED;
|
|
}
|
|
|
|
if( bCreateFlag)
|
|
{
|
|
if( uiIoFlags & FLM_IO_EXCL)
|
|
{
|
|
udCreateMode = CREATE_NEW;
|
|
}
|
|
else
|
|
{
|
|
udCreateMode = CREATE_ALWAYS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
udCreateMode = OPEN_EXISTING;
|
|
}
|
|
|
|
udAccessMode = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
if( (!bCreateFlag) && (uiIoFlags & FLM_IO_RDONLY))
|
|
{
|
|
udAccessMode = GENERIC_READ;
|
|
}
|
|
|
|
Retry_Create:
|
|
|
|
if( (m_hFile = CreateFile( (LPCTSTR)pszFileName, udAccessMode,
|
|
udShareMode, NULL, udCreateMode,
|
|
udAttrFlags, NULL)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
udErrCode = GetLastError();
|
|
if( (udErrCode == ERROR_PATH_NOT_FOUND) && (uiIoFlags & FLM_IO_CREATE_DIR))
|
|
{
|
|
char szTemp[ F_PATH_MAX_SIZE];
|
|
char szDirPath[ F_PATH_MAX_SIZE];
|
|
|
|
uiIoFlags &= ~FLM_IO_CREATE_DIR;
|
|
|
|
// Remove the file name for which we are creating the directory.
|
|
|
|
if( RC_OK( pFileSystem->pathReduce( m_pszFileName,
|
|
szDirPath, szTemp)))
|
|
{
|
|
if( RC_OK( rc = pFileSystem->createDir( szDirPath)))
|
|
{
|
|
goto Retry_Create;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = f_mapPlatformError( udErrCode,
|
|
(RCODE)(bCreateFlag
|
|
? (RCODE)(bDoDirectIO
|
|
? (RCODE)NE_FLM_DIRECT_CREATING_FILE
|
|
: (RCODE)NE_FLM_CREATING_FILE)
|
|
: (RCODE)(bDoDirectIO
|
|
? (RCODE)NE_FLM_DIRECT_OPENING_FILE
|
|
: (RCODE)NE_FLM_OPENING_FILE)));
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiIoFlags & FLM_IO_DELETE_ON_RELEASE)
|
|
{
|
|
m_bDeleteOnRelease = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_bDeleteOnRelease = FALSE;
|
|
}
|
|
|
|
// Allocate at least 64K - this will handle most read and write
|
|
// operations and will also be a multiple of the sector size most of
|
|
// the time. The calculation below rounds it up to the next sector
|
|
// boundary if it is not already on one.
|
|
|
|
m_uiAlignedBuffSize = 64 * 1024;
|
|
if( bDoDirectIO)
|
|
{
|
|
m_uiAlignedBuffSize = roundToNextSector( m_uiAlignedBuffSize);
|
|
}
|
|
|
|
if( RC_BAD( rc = f_allocAlignedBuffer( m_uiAlignedBuffSize,
|
|
&m_pucAlignedBuff)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_bFileOpened = TRUE;
|
|
m_ui64CurrentPos = 0;
|
|
m_bOpenedReadOnly = (uiIoFlags & FLM_IO_RDONLY) ? TRUE : FALSE;
|
|
m_bOpenedExclusive = (uiIoFlags & FLM_IO_SH_DENYRW) ? TRUE : FALSE;
|
|
m_bDoDirectIO = bDoDirectIO;
|
|
m_bOpenedInAsyncMode = bOpenInAsyncMode;
|
|
m_bFlushRequired = FALSE;
|
|
f_atomicInc( &gv_openFiles);
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
close();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Close a file
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_FileHdl::close( void)
|
|
{
|
|
if( m_bFlushRequired)
|
|
{
|
|
flush();
|
|
}
|
|
|
|
if( m_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle( m_hFile);
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if( m_bDeleteOnRelease)
|
|
{
|
|
DeleteFile( (LPTSTR)m_pszFileName);
|
|
m_bDeleteOnRelease = FALSE;
|
|
}
|
|
|
|
if( m_bFileOpened)
|
|
{
|
|
f_atomicDec( &gv_openFiles);
|
|
}
|
|
|
|
freeCommonData();
|
|
|
|
m_bFileOpened = FALSE;
|
|
m_ui64CurrentPos = 0;
|
|
m_bOpenedReadOnly = FALSE;
|
|
m_bOpenedExclusive = FALSE;
|
|
m_bDoDirectIO = FALSE;
|
|
m_bOpenedInAsyncMode = FALSE;
|
|
m_bFlushRequired = FALSE;
|
|
|
|
return( NE_FLM_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_FileHdl::flush( void)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( !m_bDoDirectIO || m_bFlushRequired)
|
|
{
|
|
if( !FlushFileBuffers( m_hFile))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_FLUSHING_FILE);
|
|
}
|
|
|
|
m_bFlushRequired = FALSE;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE F_FileHdl::lowLevelRead(
|
|
FLMUINT64 ui64ReadOffset,
|
|
FLMUINT uiBytesToRead,
|
|
void * pvBuffer,
|
|
IF_IOBuffer * pIOBuffer,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
DWORD uiBytesRead = 0;
|
|
OVERLAPPED * pOverlapped = NULL;
|
|
LARGE_INTEGER liTmp;
|
|
F_FileAsyncClient * pAsyncClient = NULL;
|
|
FLMBOOL bWaitForRead = FALSE;
|
|
|
|
if( pIOBuffer && pvBuffer && pvBuffer != pIOBuffer->getBufferPtr())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64ReadOffset == FLM_IO_CURRENT_POS)
|
|
{
|
|
ui64ReadOffset = m_ui64CurrentPos;
|
|
}
|
|
else
|
|
{
|
|
m_ui64CurrentPos = ui64ReadOffset;
|
|
}
|
|
|
|
if( !pvBuffer)
|
|
{
|
|
pvBuffer = pIOBuffer->getBufferPtr();
|
|
}
|
|
|
|
if( m_bOpenedInAsyncMode)
|
|
{
|
|
if( RC_BAD( rc = allocFileAsyncClient( &pAsyncClient)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAsyncClient->prepareForAsync( pIOBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pIOBuffer)
|
|
{
|
|
f_assert( pvBuffer);
|
|
bWaitForRead = TRUE;
|
|
}
|
|
|
|
pAsyncClient->m_uiBytesToDo = uiBytesToRead;
|
|
pOverlapped = &pAsyncClient->m_Overlapped;
|
|
pOverlapped->Offset = (DWORD)(ui64ReadOffset & 0xFFFFFFFF);
|
|
pOverlapped->OffsetHigh = (DWORD)(ui64ReadOffset >> 32);
|
|
pIOBuffer = NULL;
|
|
|
|
if( !ReadFile( m_hFile, pvBuffer, uiBytesToRead,
|
|
&uiBytesRead, pOverlapped))
|
|
{
|
|
DWORD udErrCode = GetLastError();
|
|
|
|
if( udErrCode != ERROR_IO_PENDING)
|
|
{
|
|
rc = f_mapPlatformError( udErrCode, NE_FLM_READING_FILE);
|
|
pAsyncClient->notifyComplete( rc, uiBytesRead, FALSE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bWaitForRead)
|
|
{
|
|
if( RC_BAD( rc = pAsyncClient->waitToComplete( FALSE)))
|
|
{
|
|
if( rc != NE_FLM_IO_END_OF_FILE)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_FLM_OK;
|
|
}
|
|
|
|
uiBytesRead = pAsyncClient->m_uiBytesDone;
|
|
}
|
|
else
|
|
{
|
|
uiBytesRead = uiBytesToRead;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pIOBuffer)
|
|
{
|
|
pIOBuffer->setPending();
|
|
}
|
|
|
|
liTmp.QuadPart = ui64ReadOffset;
|
|
if( !SetFilePointerEx( m_hFile, liTmp, NULL, FILE_BEGIN))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_POSITIONING_IN_FILE);
|
|
}
|
|
else
|
|
{
|
|
if( !ReadFile( m_hFile, pvBuffer, uiBytesToRead, &uiBytesRead, NULL))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_READING_FILE);
|
|
}
|
|
}
|
|
|
|
if( pIOBuffer)
|
|
{
|
|
pIOBuffer->notifyComplete( rc);
|
|
pIOBuffer = NULL;
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
m_ui64CurrentPos += uiBytesRead;
|
|
|
|
if( uiBytesRead < uiBytesToRead)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
f_assert( uiBytesRead || RC_BAD( rc));
|
|
|
|
if( pAsyncClient)
|
|
{
|
|
pAsyncClient->Release();
|
|
}
|
|
|
|
if( pIOBuffer && !pIOBuffer->isPending())
|
|
{
|
|
f_assert( RC_BAD( rc));
|
|
pIOBuffer->notifyComplete( rc);
|
|
}
|
|
|
|
if( puiBytesRead)
|
|
{
|
|
*puiBytesRead = uiBytesRead;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE F_FileHdl::lowLevelWrite(
|
|
FLMUINT64 ui64WriteOffset,
|
|
FLMUINT uiBytesToWrite,
|
|
const void * pvBuffer,
|
|
IF_IOBuffer * pIOBuffer,
|
|
FLMUINT * puiBytesWritten)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
OVERLAPPED * pOverlapped = NULL;
|
|
LARGE_INTEGER liTmp;
|
|
DWORD uiBytesWritten = 0;
|
|
F_FileAsyncClient * pAsyncClient = NULL;
|
|
FLMBOOL bWaitForWrite = FALSE;
|
|
FLMUINT uiTotalBytesToExtend;
|
|
FLMUINT64 ui64CurrFileSize;
|
|
|
|
if( pIOBuffer && pvBuffer && pvBuffer != pIOBuffer->getBufferPtr())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64WriteOffset == FLM_IO_CURRENT_POS)
|
|
{
|
|
ui64WriteOffset = m_ui64CurrentPos;
|
|
}
|
|
else
|
|
{
|
|
m_ui64CurrentPos = ui64WriteOffset;
|
|
}
|
|
|
|
if( m_bDoDirectIO && !m_numAsyncPending && m_uiExtendSize)
|
|
{
|
|
if( RC_BAD( rc = getPreWriteExtendSize( ui64WriteOffset, uiBytesToWrite,
|
|
&ui64CurrFileSize, &uiTotalBytesToExtend)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiTotalBytesToExtend)
|
|
{
|
|
if( RC_BAD( rc = extendFile( ui64CurrFileSize, uiTotalBytesToExtend)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !pvBuffer)
|
|
{
|
|
pvBuffer = pIOBuffer->getBufferPtr();
|
|
}
|
|
|
|
if( m_bOpenedInAsyncMode)
|
|
{
|
|
if( RC_BAD( rc = allocFileAsyncClient( &pAsyncClient)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAsyncClient->prepareForAsync( pIOBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pIOBuffer)
|
|
{
|
|
bWaitForWrite = TRUE;
|
|
}
|
|
|
|
pAsyncClient->m_uiBytesToDo = uiBytesToWrite;
|
|
pOverlapped = &pAsyncClient->m_Overlapped;
|
|
pOverlapped->Offset = (DWORD)(ui64WriteOffset & 0xFFFFFFFF);
|
|
pOverlapped->OffsetHigh = (DWORD)(ui64WriteOffset >> 32);
|
|
pIOBuffer = NULL;
|
|
|
|
if( !WriteFile( m_hFile, pvBuffer,
|
|
uiBytesToWrite, &uiBytesWritten, pOverlapped))
|
|
{
|
|
DWORD udErrCode = GetLastError();
|
|
|
|
if( udErrCode != ERROR_IO_PENDING)
|
|
{
|
|
rc = f_mapPlatformError( udErrCode, NE_FLM_WRITING_FILE);
|
|
pAsyncClient->notifyComplete( rc, uiBytesWritten, FALSE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bWaitForWrite)
|
|
{
|
|
if( RC_BAD( rc = pAsyncClient->waitToComplete( FALSE)))
|
|
{
|
|
if( rc != NE_FLM_IO_DISK_FULL)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_FLM_OK;
|
|
}
|
|
|
|
uiBytesWritten = pAsyncClient->m_uiBytesDone;
|
|
}
|
|
else
|
|
{
|
|
uiBytesWritten = uiBytesToWrite;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pIOBuffer)
|
|
{
|
|
pIOBuffer->setPending();
|
|
}
|
|
|
|
liTmp.QuadPart = ui64WriteOffset;
|
|
if( !SetFilePointerEx( m_hFile, liTmp, NULL, FILE_BEGIN))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_POSITIONING_IN_FILE);
|
|
}
|
|
else
|
|
{
|
|
if( !WriteFile( m_hFile, pvBuffer, uiBytesToWrite,
|
|
&uiBytesWritten, NULL))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_WRITING_FILE);
|
|
}
|
|
}
|
|
|
|
if( pIOBuffer)
|
|
{
|
|
pIOBuffer->notifyComplete( rc);
|
|
pIOBuffer = NULL;
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
m_ui64CurrentPos += uiBytesWritten;
|
|
|
|
if( uiBytesWritten < uiBytesToWrite)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_FLM_IO_DISK_FULL);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAsyncClient)
|
|
{
|
|
pAsyncClient->Release();
|
|
}
|
|
|
|
if( pIOBuffer && !pIOBuffer->isPending())
|
|
{
|
|
f_assert( RC_BAD( rc));
|
|
pIOBuffer->notifyComplete( rc);
|
|
}
|
|
|
|
if( puiBytesWritten)
|
|
{
|
|
*puiBytesWritten = uiBytesWritten;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Return the size of the file
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_FileHdl::size(
|
|
FLMUINT64 * pui64Size)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LARGE_INTEGER liTmp;
|
|
|
|
if( !GetFileSizeEx( m_hFile, &liTmp))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_GETTING_FILE_SIZE);
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64Size = liTmp.QuadPart;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Truncate the file to the indicated size
|
|
WARNING: Direct IO methods are calling this method. Make sure that all changes
|
|
to this method work in direct IO mode.
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_FileHdl::truncate(
|
|
FLMUINT64 ui64NewSize)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LARGE_INTEGER liTmp;
|
|
FLMUINT64 ui64CurrentSize;
|
|
|
|
f_assert( m_bFileOpened);
|
|
|
|
if( RC_BAD( rc = size( &ui64CurrentSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64NewSize >= ui64CurrentSize)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
liTmp.QuadPart = ui64NewSize;
|
|
if( !SetFilePointerEx( m_hFile, liTmp, NULL, FILE_BEGIN))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_POSITIONING_IN_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !SetEndOfFile( m_hFile))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_TRUNCATING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
m_bFlushRequired = TRUE;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE F_FileHdl::extendFile(
|
|
FLMUINT64 ui64FileSize,
|
|
FLMUINT uiTotalBytesToExtend)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT uiBytesToWrite;
|
|
FLMUINT uiBytesWritten;
|
|
FLMBYTE * pucBuffer = NULL;
|
|
FLMUINT uiBufferSize;
|
|
F_FileAsyncClient * pAsyncClient = NULL;
|
|
|
|
uiBufferSize = 64 * 1024;
|
|
if( RC_BAD( rc = f_allocAlignedBuffer( uiBufferSize, &pucBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_memset( pucBuffer, 0, uiBufferSize);
|
|
|
|
// Extend the file until we run out of bytes to write.
|
|
|
|
while( uiTotalBytesToExtend)
|
|
{
|
|
if( (uiBytesToWrite = uiBufferSize) > uiTotalBytesToExtend)
|
|
{
|
|
uiBytesToWrite = uiTotalBytesToExtend;
|
|
}
|
|
|
|
if( m_bOpenedInAsyncMode)
|
|
{
|
|
OVERLAPPED * pOverlapped;
|
|
|
|
if( RC_BAD( rc = allocFileAsyncClient( &pAsyncClient)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAsyncClient->prepareForAsync( NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pAsyncClient->m_uiBytesToDo = uiBytesToWrite;
|
|
pOverlapped = &pAsyncClient->m_Overlapped;
|
|
pOverlapped->Offset = (DWORD)(ui64FileSize & 0xFFFFFFFF);
|
|
pOverlapped->OffsetHigh = (DWORD)(ui64FileSize >> 32);
|
|
|
|
if( !WriteFile( m_hFile, pucBuffer,
|
|
uiBytesToWrite, &uiBytesWritten, pOverlapped))
|
|
{
|
|
DWORD udErrCode = GetLastError();
|
|
|
|
if( udErrCode != ERROR_IO_PENDING)
|
|
{
|
|
rc = f_mapPlatformError( udErrCode, NE_FLM_WRITING_FILE);
|
|
pAsyncClient->notifyComplete( rc, uiBytesWritten, FALSE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pAsyncClient->waitToComplete( FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiBytesWritten = pAsyncClient->m_uiBytesDone;
|
|
pAsyncClient->Release();
|
|
pAsyncClient = NULL;
|
|
}
|
|
else
|
|
{
|
|
LONG lDummy = 0;
|
|
|
|
if( SetFilePointer( m_hFile, (LONG)ui64FileSize,
|
|
&lDummy, FILE_BEGIN) == 0xFFFFFFFF)
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_POSITIONING_IN_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !WriteFile( m_hFile, (LPVOID)pucBuffer,
|
|
(DWORD)uiBytesToWrite, &uiBytesWritten, NULL))
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_WRITING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// No more room on disk
|
|
|
|
if( uiBytesWritten < uiBytesToWrite)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_DISK_FULL);
|
|
goto Exit;
|
|
}
|
|
|
|
uiTotalBytesToExtend -= uiBytesToWrite;
|
|
ui64FileSize += uiBytesToWrite;
|
|
}
|
|
|
|
m_bFlushRequired = TRUE;
|
|
|
|
Exit:
|
|
|
|
if( pucBuffer)
|
|
{
|
|
f_freeAlignedBuffer( &pucBuffer);
|
|
}
|
|
|
|
if( pAsyncClient)
|
|
{
|
|
pAsyncClient->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_FileHdl::lock( void)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( !LockFile( m_hFile, 0, 0, 1, 1))
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_FILE_LOCK_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_FileHdl::unlock( void)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( !UnlockFile( m_hFile, 0, 0, 1, 1))
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_FILE_LOCK_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
void FLMAPI f_yieldCPU( void)
|
|
{
|
|
Sleep( 0);
|
|
}
|
|
|
|
/**********************************************************************
|
|
Desc:
|
|
**********************************************************************/
|
|
RCODE FLMAPI f_chdir(
|
|
const char * pszDir)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( _chdir( pszDir) != 0)
|
|
{
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_IO_PATH_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/**********************************************************************
|
|
Desc:
|
|
**********************************************************************/
|
|
RCODE FLMAPI f_getcwd(
|
|
char * pszDir)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( _getcwd( pszDir, F_PATH_MAX_SIZE) == NULL)
|
|
{
|
|
*pszDir = 0;
|
|
rc = f_mapPlatformError( GetLastError(), NE_FLM_IO_PATH_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
#endif // FLM_WIN
|
|
|
|
/****************************************************************************
|
|
Desc: Deletes a file
|
|
****************************************************************************/
|
|
#if defined( FLM_WATCOM_NLM) || defined( FLM_OSX)
|
|
int gv_ftkwinDummy(void)
|
|
{
|
|
return( 0);
|
|
}
|
|
#endif
|