You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
671 lines
13 KiB
671 lines
13 KiB
#ifndef _FILECACHE_HXX_
|
|
#define _FILECACHE_HXX_
|
|
|
|
#include "datetime.hxx"
|
|
#include "usercache.hxx"
|
|
|
|
//
|
|
// Users of the file cache can associate (1) object with a cache entry which
|
|
// will get cleaned up (by calling the Cleanup() method) when the object
|
|
// is flushed
|
|
//
|
|
|
|
class ASSOCIATED_FILE_OBJECT
|
|
{
|
|
public:
|
|
|
|
virtual
|
|
VOID
|
|
Cleanup(
|
|
VOID
|
|
) = 0;
|
|
};
|
|
|
|
class W3_FILE_INFO_KEY : public CACHE_KEY
|
|
{
|
|
public:
|
|
|
|
W3_FILE_INFO_KEY()
|
|
: _strFileKey( _achFileKey, sizeof( _achFileKey ) ),
|
|
_pszFileKey( NULL ),
|
|
_cchFileKey( 0 )
|
|
{
|
|
}
|
|
|
|
virtual ~W3_FILE_INFO_KEY()
|
|
{
|
|
}
|
|
|
|
WCHAR *
|
|
QueryHintKey(
|
|
VOID
|
|
)
|
|
{
|
|
return _pszFileKey;
|
|
}
|
|
|
|
HRESULT
|
|
CreateCacheKey(
|
|
WCHAR * pszFileKey,
|
|
DWORD cchFileKey,
|
|
BOOL fCopy
|
|
);
|
|
|
|
DWORD
|
|
QueryKeyHash(
|
|
VOID
|
|
) const
|
|
{
|
|
return HashString( _pszFileKey );
|
|
}
|
|
|
|
BOOL
|
|
QueryIsEqual(
|
|
const CACHE_KEY * pCacheCompareKey
|
|
) const
|
|
{
|
|
W3_FILE_INFO_KEY * pFileKey = (W3_FILE_INFO_KEY*) pCacheCompareKey;
|
|
|
|
return _cchFileKey == pFileKey->_cchFileKey &&
|
|
!wcscmp( _pszFileKey, pFileKey->_pszFileKey );
|
|
}
|
|
|
|
WCHAR _achFileKey[ 64 ];
|
|
STRU _strFileKey;
|
|
WCHAR * _pszFileKey;
|
|
DWORD _cchFileKey;
|
|
};
|
|
|
|
// The maximum length of an ETag is 16 chars for the last modified time plus
|
|
// one char for the colon plus 2 chars for the quotes plus 8 chars for the
|
|
// system change notification number plus two for the optional prefix W/ and
|
|
// one for the trailing NULL, for a total of 30 chars.
|
|
|
|
#define MAX_ETAG_BUFFER_LENGTH 30
|
|
|
|
//
|
|
// Embedded security descriptor used for cache hits
|
|
//
|
|
|
|
#define SECURITY_DESC_DEFAULT_SIZE 256
|
|
|
|
class W3_FILE_INFO;
|
|
|
|
//
|
|
// The context used for async file reads
|
|
//
|
|
|
|
typedef VOID (* W3_CACHE_CALLBACK_FUNCTION)(PVOID pContext,
|
|
HRESULT hr);
|
|
|
|
typedef struct
|
|
{
|
|
//
|
|
// Callback function to be notified
|
|
//
|
|
W3_CACHE_CALLBACK_FUNCTION pfnCallback;
|
|
|
|
//
|
|
// Overlapped for async file read
|
|
//
|
|
OVERLAPPED Overlapped;
|
|
|
|
//
|
|
// The file-info for which this async IO is being done
|
|
//
|
|
W3_FILE_INFO *pFileInfo;
|
|
|
|
} FILE_CACHE_ASYNC_CONTEXT;
|
|
|
|
//
|
|
// File cache entry object
|
|
//
|
|
|
|
#define W3_FILE_INFO_SIGNATURE ((DWORD)'IF3W')
|
|
#define W3_FILE_INFO_SIGNATURE_FREE ((DWORD)'if3w')
|
|
|
|
class W3_FILE_INFO : public CACHE_ENTRY
|
|
{
|
|
public:
|
|
|
|
W3_FILE_INFO( OBJECT_CACHE * pObjectCache )
|
|
: CACHE_ENTRY( pObjectCache ),
|
|
_hFile( INVALID_HANDLE_VALUE ),
|
|
_pFileBuffer( NULL ),
|
|
_dwFileAttributes( 0 ),
|
|
_nFileSizeLow( 0 ),
|
|
_nFileSizeHigh( 0 ),
|
|
_bufSecDesc( _abSecDesc, sizeof( _abSecDesc ) ),
|
|
_cchETag( 0 ),
|
|
_pAssociatedObject( NULL ),
|
|
_pLastSid( NULL ),
|
|
_fUlCacheAllowed( FALSE ),
|
|
_msLastAttributeCheckTime( 0 )
|
|
{
|
|
_dwSignature = W3_FILE_INFO_SIGNATURE;
|
|
}
|
|
|
|
virtual ~W3_FILE_INFO(
|
|
VOID
|
|
);
|
|
|
|
VOID *
|
|
operator new(
|
|
#if DBG
|
|
size_t size
|
|
#else
|
|
size_t
|
|
#endif
|
|
)
|
|
{
|
|
DBG_ASSERT( size == sizeof( W3_FILE_INFO ) );
|
|
DBG_ASSERT( sm_pachW3FileInfo != NULL );
|
|
return sm_pachW3FileInfo->Alloc();
|
|
}
|
|
|
|
VOID
|
|
operator delete(
|
|
VOID * pW3FileInfo
|
|
)
|
|
{
|
|
DBG_ASSERT( pW3FileInfo != NULL );
|
|
DBG_ASSERT( sm_pachW3FileInfo != NULL );
|
|
|
|
DBG_REQUIRE( sm_pachW3FileInfo->Free( pW3FileInfo ) );
|
|
}
|
|
|
|
CACHE_KEY *
|
|
QueryCacheKey(
|
|
VOID
|
|
) const
|
|
{
|
|
return (CACHE_KEY*) &_cacheKey;
|
|
}
|
|
|
|
BOOL
|
|
QueryIsOkToFlushDirmon(
|
|
WCHAR * pszPath,
|
|
DWORD cchPath
|
|
);
|
|
|
|
BOOL
|
|
CheckSignature(
|
|
VOID
|
|
) const
|
|
{
|
|
return _dwSignature == W3_FILE_INFO_SIGNATURE;
|
|
}
|
|
|
|
virtual
|
|
BOOL
|
|
Checkout(
|
|
CACHE_USER *pOpeningUser
|
|
);
|
|
|
|
HRESULT
|
|
GetFileHandle(
|
|
HANDLE * phHandle
|
|
);
|
|
|
|
PBYTE
|
|
QueryFileBuffer(
|
|
VOID
|
|
) const
|
|
{
|
|
return _pFileBuffer;
|
|
}
|
|
|
|
VOID
|
|
QuerySize(
|
|
ULARGE_INTEGER * pliSize
|
|
) const
|
|
{
|
|
DBG_ASSERT( pliSize != NULL );
|
|
pliSize->LowPart = _nFileSizeLow;
|
|
pliSize->HighPart = _nFileSizeHigh;
|
|
}
|
|
|
|
WCHAR *
|
|
QueryPhysicalPath(
|
|
VOID
|
|
)
|
|
{
|
|
return _cacheKey._pszFileKey;
|
|
}
|
|
|
|
DWORD
|
|
QueryAttributes(
|
|
VOID
|
|
) const
|
|
{
|
|
return _dwFileAttributes;
|
|
}
|
|
|
|
PSECURITY_DESCRIPTOR
|
|
QuerySecDesc(
|
|
VOID
|
|
);
|
|
|
|
PSID
|
|
QueryLastSid(
|
|
VOID
|
|
)
|
|
{
|
|
return _pLastSid;
|
|
}
|
|
|
|
VOID
|
|
QueryLastWriteTime(
|
|
FILETIME * pFileTime
|
|
) const
|
|
{
|
|
DBG_ASSERT( pFileTime != NULL );
|
|
|
|
memcpy( pFileTime,
|
|
&_CastratedLastWriteTime,
|
|
sizeof( *pFileTime ) );
|
|
}
|
|
|
|
CHAR *
|
|
QueryLastModifiedString(
|
|
VOID
|
|
)
|
|
{
|
|
return _achLastModified;
|
|
}
|
|
|
|
BOOL
|
|
QueryIsWeakETag(
|
|
VOID
|
|
) const
|
|
{
|
|
return _achETag[ 0 ] == 'W' && _achETag[ 1 ] == '/';
|
|
}
|
|
|
|
HANDLE
|
|
QueryFileHandle(
|
|
VOID
|
|
)
|
|
{
|
|
return _hFile;
|
|
}
|
|
|
|
CHAR *
|
|
QueryETag(
|
|
|
|
VOID
|
|
)
|
|
{
|
|
return _achETag;
|
|
}
|
|
|
|
USHORT
|
|
QueryETagSize(
|
|
VOID
|
|
) const
|
|
{
|
|
return _cchETag;
|
|
}
|
|
|
|
DWORD
|
|
QueryLastAttributeCheckTime(
|
|
VOID
|
|
) const
|
|
{
|
|
return _msLastAttributeCheckTime;
|
|
}
|
|
|
|
dllexp
|
|
BOOL
|
|
SetAssociatedObject(
|
|
ASSOCIATED_FILE_OBJECT * pObject
|
|
);
|
|
|
|
ASSOCIATED_FILE_OBJECT *
|
|
QueryAssociatedObject(
|
|
VOID
|
|
)
|
|
{
|
|
return _pAssociatedObject;
|
|
}
|
|
|
|
HRESULT
|
|
OpenFile(
|
|
STRU & strFileName,
|
|
CACHE_USER * pOpeningUser,
|
|
BOOL fBufferFile
|
|
);
|
|
|
|
HRESULT
|
|
DoAccessCheck(
|
|
CACHE_USER * pOpeningUser
|
|
);
|
|
|
|
HRESULT
|
|
MakeCacheable(
|
|
CACHE_USER * pOpeningUser,
|
|
FILE_CACHE_ASYNC_CONTEXT *pAsyncContext,
|
|
BOOL *pfHandledSync,
|
|
BOOL fCheckForExistenceOnly
|
|
);
|
|
|
|
VOID
|
|
AllowUlCache(
|
|
VOID
|
|
)
|
|
{
|
|
_fUlCacheAllowed = TRUE;
|
|
}
|
|
|
|
BOOL
|
|
QueryUlCacheAllowed(
|
|
VOID
|
|
) const
|
|
{
|
|
return _fUlCacheAllowed;
|
|
}
|
|
|
|
BOOL
|
|
IsUlCacheable(
|
|
VOID
|
|
) const;
|
|
|
|
BOOL
|
|
IsCacheable(
|
|
VOID
|
|
) const;
|
|
|
|
HRESULT
|
|
CheckIfFileHasChanged(
|
|
BOOL * pfHasChanged,
|
|
CACHE_USER * pOpeningUser
|
|
);
|
|
|
|
static
|
|
HRESULT
|
|
Initialize(
|
|
VOID
|
|
);
|
|
|
|
static
|
|
VOID
|
|
Terminate(
|
|
VOID
|
|
);
|
|
|
|
static
|
|
VOID
|
|
CALLBACK
|
|
FileReadCompletion(
|
|
DWORD dwErrorCode,
|
|
DWORD dwNumberOfBytesTransfered,
|
|
LPOVERLAPPED lpOverlapped);
|
|
|
|
private:
|
|
|
|
W3_FILE_INFO(const W3_FILE_INFO &);
|
|
void operator=(const W3_FILE_INFO &);
|
|
|
|
HRESULT
|
|
ReadSecurityDescriptor(
|
|
VOID
|
|
);
|
|
|
|
HRESULT
|
|
GenerateETag(
|
|
VOID
|
|
);
|
|
|
|
HRESULT
|
|
GenerateLastModifiedTimeString(
|
|
VOID
|
|
);
|
|
|
|
DWORD _dwSignature;
|
|
|
|
W3_FILE_INFO_KEY _cacheKey;
|
|
|
|
//
|
|
// File info data
|
|
//
|
|
|
|
HANDLE _hFile;
|
|
PBYTE _pFileBuffer;
|
|
FILETIME _ftLastWriteTime;
|
|
FILETIME _CastratedLastWriteTime;
|
|
DWORD _dwFileAttributes;
|
|
ULONG _nFileSizeLow;
|
|
ULONG _nFileSizeHigh;
|
|
|
|
//
|
|
// Security descriptor stuff
|
|
//
|
|
|
|
BYTE _abSecDesc[ SECURITY_DESC_DEFAULT_SIZE ];
|
|
BUFFER _bufSecDesc;
|
|
|
|
//
|
|
// ETag
|
|
//
|
|
|
|
CHAR _achETag[ MAX_ETAG_BUFFER_LENGTH ];
|
|
USHORT _cchETag;
|
|
|
|
//
|
|
// Last modified time
|
|
//
|
|
|
|
CHAR _achLastModified[ GMT_STRING_SIZE ];
|
|
|
|
//
|
|
// Last SID to access the file
|
|
//
|
|
|
|
BYTE _abLastSid[ 64 ];
|
|
PSID _pLastSid;
|
|
|
|
//
|
|
// UL cache status
|
|
//
|
|
BOOL _fUlCacheAllowed;
|
|
|
|
//
|
|
// Associated object (only one is allowed)
|
|
//
|
|
|
|
ASSOCIATED_FILE_OBJECT* _pAssociatedObject;
|
|
|
|
//
|
|
// TickCount since file was last checked for change
|
|
//
|
|
|
|
DWORD _msLastAttributeCheckTime;
|
|
|
|
//
|
|
// Lookaside
|
|
//
|
|
|
|
static ALLOC_CACHE_HANDLER * sm_pachW3FileInfo;
|
|
};
|
|
|
|
//
|
|
// The file cache itself
|
|
//
|
|
|
|
#define DEFAULT_FILE_SIZE_THRESHOLD (256*1024)
|
|
#define DEFAULT_FILE_ATTRIBUTE_CHECK_THRESHOLD (5) // in seconds
|
|
|
|
#define DEFAULT_W3_FILE_INFO_CACHE_TTL (30)
|
|
#define DEFAULT_W3_FILE_INFO_CACHE_ACTIVITY (10)
|
|
|
|
class W3_FILE_INFO_CACHE : public OBJECT_CACHE
|
|
{
|
|
public:
|
|
|
|
W3_FILE_INFO_CACHE();
|
|
|
|
virtual ~W3_FILE_INFO_CACHE();
|
|
|
|
dllexp
|
|
HRESULT
|
|
GetFileInfo(
|
|
STRU & strFileName,
|
|
DIRMON_CONFIG * pDirmonConfig,
|
|
CACHE_USER * pOpeningUser,
|
|
BOOL fDoCache,
|
|
W3_FILE_INFO ** ppFileInfo,
|
|
FILE_CACHE_ASYNC_CONTEXT *pAsyncContext = NULL,
|
|
BOOL *pfHandledSync = NULL,
|
|
BOOL fAllowNoBuffering = FALSE,
|
|
BOOL fCheckForExistanceOnly = FALSE
|
|
);
|
|
|
|
WCHAR *
|
|
QueryName(
|
|
VOID
|
|
) const
|
|
{
|
|
return L"W3_FILE_INFO_CACHE";
|
|
}
|
|
|
|
HRESULT
|
|
ReadFileIntoMemoryCache(
|
|
HANDLE hFile,
|
|
DWORD cbFile,
|
|
VOID ** ppvFileBuffer,
|
|
FILE_CACHE_ASYNC_CONTEXT *pAsyncContext,
|
|
BOOL *pfHandledSync
|
|
);
|
|
|
|
HRESULT
|
|
ReleaseFromMemoryCache(
|
|
VOID * pFileBuffer,
|
|
DWORD cbFileBuffer
|
|
);
|
|
|
|
VOID
|
|
DoDirmonInvalidationSpecific(
|
|
WCHAR * pszPath
|
|
);
|
|
|
|
ULONGLONG
|
|
QueryFileSizeThreshold(
|
|
VOID
|
|
) const
|
|
{
|
|
return _cbFileSizeThreshold;
|
|
}
|
|
|
|
DWORD
|
|
QueryFileAttributeCheckThreshold(
|
|
VOID
|
|
) const
|
|
{
|
|
return _cmsecFileAttributeCheckThreshold;
|
|
}
|
|
|
|
BOOL
|
|
QueryCacheEnabled(
|
|
VOID
|
|
) const
|
|
{
|
|
return _fEnableCache;
|
|
}
|
|
|
|
BOOL
|
|
QueryElementLimitExceeded(
|
|
VOID
|
|
)
|
|
{
|
|
return _cMaxFileEntries && _cMaxFileEntries <= PerfQueryCurrentEntryCount();
|
|
}
|
|
|
|
ULONGLONG
|
|
PerfQueryCurrentMemCacheSize(
|
|
VOID
|
|
) const
|
|
{
|
|
return _cbMemCacheCurrentSize;
|
|
}
|
|
|
|
ULONGLONG
|
|
PerfQueryMaxMemCacheSize(
|
|
VOID
|
|
) const
|
|
{
|
|
return _cbMaxMemCacheSize;
|
|
}
|
|
|
|
HRESULT
|
|
Initialize(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Terminate(
|
|
VOID
|
|
);
|
|
|
|
dllexp
|
|
static
|
|
W3_FILE_INFO_CACHE *
|
|
GetFileCache(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
QueryDoDirmonForUnc()
|
|
{
|
|
return _fDoDirmonForUnc;
|
|
}
|
|
|
|
private:
|
|
|
|
W3_FILE_INFO_CACHE(const W3_FILE_INFO_CACHE &);
|
|
void operator=(const W3_FILE_INFO_CACHE &);
|
|
|
|
HRESULT
|
|
InitializeMemoryCache(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
TerminateMemoryCache(
|
|
VOID
|
|
);
|
|
|
|
static
|
|
VOID
|
|
MemoryCacheAdjustor(
|
|
PVOID pFileCache,
|
|
BOOLEAN TimerOrWaitFired
|
|
);
|
|
|
|
ULONGLONG _cbFileSizeThreshold;
|
|
ULONGLONG _cbMemoryCacheSize;
|
|
DWORD _cMaxFileEntries;
|
|
BOOL _fEnableCache;
|
|
|
|
//
|
|
// Memcache stuff
|
|
//
|
|
|
|
CRITICAL_SECTION _csMemCache;
|
|
ULONGLONG _cbMemCacheLimit;
|
|
ULONGLONG _cbMemCacheCurrentSize;
|
|
ULONGLONG _cbMaxMemCacheSize;
|
|
HANDLE _hMemCacheHeap;
|
|
HANDLE _hTimer;
|
|
|
|
//
|
|
// Do we do dirmonitoring for UNC files?
|
|
//
|
|
BOOL _fDoDirmonForUnc;
|
|
|
|
//
|
|
// Threshold for attribute checking
|
|
//
|
|
DWORD _cmsecFileAttributeCheckThreshold;
|
|
};
|
|
|
|
#endif
|