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