|
|
/**********************************************************************/ /** Microsoft Windows NT **/ /** Copyright(c) Microsoft Corp., 1998 **/ /**********************************************************************/
/*
fileinfo.cxx
This module contains the methods for TS_OPEN_FILE_INFO
FILE HISTORY: MCourage 09-Dec-1997 Created */
#include <tsunami.hxx>
#include "tsunamip.hxx"
#include <iistypes.hxx>
#include <acache.hxx>
#include <imd.h>
#include <mb.hxx>
#include "string.h"
#include "filecach.hxx"
#include "filehash.hxx"
#include "tlcach.h"
#include "etagmb.h"
GENERIC_MAPPING g_gmFile = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
ALLOC_CACHE_HANDLER * TS_OPEN_FILE_INFO::sm_pachFileInfos; CRITICAL_SECTION TS_OPEN_FILE_INFO::sm_cs;
TS_OPEN_FILE_INFO::TS_OPEN_FILE_INFO() : m_Signature(TS_FILE_INFO_SIGNATURE), m_hFile(INVALID_HANDLE_VALUE), m_pFileBuffer(0), m_hUser(INVALID_HANDLE_VALUE), m_cbSecDescMaxSize(0), m_pSecurityDescriptor(m_abSecDesc), m_fSecurityDescriptor(FALSE), m_cchHttpInfo(0), m_cchETag(0), m_ETagIsWeak(TRUE), m_bIsCached(FALSE), m_state(FI_UNINITIALIZED), m_lRefCount(0), m_dwIORefCount(0), m_TTL(1), m_FileAttributes(0xFFFFFFFF), m_pvContext( NULL ), m_pfnFreeRoutine( NULL ) { m_FileKey.m_cbFileName = 0; m_FileKey.m_pszFileName = NULL; }
BOOL TS_OPEN_FILE_INFO::SetContext( PVOID pvContext, PCONTEXT_FREE_ROUTINE pfnFreeRoutine ) /*++
Routine Description
Used by external components (SSI) to set an opaque context and a free routine to be called when freeing the context. This allows SSI to associate the SSI parsed template with actual TS_OPEN_FILE_INFO
Arguments
None.
Return
TRUE if the context was set. FALSE if there was already a context.
--*/ { BOOL fRet;
Lock();
if ( m_pvContext != NULL ) { fRet = FALSE; } else { m_pvContext = pvContext; m_pfnFreeRoutine = pfnFreeRoutine; fRet = TRUE; }
Unlock();
return fRet; }
PVOID TS_OPEN_FILE_INFO::QueryContext( VOID ) const /*++
Routine Description
Returns the context associated with the TS_OPEN_FILE_INFO
Arguments
None.
Return
Pointer to context
--*/ { PVOID pvContext;
Lock(); pvContext = m_pvContext; Unlock();
return pvContext; }
VOID TS_OPEN_FILE_INFO::FreeContext( VOID ) /*++
Routine Description
Frees the opaque context by calling the free routine
Arguments
None.
Return
None
--*/ { Lock(); if ( m_pvContext ) { if ( m_pfnFreeRoutine ) { __try { m_pfnFreeRoutine( m_pvContext ); } __finally { m_pvContext = NULL; } } else { DBG_ASSERT( FALSE ); } } Unlock(); }
BOOL FileFlushFilterContext( TS_OPEN_FILE_INFO *pOpenFile, PVOID pv ) /*++
Routine Description
Filter used by FilteredFlushFileCache to select those TS_OPEN_FILE_INFO objects which have a context. This routine will actually do the freeing and will return FALSE. This is done to prevent premature flushing of the cache when SSI shuts down.
Arguments
pOpenFile - TS_OPEN_FILE_INFO object pv - Unused context
Return
Always returns FALSE
--*/ { DBG_ASSERT( pOpenFile );
pOpenFile->FreeContext();
DBG_ASSERT( !pOpenFile->QueryContext() );
return FALSE; }
VOID TsFlushFilesWithContext( VOID ) /*++
Routine Description
Exported routine used by SSI to free all opaque contexts. This is called before SSINC.DLL is unloaded to prevent AVs in context free
Arguments
None
Return
None
--*/ { FilteredFlushFileCache( FileFlushFilterContext, NULL ); }
BOOL TS_OPEN_FILE_INFO::SetFileName(const CHAR * pszFileName) { DBG_ASSERT( pszFileName ); DBG_ASSERT( pszFileName[0] );
m_FileKey.m_cbFileName = strlen(pszFileName);
if (m_FileKey.m_cbFileName < TS_DEFAULT_PATH_SIZE) { //
// It fits in our fixed size buffer
//
m_FileKey.m_pszFileName = m_FileKey.m_achFileNameBuf; } else { //
// we need a bigger buffer
//
m_FileKey.m_pszFileName = new CHAR[m_FileKey.m_cbFileName + 1]; }
if (NULL != m_FileKey.m_pszFileName) { memcpy(m_FileKey.m_pszFileName, pszFileName, m_FileKey.m_cbFileName + 1); } else { m_FileKey.m_cbFileName = 0; }
return (0 != m_FileKey.m_cbFileName); }
TS_OPEN_FILE_INFO::~TS_OPEN_FILE_INFO( VOID) { DBG_ASSERT( 0 == m_lRefCount ); DBG_ASSERT( 0 == m_dwIORefCount ); DBG_ASSERT( CheckSignature() );
m_Signature = TS_FREE_FILE_INFO_SIGNATURE;
if (m_FileKey.m_pszFileName && (m_FileKey.m_achFileNameBuf != m_FileKey.m_pszFileName)) {
delete [] m_FileKey.m_pszFileName; }
if (m_pFileBuffer) { DWORD dwError;
dwError = ReleaseFromMemoryCache( m_pFileBuffer, m_nFileSizeLow );
DBG_ASSERT(dwError == ERROR_SUCCESS); }
if (m_hFile != INVALID_HANDLE_VALUE) { ::CloseHandle(m_hFile); }
if (m_pSecurityDescriptor && (m_pSecurityDescriptor != m_abSecDesc)) { FREE(m_pSecurityDescriptor); }
if (m_pvContext) { FreeContext(); } }
BOOL TS_OPEN_FILE_INFO::AccessCheck( IN HANDLE hUser, IN BOOL bCache ) { DBG_ASSERT(hUser != INVALID_HANDLE_VALUE);
//
// If it's the same user that last opened the file
// then we know we have access.
//
if (hUser == m_hUser) { TraceCheckpointEx(TS_MAGIC_ACCESS_CHECK, (PVOID)hUser, (PVOID)(LONG_PTR)0xffffffff); return TRUE; }
//
// If we've got a security descriptor we can check
// against that, otherwise fail the check.
//
BYTE psFile[SIZE_PRIVILEGE_SET]; DWORD dwPS; DWORD dwGrantedAccess; BOOL fAccess;
dwPS = sizeof(psFile); ((PRIVILEGE_SET*)&psFile)->PrivilegeCount = 0;
if (m_fSecurityDescriptor && ::AccessCheck(m_pSecurityDescriptor, hUser, FILE_GENERIC_READ, &g_gmFile, (PRIVILEGE_SET*)psFile, &dwPS, &dwGrantedAccess, &fAccess) ) {
if (fAccess && bCache) { m_hUser = hUser; }
TraceCheckpointEx(TS_MAGIC_ACCESS_CHECK, (PVOID)hUser, (PVOID) (ULONG_PTR) fAccess); return fAccess; } else { return FALSE; } }
VOID TS_OPEN_FILE_INFO::SetFileInfo( HANDLE hFile, HANDLE hUser, PSECURITY_DESCRIPTOR pSecDesc, DWORD dwSecDescSize, PBY_HANDLE_FILE_INFORMATION pFileInfo, PBYTE pFileBuff ) { m_FileAttributes = pFileInfo->dwFileAttributes; m_nFileSizeLow = pFileInfo->nFileSizeLow; m_nFileSizeHigh = pFileInfo->nFileSizeHigh;
m_ftLastWriteTime = pFileInfo->ftLastWriteTime;
//
// Save file buffer
//
m_pFileBuffer = pFileBuff;
//
// Save away the given parameters
//
m_hFile = hFile; m_hUser = hUser;
m_pSecurityDescriptor = pSecDesc; m_cbSecDescMaxSize = dwSecDescSize; if (dwSecDescSize) m_fSecurityDescriptor = TRUE;
//
// Generate some other file attributes
//
DWORD dwChangeNumber = ETagChangeNumber::GetChangeNumber(); BOOL fReturn = TRUE; UINT64 Int64Value = (FILETIMEToUINT64(m_ftLastWriteTime) / 10000000) * 10000000;
m_CastratedLastWriteTime = UINT64ToFILETIME(Int64Value);
//
// Make the ETag
//
m_ETagIsWeak = TRUE;
m_cchETag = FORMAT_ETAG(m_achETag, *(FILETIME*) &m_ftLastWriteTime, dwChangeNumber);
//
// Make the ETag strong if possible
//
MakeStrongETag();
//
// Turn off the hidden attribute if this is a root directory listing
// (root some times has the bit set for no apparent reason)
//
if ( m_FileAttributes & FILE_ATTRIBUTE_HIDDEN ) { CHAR * pszFileName = m_FileKey.m_pszFileName; if ( m_FileKey.m_cbFileName >= 2 ) { if ( pszFileName[ 1 ] == ':' ) { if ( ( pszFileName[ 2 ] == '\0' ) || ( pszFileName[ 2 ] == '\\' && pszFileName[ 3 ] == '\0' ) ) { //
// This looks like a local root. Mask out the bit
//
m_FileAttributes &= ~FILE_ATTRIBUTE_HIDDEN; } } } } }
VOID TS_OPEN_FILE_INFO::CloseHandle( void ) { HANDLE hFile; PBYTE pFileBuffer; BOOL bClose = FALSE; BOOL bRelease = FALSE; DWORD dwError;
Lock(); ASSERT( DisableTsunamiCaching || (m_state == FI_FLUSHED) || (m_bIsCached == FALSE) ); ASSERT( m_dwIORefCount == 0 );
m_state = FI_CLOSED;
if (m_pFileBuffer) { pFileBuffer = m_pFileBuffer; m_pFileBuffer = NULL;
bRelease = TRUE; }
if (m_hFile != INVALID_HANDLE_VALUE) { hFile = m_hFile; m_hFile = INVALID_HANDLE_VALUE;
bClose = TRUE; }
Unlock();
if (bRelease) { TraceCheckpointEx(TS_MAGIC_CLOSE, pFileBuffer, (PVOID) 1);
dwError = ReleaseFromMemoryCache( pFileBuffer, m_nFileSizeLow );
DBG_ASSERT(dwError == ERROR_SUCCESS); }
if (bClose) { TraceCheckpointEx(TS_MAGIC_CLOSE, hFile, 0); ::CloseHandle(hFile); } }
INT FormatETag( PCHAR pszBuffer, const FILETIME& rft, DWORD mdchange) { PCHAR psz = pszBuffer; PBYTE pbTime = (PBYTE) &rft; const char szHex[] = "0123456789abcdef";
*psz++ = '\"'; for (int i = 0; i < 8; i++) { BYTE b = *pbTime++; BYTE bH = b >> 4; if (bH != 0) *psz++ = szHex[bH]; *psz++ = szHex[b & 0xF]; } *psz++ = ':'; psz += strlen(_itoa((DWORD) mdchange, psz, 16)); *psz++ = '\"'; *psz = '\0';
return (INT)(psz - pszBuffer); }
VOID TS_OPEN_FILE_INFO::MakeStrongETag( VOID ) /*++
Routine Description
Try and make an ETag 'strong'. To do this we see if the difference between now and the last modified date is greater than our strong ETag delta - if so, we mark the ETag strong.
Arguments
None.
Returns
Nothing.
--*/ { FILETIME ftNow; SYSTEMTIME stNow; FILETIME iNow, iFileTime;
if ( m_pFileBuffer || m_hFile != INVALID_HANDLE_VALUE ) { ::GetSystemTimeAsFileTime(&ftNow);
iNow = ftNow; iFileTime = m_ftLastWriteTime;
if ((FILETIMEToUINT64(iNow) - FILETIMEToUINT64(iFileTime)) > STRONG_ETAG_DELTA ) { m_ETagIsWeak = FALSE; } } }
BOOL TS_OPEN_FILE_INFO::SetHttpInfo( IN PSTR pszInfo, IN INT InfoLength ) /*++
Routine Description
Set the "Last-Modified:" header field in the file structure.
Arguments
pszDate - pointer to the header value to save InfoLength - length of the header value to save
Returns
TRUE if information was cached, FALSE if not cached
--*/ { if ( !m_ETagIsWeak && InfoLength < sizeof(m_achHttpInfo)-1 ) {
CopyMemory( m_achHttpInfo, pszInfo, InfoLength+1 );
//
// this MUST be set after updating the array,
// as this is checked to know if the array content is valid.
//
m_cchHttpInfo = InfoLength; return TRUE; } return FALSE; } // TS_OPEN_FILE_INFO::SetHttpInfo
/*
* Static members */
BOOL TS_OPEN_FILE_INFO::Initialize( DWORD dwMaxFiles ) { ALLOC_CACHE_CONFIGURATION acConfig = { 1, dwMaxFiles, sizeof(TS_OPEN_FILE_INFO)};
if ( NULL != sm_pachFileInfos) {
// already initialized
return ( TRUE); }
sm_pachFileInfos = new ALLOC_CACHE_HANDLER( "FileInfos", &acConfig);
if ( sm_pachFileInfos ) { INITIALIZE_CRITICAL_SECTION(&sm_cs); }
return ( NULL != sm_pachFileInfos); }
VOID TS_OPEN_FILE_INFO::Cleanup( VOID ) { if ( NULL != sm_pachFileInfos) {
delete sm_pachFileInfos; sm_pachFileInfos = NULL;
DeleteCriticalSection(&sm_cs); } }
VOID TS_OPEN_FILE_INFO::Lock( VOID ) { EnterCriticalSection(&sm_cs); }
VOID TS_OPEN_FILE_INFO::Unlock( VOID ) { LeaveCriticalSection(&sm_cs); }
VOID * TS_OPEN_FILE_INFO::operator new( size_t s) { DBG_ASSERT( s == sizeof( TS_OPEN_FILE_INFO));
// allocate from allocation cache.
DBG_ASSERT( NULL != sm_pachFileInfos); return (sm_pachFileInfos->Alloc()); }
VOID TS_OPEN_FILE_INFO::operator delete( void * pOpenFile) { DBG_ASSERT( NULL != pOpenFile);
// free to the allocation pool
DBG_ASSERT( NULL != sm_pachFileInfos); DBG_REQUIRE( sm_pachFileInfos->Free(pOpenFile));
return; }
//
// fileopen.cxx
//
|