/*++ 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 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 ***********************/