OPENF.C

/*++ 

Copyright (c) 1995-1997 Microsoft Corporation

Module Name :

openf.c

Abstract:

This module implements a simple open file handle cache

Project:

ISAPI Extensions Sample DLL

Functions Exported:


Note:
THIS IS NOT ROBUST for REAL WORLD.
I wrote this for testing the ISAPI Async IO processing.

--*/


/************************************************************
* Include Headers
************************************************************/

# include "openf.h"


/************************************************************
* Type definitions and Globals
************************************************************/

//
// internal data structure for maintaining the list of open file handles.
//

typedef struct _OPEN_FILE {

HANDLE hFile;
struct _OPEN_FILE * pNext;
LONG nHits;
LONG nRefs;
CHAR rgchFile[MAX_PATH+1];

} OPEN_FILE, * LPOPEN_FILE;


LPOPEN_FILE g_pOpenFiles = NULL;
CRITICAL_SECTION g_csOpenFiles;
BOOL g_fIsNt = TRUE;

//
// Set up global variables containing the flags for CreateFile
// The flags can be masked for Windows 95 system
//

DWORD g_dwCreateFileShareMode =
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE);

DWORD g_dwCreateFileFlags =
(FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED);

/************************************************************
* Functions
************************************************************/


DWORD
InitFileHandleCache(VOID)
/*++

This function initializes the file handle cache.
It should be called at the initialization time.

Arguments:
None

Returns:
Win32 error code. NO_ERROR indicates that the call succeeded.
--*/
{
OSVERSIONINFO osInfo;

InitializeCriticalSection( &g_csOpenFiles);

//
// obtain the platform type to find out how to open the file
//

osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

if ( GetVersionEx( &osInfo ) ) {
g_fIsNt = (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
}

if ( !g_fIsNt) {

//
// Reset the flags appropriately so that Windows 95 will be happy
//

g_dwCreateFileShareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE);
g_dwCreateFileFlags = (FILE_FLAG_SEQUENTIAL_SCAN);
}

return (NO_ERROR);

} // InitFileHandleCache()




DWORD
CleanupFileHandleCache(VOID)
{
LPOPEN_FILE pFileScan;

while ( g_pOpenFiles != NULL) {

pFileScan = g_pOpenFiles;
g_pOpenFiles = g_pOpenFiles->pNext;

if ( pFileScan->hFile != INVALID_HANDLE_VALUE) {

CloseHandle( pFileScan->hFile);
}

LocalFree( pFileScan);
}

DeleteCriticalSection( &g_csOpenFiles);

return (NO_ERROR);
} // CleanupFileHandleCache()




HANDLE
FcOpenFile(IN EXTENSION_CONTROL_BLOCK * pecb, IN LPCSTR pszFile)
/*++

FcOpenFile()

Description:
This function opens the file specified in the 'pszFile'.
If the file name starts with a '/' we use the ECB to map
the given path into a physical file path.

Arguments:
pecb - pointer to the ECB block
pszFile - pointer to file name

Returns:
valid File handle on success
--*/
{
LPOPEN_FILE pFileScan;
HANDLE hFile = INVALID_HANDLE_VALUE;

EnterCriticalSection( &g_csOpenFiles);

for ( pFileScan = g_pOpenFiles;
NULL != pFileScan;
pFileScan = pFileScan->pNext) {

if ( 0 == lstrcmpi( pFileScan->rgchFile, pszFile)) {

//
// there is a file match.
//

break;
}

} // for


if ( NULL == pFileScan) {

//
// File was not found. Create a new file handle
//

CHAR rgchFileName[ MAX_PATH]; // local copy
LPCSTR pszInputPath = pszFile;

lstrcpyn( rgchFileName, pszFile, MAX_PATH);
if ( *pszFile == '/') {

DWORD cbSize = sizeof(rgchFileName);
BOOL fRet;

// reset the file pointer, so subsequent use will fail
pszFile = NULL;

//
// Using the ECB map the Virtual path to the Physical path
//

fRet = pecb->ServerSupportFunction( pecb->ConnID,
HSE_REQ_MAP_URL_TO_PATH,
rgchFileName,
&cbSize, NULL);

if (fRet) {
// we got the mapping. Use it.
pszFile = rgchFileName;
}
}

if ( NULL != pszFile) {
pFileScan = LocalAlloc( LPTR, sizeof( *pFileScan));

if ( NULL != pFileScan) {

SECURITY_ATTRIBUTES sa;

sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;

pFileScan->hFile =
CreateFile( pszFile,
GENERIC_READ,
g_dwCreateFileShareMode,
&sa,
OPEN_EXISTING,
g_dwCreateFileFlags,
NULL );

if ( INVALID_HANDLE_VALUE == pFileScan->hFile) {

LocalFree( pFileScan);
pFileScan = NULL;
} else {

// insert this into the list at the top
lstrcpyn( pFileScan->rgchFile, pszInputPath, MAX_PATH);
pFileScan->pNext = g_pOpenFiles;
g_pOpenFiles = pFileScan;
pFileScan->nRefs = 1;
pFileScan->nHits = 0;
}
}
}
}

if ( NULL != pFileScan) {

hFile = pFileScan->hFile;
pFileScan->nHits++;
pFileScan->nRefs++;
}

LeaveCriticalSection( &g_csOpenFiles);

return (hFile);

} // FcOpenFile()



