451 lines
11 KiB
C
451 lines
11 KiB
C
/*++
|
||
|
||
Copyright (c) 1995-1996 Microsoft Corporation
|
||
|
||
Module Name :
|
||
|
||
openf.c
|
||
|
||
Abstract:
|
||
|
||
This module implements a simple open file handle cache
|
||
|
||
Author:
|
||
|
||
Murali R. Krishnan ( MuraliK ) 30-Apr-1996
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Project:
|
||
|
||
Internet Server 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"
|
||
|
||
#define DEFAULT_TRACE_FLAGS (DEBUG_ERROR)
|
||
|
||
#include "dbgutil.h"
|
||
|
||
#include <initguid.h>
|
||
DEFINE_GUID(IisFtransGuid,
|
||
0x784d8935, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
|
||
|
||
|
||
/************************************************************
|
||
* Type definitions and Globals
|
||
************************************************************/
|
||
|
||
#ifdef _NO_TRACING_
|
||
DECLARE_DEBUG_VARIABLE();
|
||
#endif
|
||
DECLARE_DEBUG_PRINTS_OBJECT();
|
||
DECLARE_PLATFORM_TYPE();
|
||
|
||
//
|
||
// 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;
|
||
|
||
//
|
||
// 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.
|
||
--*/
|
||
{
|
||
|
||
#ifdef _NO_TRACING_
|
||
CREATE_DEBUG_PRINT_OBJECT( "TEST_ISAPI-openf");
|
||
#else
|
||
CREATE_DEBUG_PRINT_OBJECT( "TEST_ISAPI-openf", IisFtransGuid);
|
||
#endif
|
||
if ( !VALID_DEBUG_PRINT_OBJECT()) {
|
||
|
||
return ( GetLastError());
|
||
}
|
||
|
||
INITIALIZE_CRITICAL_SECTION( &g_csOpenFiles);
|
||
|
||
#ifdef _NO_TRACING_
|
||
SET_DEBUG_FLAGS(DEBUG_ERROR);
|
||
#endif
|
||
INITIALIZE_PLATFORM_TYPE();
|
||
DBG_ASSERT( IISIsValidPlatform());
|
||
|
||
if ( TsIsWindows95()) {
|
||
|
||
//
|
||
// 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);
|
||
|
||
DELETE_DEBUG_PRINT_OBJECT();
|
||
|
||
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--;
|
||
|
||
//
|
||
// NOTE: 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;
|
||
|
||
DBG_ASSERT( hFile != INVALID_HANDLE_VALUE);
|
||
DBG_ASSERT( NULL != pchBuffer);
|
||
DBG_ASSERT( NULL != pov);
|
||
DBG_ASSERT( NULL != pcbRead);
|
||
DBG_ASSERT( 0 < dwBufferSize);
|
||
|
||
*pcbRead = 0;
|
||
|
||
if ( TsIsWindows95()) {
|
||
//
|
||
// Windows95 does not support Overlapped IO.
|
||
// So we shall thunk it out and use Synchronous IO
|
||
//
|
||
|
||
DWORD dwError = SetFilePointer( hFile,
|
||
pov->Offset,
|
||
NULL,
|
||
FILE_BEGIN);
|
||
|
||
// Apparently SetFilePointer() returns -1 for failure.
|
||
fRet = (dwError != 0xFFFFFFFF);
|
||
|
||
if ( fRet) {
|
||
fRet = ReadFile( hFile,
|
||
pchBuffer,
|
||
dwBufferSize,
|
||
pcbRead,
|
||
NULL
|
||
);
|
||
if ( fRet && (*pcbRead == 0)) {
|
||
// we are at end of file
|
||
fRet = FALSE;
|
||
SetLastError( ERROR_HANDLE_EOF);
|
||
}
|
||
}
|
||
|
||
} 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 ***********************/
|