NT4/private/windows/win4help/ftsrch/unbuffio.cpp
2020-09-30 17:12:29 +02:00

1131 lines
25 KiB
C++

// UnbuffIO.cpp -- Implements the class CUnbufferedIO
#include "stdafx.h"
#include "UnbuffIO.h"
#include "MemEx.h"
#include <stdlib.h>
#include "ftsrch.h" // for uOpSys
#include "globals.h"
#include "Except.h"
static HWND hwndWhereIsIt = NULL;
extern "C" void APIENTRY SetDirectoryLocator(HWND hwndLocator)
{
hwndWhereIsIt= hwndLocator;
}
HFONT GetDefaultFont()
{
if (!hwndWhereIsIt) return NULL;
HFONT hFont = (HFONT) ::SendMessage(hwndWhereIsIt, MSG_GET_DEFFONT, 0, 0);
HFONT hFontClone = NULL;
#ifdef _DEBUG
UINT uErrCode= 0;
#endif // _DEBUG
if (hFont)
{
LOGFONT lf;
UINT cbObj= ::GetObject(hFont, sizeof(lf), &lf);
if (cbObj)
hFontClone= ::CreateFontIndirect(&lf);
#ifdef _DEBUG
else uErrCode= ::GetLastError();
#endif // _DEBUG
}
return hFontClone;
}
BOOL FindFile(FILENAMEBUFFER pszFile, BOOL *pfStartEnumeration)
{
ASSERT(pszFile && pszFile[0]);
if (!hwndWhereIsIt) return FALSE;
FILENAMEBUFFER szPath;
lstrcpy(szPath, pszFile);
::SendMessage(hwndWhereIsIt, MSG_FTS_WHERE_IS_IT,
(WPARAM) *pfStartEnumeration,
(LPARAM) pszFile
);
*pfStartEnumeration= FALSE;
/*
* 23-Jan-1995 [ralphw] I switched this to lstrcmpi from stricmp().
* stricmp won't recognize locales, so this function would fail with
* filenames on international release.
*/
if (lstrcmpi(pszFile, szPath))
return (*pszFile)? TRUE : FALSE;
::SendMessage(hwndWhereIsIt, MSG_FTS_WHERE_IS_IT,
(WPARAM) FALSE,
(LPARAM) pszFile
);
if (!*pszFile) return FALSE;
return BOOL(lstrcmpi(pszFile, szPath));
}
CUnbufferedIO::CUnbufferedIO()
{
m_fInitialed = FALSE;
m_fFileAttached = FALSE;
m_hFile = NULL;
m_cbSector = 0;
m_cbCluster = 0;
m_cActiveIOTransactions = 0;
m_cWaitingForLull = 0;
m_fWaitingForLullEnd = FALSE;
m_pfnCompletion = NULL;
m_hEventLull = NULL;
m_hEventLullEnd = NULL;
m_hMapFile = NULL;
m_pvMemoryImage = NULL;
m_fAlready_Out_of_Space = FALSE;
}
void CUnbufferedIO::Initial()
{
InitializeCriticalSection(&m_cs);
m_hEventLull = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hEventLullEnd = CreateEvent(NULL, TRUE , TRUE , NULL);
if (!m_hEventLull || !m_hEventLullEnd)
{
#ifdef _DEBUG
MessageBox(NULL, "In CUnbufferedIO::Initial; Failure: !m_hEventLull || !m_hEventLullEnd", "Search System Failure", MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
#endif // _DEBUG
RaiseException(STATUS_SYSTEM_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
}
void CUnbufferedIO::BeginLull()
{
EnterCriticalSection(&m_cs);
m_cWaitingForLull++; ResetEvent(m_hEventLullEnd);
while (m_cActiveIOTransactions)
{
LeaveCriticalSection(&m_cs);
UINT uiResult;
do uiResult= WaitForSingleObjectEx(m_hEventLull, INFINITE, TRUE);
while (uiResult != WAIT_OBJECT_0);
EnterCriticalSection(&m_cs);
}
}
void CUnbufferedIO::EndLull()
{
ASSERT(m_cWaitingForLull);
if (--m_cWaitingForLull) SetEvent(m_hEventLull);
else
if (m_fWaitingForLullEnd) SetEvent(m_hEventLullEnd);
LeaveCriticalSection(&m_cs);
}
void CUnbufferedIO::BeginTransaction()
{
EnterCriticalSection(&m_cs);
if (m_cWaitingForLull)
{
m_fWaitingForLullEnd= TRUE;
while(m_cWaitingForLull)
{
LeaveCriticalSection(&m_cs);
UINT uiResult;
do uiResult= WaitForSingleObjectEx(m_hEventLullEnd, INFINITE, TRUE);
while (uiResult != WAIT_OBJECT_0);
EnterCriticalSection(&m_cs);
}
}
++m_cActiveIOTransactions;
}
void CUnbufferedIO::ReleaseTransaction()
{
// ASSERT(m_cActiveIOTransactions);
LeaveCriticalSection(&m_cs);
}
void CUnbufferedIO::AbortTransaction()
{
ASSERT(m_cActiveIOTransactions);
--m_cActiveIOTransactions;
ReleaseTransaction();
}
void CUnbufferedIO::FinishTransaction()
{
EnterCriticalSection(&m_cs);
ASSERT(m_cActiveIOTransactions);
if (!--m_cActiveIOTransactions && m_cWaitingForLull) SetEvent(m_hEventLull);
LeaveCriticalSection(&m_cs);
}
CUnbufferedIO::~CUnbufferedIO()
{
if (m_fFileAttached)
{
if (m_pvMemoryImage)
{
UnmapViewOfFile(m_pvMemoryImage); m_pvMemoryImage= NULL;
CloseHandle(m_hMapFile); m_hMapFile= NULL;
}
BeginLull();
CloseHandle(m_hFile); m_fFileAttached= FALSE;
EndLull();
if (m_fTemporary)
{
BOOL fDeleted= DeleteFile( m_szFile);
ASSERT(fDeleted);
}
}
DeleteCriticalSection(&m_cs);
if (m_hEventLull ) { CloseHandle(m_hEventLull ); m_hEventLull = NULL; }
if (m_hEventLullEnd) { CloseHandle(m_hEventLullEnd); m_hEventLullEnd = NULL; }
}
BOOL CUnbufferedIO::EmptyFile()
{
ASSERT(m_fFileAttached);
BeginLull();
LONG zero= 0;
UINT ibLow= SetFilePointer(m_hFile, 0, &zero, FILE_BEGIN);
#ifdef _DEBUG
UINT uiLastError= GetLastError();
#endif // _DEBUG
ASSERT(ibLow != -1 || !GetLastError());
BOOL fResult= SetEndOfFile(m_hFile);
EndLull();
return fResult;
}
CUnbufferedIO *CUnbufferedIO::NewTempFile(PSZ pszSource, BOOL fPersistent)
{
FILENAMEBUFFER szPath;
FILENAMEBUFFER szFile;
FILENAMEBUFFER szDirectory;
FILENAMEBUFFER szCandidate;
BYTE szFName[_MAX_FNAME];
BYTE szEXT [_MAX_EXT ];
BYTE szDrive[_MAX_DRIVE];
HANDLE hFile = NULL;
CUnbufferedIO *puio = NULL;
UINT UErrCode = SetErrorMode(0);
SetErrorMode(UErrCode || SEM_NOOPENFILEERRORBOX || SEM_FAILCRITICALERRORS );
if (!pszSource || !*pszSource) fPersistent= FALSE;
__try
{
for (UINT iPhase= SourceDirectory; iPhase < PhaseLimit; ++iPhase)
{
switch (iPhase)
{
// BugBug! Need to make this directory sequence settable by for each Indexer
case SourceDirectory: // See if we were passed a source file name.
if (!pszSource) continue; // If not go to the next phase.
_splitpath(pszSource, PSZ(szDrive), PSZ(szDirectory), PSZ(szFName), PSZ(szEXT));
if (GetDriveType(PSZ(szDrive)) == DRIVE_CDROM) continue; // Can't write to a CD-Rom!
if (!szDirectory[0]) GetCurrentDirectory(MAX_PATH, PSZ(szPath));
else
{
lstrcpy(PSZ(szPath), PSZ(szDrive));
lstrcat(PSZ(szPath), PSZ(szDirectory));
}
break;
case HelpDirectory:
GetWindowsDirectory((PSZ) szPath,MAX_PATH);
lstrcat(PSZ(szPath), "\\Help\\");
break;
case WindowsDirectory:
GetWindowsDirectory((PSZ) szPath, MAX_PATH);
lstrcat(PSZ(szPath), "\\");
break;
}
if (fPersistent)
{
// When we're creating a tmp file which will be eventually made into
// a permanent file, we must look to see if a read-only file already
// exists with the permanent name we plan to use.
//
// Note that the final rename operation can still fail if some program
// creates such a read-only file after this test.
lstrcpy(szCandidate, PSZ(szPath ));
lstrcat(szCandidate, PSZ(szFName));
lstrcat(szCandidate, PSZ(szEXT ));
WIN32_FIND_DATA fd;
HANDLE hfd;
if ((hfd = FindFirstFile(szCandidate, &fd)) != INVALID_HANDLE_VALUE)
{
FindClose(hfd);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) continue;
}
}
if (!GetTempFileName((char *) szPath, "~ft", 0, (char *) szFile)) continue;
hFile = CreateFile((char *) szFile, GENERIC_READ | GENERIC_WRITE, 0,
(LPSECURITY_ATTRIBUTES) NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING
| ((uOpSys != WIN40) ? FILE_FLAG_OVERLAPPED : 0)
, (HANDLE) NULL
);
if (hFile == INVALID_HANDLE_VALUE) continue;
puio= New CUnbufferedIO();
puio->Initial();
HANDLE hfTemp= hFile; hFile= NULL;
if (!puio->SetupFile((char *) szPath, (char *) szFile, hfTemp, TRUE))
{
delete puio; puio= NULL;
continue;
}
__leave;
}
// Couldn't create the temp file anywhere...
RaiseException(STATUS_DISK_CREATE_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
__finally
{
if (_abnormal_termination())
{
if (puio) { delete puio; puio = NULL; }
if (hFile && hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile); hFile = NULL;
}
}
}
SetErrorMode(UErrCode);
return puio;
}
BOOL CUnbufferedIO::CbFile(PUINT pibFileLow, PUINT pibFileHigh)
{
BY_HANDLE_FILE_INFORMATION bhfi;
if (!GetFileInformationByHandle(m_hFile, &bhfi)) return FALSE;
if (pibFileHigh) *pibFileHigh= bhfi.nFileSizeHigh;
ASSERT(pibFileLow);
*pibFileLow= bhfi.nFileSizeLow;
return TRUE;
}
BOOL CUnbufferedIO::SetupFile(PSZ pszPath, PSZ pszFile, HANDLE hFile, BOOL fTemporary)
{
m_hFile = hFile;
m_fFileAttached = TRUE;
m_fTemporary = fTemporary;
lstrcpy((char *) m_szPath, pszPath);
lstrcpy((char *) m_szFile, pszFile);
if (GetStatistics()) m_fInitialed = TRUE;
return m_fInitialed;
#if 0
else
{
#ifdef _DEBUG
MessageBox(NULL, "In CUnbufferedIO::SetupFile; Failure: !GetStatistics()", "Search System Failure", MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
#endif // _DEBUG
RaiseException(STATUS_SYSTEM_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
#endif // 0
}
CUnbufferedIO *CUnbufferedIO::OpenExistingFile(PSZ pszFile, BOOL fAllowWrites)
{
HANDLE hFile = NULL;
CUnbufferedIO *puio = NULL;
__try
{
FILENAMEBUFFER szPath;
FILENAMEBUFFER szFile;
PSZ pszFileName;
if (!GetFullPathName(pszFile, MAX_PATH, szFile, &pszFileName))
RaiseException(STATUS_DISK_OPEN_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
hFile= CreateFile(szFile,
fAllowWrites? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,
fAllowWrites? 0 : FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING
| ((uOpSys != WIN40) ? FILE_FLAG_OVERLAPPED : 0)
,(HANDLE) NULL
);
if (hFile == INVALID_HANDLE_VALUE)
RaiseException(STATUS_DISK_OPEN_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
if (!GetFullPathName(szFile, MAX_PATH, szPath, &pszFileName))
RaiseException(STATUS_DISK_OPEN_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
lstrcmp(szFile, szPath);
*pszFileName = 0;
puio= New CUnbufferedIO();
puio->Initial();
HANDLE hfTemp= hFile; hFile= NULL;
puio->SetupFile(szPath, szFile, hfTemp, FALSE);
}
__finally
{
if (_abnormal_termination())
{
if (puio) { delete puio; puio = NULL; }
if (hFile && hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile); hFile = NULL;
}
}
}
return puio;
}
CUnbufferedIO *CUnbufferedIO::CreateNewFile(PSZ pszFile, BOOL fOverwriteExistingFile)
{
HANDLE hFile = NULL;
CUnbufferedIO *puio = NULL;
__try
{
hFile = CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, 0,
(LPSECURITY_ATTRIBUTES) NULL,
fOverwriteExistingFile? CREATE_ALWAYS : CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING
| ((uOpSys != WIN40) ? FILE_FLAG_OVERLAPPED : 0)
,(HANDLE) NULL
);
FILENAMEBUFFER szPath;
PSZ pszFileName;
if (hFile == INVALID_HANDLE_VALUE || !GetFullPathName(pszFile, MAX_PATH, (char *) szPath, &pszFileName))
RaiseException(STATUS_DISK_CREATE_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
CUnbufferedIO *puio= New CUnbufferedIO();
puio->Initial();
HANDLE hfTemp= hFile; hFile= NULL;
puio->SetupFile((char *) szPath, (char *) pszFile, hfTemp, TRUE);
}
__finally
{
if (_abnormal_termination())
{
if (puio) { delete puio; puio = NULL; }
if (hFile && hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile); hFile = NULL;
}
}
}
return puio;
}
BOOL CUnbufferedIO::GetStatistics()
{
FILENAMEBUFFER szDrive;
_splitpath((char *) m_szFile, (char *) &szDrive, NULL, NULL, NULL);
UINT cbDrive = 0;
BOOL fUNCPath = FALSE;
if (*szDrive)
cbDrive = lstrlen(szDrive);
else
{
// Maybe this is a UNC path. Scan for the pattern \\MachineName\Share\...
char c, *pszSrc= m_szFile;
c= *pszSrc;
if (c != '\\' && c != '/')
return FALSE;
c= *(pszSrc= CharNext(pszSrc));
if (c != '\\' && c != '/')
return FALSE;
for ( ; ; )
{
c= *(pszSrc= CharNext(pszSrc));
if (!c || c == '\\' || c == '/')
break;
}
if (!c)
return FALSE;
for ( ; ; )
{
c= *(pszSrc= CharNext(pszSrc));
if (!c || c == '\\' || c == '/')
break;
}
/*
* Note that we specifically do NOT check for !c here -- if there
* is no trailing backslash (theoretically impossible) we will add one
* anyway, get the drive, and fail elsewhere because there is no
* filename.
*/
cbDrive= pszSrc - m_szFile;
CopyMemory(szDrive, m_szFile, cbDrive);
fUNCPath= TRUE;
}
szDrive[cbDrive ]= '\\';
szDrive[cbDrive + 1] = 0;
ULONG cbSector, cSectorsPerCluster, cFreeClusters, cTotalClusters;
BOOL fGotInfo=GetDiskFreeSpace((char *) szDrive, &cSectorsPerCluster, &cbSector,
&cFreeClusters, &cTotalClusters
);
if (!fGotInfo && fUNCPath) {
if (!hMPRLib) {
hMPRLib = LoadLibrary("MPR.dll");
if (hMPRLib)
{
pWNetAddConnection2 = (PWNETADDCONNECTION2A ) GetProcAddress(hMPRLib, "WNetAddConnection2A" );
pWNetCancelConnection2 = (PWNETCANCELCONNECTION2A) GetProcAddress(hMPRLib, "WNetCancelConnection2A");
if (!pWNetAddConnection2 || !pWNetCancelConnection2)
{
// If we failed to get both proc addresses, we set the pointer variables back to NULL.
pWNetAddConnection2 = NULL;
pWNetCancelConnection2 = NULL;
}
}
}
if (pWNetAddConnection2 && pWNetCancelConnection2) {
// GetDiskFreeSpace failed on a UNC path. We'll try to bind the
// UNC share to a drive letter and then ask again.
DWORD afDrives= GetLogicalDrives();
UINT iDrive;
for (iDrive= 26; iDrive--; )
if (!(afDrives & (1 << iDrive))) break; // Found a drive letter not in use.
else
if (!iDrive) return FALSE; // No drives letters available!
NETRESOURCE nr;
BYTE abDriveLetter[4];
abDriveLetter[0]= 'A' + iDrive;
abDriveLetter[1]= ':';
abDriveLetter[2]= 0;
nr.dwType = RESOURCETYPE_DISK;
nr.lpLocalName = (char *) abDriveLetter;
nr.lpRemoteName = szDrive;
nr.lpProvider = NULL;
DWORD dwResult= pWNetAddConnection2(&nr, NULL, NULL, 0);
if (dwResult != NO_ERROR) return FALSE;
abDriveLetter[2] = '\\';
abDriveLetter[3] = 0;
fGotInfo= GetDiskFreeSpace((char *) abDriveLetter, &cSectorsPerCluster, &cbSector,
&cFreeClusters, &cTotalClusters
);
abDriveLetter[2] = 0;
#ifdef _DEBUG
dwResult=
#endif // _DEBUG
pWNetCancelConnection2((LPSTR) abDriveLetter, 0, TRUE);
ASSERT(dwResult == NO_ERROR);
}
}
#ifdef _DEBUG
UINT uiLastError=GetLastError();
#endif // _DEBUG
if (!fGotInfo) return FALSE;
m_cbSector = cbSector;
m_cbCluster = cbSector * cSectorsPerCluster;
return TRUE;
}
#ifdef _DEBUG
PVOID CUnbufferedIO::_GetBuffer(PUINT pcbBuffer, PSZ pszWhichFile, UINT iWhichLine)
#else // _DEBUG
PVOID CUnbufferedIO::GetBuffer(PUINT pcbBuffer)
#endif // _DEBUG
{
// This routine creates a buffer aligned correctly for read and write operations.
// On entry *pcbBuffer defines the minimum size for the buffer. If the buffer is
// successfully allocated, *pcbBuffer will be set to the largest usable size
// for the buffer, and the explicit result will be the base address of the buffer.
// If the allocation fails, we return NULL.
PVOID pv = NULL;
PVOID pv2 = NULL;
__try
{
if (!m_fFileAttached)
{
#ifdef _DEBUG
MessageBox(NULL, "In CUnbufferedIO::GetBuffer; Failure: !m_fFileAttached", "Search System Failure", MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
#endif // _DEBUG
RaiseException(STATUS_SYSTEM_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
UINT cbBuffer= *pcbBuffer;
cbBuffer= m_cbSector * ((cbBuffer + m_cbSector - 1) / m_cbSector);
SYSTEM_INFO si;
GetSystemInfo(&si);
UINT cbPage = si.dwPageSize;
UINT cbAlloc = si.dwAllocationGranularity;
ASSERT(!(cbAlloc % m_cbSector)); // BugBug! Can this ever be false??
UINT cbReserve = cbAlloc * ((cbBuffer + cbAlloc - 1) / cbAlloc);
UINT cbCommit = cbPage * ((cbBuffer + cbPage - 1) / cbPage );
pv= VirtualAlloc(0, cbReserve, MEM_RESERVE, PAGE_NOACCESS);
ASSERT(!(UINT(pv) % m_cbSector));
if (!pv || !(pv2= VirtualAlloc(pv, cbCommit, MEM_COMMIT, PAGE_READWRITE)))
RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL);
#ifdef _DEBUG
CreateVARecord(pv, PBYTE(pv) + cbCommit, PBYTE(pv) + cbReserve, pszWhichFile, iWhichLine);
#endif // _DEBUG
*pcbBuffer= cbBuffer;
}
__finally
{
if (_abnormal_termination() && pv)
{
VirtualFree(pv, 0, MEM_RELEASE); pv= pv2= NULL;
}
}
return pv2;
}
void CUnbufferedIO::FreeBuffer(PVOID pvBuffer)
{
// This routine deallocates a buffer constructed by the GetBuffer routine.
ASSERT(!(UINT(pvBuffer) % m_cbSector));
#ifdef _DEBUG
DestroyVARecord(pvBuffer);
#endif // _DEBUG
VirtualFree(pvBuffer, 0, MEM_RELEASE);
}
typedef struct _TransactionControl
{
CUnbufferedIO *puio;
PFNCompletion pfnCompletionRoutine;
PVOID pvEnvironment;
PVOID pvTransaction;
HANDLE hEvent;
PUINT puiCompletionCode;
OVERLAPPED ov;
} TransactionControl;
static VOID WINAPI UnbufferedIOCompletionRoutine(DWORD fdwError, DWORD cbTransferred, LPOVERLAPPED lpo)
{
// We assume that lpo points to an OVERLAPPED structure within a TransactionControl object.
TransactionControl *ptc= (TransactionControl *)lpo;
ptc= (TransactionControl *) (PBYTE(ptc) - (PBYTE(&(ptc->ov)) - PBYTE(ptc)));
TransactionControl tc= *ptc; // Copy the transaction record to a stack frame variable
VFree(ptc); // Release heap storage for the transaction
tc.puio->FinishTransaction();
if (tc.pfnCompletionRoutine)
{
ASSERT(!tc.hEvent && !tc.puiCompletionCode);
tc.pfnCompletionRoutine(tc.pvEnvironment, tc.pvTransaction, fdwError, cbTransferred);
}
else
{
ASSERT(!tc.pvEnvironment && !tc.pvTransaction);
if (tc.puiCompletionCode) *(tc.puiCompletionCode)= fdwError;
ASSERT(tc.hEvent);
SetEvent(tc.hEvent);
}
}
void CUnbufferedIO::IOTransaction(BOOL fWrite, PVOID pv, UINT ibFileLow, UINT ibFileHigh,
UINT cb, PUINT puiCompletionCode, HANDLE hEvent
)
{
ASSERT(sizeof(PVOID) == sizeof(UINT));
ASSERT(m_fInitialed);
ASSERT(m_fFileAttached);
BeginTransaction();
TransactionControl *ptc = NULL;
BOOL fSynchronous = FALSE;
__try
{
ASSERT(!(ibFileLow % m_cbSector));
ASSERT(!(cb % m_cbSector));
ASSERT(!(UINT(pv) % m_cbSector));
ptc= (TransactionControl *) VAlloc(TRUE, sizeof(TransactionControl));
fSynchronous = !hEvent;
UINT uiCompletionCode = 0;
if (fSynchronous) hEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
else ResetEvent(hEvent);
ptc->hEvent = hEvent;
ptc->puio = this;
ptc->puiCompletionCode = fSynchronous? &uiCompletionCode : puiCompletionCode;
ptc->ov.Offset = ibFileLow;
ptc->ov.OffsetHigh = ibFileHigh;
ptc->pfnCompletionRoutine = NULL;
ptc->pvEnvironment = NULL;
ptc->pvTransaction = NULL;
BOOL fResult;
ULONG cbXfered= 0;
if (uOpSys == WIN40)
{
SetFilePointer(m_hFile,ibFileLow,(LONG *)&(ptc->ov.OffsetHigh),FILE_BEGIN);
if (fWrite) fResult= WriteFile(m_hFile, pv, cb, &cbXfered, NULL /* &(ptc->ov) */);
else fResult= ReadFile(m_hFile, pv, cb, &cbXfered, NULL /* &(ptc->ov) */);
}
else
{
if (fWrite) fResult= WriteFileEx(m_hFile, pv, cb, &(ptc->ov), UnbufferedIOCompletionRoutine);
else fResult= ReadFileEx(m_hFile, pv, cb, &(ptc->ov), UnbufferedIOCompletionRoutine);
}
if (!fResult && GetLastError() != ERROR_IO_PENDING)
{
#ifdef _DEBUG
UINT uiLastError= GetLastError();
#endif // _DEBUG
if (puiCompletionCode) *puiCompletionCode= GetLastError();
RaiseException(fWrite? STATUS_DISK_WRITE_ERROR : STATUS_DISK_READ_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
if (uOpSys == WIN40)
UnbufferedIOCompletionRoutine(fResult? NO_ERROR : GetLastError(), cbXfered, &(ptc->ov));
ReleaseTransaction();
if (!fSynchronous) __leave;
UINT uiResult;
do uiResult= WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
while (uiResult != WAIT_OBJECT_0);
if (puiCompletionCode) *puiCompletionCode= uiCompletionCode;
}
__finally
{
if (fSynchronous && hEvent) CloseHandle(hEvent);
if (_abnormal_termination())
{
AbortTransaction();
if (ptc) { VFree(ptc); ptc= NULL; }
}
}
}
void CUnbufferedIO::StartIOTransaction(BOOL fWrite, PVOID pvData, UINT ibFileLow, UINT ibFileHigh, UINT cb,
PVOID pvEnvironment, PVOID pvTransaction
)
{
ASSERT(m_pfnCompletion);
ASSERT(sizeof(PVOID) == sizeof(UINT));
ASSERT(m_fInitialed);
ASSERT(m_fFileAttached);
BeginTransaction();
TransactionControl *ptc= NULL;
__try
{
ASSERT(!(ibFileLow % m_cbSector));
ASSERT(!(cb % m_cbSector));
ASSERT(!(UINT(pvData) % m_cbSector));
ptc= (TransactionControl *) VAlloc(TRUE, sizeof(TransactionControl));
ptc->hEvent = NULL;
ptc->puiCompletionCode = NULL;
ptc->puio = this;
ptc->pfnCompletionRoutine = m_pfnCompletion;
ptc->pvEnvironment = pvEnvironment;
ptc->pvTransaction = pvTransaction;
ptc->ov.Offset = ibFileLow;
ptc->ov.OffsetHigh = ibFileHigh;
BOOL fResult;
ULONG cbXfered= 0;
if (uOpSys == WIN40)
{
SetFilePointer(m_hFile,ibFileLow,(LONG *)&(ptc->ov.OffsetHigh),FILE_BEGIN);
if (fWrite) fResult= WriteFile(m_hFile, pvData, cb, &cbXfered, NULL /* &(ptc->ov) */);
else fResult= ReadFile(m_hFile, pvData, cb, &cbXfered, NULL /* &(ptc->ov) */);
}
else
{
if (fWrite) fResult= WriteFileEx(m_hFile, pvData, cb, &(ptc->ov), UnbufferedIOCompletionRoutine);
else fResult= ReadFileEx(m_hFile, pvData, cb, &(ptc->ov), UnbufferedIOCompletionRoutine);
}
if (!fResult && GetLastError() != ERROR_IO_PENDING)
{
#ifdef _DEBUG
UINT uiLastError= GetLastError();
#endif // _DEBUG
RaiseException(fWrite? STATUS_DISK_WRITE_ERROR : STATUS_DISK_READ_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
if (uOpSys == WIN40)
UnbufferedIOCompletionRoutine(fResult? NO_ERROR : GetLastError(), cbXfered, &(ptc->ov));
}
__finally
{
if (_abnormal_termination())
{
AbortTransaction();
if (ptc) { VFree(ptc); ptc= NULL; }
}
}
ReleaseTransaction();
}
void CUnbufferedIO::UnmapImage()
{
ASSERT(m_pvMemoryImage && m_hMapFile);
UnmapViewOfFile(m_pvMemoryImage); m_pvMemoryImage= NULL;
CloseHandle(m_hMapFile); m_hMapFile= NULL;
}
PVOID CUnbufferedIO::MappedImage( )
{
ASSERT(m_fInitialed);
#ifdef _DEBUG
DWORD iLastError= 0;
#endif // _DEBUG
ASSERT(m_fFileAttached);
if (m_pvMemoryImage) return m_pvMemoryImage;
__try
{
ASSERT(!m_hMapFile);
m_hMapFile = CreateFileMapping(m_hFile, (LPSECURITY_ATTRIBUTES) NULL,
PAGE_READONLY, 0, 0, NULL
);
if (!m_hMapFile || !(m_pvMemoryImage = MapViewOfFile(m_hMapFile, FILE_MAP_READ, 0, 0, 0)))
{
UINT ec= GetLastError();
#ifdef _DEBUG
UINT cbFile = GetFileSize(m_hFile, 0);
UINT iResult = SetFilePointer(m_hFile, 0, 0, FILE_BEGIN);
#endif // _DEBUG
#ifdef _DEBUG
MessageBox(NULL, "In CUnbufferedIO::MappedImage; Failure: !m_hMapFile || !m_pvMemoryImage", "Search System Failure", MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
#endif // _DEBUG
RaiseException((ec == ERROR_NOT_ENOUGH_MEMORY)? STATUS_NO_MEMORY : STATUS_SYSTEM_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
}
__finally
{
if (_abnormal_termination() && m_hMapFile)
{
CloseHandle(m_hMapFile); m_hMapFile= NULL;
}
}
return m_pvMemoryImage;
}
void CUnbufferedIO::MakePermanent(PSZ pszFileName, BOOL fAllowOverwrite, int cbSize)
{
// BugBug! If we have outstanding I/O transactions, will this call fail?
// Or will the CloseHandle call simply wait until the last transaction
// finishes? If not we'll have to add code to track the number of
// active I/O transactions.
BOOL fMoved = FALSE;
ASSERT(m_fTemporary);
FILENAMEBUFFER szFileName ;
FILENAMEBUFFER szName ;
FILENAMEBUFFER szExtension;
_splitpath(pszFileName, NULL, NULL, szName, szExtension);
lstrcpy(szFileName, m_szPath);
UINT cbPath= lstrlen(szFileName);
if (!cbPath || szFileName[cbPath - 1] != '\\')
lstrcat(szFileName, "\\");
lstrcat(szFileName, szName);
lstrcat(szFileName, szExtension);
CloseHandle(m_hFile);
m_fFileAttached = FALSE;
m_fTemporary = FALSE;
m_hFile = NULL;
m_cbSector = 0;
m_cbCluster = 0;
// REVIEW: Win95 supports MoveFileEx so why not use the same code for
// all three operating systems?
if (uOpSys != WIN40)
{
fMoved= MoveFileEx(m_szFile, szFileName,
fAllowOverwrite? MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING
: MOVEFILE_COPY_ALLOWED
);
}
else
{
if (fAllowOverwrite && lstrcmp(m_szFile, szFileName))
DeleteFile(szFileName);
fMoved= MoveFile(m_szFile, szFileName);
}
if (!fMoved)
{
BOOL fCopied= CopyFile(m_szFile, szFileName, !fAllowOverwrite);
DeleteFile(m_szFile);
if (!fCopied)
RaiseException(STATUS_DISK_WRITE_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
}
#ifdef _DEBUG
UINT uiLastError= GetLastError();
#endif // _DEBUG
CUnbufferedIO *puio= OpenExistingFile(fMoved? szFileName : m_szFile, TRUE);
if (!puio) RaiseException(STATUS_DISK_OPEN_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
m_hFile= puio->m_hFile;
if (fMoved && cbSize >= 0)
{
cbSize= puio->m_cbSector * ((cbSize + puio->m_cbSector - 1) / puio->m_cbSector);
SetFilePointer(m_hFile, cbSize, NULL, FILE_BEGIN);
SetEndOfFile (m_hFile);
}
m_fFileAttached = TRUE;
m_fTemporary = !fMoved;
m_cbSector = puio->m_cbSector;
m_cbCluster = puio->m_cbCluster;
lstrcpy(m_szFile, puio->m_szFile);
lstrcpy(m_szPath, puio->m_szPath);
puio->m_fFileAttached= FALSE;
delete puio;
}