/*++ FILEHC.H This file defines the public interfaces for issuing async Reads/Writes to a file using the fileh wrapper library. --*/ #ifndef _FILEHC_H_ #define _FILEHC_H_ // Published parts of the File Handle cache ! #ifdef __cplusplus extern "C" { #endif typedef VOID (*PFN_IO_COMPLETION)( IN struct FIO_CONTEXT* pContext, IN struct FH_OVERLAPPED* lpo, IN DWORD cb, IN DWORD dwCompletionStatus ); struct FH_OVERLAPPED { /*++ This structure defines the extended OVERLAPPED structure used by the File IO layer implemented in this module. The first 5 elements of this structure are identical to NT's OVERLAPPED structure and have the exact same semantics. The final additional parameter is a pointer to a function that will be called to complete the IO. --*/ UINT_PTR Internal ; UINT_PTR InternalHigh ; DWORD Offset ; DWORD OffsetHigh ; HANDLE hEvent ; PFN_IO_COMPLETION pfnCompletion ; UINT_PTR Reserved1 ; UINT_PTR Reserved2 ; UINT_PTR Reserved3 ; UINT_PTR Reserved4 ; } ; typedef struct FH_OVERLAPPED* PFH_OVERLAPPED ; struct FIO_CONTEXT { /*++ This structure defines the context object that is used to represent file handles. --*/ // // Temporary hack - mailmsg object assumes it can put a NULL in us ! // DWORD m_dwTempHack ; // // The context signature ! // DWORD m_dwSignature ; // // The users file handle ! // HANDLE m_hFile ; // // The offset to back fill Lines header - nntp aware only // DWORD m_dwLinesOffset; // // Header length - nntp aware only // DWORD m_dwHeaderLength; } ; typedef FIO_CONTEXT* PFIO_CONTEXT ; #ifdef _FILEHC_IMPLEMENTATION_ #define FILEHC_EXPORT __declspec( dllexport ) #else #define FILEHC_EXPORT __declspec( dllimport ) #endif // // Initialize the DLL for Async IO - // This is a counting initialize - for each call to FIOInitialize() // there should be a matching call to FIOTerminate // FILEHC_EXPORT BOOL __stdcall FIOInitialize( IN DWORD dwFlags ); // // Terminate the DLL's support for Async IO ! // FILEHC_EXPORT BOOL __stdcall FIOTerminate( VOID ); // // Do an async read against the File ! // FILEHC_EXPORT BOOL __stdcall FIOReadFile( IN PFIO_CONTEXT pContext, IN LPVOID lpBuffer, IN DWORD BytesToRead, IN FH_OVERLAPPED * lpo ); // // Do an async read against the file - pass extra args // so that if the FIO_CONTEXT is doing dot stuffing for the user // it can do so efficiently ! // FILEHC_EXPORT BOOL __stdcall FIOReadFileEx( IN PFIO_CONTEXT pContext, IN LPVOID lpBuffer, IN DWORD BytesToRead, IN DWORD BytesAvailable, // must be >= BytesToWrite - number of bytes I can mess with. IN FH_OVERLAPPED * lpo, IN BOOL fFinalWrite, // Is this the final write ? IN BOOL fIncludeTerminator // if TRUE contains CRLF.CRLF terminator which shouldn't be stuffed ); // // Do an async write against the file ! // FILEHC_EXPORT BOOL __stdcall FIOWriteFile( IN PFIO_CONTEXT pContext, IN LPCVOID lpBuffer, IN DWORD BytesToWrite, IN FH_OVERLAPPED * lpo ); // // Do an async write against the file - pass extra args // so that if the FIO_CONTEXT is doing dot stuffing for the user // it can do so efficiently ! // FILEHC_EXPORT BOOL __stdcall FIOWriteFileEx( IN PFIO_CONTEXT pContext, IN LPVOID lpBuffer, IN DWORD BytesToWrite, IN DWORD BytesAvailable, // must be >= BytesToWrite - number of bytes I can mess with. IN FH_OVERLAPPED* lpo, IN BOOL fFinalWrite, // Is this the final write ? IN BOOL fIncludeTerminator // if TRUE contains CRLF.CRLF terminator which shouldn't be stuffed ) ; // // Callback functions which create things in the cache ! // // NOTE: this is equivalent to FCACHE_RICHCREATE_CALLBACK where // // pfDidWeScanIt - returns FALSE // pfIsStuffed - return FALSE // pfStoredWithDots - return FALSE // typedef HANDLE (__stdcall *FCACHE_CREATE_CALLBACK) ( IN LPSTR lpstrName, IN LPVOID lpvData, OUT DWORD* cbFileSize, OUT DWORD* cbFileSizeHigh ) ; // // Callback functions which create things in the cache ! // // This function will be called by CacheRichCreateFile(). // // lpstrName - the name of the file // lpvData - User provided data, provided to CacheRichCreateFile // cbFileSize - The function should return the size of the file through this // cbFileSizeHigh - place to return the High DWORD of the file size // pfDidWeScanIt - if THIS is true then at some point the created file has been // scanned for DOTs appearing at the beginning of lines // pfIsStuffed - This is only meaningfull if pfDidWeScanIt==TRUE, in which case // if this is TRUE this indicates that there are DOTs at the beginning of lines // pfStoredWithDots - If this is TRUE then it indicates that any DOTs that appear // at the beginning of lines are stored with an extra dot as required in NNTP, // SMTP and POP3 protocols. if this is FALSE then the message is stored without // DOT stuffing. // typedef HANDLE (__stdcall *FCACHE_RICHCREATE_CALLBACK) ( IN LPSTR lpstrName, IN LPVOID lpvData, OUT DWORD* cbFileSize, OUT DWORD* cbFileSizeHigh, OUT BOOL* pfDidWeScanIt, OUT BOOL* pfIsStuffed, OUT BOOL* pfStoredWithDots, OUT BOOL* pfStoredWithTerminatingDot ) ; // // Initialize the File Handle Cache - // // NOTE : this will automatically initialize the DLL for async // IO as well ! // FILEHC_EXPORT BOOL __stdcall InitializeCache() ; // // Terminate the cache ! // // NOTE : this will terminate the DLL for async IO as well ! // FILEHC_EXPORT BOOL __stdcall TerminateCache() ; // // Associate a file with an async context ! // FILEHC_EXPORT PFIO_CONTEXT __stdcall AssociateFile( HANDLE hFile ) ; // // This allows the user to specify whether file stores content with extra DOTS // added for RFC 822 protocols (i.e. NNTP and SMTP DATA commands). // // NOTE: AssociateFile() is the same as AssociateFileEx( hFile, FALSE ) ; // // hFile - The file that contains message content, or in which we will write message content // fStoreWithDots - if TRUE then each period or DOT in the file which starts a line // but is NOT part of the terminating CRLF.CRLF will be stored with an extra dot // adjacent to it. This is the on the wire format for NNTP for instance. // FILEHC_EXPORT PFIO_CONTEXT __stdcall AssociateFileEx( HANDLE hFile, BOOL fStoreWithDots, BOOL fStoredWithTerminatingDot ) ; // // Add a reference to a context - // // Each call to AddRefContext() must be matched by a corresponding // call to ReleaseContext(). Both AssociateFile and CacheCreateFile() // also add a single reference which must be matched by a call to ReleaseContext(). // FILEHC_EXPORT void __stdcall AddRefContext( PFIO_CONTEXT ) ; // // Release a Context ! // // FIO_CONTEXT's are reference counted - the user must call // this for each successfull call to CacheCreateFile(), and // each call to InsertFile() where fKeepReference is TRUE // FILEHC_EXPORT void __stdcall ReleaseContext( PFIO_CONTEXT ) ; // // Close a handle associated with a non-cached FIO_CONTEXT // // This is used to Close the file handle within a context. // This only succeeds if the FIO_CONTEXT is not cached ! // FILEHC_EXPORT BOOL __stdcall CloseNonCachedFile( PFIO_CONTEXT ) ; // // Create a file in the cache, or find an existing one ! // // If the file is not in the cache, the cache will call // pfnCallBack with lpv to do the actual work of calling // CreateFile(). // FILEHC_EXPORT FIO_CONTEXT* __stdcall CacheCreateFile( IN LPSTR lpstrName, IN FCACHE_CREATE_CALLBACK pfnCallBack, IN LPVOID lpv, IN BOOL fAsyncContext ) ; // // Create a file in the cache or find an existing one, // if we create the file we can add properties onto it in // the cache ! // FILEHC_EXPORT FIO_CONTEXT* __stdcall CacheRichCreateFile( IN LPSTR lpstrName, IN FCACHE_RICHCREATE_CALLBACK pfnCallBack, IN LPVOID lpv, IN BOOL fAsyncContext ) ; // // This function allows a user to remove all files with the specified // Name from the cache. if fAllPrefixes is TRUE, we will remove all files // where the Name matches the beginning of the path ! // If fAllPrefixes is FALSE then we will remove only the one file which // exactly matches lpstrName ! // FILEHC_EXPORT void __stdcall CacheRemoveFiles( IN LPSTR lpstrName, IN BOOL fAllPrefixes ) ; // // Insert the file into the cache ! // // This function will add the file handle in the FIO_CONTEXT // to the cache. All searches by lpstrName will find this // item untill it expires from the cache. // // If fKeepReference is TRUE then the user must make a call to // ReleaseContext() for the inserted FIO_CONTEXT ! // FILEHC_EXPORT BOOL __stdcall InsertFile( IN LPSTR lpstrName, IN FIO_CONTEXT* pContext, IN BOOL fKeepReference ) ; // // Report the file size that we've cached with the handle // FILEHC_EXPORT DWORD __stdcall GetFileSizeFromContext( IN FIO_CONTEXT* pContext, OUT DWORD* pcbFileSizeHigh ) ; //---------------------------------------------------------------------- // NAME CACHE NAME CACHE NAME CACHE - // // Name Cache API's // // // // This is the function pointer provided by clients to compare // keys. This must be provided on all calls. // // The function has memcmp() semantics, i.e. it must order the keys // consistently, and return <0 if key1 is smaller then key2, ==0 if the // keys match and >0 if key1 is greater then key2. // typedef int (__stdcall *CACHE_KEY_COMPARE)( IN DWORD cbKey1, IN LPBYTE lpbKey1, IN DWORD cbKey2, IN LPBYTE lpbKey2 ) ; // // This is the function provided by clients to compute a hash // value on Keys - NOTE: The Cache will provide a hash function // IF the user does not, however the internally provided hash // function is best only for things that appear to be regular strings. // typedef DWORD (__stdcall *CACHE_KEY_HASH)( IN LPBYTE lpbKey, IN DWORD cbKey ) ; // // This is the generic callback function that is provided to the // cache to help examine items within the cache. // The BOOL return value is meaningfull to the Cache API's only // on the following calls : // // typedef BOOL (__stdcall *CACHE_READ_CALLBACK)( IN DWORD cb, IN LPBYTE lpb, IN LPVOID lpvContext ) ; // // This is a callback that is called whenever we destroy an entry in // the name cache - this is called once for both key and data components, // and gives the client a chance to track any relationships // // NOTE : if the client does not associate // data with the name, the function will only be called for the Key data. // typedef void (__stdcall *CACHE_DESTROY_CALLBACK)( IN DWORD cb, IN LPBYTE lpb ) ; // // This is a callback this is called whenever we evaluate a security descriptor. // If it is not provided we will call the standard NT AccessCheck() call ! // // The function has the same signature as AccessCheck, however there are arguments // we don't use - PrivilegeSet will always be NULL and PrivilegeSetLength will always be 0 ! // typedef BOOL (WINAPI *CACHE_ACCESS_CHECK)( IN PSECURITY_DESCRIPTOR pSecurityDescriptor, IN HANDLE hClientToken, IN DWORD dwDesiredAccess, IN PGENERIC_MAPPING GenericMapping, IN PRIVILEGE_SET* PrivilegeSet, IN LPDWORD PrivilegeSetLength, IN LPDWORD GrantedAccess, IN LPBOOL AccessStatus ) ; // // This is the externally exposed structure representing a Name Cache - // it doesn't contain any fields usefull for a client, but must be passed // back into all of the name cache API's // struct NAME_CACHE_CONTEXT { // // Signature DWORD ! - user must not touch this ! // DWORD m_dwSignature ; } ; typedef struct NAME_CACHE_CONTEXT* PNAME_CACHE_CONTEXT ; // // API's for creating/manging NAME CACHE's // NOTE : Name Cache's are reference counted, and if this // function is called twice with the same name we will // Add a reference to an existing Name Cache. // FILEHC_EXPORT PNAME_CACHE_CONTEXT __stdcall FindOrCreateNameCache( // // Must not be NULL ! - this is CASE SENSITVE ! // LPSTR lpstrName, // // Must not be NULL ! // CACHE_KEY_COMPARE pfnKeyCompare, // // This may be NULL, in which case the cache will provide one ! // CACHE_KEY_HASH pfnKeyHash, // // The following two function pointers may be NULL ! // CACHE_DESTROY_CALLBACK pfnKeyDestroy, CACHE_DESTROY_CALLBACK pfnDataDestroy ) ; // // API's for releasing the NAME CACHE ! // // The caller must guarantee the thread safety of this call - This function must not // be called if any other thread is simultanesouly executing within // CacheFindContectFromName(), AssociateContextWithName(), AssociateDataWithName(), or InvalidateName() // FILEHC_EXPORT long __stdcall ReleaseNameCache( // // Must not be NULL ! // PNAME_CACHE_CONTEXT pNameCache ) ; // // API's for setting options on the name cache - this can be used to change // how Security is evaluated ! // FILEHC_EXPORT BOOL __stdcall SetNameCacheSecurityFunction( // // Must not be NULL ! // PNAME_CACHE_CONTEXT pNameCache, // // This is the function pointer that will be used to evaluate security - // this may be NULL - if it is we will use the Win32 Access Check ! // CACHE_ACCESS_CHECK pfnAccessCheck ) ; // // Find the FIO_CONTEXT that is associated with some user name. // // The function returns TRUE if the Name was found in the cache. // FALSE if the name was not found in the cache. // // If the function returns FALSE then the pfnCallback function will not be // called. // // If the function returns TRUE, ppFIOContext may return a NULL pointer, // if the user passed a NULL FIO_CONTEXT to AssociateContextWithName() ! // // FILEHC_EXPORT BOOL __stdcall FindContextFromName( // // The name cache the client wishes to use ! // PNAME_CACHE_CONTEXT pNameCache, // // User provides arbitrary bytes for Key to the cache item - pfnKeyCompare() used // to compare keys ! // IN LPBYTE lpbName, IN DWORD cbName, // // User provides function which is called with the key once the key comparison // matches the key. This lets the user do some extra checking that they're getting // what they want. // IN CACHE_READ_CALLBACK pfnCallback, IN LPVOID lpvClientContext, // // Ask the cache to evaluate the embedded security descriptor // if hToken is 0 then we ignore and security descriptor data // IN HANDLE hToken, IN ACCESS_MASK accessMask, // // We have a separate mechanism for returning the FIO_CONTEXT // from the cache. // OUT FIO_CONTEXT** ppContext ) ; // // Find the FIO_CONTEXT that is associated with some user name. // // The function returns TRUE if the Name was found in the cache. // FALSE if the name was not found in the cache. // // If the function returns FALSE then the pfnCallback function will not be // called. // // If the function returns TRUE, ppFIOContext may return a NULL pointer, // if the user passed a NULL FIO_CONTEXT to AssociateContextWithName() ! // // FILEHC_EXPORT BOOL __stdcall FindSyncContextFromName( // // The name cache the client wishes to use ! // PNAME_CACHE_CONTEXT pNameCache, // // User provides arbitrary bytes for Key to the cache item - pfnKeyCompare() used // to compare keys ! // IN LPBYTE lpbName, IN DWORD cbName, // // User provides function which is called with the key once the key comparison // matches the key. This lets the user do some extra checking that they're getting // what they want. // IN CACHE_READ_CALLBACK pfnCallback, IN LPVOID lpvClientContext, // // Ask the cache to evaluate the embedded security descriptor // if hToken is 0 then we ignore and security descriptor data // IN HANDLE hToken, IN ACCESS_MASK accessMask, // // We have a separate mechanism for returning the FIO_CONTEXT // from the cache. // OUT FIO_CONTEXT** ppContext ) ; // // Cache Associate context with name ! // This insert a Name into the Name cache, that will find the specified FIO_CONTEXT ! // // If the name is already present in the cache, this will fail with GetLastError()==ERROR_DUP_NAME ! // FILEHC_EXPORT BOOL __stdcall AssociateContextWithName( // // The name cache the client wishes to use ! // PNAME_CACHE_CONTEXT pNameCache, // // User provides arbitrary bytes for the Name of the cache item. // IN LPBYTE lpbName, IN DWORD cbName, // // User may provide some arbitrary data to assoicate with the name ! // IN LPBYTE lpbData, IN DWORD cbData, // // User may provide a self relative security descriptor to // be associated with the name ! // IN PGENERIC_MAPPING pGenericMapping, IN PSECURITY_DESCRIPTOR pSecurityDescriptor, // // User provides the FIO_CONTEXT that the name should reference // FIO_CONTEXT* pContext, // // User specifies whether they wish to keep their reference on the FIO_CONTEXT // BOOL fKeepReference ) ; // // This function allows the user to remove a single name and all associated data // from the name cache. // FILEHC_EXPORT BOOL InvalidateName( // // The name cache the client wishes to use ! // PNAME_CACHE_CONTEXT pNameCache, // // User provides arbitrary bytes for the Name of the cache item. // IN LPBYTE lpbName, IN DWORD cbName ) ; // // End of Name Cache API's //---------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- // DOT STUFFING API's // // // This function gets an FIO_CONTEXT with the requested state. // We may or may not create a new FIO_CONTEXT, if we do create one we'll stick // it into the cache so it can be used again ! // NOTE: if we have to do work, the user has the only reference to the resulting // FIO_CONTEXT which will go away when they call ReleaseContext() ! // // pContext - the original FIO_CONTEXT // lpstrName - the file name associated with pContext // fWantItDotStuffed - if TRUE the resulting FIO_CONTEXT should be dot stuffed ! // fTerminatorIncluded - if this is TRUE the source FIO_CONTEXT contains a terminating // dot that we should be carefull not to stuff ! // // NOTE: We may return the same FIO_CONTEXT as the caller provided - in which case // an extra reference has been added that needs to be dropped with ReleaseContext() ! // // FILEHC_EXPORT FIO_CONTEXT* __stdcall ProduceDotStuffedContext( IN FIO_CONTEXT* pContext, IN LPSTR lpstrName, IN BOOL fWantItDotStuffed // if TRUE add dots, if FALSE remove dots ) ; // // This function takes a source FIO_CONTEXT (pContextSource) and copies // the content into pContextDestination. // // The user specifies whether the Destination FIO_CONTEXT should be dot stuffed // with fWantItDotStuffed, and whether the source FIO_CONTEXT includes the // terminating CRLF.CRLF // // The out parameter pfModified is TRUE if there were modifications when // Source was copied to Destination ! // // The function returns TRUE if successfull, FALSE otherwise ! // FILEHC_EXPORT BOOL __stdcall ProduceDotStuffedContextInContext( IN FIO_CONTEXT* pContextSource, IN FIO_CONTEXT* pContextDestination, IN BOOL fWantItDotStuffed, OUT BOOL* pfModified ) ; // // Find out whether the file has a terminating 'CRLF.CRLF' sequence ! // FILEHC_EXPORT BOOL __stdcall GetIsFileDotTerminated( IN FIO_CONTEXT* pContext ) ; // // Set whether the file has a terminating 'CRLF.CRLF' sequence ! // FILEHC_EXPORT void __stdcall SetIsFileDotTerminated( IN FIO_CONTEXT* pContext, IN BOOL fIsDotTerminated ) ; // // Enable dot stuffing properties on the write path of the file // handle cache of this message ! // // if fEnable is FALSE then all dot stuffing behaviour is turned // off. // // if fStripDots is TRUE the File Handle Cache will convert // occurrences of "\r\n." to "\r\n" within your message. // // if fStripDots is FALSE the FileHandle Cache will convert occurrences // of "\r\n.." to "\r\n" within your message. // // FILEHC_EXPORT BOOL __stdcall SetDotStuffingOnWrites( IN FIO_CONTEXT* pContext, // // fEnable == FALSE means ignore fStripDots, and writes are unmodified // IN BOOL fEnable, // // fStripDots == TRUE means we remove dots that are dot stuffed, // fStripDots == FALSE means that we add dots to make the message dot stuffed // IN BOOL fStripDots ) ; #if 0 // // This function temporarily disabled ! // FILEHC_EXPORT BOOL __stdcall SetDotStuffingOnReads( IN FIO_CONTEXT* pContext, IN BOOL fEnable, IN BOOL fStripDots ) ; #endif // // Enable dot scanning properties on the write path // of the file handle cache for this file ! // // if fEnable is TRUE the we will examine each write // that goes through us to determine whether the // message has any occurrences of "\r\n.". // FILEHC_EXPORT BOOL __stdcall SetDotScanningOnWrites( IN FIO_CONTEXT* pContext, IN BOOL fEnable ) ; // // // This function should be called when we have finished doing all writes to an FIO_CONTEXT // This function should be paired with SetDotStuffingOnWrites() and the fStripDots // parameter should be the same as when SetDotStuffingOnWrites() was called. // // We will update the Dot Stuffing State of the FIO_CONTEXT and discard // all dot stuffing memory and stuff that may have been required ! // // If this function call is paired with a call to SetDotScanningOnWrites() fStripDots should be TRUE ! // FILEHC_EXPORT void __stdcall CompleteDotStuffingOnWrites( IN FIO_CONTEXT* pContext, IN BOOL fStripDots ) ; // // This will cause us to examine each read for occurrences of // "\r\n." // // NOTE : the user must use ASYNC Reads for this to work - we will assert // if the user tries to pend any synchronous reads while we are in this state ! // FILEHC_EXPORT BOOL __stdcall SetDotScanningOnReads( IN FIO_CONTEXT* pContext, IN BOOL fEnable ) ; // // If any of the dot stuffing mechanism our turned on, // this will get a count of the number of occurrences/modifications // have occurred. // // if fReads is TRUE we get the count for occurrences on Read's // if fReads is FALSE we get the count for occurrences on Write's // // if dot stuffing was turned off or not enabled somehow then // GetDotStuffState() will return FALSE. // // NOTE: A NULL pfStuffed is not allowed ! // FILEHC_EXPORT BOOL __stdcall GetDotStuffState( IN FIO_CONTEXT* pContext, IN BOOL fReads, OUT BOOL* pfStuffed, OUT BOOL* pfStoredWithDots ) ; // // In this case we always assume that the FIO_CONTEXT is not going to be dot stuffed. // fRequiresStuffing == TRUE indicates that it SHOULD BE stuffed. // fRequiresStuffing == FALSE indicates that the message does not need dot stuffing. // FILEHC_EXPORT void __stdcall SetDotStuffState( IN FIO_CONTEXT* pContext, // // fIsStuffed is only relevant when fKnown == TRUE // IN BOOL fKnown, // We do know the dot stuff state // // if fKnown is TRUE then fIsStuffed is meaningfull, when thats the case // if fIsStuffed is TRUE then the message // IN BOOL fRequiresStuffing// if fKnown is TRUE this arg is meaningfull ) ; #ifdef __cplusplus } #endif #endif // _FILEHC_H_