DWORD
FcCloseFile(IN HANDLE hFile)
{
LPOPEN_FILE pFileScan;
DWORD dwError = NO_ERROR;

EnterCriticalSection( &g_csOpenFiles);

//
// Look for the handle and decrement the ref count.
//
for ( pFileScan = g_pOpenFiles;
NULL != pFileScan;
pFileScan = pFileScan->pNext) {

if ( hFile == pFileScan->hFile) {

//
// there is a file match.
//

pFileScan->nRefs--;

//
// BUGBUG: There is no freeing of the file when Ref hits '0' :(
//

break;
}

} // for


if ( NULL == pFileScan) {
//
// file handle not found
//
dwError = ( ERROR_INVALID_HANDLE);
}

LeaveCriticalSection( &g_csOpenFiles);


return ( dwError);

} // FcCloseFile()




BOOL
FcReadFromFile(
IN HANDLE hFile,
OUT CHAR * pchBuffer,
IN DWORD dwBufferSize,
OUT LPDWORD pcbRead,
IN OUT LPOVERLAPPED pov
)
/*++
Description:
Reads contents of file [hFile] from the specified offset in the overlapped
structure. The contents are read into the buffer supplied.

Arguments:
hFile - handle for the File from which to read data
pchBuffer - pointer to the buffer into which the data is to be read
dwBufferSize - DWORD containing the max size of the buffer supplied
pcbRead - number of bytes read from the file
pov - pointer to an overlapped structure that contains the
offset from where to read the contents. The
overlapped structure also is used for Overlapped
IO in NT.

Notes:
This function automatically handles both Windows 95 and NT


Returns:
TRUE on success and FALSE if there is a failure.
Use GetLastError() to get the last error code on failure.
--*/
{
BOOL fRet = TRUE;

*pcbRead = 0;

if ( !g_fIsNt ) {
//
// Windows95 does not support Overlapped IO.
// So we shall thunk it out and use Synchronous IO
//

fRet = (
SetFilePointer( hFile,
pov->Offset,
NULL,
FILE_BEGIN) &&
ReadFile( hFile,
pchBuffer,
dwBufferSize,
pcbRead,
NULL
)
);
} else {

ResetEvent( pov->hEvent);

fRet = TRUE;

// read data from file
if (!ReadFile(hFile,
pchBuffer,
dwBufferSize,
pcbRead,
pov
)) {

DWORD err = GetLastError();

if ( (err != ERROR_IO_PENDING) ||
!GetOverlappedResult( hFile, pov,
pcbRead, TRUE)) {

fRet = FALSE;
}
}
}

if ( fRet) {
pov->Offset += *pcbRead;
}

return ( fRet);
} // FcReadFromFile()

/************************ End of File ***********************/