/*++ Copyright (C) Microsoft Corporation, 1996 - 2001 (c) 1998 Seagate Software, Inc. All rights reserved. Module Name: RpFsa.h Abstract: Contains function declarations and structures for the File System Filter for Remote Storage Author: Rick Winter Environment: Kernel mode Revision History: X-13 108353 Michael C. Johnson 3-May-2001 When checking a file to determine the type of recall also check a the potential target disk to see whether or not it is writable. This is necessary now that we have read-only NTFS volumes. X-12 365077 Michael C. Johnson 1-May-2001 Revert to previous form of RsOpenTarget() with extra access parameter to allow us to apply the desired access bypassing the access check. X-11 194325 Michael C. Johnson 1-Mar-2001 Clean up RsMountCompletion() and RsLoadFsCompletion() to ensure they don't call routines such as IoDeleteDevice() if not running at PASSIVE_LEVEL. Add in memory trace mechanism in preparation for attempts to flush out lingering reparse point deletion troubles. X-10 326345 Michael C. Johnson 26-Feb-2001 Only send a single RP_RECALL_WAITING to the fsa on any one file object. Use the new flag RP_NOTIFICATION_SENT to record when notification has been done. --*/ /* Defines */ // memory allocation Tags for debug usage #define RP_RQ_TAG 'SFSR' // Recall queue #define RP_FN_TAG 'NFSR' // File name cache #define RP_SE_TAG 'ESSR' // Security info #define RP_WQ_TAG 'QWSR' // Work queue #define RP_QI_TAG 'IQSR' // Work Q info #define RP_LT_TAG 'TLSR' // Long term memory #define RP_IO_TAG 'OISR' // IOCTL queue #define RP_FO_TAG 'OFSR' // File Object Queue #define RP_VO_TAG 'OVSR' // Validate Queue #define RP_ER_TAG 'RESR' // Error log data #define RP_CC_TAG 'CCSR' // Cache buffers #define RP_US_TAG 'SUSR' // Usn record #define RP_CX_TAG 'CCSR' // Completion context #define RP_TC_TAG 'CTSR' // Trace control block #define RP_TE_TAG 'ETSR' // Trace entry buffer #define RP_RD_TAG 'DRSR' // Root directory path // // Device extension for the RsFilter device object // typedef enum _RP_VOLUME_WRITE_STATUS { RsVolumeStatusUnknown = 0, // No attempt has been made to determine volume writeability // or attempt to determine volume writeability failed RsVolumeStatusReadOnly, // volume is readonly RsVolumeStatusReadWrite // Volume is writeable } RP_VOLUME_WRITE_STATUS; typedef struct _DEVICE_EXTENSION { CSHORT Type; CSHORT Size; PDEVICE_OBJECT FileSystemDeviceObject; PDEVICE_OBJECT RealDeviceObject; BOOLEAN Attached; BOOLEAN AttachedToNtfsControlDevice; volatile RP_VOLUME_WRITE_STATUS WriteStatus; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; #define RSFILTER_PARAMS_KEY L"RsFilter\\Parameters" #define RS_TRACE_LEVEL_VALUE_NAME L"TraceLevel" #define RS_TRACE_LEVEL_DEFAULT 0 extern PDEVICE_OBJECT FsDeviceObject; // Fsa validate job registry entry location #define FSA_VALIDATE_LOG_KEY_NAME L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Remote_Storage_File_System_Agent\\Validate" #define FT_VOL_LEN 32 /* First guess at device name length */ #define AV_DEV_OBJ_NAME_SIZE (40 * sizeof(wchar_t)) /* Space for a NULL and a delimiter */ #define AV_NAME_OVERHEAD (2 * sizeof(wchar_t)) #define RP_NTFS_NAME L"\\FileSystem\\NTFS" // FILE_HSM_ACTION_ACCESS is any access that requires HSM action (delete or recall or both) #ifdef WHEN_WE_HANDLE_DELETE #define FILE_HSM_ACTION_ACCESS (FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE | DELETE) #else #define FILE_HSM_ACTION_ACCESS (FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE) #endif /* FILE_HSM_RECALL_ACCESS is any access that allows the data to be read. */ #define FILE_HSM_RECALL_ACCESS (FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE) // // Timeout and retry values when waiting for the FSA to issue an IOCTL // Represents the amount of time - under multiple concurrent recall situations - // that an app will have to wait before the i/o it issued completes with // STATUS_FILE_IS_OFFLINE because RsFilter couldn't get any IOCTLs to // communicate with the FSA // #define RP_WAIT_FOR_FSA_IO_TIMEOUT -((LONGLONG) 4800000000) // 8 minutes /* Module ID defines for error/event logging */ #define AV_MODULE_RPFILTER 1 #define AV_MODULE_RPFILFUN 2 #define AV_MODULE_RPSEC 3 #define AV_MODULE_RPZW 4 #define AV_MODULE_RPCACHE 5 #define AV_BUFFER_SIZE 1024 #ifndef BooleanFlagOn #define BooleanFlagOn(F,SF) ( (BOOLEAN)(((F) & (SF)) != 0) ) #endif #define AV_FT_TICKS_PER_SECOND ((LONGLONG) 10000000) #define AV_FT_TICKS_PER_MINUTE ((LONGLONG) ((LONGLONG) 60 * AV_FT_TICKS_PER_SECOND)) #define AV_FT_TICKS_PER_HOUR ((LONGLONG) ((LONGLONG) 60 * AV_FT_TICKS_PER_MINUTE)) // // The filter ID tracks recalls and no-recalls as follows: // The id is a longlong where the highest order bit identifies the type of recall // (no-recall or recall). The remaining part of the high order long identifies the // read RP_IRP_QUEUE entry (for no-recall) or the file object entry (for recall). // The lower long identifies the file context entry. // #define RP_TYPE_RECALL (ULONGLONG) 0x8000000000000000 #define RP_CONTEXT_MASK (ULONGLONG) 0x00000000ffffffff #define RP_READ_MASK 0x7fffffff #define RP_FILE_MASK (ULONGLONG) 0xffffffff00000000 typedef struct _RP_CREATE_INFO { PIRP irp; PIO_STACK_LOCATION irpSp; POBJECT_NAME_INFORMATION str; ULONG options; // // Reparse point data // RP_DATA rpData; LONGLONG fileId; LONGLONG objIdHi; LONGLONG objIdLo; ULONG serial; ULONG action; ULONG desiredAccess; } RP_CREATE_INFO, *PRP_CREATE_INFO; typedef struct _RP_PENDING_CREATE { // // Filter id // ULONGLONG filterId; // // // PRP_CREATE_INFO qInfo; // // Event used to signal irp completion // KEVENT irpCompleteEvent; // // File object for irp // PFILE_OBJECT fileObject; // // Device object for irp // PDEVICE_OBJECT deviceObject; // // Open options // ULONG options; // // Indicates if oplocks should not be granted (to CI for instance..) // #define RP_PENDING_NO_OPLOCK 0x1 // // Indicates if IRP should be sent down again // #define RP_PENDING_RESEND_IRP 0x2 // // Indicates if we should wait for irp to complete // #define RP_PENDING_WAIT_FOR_EVENT 0x4 // // Indicates if this is a recall // #define RP_PENDING_IS_RECALL 0x8 // // Indicates if we should reset the offline attribute of the file // #define RP_PENDING_RESET_OFFLINE 0x10 ULONG flags; } RP_PENDING_CREATE, *PRP_PENDING_CREATE; #define RP_IRP_NO_RECALL 1 typedef struct _RP_IRP_QUEUE { LIST_ENTRY list; PIRP irp; PDEVICE_EXTENSION deviceExtension; ULONG flags; // // For regular read and write, offset and length // denote the offset and length within the file // For no-recall reads, offset and length would // denote the offset/length within the cacheBuffer // ULONGLONG offset; ULONGLONG length; // // These fields are used only for no-recall reads // filterId for no-recall (see filterid description) ULONGLONG readId; ULONGLONG recallOffset; ULONGLONG recallLength; // // User buffer for data from read-no-recall // PVOID userBuffer; // // Cache block buffer for no recall data // PVOID cacheBuffer; } RP_IRP_QUEUE, *PRP_IRP_QUEUE; // // Structure tracking the no-recall master IRP and associated irps // typedef struct _RP_NO_RECALL_MASTER_IRP { LIST_ENTRY AssocIrps; PIRP MasterIrp; } RP_NO_RECALL_MASTER_IRP, *PRP_NO_RECALL_MASTER_IRP; // // User security info structure: this is required for HSM // to do the pop-up for clients indicating the file is being recalled // typedef struct _RP_USER_SECURITY_INFO { // // Sid info // PCHAR userInfo; ULONG userInfoLen; LUID userAuthentication; LUID userInstance; LUID tokenSourceId; // // Token source info for user // CHAR tokenSource[TOKEN_SOURCE_LENGTH]; // // Indicates if this was opened by user with admin privileges // BOOLEAN isAdmin; // // Indicates if this is a local proc // BOOLEAN localProc; } RP_USER_SECURITY_INFO, *PRP_USER_SECURITY_INFO; // // Associated macro for above // #define RsFreeUserSecurityInfo(UserSecurityInfo) { \ if (UserSecurityInfo) { \ if (UserSecurityInfo->userInfo) { \ ExFreePool(UserSecurityInfo->userInfo); \ } \ ExFreePool(UserSecurityInfo); \ } \ } // // The file object entry keeps track of an open instance of a file. // For each NTFS file object there is one of these (if the file has an HSM tag) // This structure points to a FS_CONTEXT entry for which there is one for each file. // For instance if 3 clients open \\server\share\foo there will be 3 file object // structures and they will all point to the same FS_CONTEXT structure. // // The file objects we are tracking will have a pointer to one of there structures attached via // FsRtlInsertFilterContext. From there one can find the file context entry via the pointer to it. // typedef struct _RP_FILE_OBJ { // // Link to next file object // LIST_ENTRY list; // // File object itself // PFILE_OBJECT fileObj; // // Device object // PDEVICE_OBJECT devObj; // // Pointer to the RP_FILE_CONTEXT entry - there's one such entry for every *file* // PVOID fsContext; // // Resource protecting this entry // ERESOURCE resource; // // Spin lock protecting read/write IRP queues // KSPIN_LOCK qLock; // // Pending read IRP queue // LIST_ENTRY readQueue; // // Pending write IRP queue // LIST_ENTRY writeQueue; // // File create options specified when opening it // ULONG openOptions; // // File desired access spcecified when opening it // ULONG desiredAccess; // // Flags (descriptions below) // ULONG flags; // // Object id // LONGLONG objIdHi; LONGLONG objIdLo; // // File Id if available // LONGLONG fileId; // // Unique ID we generate for the file object // ULONGLONG filterId; // // Recall action flags (see rpio.h - RP_RECALL_ACTION..) // ULONG recallAction; PRP_USER_SECURITY_INFO userSecurityInfo; } RP_FILE_OBJ, *PRP_FILE_OBJ; // // RP_FILE_OBJ Flags // // // File was not opened for read or write access // #define RP_NO_DATA_ACCESS 1 // // Opener is admin equivalent // #define RP_OPEN_BY_ADMIN 2 // // Opened by local process // #define RP_OPEN_LOCAL 4 // // Recall waiting notification already sent // #define RP_NOTIFICATION_SENT 8 // // Recall state // typedef enum _RP_RECALL_STATE { RP_RECALL_INVALID = -1, RP_RECALL_NOT_RECALLED, RP_RECALL_STARTED, RP_RECALL_COMPLETED } RP_RECALL_STATE, *PRP_RECALL_STATE; // // Filter context for RsFilter: // Since filter contexts are attached to the SCB (stream control block) we need to use // the instance ID to indicate which file object we are interested in. We attach this // structure to and use myFileObjEntry to point to the RP_FILE_OBJ struct that // represents this file object. // typedef struct _RP_FILTER_CONTEXT { FSRTL_PER_STREAM_CONTEXT context; PVOID myFileObjEntry; } RP_FILTER_CONTEXT, *PRP_FILTER_CONTEXT; // // File context: one per *file* // typedef struct _RP_FILE_CONTEXT { // // Links to next/prev file (hanging off RsFileObjQHead) // LIST_ENTRY list; // // Lock protecting file object queue // KSPIN_LOCK qLock; // // Queue of all related file object entries // LIST_ENTRY fileObjects; // // Recalled data is written using this file object // PFILE_OBJECT fileObjectToWrite; // // Handle for the file object we use to write to // HANDLE handle; PDEVICE_OBJECT devObj; PDEVICE_OBJECT FilterDeviceObject; // // Unicode name of file // POBJECT_NAME_INFORMATION uniName; // // From the file object - unique file identifier // PVOID fsContext; // // Buffer to write out to file // PVOID nextWriteBuffer; // // Size of next write to the file (of recall data) // ULONG nextWriteSize; // // Lock protecting this entry // ERESOURCE resource; // // This notification event is signalled when recall completes for this file // KEVENT recallCompletedEvent; // // File id if available // LONGLONG fileId; // // Size in bytes of recall needed // LARGE_INTEGER recallSize; // // All bytes up to this offset have been recalled // LARGE_INTEGER currentOffset; // // Lower half of filter id (unique per file) // ULONGLONG filterId; // // Volume serial number // ULONG serial; // // If the recall is complete this is the status // NTSTATUS recallStatus; // // Recall state // RP_RECALL_STATE state; // // Flags (see below for description) // ULONG flags; // // Reference count for the file context // ULONG refCount; // // Usn of the file // USN usn; // // Tracks create section lock // LONG createSectionLock; // // Reparse point data // RP_DATA rpData; } RP_FILE_CONTEXT, *PRP_FILE_CONTEXT; // // RP_FILE_CONTEXT Flags // // We have seen a write to this file #define RP_FILE_WAS_WRITTEN 1 #define RP_FILE_INITIALIZED 2 #define RP_FILE_REPARSE_POINT_DELETED 4 /*++ VOID RsInitializeFileContextQueueLock() Routine Description Initializes lock guarding the file context queue Arguments none Return Value none --*/ #define RsInitializeFileContextQueueLock() { \ DebugTrace((DPFLTR_RSFILTER_ID, DBG_LOCK,"RsFilter: RsInitializeFileContextQueueLock.\n"));\ ExInitializeFastMutex(&RsFileContextQueueLock); \ } /*++ VOID RsAcquireFileContextQueueLock() Routine Description Acquire lock guarding the file context queue Arguments none Return Value none --*/ #define RsAcquireFileContextQueueLock() { \ ExAcquireFastMutex(&RsFileContextQueueLock); \ DebugTrace((DPFLTR_RSFILTER_ID, DBG_LOCK, "RsFilter: RsAcquireFileContextQueueLock.\n"));\ } /*++ VOID RsReleaseFileContextQueueLock() Routine Description Release lock guarding the file context queue Arguments none Return Value none --*/ #define RsReleaseFileContextQueueLock() { \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsReleaseFileContextQueueLock.\n"));\ ExReleaseFastMutex(&RsFileContextQueueLock); \ } /*++ VOID RsAcquireFileObjectLockExclusive() Routine Description Acquire lock guarding a file object entry Arguments none Return Value none --*/ #define RsAcquireFileObjectEntryLockExclusive(entry) { \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileObjectEntryLockExclusive Waiting (%x).\n", entry));\ FsRtlEnterFileSystem(); \ ExAcquireResourceExclusiveLite(&(entry)->resource, TRUE); \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileObjectEntryLockExclusive Owned (%x).\n", entry));\ } /*++ VOID RsAcquireFileObjectEntryLockShared() Routine Description Acquire lock guarding a file object entry Arguments none Return Value none --*/ #define RsAcquireFileObjectEntryLockShared(entry) { \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileObjectEntryLockShared Waiting (%x).\n", entry));\ FsRtlEnterFileSystem(); \ ExAcquireResourceSharedLite(&(entry)->resource, TRUE); \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileObjectEntryLockShared Owned (%x).\n", entry));\ } /*++ VOID RsReleaseFileObjectEntryLock() Routine Description Release lock guarding a file object entry Arguments none Return Value none --*/ #define RsReleaseFileObjectEntryLock(entry) { \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsReleaseFileObjectEntryLock (%x).\n", entry));\ ExReleaseResourceLite(&(entry)->resource); \ FsRtlExitFileSystem(); \ } /*++ VOID RsAcquireFileContextEntryLockExclusive() Routine Description Acquire lock guarding a file context entry Arguments none Return Value none --*/ #define RsAcquireFileContextEntryLockExclusive(entry) { \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileContextEntryLockExclusive Waiting (%x).\n", entry));\ FsRtlEnterFileSystem(); \ ExAcquireResourceExclusiveLite(&(entry)->resource, TRUE); \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileContextEntryLockExclusive Owned (%x).\n", entry));\ } /*++ VOID RsAcquireFileContextEntryLockShared() Routine Description Acquire lock guarding a file context entry Arguments none Return Value none --*/ #define RsAcquireFileContextEntryLockShared(entry) { \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileContextEntryLockShared Waiting (%x).\n", entry));\ FsRtlEnterFileSystem(); \ ExAcquireResourceSharedLite(&(entry)->resource, TRUE); \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsAcquireFileContextEntryLockShared Owned (%x).\n", entry));\ } /*++ VOID RsReleaseFileContextEntryLock() Routine Description Release lock guarding a file context entry Arguments none Return Value none --*/ #define RsReleaseFileContextEntryLock(entry) { \ DebugTrace((DPFLTR_RSFILTER_ID,DBG_LOCK, "RsFilter: RsReleaseFileContextEntryLock. (%x)\n", entry));\ ExReleaseResourceLite(&(entry)->resource); \ FsRtlExitFileSystem(); \ } /*++ VOID RsGetValidateLock(PKIRQL irql) Routine Description: Get a lock on the validate queue Arguments: Place to save irql Return Value: None --*/ #define RsGetValidateLock(irql) ExAcquireSpinLock(&RsValidateQueueLock, irql) /*++ VOID RsPutValidateLock(KIRQL oldIrql) Routine Description: Free a lock on the validate queue Arguments: Saved irql Return Value: None --*/ #define RsPutValidateLock(oldIrql) ExReleaseSpinLock(&RsValidateQueueLock, oldIrql) /*++ VOID RsGetIoLock(PKIRQL irql) Routine Description: Lock the IO queue Arguments: Variable to receive current irql Return Value: 0 Note: --*/ #define RsGetIoLock(irql) ExAcquireSpinLock(&RsIoQueueLock, irql) /*++ VOID RsPutIoLock(KIRQL oldIrql) Routine Description: Unlock the IO queue Arguments: oldIrql - Saved irql Return Value: 0 Note: --*/ #define RsPutIoLock(oldIrql) ExReleaseSpinLock(&RsIoQueueLock, oldIrql) #define RP_IS_NO_RECALL_OPTION(OpenOptions) \ (RsNoRecallDefault?!((OpenOptions) & FILE_OPEN_NO_RECALL) : ((OpenOptions) & FILE_OPEN_NO_RECALL)) #define RP_SET_NO_RECALL_OPTION(OpenOptions) \ (RsNoRecallDefault ? ((OpenOptions) &= ~FILE_OPEN_NO_RECALL):((OpenOptions) |= FILE_OPEN_NO_RECALL)) #define RP_RESET_NO_RECALL_OPTION(OpenOptions) \ (RsNoRecallDefault ?((OpenOptions) |= FILE_OPEN_NO_RECALL) : ((OpenOptions) &= ~FILE_OPEN_NO_RECALL)) #define RP_IS_NO_RECALL(Entry) \ (RP_IS_NO_RECALL_OPTION((Entry)->openOptions) && !(((PRP_FILE_CONTEXT) (Entry)->fsContext)->flags & RP_FILE_WAS_WRITTEN)) #define RP_SET_NO_RECALL(Entry) \ RP_SET_NO_RECALL_OPTION((Entry)->openOptions) #define RP_RESET_NO_RECALL(Entry) \ RP_RESET_NO_RECALL_OPTION(Entry->openOptions) typedef struct _RP_VALIDATE_INFO { LIST_ENTRY list; LARGE_INTEGER lastSetTime; // Last time a RP was set. ULONG serial; // Volume serial number } RP_VALIDATE_INFO, *PRP_VALIDATE_INFO; typedef struct _AV_ERR { ULONG line; ULONG file; ULONG code; WCHAR string[1]; /* Actual size will vary */ } AV_ERR, *PAV_ERR; // // Possible create flags: // #define SF_FILE_CREATE_PATH 1 #define SF_FILE_CREATE_ID 2 #define SF_FILE_READ 3 typedef enum _RP_FILE_BUF_STATE { RP_FILE_BUF_INVALID=0, RP_FILE_BUF_IO, RP_FILE_BUF_VALID, RP_FILE_BUF_ERROR } RP_FILE_BUF_STATE, *PRP_FILE_BUF_STATE; // // Define the cache buffer structure // typedef struct _RP_FILE_BUF { // // IRPs waiting on this block // LIST_ENTRY WaitQueue; // // Volume serial number for the volume on which the file // this block maps to resides // ULONG VolumeSerial; // // File id uniquely indicating which file this block // belongs to // ULONGLONG FileId; // // Block number this buffer maps to // ULONGLONG Block; // // Lock for the buffer // ERESOURCE Lock; // // Links in the hash queue this buffer belongs // LIST_ENTRY BucketLinks; // // Links in the lru list // LIST_ENTRY LruLinks; // // Indicates the current buffer state // RP_FILE_BUF_STATE State; // // If i/o completed with errors, this is useful // NTSTATUS IoStatus; // // Actual buffer contents themselves // PUCHAR Data; // // Usn used to validate block // LONGLONG Usn; } RP_FILE_BUF, *PRP_FILE_BUF; // // The hash bucket structure // typedef struct _RP_CACHE_BUCKET { // // Link to the head of the entries in this bucket // LIST_ENTRY FileBufHead; } RP_CACHE_BUCKET, *PRP_CACHE_BUCKET; // // Cache LRU structure // typedef struct _RP_CACHE_LRU { // // Pointer to head of LRU // LIST_ENTRY FileBufHead; // // Lock structure for protecting the LRU // FAST_MUTEX Lock; // // Total number of buffers in the cache // // ULONG TotalCount; // // Number of buffers in LRU (just for bookkeeping) // ULONG LruCount; // // Counting semaphore used to signal availability (and number) // of buffers in LRU // KSEMAPHORE AvailableSemaphore; } RP_CACHE_LRU, *PRP_CACHE_LRU; // // Completion Context used by Mount and LoadFs completion routines. // typedef struct _RP_COMPLETION_CONTEXT { LIST_ENTRY leQueueHead; PIO_WORKITEM pIoWorkItem; PIRP pIrp; PIO_WORKITEM_ROUTINE prtnWorkItemRoutine; union { struct { PVPB pvpbOriginalVpb; PDEVICE_OBJECT pdoRealDevice; PDEVICE_OBJECT pdoNewFilterDevice; } Mount; struct { PVOID pvDummy; } LoadFs; } Parameters; } RP_COMPLETION_CONTEXT, *PRP_COMPLETION_CONTEXT; // // Some utility macros // #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) > (b) ? (b) : (a)) // // Debug support // #define DBG_INFO DPFLTR_INFO_LEVEL #define DBG_ERROR DPFLTR_ERROR_LEVEL #define DBG_VERBOSE DPFLTR_TRACE_LEVEL #define DBG_LOCK DPFLTR_TRACE_LEVEL #define DebugTrace(MSG) DbgPrintEx MSG // // Function prototypes // NTSTATUS RsAddQueue(IN ULONG Serial, OUT PULONGLONG RecallId, IN ULONG OpenOption, IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DevObj, IN PDEVICE_OBJECT FilterDeviceObject, IN PRP_DATA PhData, IN LARGE_INTEGER RecallStart, IN LARGE_INTEGER RecallSize, IN LONGLONG FileId, IN LONGLONG ObjIdHi, IN LONGLONG ObjIdLo, IN ULONG DesiredAccess, IN PRP_USER_SECURITY_INFO UserSecurityInfo); NTSTATUS RsAddFileObj(IN PFILE_OBJECT fileObj, IN PDEVICE_OBJECT FilterDeviceObject, IN RP_DATA *phData, IN ULONG openOption); NTSTATUS RsQueueCancel(IN ULONGLONG filterId); NTSTATUS RsMakeContext(IN PFILE_OBJECT fileObj, OUT PRP_FILE_CONTEXT *context); NTSTATUS RsReleaseFileContext(IN PRP_FILE_CONTEXT context); NTSTATUS RsFreeFileObject(IN PLIST_ENTRY FilterContext); PRP_FILE_CONTEXT RsAcquireFileContext(IN ULONGLONG FilterId, IN BOOLEAN Exclusive); VOID RsReleaseFileObject(IN PRP_FILE_OBJ entry); NTSTATUS RsGenerateDevicePath(IN PDEVICE_OBJECT deviceObject, OUT POBJECT_NAME_INFORMATION *nameInfo ); NTSTATUS RsGenerateFullPath(IN POBJECT_NAME_INFORMATION fileName, IN PDEVICE_OBJECT deviceObject, OUT POBJECT_NAME_INFORMATION *nameInfo ); ULONG RsRemoveQueue(IN PFILE_OBJECT fileObj); NTSTATUS RsCompleteRecall(IN PDEVICE_OBJECT DeviceObject, IN ULONGLONG FilterId, IN NTSTATUS Status, IN ULONG RecallAction, IN BOOLEAN CancellableRead); NTSTATUS RsCompleteReads(IN PRP_FILE_CONTEXT Context); NTSTATUS RsPreserveDates(IN PRP_FILE_CONTEXT Context); NTSTATUS RsMarkUsn(IN PRP_FILE_CONTEXT Context); NTSTATUS RsOpenTarget(IN PRP_FILE_CONTEXT Context, IN ULONG OpenAccess, IN ULONG AdditionalAccess, OUT HANDLE *Handle, OUT PFILE_OBJECT *FileObject); ULONG RsIsNoRecall(IN PFILE_OBJECT fileObj, OUT PRP_DATA *rpData); NTSTATUS RsPartialData(IN PDEVICE_OBJECT DeviceObject, IN ULONGLONG filterId, IN NTSTATUS status, IN CHAR *buffer, IN ULONG bytesRead, IN ULONGLONG offset); NTSTATUS RsPartialWrite(IN PDEVICE_OBJECT DeviceObject, IN PRP_FILE_CONTEXT Context, IN CHAR *Buffer, IN ULONG BufLen, IN ULONGLONG Offset); NTSTATUS RsDoWrite(IN PDEVICE_OBJECT DeviceObject, IN PRP_FILE_CONTEXT Context); NTSTATUS RsQueueRecall(IN ULONGLONG filterId, IN ULONGLONG recallStart, IN ULONGLONG recallSize); NTSTATUS RsQueueNoRecall(IN PFILE_OBJECT FileObject, IN PIRP Irp, IN ULONGLONG RecallStart, IN ULONGLONG RecallSize, IN ULONG BufferOffset, IN ULONG BufferLength, IN PRP_FILE_BUF CacheBuffer, IN PVOID UserBuffer); NTSTATUS RsQueueNoRecallOpen(IN PRP_FILE_OBJ entry, IN ULONGLONG filterId, IN ULONGLONG offset, IN ULONGLONG size); NTSTATUS RsQueueRecallOpen(IN PRP_FILE_CONTEXT Context, IN PRP_FILE_OBJ Entry, IN ULONGLONG FilterId, IN ULONGLONG Offset, IN ULONGLONG Size, IN ULONG Command); NTSTATUS RsGetFileInfo(IN PRP_FILE_OBJ Entry, IN PDEVICE_OBJECT DeviceObject); NTSTATUS RsGetFileId(IN PRP_FILE_OBJ entry, IN PDEVICE_OBJECT DeviceObject); NTSTATUS RsGetFileName(IN PRP_FILE_OBJ entry, IN PDEVICE_OBJECT DeviceObject); NTSTATUS RsCloseFile(IN ULONGLONG filterId); NTSTATUS RsCleanupFileObject(IN ULONGLONG filterId); NTSTATUS RsCompleteIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context); NTSTATUS RsCheckRead(IN PIRP irp, IN PFILE_OBJECT fileObject, IN PDEVICE_EXTENSION deviceExtension); NTSTATUS RsCheckWrite(IN PIRP irp, IN PFILE_OBJECT fileObject, IN PDEVICE_EXTENSION deviceExtension); NTSTATUS RsFailAllRequests(IN PRP_FILE_CONTEXT Context, IN BOOLEAN Norecall); NTSTATUS RsCompleteAllRequests( IN PRP_FILE_CONTEXT Context, IN PRP_FILE_OBJ Entry, IN NTSTATUS Status ); NTSTATUS RsWriteReparsePointData(IN PRP_FILE_CONTEXT Context); NTSTATUS RsTruncateFile(IN PRP_FILE_CONTEXT Context); NTSTATUS RsSetEndOfFile(IN PRP_FILE_CONTEXT Context, IN ULONGLONG size); BOOLEAN RsIsFastIoPossible(IN PFILE_OBJECT fileObj); PIRP RsGetFsaRequest(VOID); PRP_FILE_OBJ RsFindQueue(IN ULONGLONG filterId); NTSTATUS RsAddIo(IN PIRP irp); PIRP RsRemoveIo(VOID); VOID RsCompleteRead(IN PRP_IRP_QUEUE Irp, IN BOOLEAN unlock); BOOLEAN RsIsFileObj(IN PFILE_OBJECT fileObj, IN BOOLEAN returnContextData, OUT PRP_DATA *rpData, OUT POBJECT_NAME_INFORMATION *str, OUT LONGLONG *fileId, OUT LONGLONG *objIdHi, OUT LONGLONG *objIdLo, OUT ULONG *options, OUT ULONGLONG *filterId, OUT USN *usn); VOID RsCancelRecalls(VOID); VOID RsCancelIo(VOID); VOID RsLogValidateNeeded(IN ULONG serial); BOOLEAN RsAddValidateObj(IN ULONG serial, IN LARGE_INTEGER cTime); BOOLEAN RsRemoveValidateObj(IN ULONG serial); NTSTATUS RsQueueValidate(IN ULONG serial); ULONG RsTerminate(VOID); NTSTATUS RsGetRecallInfo(IN OUT PRP_MSG Msg, OUT PULONG_PTR InfoSize, IN KPROCESSOR_MODE RequestorMode); VOID RsCancelReadRecall(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); VOID RsCancelWriteRecall(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); VOID RsLogError(IN ULONG line, IN ULONG file, IN ULONG code, IN NTSTATUS ioError, IN PIO_STACK_LOCATION irpSp, IN WCHAR *msgString); ULONG RsGetReparseData(IN PFILE_OBJECT fileObject, IN PDEVICE_OBJECT deviceObject, OUT PRP_DATA rpData); NTSTATUS RsCheckVolumeReadOnly (IN PDEVICE_OBJECT FilterDeviceObject, IN OUT PBOOLEAN pbReturnedFlagReadOnly); NTSTATUS RsQueryValueKey ( IN PUNICODE_STRING KeyName, IN PUNICODE_STRING ValueName, IN OUT PULONG ValueLength, IN OUT PKEY_VALUE_FULL_INFORMATION *KeyValueInformation, IN OUT PBOOLEAN DeallocateKeyValue); NTSTATUS RsCacheInitialize( VOID ); VOID RsCacheFsaPartialData( IN PRP_IRP_QUEUE ReadIo, IN PUCHAR Buffer, IN ULONGLONG Offset, IN ULONG Length, IN NTSTATUS Status ); VOID RsCacheFsaIoComplete( IN PRP_IRP_QUEUE ReadIo, IN NTSTATUS Status ); NTSTATUS RsGetNoRecallData( IN PFILE_OBJECT FileObject, IN PIRP Irp, IN USN Usn, IN LONGLONG FileOffset, IN LONGLONG Length, IN PUCHAR UserBuffer ); LONG RsExceptionFilter( IN WCHAR *FunctionName, IN PEXCEPTION_POINTERS ExceptionPointer); NTSTATUS RsTruncateOnClose( IN PRP_FILE_CONTEXT Context ); NTSTATUS RsSetPremigratedState(IN PRP_FILE_CONTEXT Context); NTSTATUS RsDeleteReparsePoint(IN PRP_FILE_CONTEXT Context); NTSTATUS RsSetResetAttributes(IN PFILE_OBJECT FileObject, IN ULONG SetAttributes, IN ULONG ResetAttributes); BOOLEAN RsSetCancelRoutine(IN PIRP Irp, IN PDRIVER_CANCEL CancelRoutine); BOOLEAN RsClearCancelRoutine ( IN PIRP Irp ); NTSTATUS RsGetFileUsn(IN PRP_FILE_CONTEXT Context, IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT FilterDeviceObject); VOID RsInterlockedRemoveEntryList(PLIST_ENTRY Entry, PKSPIN_LOCK Lock); VOID RsGetUserInfo( IN PSECURITY_SUBJECT_CONTEXT SubjectContext, OUT PRP_USER_SECURITY_INFO UserSecurityInfo); typedef enum _RpModuleCode { ModRpFilter = 100 ,ModRpFilfun ,ModRpCache ,ModRpzw ,ModRpSec } RpModuleCode; typedef struct _RP_TRACE_ENTRY { RpModuleCode ModuleCode; USHORT usLineNumber; USHORT usIrql; LARGE_INTEGER Timestamp; ULONG_PTR Value1; ULONG_PTR Value2; ULONG_PTR Value3; ULONG_PTR Value4; } RP_TRACE_ENTRY, *PRP_TRACE_ENTRY; typedef struct _RP_TRACE_CONTROL_BLOCK { KSPIN_LOCK Lock; PRP_TRACE_ENTRY EntryBuffer; ULONG EntryMaximum; ULONG EntryNext; } RP_TRACE_CONTROL_BLOCK, *PRP_TRACE_CONTROL_BLOCK; #define RsTrace0(_ModuleCode) RsTrace4 ((_ModuleCode), 0, 0, 0, 0) #define RsTrace1(_ModuleCode, _Value1) RsTrace4 ((_ModuleCode), (_Value1), 0, 0, 0) #define RsTrace2(_ModuleCode, _Value1, _Value2) RsTrace4 ((_ModuleCode), (_Value1), (_Value2), 0, 0) #define RsTrace3(_ModuleCode, _Value1, _Value2, _Value3) RsTrace4 ((_ModuleCode), (_Value1), (_Value2), (_Value3), 0) #if DBG #define RsTrace4(_ModuleCode, _Value1, _Value2, _Value3, _Value4) RsTraceAddEntry ((_ModuleCode), \ ((USHORT)(__LINE__)), \ ((ULONG_PTR)(_Value1)), \ ((ULONG_PTR)(_Value2)), \ ((ULONG_PTR)(_Value3)), \ ((ULONG_PTR)(_Value4))) #else #define RsTrace4(_ModuleCode, _Value1, _Value2, _Value3, _Value4) #endif #if DBG #define DEFAULT_TRACE_ENTRIES (0x4000) #else #define DEFAULT_TRACE_ENTRIES (0) #endif VOID RsTraceAddEntry (RpModuleCode ModuleCode, USHORT usLineNumber, ULONG_PTR Value1, ULONG_PTR Value2, ULONG_PTR Value3, ULONG_PTR Value4); NTSTATUS RsTraceInitialize (ULONG ulRequestedTraceEntries); extern PRP_TRACE_CONTROL_BLOCK RsTraceControlBlock; extern ULONG RsDefaultTraceEntries; NTSTATUS RsLookupContext (PFILE_OBJECT pFileObject, PRP_FILE_OBJ *pReturnedRpFileObject, PRP_FILE_CONTEXT *pReturnedRpFileContext);