You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
924 lines
23 KiB
924 lines
23 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* NtfsStream.cpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* This file provides the Flat File IStream definition.
|
|
*
|
|
* Created:
|
|
*
|
|
* 4/26/1999 Mike Hillberg
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
#include "LargeInt.hpp"
|
|
#include "time.h"
|
|
#include "FileTime.hpp"
|
|
#include "NtfsStream.hpp"
|
|
|
|
IStream *
|
|
CreateStreamOnFile(
|
|
const OLECHAR * pwcsName,
|
|
UINT access // GENERIC_READ and/or GENERIC_WRITE
|
|
)
|
|
{
|
|
HANDLE hFile;
|
|
FileStream * stream;
|
|
UINT disposition;
|
|
DWORD grfMode = STGM_SHARE_EXCLUSIVE;
|
|
DWORD shareMode = 0;
|
|
|
|
switch (access)
|
|
{
|
|
case GENERIC_READ:
|
|
disposition = OPEN_EXISTING;
|
|
shareMode = FILE_SHARE_READ;
|
|
grfMode |= STGM_READ;
|
|
break;
|
|
|
|
case GENERIC_WRITE:
|
|
disposition = CREATE_ALWAYS;
|
|
grfMode |= STGM_WRITE;
|
|
break;
|
|
|
|
// Note that OPEN_ALWAYS does NOT clear existing file attributes (like size)
|
|
case GENERIC_READ|GENERIC_WRITE:
|
|
disposition = OPEN_ALWAYS;
|
|
grfMode |= STGM_READWRITE;
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
if (Globals::IsNt)
|
|
{
|
|
hFile = CreateFileW(pwcsName, access, shareMode, NULL,
|
|
disposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
else // Windows 9x - non-Unicode
|
|
{
|
|
AnsiStrFromUnicode nameStr(pwcsName);
|
|
|
|
if (nameStr.IsValid())
|
|
{
|
|
hFile = CreateFileA(nameStr, access, shareMode, NULL,
|
|
disposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
else
|
|
{
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != NULL))
|
|
{
|
|
stream = new FileStream();
|
|
if (stream != NULL)
|
|
{
|
|
HRESULT hResult;
|
|
|
|
hResult = stream->Init(hFile, grfMode, pwcsName);
|
|
|
|
if (!FAILED(hResult))
|
|
{
|
|
return stream;
|
|
}
|
|
delete stream;
|
|
}
|
|
CloseHandle(hFile);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::AddRef (IUnknown)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
ULONG
|
|
FileStream::AddRef()
|
|
{
|
|
LONG cRefs;
|
|
|
|
cRefs = InterlockedIncrement( &_cRefs );
|
|
return cRefs;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Release (IUnknown)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
ULONG
|
|
FileStream::Release()
|
|
{
|
|
ULONG ulRet = InterlockedDecrement( &_cRefs );
|
|
|
|
if( 0 == ulRet )
|
|
delete this;
|
|
|
|
return( ulRet );
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::AddRef (IUnknown)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::QueryInterface(
|
|
REFIID riid,
|
|
void** ppv )
|
|
{
|
|
HRESULT sc=S_OK;
|
|
|
|
if( IsEqualIID( riid, IID_IUnknown )
|
|
||
|
|
IsEqualIID( riid, IID_IStream )
|
|
||
|
|
IsEqualIID( riid, IID_ISequentialStream ) )
|
|
{
|
|
*ppv = static_cast<IStream*>(this);
|
|
AddRef();
|
|
return( S_OK );
|
|
}
|
|
else
|
|
{
|
|
return( E_NOINTERFACE );
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Seek (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Seek(
|
|
LARGE_INTEGER dlibMove,
|
|
DWORD dwOrigin,
|
|
ULARGE_INTEGER *puliNewPos)
|
|
{
|
|
HRESULT sc = S_OK;
|
|
LARGE_INTEGER liFileSize;
|
|
LARGE_INTEGER liNewPos;
|
|
|
|
Lock( INFINITE );
|
|
|
|
switch( dwOrigin )
|
|
{
|
|
case STREAM_SEEK_SET:
|
|
liNewPos.QuadPart = dlibMove.QuadPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_CUR:
|
|
liNewPos.QuadPart = _liCurrentSeekPosition.QuadPart + dlibMove.QuadPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_END:
|
|
liFileSize.LowPart = GetFileSize( _hFile,
|
|
(ULONG*)(&liFileSize.HighPart) );
|
|
|
|
if( 0xFFFFFFFF == liFileSize.LowPart && NO_ERROR != GetLastError() )
|
|
{
|
|
nffChk( HRESULT_FROM_WIN32( GetLastError() ) );
|
|
}
|
|
|
|
liNewPos.QuadPart = liFileSize.QuadPart + dlibMove.QuadPart;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Compatibility with Docfile. Seeking < 0 fails.
|
|
if( liNewPos.QuadPart < 0 )
|
|
nffErr( EH_Err, STG_E_INVALIDFUNCTION );
|
|
|
|
_liCurrentSeekPosition = liNewPos;
|
|
|
|
|
|
// If desired, give the caller the now-current seek position.
|
|
if( NULL != puliNewPos )
|
|
*puliNewPos = _liCurrentSeekPosition;
|
|
|
|
EH_Err:
|
|
Unlock();
|
|
return( sc );
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::SetSize (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::SetSize(
|
|
ULARGE_INTEGER uliNewSize)
|
|
{
|
|
HRESULT sc = S_OK;
|
|
CLargeInteger liEOF;
|
|
|
|
if ( uliNewSize.HighPart != 0 )
|
|
nffErr(EH_Err, STG_E_INVALIDFUNCTION);
|
|
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
// If this stream is mapped, set the size accordingly
|
|
|
|
sc = SetFileSize( CULargeInteger(uliNewSize) );
|
|
|
|
if( !FAILED(sc) )
|
|
sc = S_OK;
|
|
|
|
EH_Err:
|
|
|
|
Unlock();
|
|
return( sc);
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::CopyTo (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::CopyTo(
|
|
IStream *pstm,
|
|
ULARGE_INTEGER cb,
|
|
ULARGE_INTEGER *pcbRead,
|
|
ULARGE_INTEGER *pcbWritten)
|
|
{
|
|
|
|
HRESULT sc = S_OK;
|
|
PVOID pv = NULL;
|
|
ULONG cbRead = 0, cbWritten = 0;
|
|
CULargeInteger cbReadTotal = 0, cbWrittenTotal = 0;
|
|
CLargeInteger liZero = 0;
|
|
CULargeInteger uliOriginalSourcePosition, uliOriginalDestPosition;
|
|
CULargeInteger cbSourceSize, cbDestSize;
|
|
ULONG cbPerCopy = 0;
|
|
STATSTG statstg;
|
|
CULargeInteger cbRequested = cb;
|
|
BOOL fCopyForward;
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
if( NULL == pstm)
|
|
nffErr( EH_Err, STG_E_INVALIDPARAMETER );
|
|
|
|
// Determine how much we'll copy at a time.
|
|
// As of this writing, STREAMBUFFERSIZE is 8192 bytes
|
|
|
|
if( cbRequested > STREAMBUFFERSIZE )
|
|
cbPerCopy = STREAMBUFFERSIZE;
|
|
else
|
|
cbPerCopy = cbRequested.LowPart;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Get the current stream sizes/positions, and adjust the destination
|
|
// size if necessary
|
|
// ------------------------------------------------------------------
|
|
|
|
nffChk( this->Seek( liZero, STREAM_SEEK_CUR, &uliOriginalSourcePosition ) );
|
|
|
|
nffChk( pstm->Seek( liZero, STREAM_SEEK_CUR, &uliOriginalDestPosition ) );
|
|
|
|
nffChk( this->Stat( &statstg, STATFLAG_NONAME ) );
|
|
|
|
cbSourceSize = statstg.cbSize;
|
|
|
|
nffChk( pstm->Stat( &statstg, STATFLAG_NONAME ) );
|
|
|
|
cbDestSize = statstg.cbSize;
|
|
|
|
// Ensure the sizes are valid (we can't handle anything with the high bit
|
|
// set, because Seek takes a signed offset).
|
|
|
|
if( static_cast<CLargeInteger>(cbSourceSize) < 0
|
|
||
|
|
static_cast<CLargeInteger>(cbDestSize) < 0 )
|
|
{
|
|
nffErr( EH_Err, STG_E_INVALIDHEADER );
|
|
}
|
|
|
|
// Don't copy more than the source stream has available
|
|
if( cbRequested > cbSourceSize - uliOriginalSourcePosition )
|
|
cbRequested = cbSourceSize - uliOriginalSourcePosition;
|
|
|
|
// If necessary, grow the destination stream.
|
|
|
|
if( cbSourceSize - uliOriginalSourcePosition > cbDestSize - uliOriginalDestPosition )
|
|
{
|
|
cbDestSize = cbSourceSize - uliOriginalSourcePosition + uliOriginalDestPosition;
|
|
nffChk( pstm->SetSize( cbDestSize ) );
|
|
}
|
|
|
|
// ----------------------
|
|
// Allocate a copy buffer
|
|
// ----------------------
|
|
|
|
nffMem( pv = CoTaskMemAlloc( cbPerCopy ) );
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Determine if we're copying forwards (high seek position to low) or backwards.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
fCopyForward = TRUE;
|
|
if( uliOriginalSourcePosition < uliOriginalDestPosition )
|
|
{
|
|
// E.g., say we're copying 15 bytes from offset 0 to offset 5,
|
|
// and we're only able to copy 10 bytes at a time.
|
|
// If we copy bytes 0-9 to offset 5, we'll end up overwriting
|
|
// bytes 10-14, and be unable to complete the copy.
|
|
// So instead, we'll copy bytes 5-14 to offset 10, and finish
|
|
// up by copying bytes 0-4 to offset 5.
|
|
|
|
fCopyForward = FALSE;
|
|
|
|
// To do this kind of backwards copy, we need to start by seeking
|
|
// towards the end of the stream.
|
|
|
|
CULargeInteger uliNewSourcePosition, uliNewDestPosition;
|
|
|
|
uliNewSourcePosition = cbSourceSize - cbPerCopy;
|
|
nffChk( this->Seek( uliNewSourcePosition, STREAM_SEEK_SET, NULL ) );
|
|
|
|
uliNewDestPosition = cbDestSize - cbPerCopy;
|
|
nffChk( pstm->Seek( uliNewDestPosition, STREAM_SEEK_SET, NULL ) );
|
|
|
|
}
|
|
|
|
// --------------
|
|
// Copy in chunks
|
|
// --------------
|
|
|
|
cbPerCopy = cbRequested > cbPerCopy ? cbPerCopy : cbRequested.LowPart;
|
|
while( cbRequested > 0 )
|
|
{
|
|
// Read from the source
|
|
nffChk( this->Read( pv, cbPerCopy, &cbRead ) );
|
|
|
|
if( cbRead != cbPerCopy )
|
|
nffErr(EH_Err, STG_E_READFAULT);
|
|
|
|
cbReadTotal += cbRead;
|
|
|
|
// Write to the dest
|
|
nffChk( pstm->Write( pv, cbPerCopy, &cbWritten ) );
|
|
|
|
if( cbWritten != cbPerCopy )
|
|
nffErr( EH_Err, STG_E_WRITEFAULT );
|
|
|
|
cbWrittenTotal += cbWritten;
|
|
|
|
// Adjust the amount remaining to be copied
|
|
cbRequested -= cbPerCopy;
|
|
|
|
|
|
// Determine how much to copy in the next iteration (this will
|
|
// always be cbPerCopy until the last iteration). If copying
|
|
// backwards, we need to manually adjust the seek pointer.
|
|
|
|
cbPerCopy = (cbRequested > cbPerCopy) ? cbPerCopy : cbRequested.LowPart;
|
|
if( !fCopyForward && (cbRequested > 0))
|
|
{
|
|
nffChk( this->Seek( -static_cast<CLargeInteger>(cbPerCopy+STREAMBUFFERSIZE),
|
|
STREAM_SEEK_CUR, NULL ) );
|
|
|
|
nffChk( pstm->Seek( -static_cast<CLargeInteger>(cbPerCopy+STREAMBUFFERSIZE),
|
|
STREAM_SEEK_CUR, NULL ) );
|
|
}
|
|
|
|
}
|
|
|
|
// If we were backward-copying, adjust the seek pointers
|
|
// as if we had forward-copied
|
|
|
|
if( !fCopyForward )
|
|
{
|
|
uliOriginalSourcePosition += cbReadTotal;
|
|
nffChk( this->Seek( uliOriginalSourcePosition, STREAM_SEEK_SET, NULL ) );
|
|
|
|
uliOriginalDestPosition += cbWrittenTotal;
|
|
nffChk( pstm->Seek( uliOriginalDestPosition, STREAM_SEEK_SET, NULL ) );
|
|
}
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
if( NULL != pcbRead )
|
|
*pcbRead = cbReadTotal;
|
|
if( NULL != pcbWritten )
|
|
*pcbWritten = cbWrittenTotal;
|
|
|
|
EH_Err:
|
|
|
|
if( NULL != pv )
|
|
CoTaskMemFree(pv);
|
|
|
|
Unlock();
|
|
return(sc);
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Commit (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Commit( DWORD grfCommitFlags )
|
|
{
|
|
HRESULT sc = S_OK;
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
// NTRAID#NTBUG9-368729-2001-04-13-gilmanw "ISSUE: FileStream object - handle other stream commit flags"
|
|
// Are there other commit flags that need to be handled?
|
|
|
|
if( !(STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE & grfCommitFlags) )
|
|
{
|
|
if( !FlushFileBuffers( _hFile ))
|
|
sc = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
EH_Err:
|
|
Unlock();
|
|
return sc;
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Revert (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Revert(void)
|
|
{
|
|
// We only support direct-mode.
|
|
|
|
return CheckReverted();
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::LockRegion (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::LockRegion(
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
HRESULT sc = S_OK;
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
// NTRAID#NTBUG9-368745-2001-04-13-gilmanw "ISSUE: FileStream::LockRegion - handle other lock flags"
|
|
// Are all the lock types supported here?
|
|
|
|
if (dwLockType != LOCK_EXCLUSIVE && dwLockType != LOCK_ONLYONCE)
|
|
nffErr( EH_Err, STG_E_INVALIDFUNCTION );
|
|
|
|
if( !LockFile( _hFile, libOffset.LowPart, libOffset.HighPart,
|
|
cb.LowPart, cb.HighPart))
|
|
{
|
|
nffErr( EH_Err, HRESULT_FROM_WIN32( GetLastError() ));
|
|
}
|
|
|
|
EH_Err:
|
|
|
|
Unlock();
|
|
return( sc );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Stat (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Stat(
|
|
STATSTG *pstatstg,
|
|
DWORD grfStatFlag)
|
|
{
|
|
STATSTG statstg;
|
|
HRESULT sc = S_OK;
|
|
|
|
BY_HANDLE_FILE_INFORMATION ByHandleFileInformation;
|
|
|
|
statstg.pwcsName = NULL;
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
ZeroMemory((void*)&statstg, sizeof(STATSTG));
|
|
|
|
// Get the name, if desired
|
|
|
|
if( (STATFLAG_NONAME & grfStatFlag) )
|
|
statstg.pwcsName = NULL;
|
|
else
|
|
{
|
|
nffMem( statstg.pwcsName = reinterpret_cast<WCHAR*>
|
|
( CoTaskMemAlloc( sizeof(WCHAR)*(UnicodeStringLength(_pwcsName) + 1) )));
|
|
UnicodeStringCopy( statstg.pwcsName, _pwcsName );
|
|
}
|
|
|
|
// Get the type
|
|
statstg.type = STGTY_STREAM;
|
|
|
|
statstg.grfLocksSupported = LOCK_EXCLUSIVE | LOCK_ONLYONCE;
|
|
|
|
// Get the size & times.
|
|
|
|
if( !GetFileInformationByHandle( _hFile, &ByHandleFileInformation ))
|
|
nffErr( EH_Err, HRESULT_FROM_WIN32( GetLastError() ));
|
|
|
|
statstg.cbSize.LowPart = ByHandleFileInformation.nFileSizeLow;
|
|
statstg.cbSize.HighPart = ByHandleFileInformation.nFileSizeHigh;
|
|
|
|
// We get a time back in ByHandleFileInformation, but it's the file's times,
|
|
// not the streams times. So really the stream times are not supported, and
|
|
// we'll just set them to zero.
|
|
|
|
statstg.mtime = statstg.atime = statstg.ctime = CFILETIME(0);
|
|
|
|
// Get the STGM modes
|
|
statstg.grfMode = _grfMode & ~STGM_CREATE;
|
|
|
|
*pstatstg = statstg;
|
|
|
|
EH_Err:
|
|
if( FAILED(sc) && NULL != statstg.pwcsName )
|
|
CoTaskMemFree( statstg.pwcsName );
|
|
|
|
Unlock();
|
|
return( sc );
|
|
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Clone (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Clone(
|
|
IStream** ppstm)
|
|
{
|
|
// NTRAID#NTBUG9-368747-2001-04-13-gilmanw "ISSUE: FileStream::Clone returns E_NOTIMPL"
|
|
|
|
return( E_NOTIMPL );
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Read (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Read(
|
|
void* pv,
|
|
ULONG cb,
|
|
ULONG* pcbRead)
|
|
{
|
|
LARGE_INTEGER lOffset;
|
|
HRESULT sc = S_OK;
|
|
ULONG cbRead = 0;
|
|
|
|
lOffset.LowPart = _liCurrentSeekPosition.LowPart;
|
|
lOffset.HighPart = _liCurrentSeekPosition.HighPart;
|
|
|
|
if (lOffset.HighPart < 0)
|
|
{
|
|
return( TYPE_E_SIZETOOBIG );
|
|
}
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
if(SetFilePointer(_hFile, lOffset.LowPart, &lOffset.HighPart,
|
|
FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
|
{
|
|
nffChk( HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
if(!ReadFile(_hFile, pv, cb, &cbRead, NULL))
|
|
{
|
|
nffChk( HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
_liCurrentSeekPosition += cbRead;
|
|
if( NULL != pcbRead )
|
|
*pcbRead = cbRead;
|
|
|
|
EH_Err:
|
|
|
|
Unlock();
|
|
return( sc );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: FileStream::Write (IStream)
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Write(
|
|
const void* pv,
|
|
ULONG cb,
|
|
ULONG* pcbWritten)
|
|
{
|
|
LARGE_INTEGER lOffset;
|
|
HRESULT sc = S_OK;
|
|
ULONG cbWritten = 0;
|
|
|
|
lOffset.LowPart = _liCurrentSeekPosition.LowPart;
|
|
lOffset.HighPart = _liCurrentSeekPosition.HighPart;
|
|
|
|
if (lOffset.HighPart < 0)
|
|
{
|
|
return( TYPE_E_SIZETOOBIG );
|
|
}
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
if(SetFilePointer(_hFile, lOffset.LowPart, &lOffset.HighPart,
|
|
FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
|
{
|
|
nffChk( HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
if(!WriteFile(_hFile, pv, cb, &cbWritten, NULL))
|
|
{
|
|
nffChk(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
_liCurrentSeekPosition += cbWritten;
|
|
|
|
if( NULL != pcbWritten )
|
|
*pcbWritten = cbWritten;
|
|
|
|
EH_Err:
|
|
|
|
Unlock();
|
|
return( sc );
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: FileStream Constructor
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
FileStream::FileStream( )
|
|
{
|
|
_cRefs = 1;
|
|
_grfMode = 0;
|
|
_hFile = INVALID_HANDLE_VALUE;
|
|
_liCurrentSeekPosition = 0;
|
|
_pwcsName = NULL;
|
|
_bCritSecInitialized = FALSE;
|
|
|
|
__try
|
|
{
|
|
InitializeCriticalSection( &_critsec );
|
|
_bCritSecInitialized = TRUE;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// If we've thrown then _bCritSecInitialized will be FALSE and
|
|
// Init() will automatically fail.
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: FileStream Destructor
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
FileStream::~FileStream()
|
|
{
|
|
|
|
// Close the file
|
|
if( INVALID_HANDLE_VALUE != _hFile )
|
|
CloseHandle( _hFile );
|
|
|
|
if( NULL != _pwcsName )
|
|
CoTaskMemFree( _pwcsName );
|
|
|
|
if (_bCritSecInitialized)
|
|
{
|
|
// We don't need to reset _bCrisSecInitialized to FALSE since the
|
|
// object has been destroyed
|
|
DeleteCriticalSection( &_critsec );
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: FileStream::Init
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::Init(
|
|
HANDLE hFile, // File handle of this Stream.
|
|
DWORD grfMode, // Open Modes
|
|
const OLECHAR * pwcsName) // Name of the Stream
|
|
{
|
|
// If we couldn't allocate the critical section then return an Error
|
|
if (!_bCritSecInitialized)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT sc=S_OK;
|
|
HANDLE ev;
|
|
|
|
// We now own this file handle, and are responsible for closing it.
|
|
_hFile = hFile;
|
|
|
|
// Save the STGM_ flags so we can return them in a Stat call.
|
|
_grfMode = grfMode;
|
|
|
|
// Save the stream name
|
|
|
|
if( NULL != _pwcsName )
|
|
{
|
|
CoTaskMemFree( _pwcsName );
|
|
_pwcsName = NULL;
|
|
}
|
|
|
|
if( NULL != pwcsName )
|
|
{
|
|
nffMem( _pwcsName = reinterpret_cast<WCHAR*>
|
|
( CoTaskMemAlloc( sizeof(WCHAR)*(UnicodeStringLength(pwcsName) + 1) )));
|
|
UnicodeStringCopy( _pwcsName, pwcsName );
|
|
}
|
|
|
|
EH_Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// FileStream Non-Interface::ShutDown
|
|
//
|
|
// Flush data, Close File handle and mark the object as reverted.
|
|
// This is called when the Storage is released and when the Oplock Breaks.
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
FileStream::ShutDown()
|
|
{
|
|
HRESULT sc=S_OK;
|
|
|
|
if( INVALID_HANDLE_VALUE == _hFile )
|
|
return S_OK;
|
|
|
|
//
|
|
// Close the file/stream handle and mark the IStream object as
|
|
// Reverted by giving the file handle an invalid value.
|
|
//
|
|
CloseHandle(_hFile);
|
|
_hFile = INVALID_HANDLE_VALUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// FileStream::SetFileSize (private, non-interface method)
|
|
//
|
|
// Set the size of the _hFile. This is used by the IStream & IMappedStream
|
|
// SetSize methods
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
HRESULT // private
|
|
FileStream::SetFileSize( const CULargeInteger &uliNewSize )
|
|
{
|
|
HRESULT sc = S_OK;
|
|
CLargeInteger liEOF;
|
|
|
|
// We have to convert uliNewSize into a LARGE_INTEGER, so ensure that it can
|
|
// be cast without loss of data.
|
|
|
|
liEOF = static_cast<CLargeInteger>(uliNewSize);
|
|
if( liEOF < 0 )
|
|
nffErr( EH_Err, STG_E_INVALIDPARAMETER );
|
|
|
|
// Move to what will be the new end-of-file position.
|
|
|
|
liEOF.LowPart = SetFilePointer( _hFile, liEOF.LowPart,
|
|
&liEOF.HighPart, FILE_BEGIN );
|
|
if( 0xFFFFFFFF == liEOF.LowPart && NO_ERROR != GetLastError() )
|
|
nffErr( EH_Err, HRESULT_FROM_WIN32( GetLastError() ));
|
|
|
|
// Set this as the new eof
|
|
|
|
if( !SetEndOfFile( _hFile ))
|
|
nffErr( EH_Err, HRESULT_FROM_WIN32( GetLastError() ));
|
|
|
|
EH_Err:
|
|
|
|
return( sc );
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
FileStream::UnlockRegion(
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
HRESULT sc = S_OK;
|
|
|
|
Lock( INFINITE );
|
|
|
|
nffChk( CheckReverted() );
|
|
|
|
if (dwLockType != LOCK_EXCLUSIVE && dwLockType != LOCK_ONLYONCE)
|
|
{
|
|
nffErr( EH_Err, STG_E_INVALIDFUNCTION );
|
|
}
|
|
|
|
if( !UnlockFile(_hFile, libOffset.LowPart, libOffset.HighPart,
|
|
cb.LowPart, cb.HighPart))
|
|
{
|
|
nffErr( EH_Err, HRESULT_FROM_WIN32(GetLastError()) );
|
|
}
|
|
|
|
EH_Err:
|
|
|
|
Unlock();
|
|
return( sc );
|
|
|
|
}
|